Bug Summary

File:Tree.c
Location:line 875, column 11
Description:Dereference of null pointer

Annotated Source Code

1/*
2
3Copyright (c) 1990, 1994 X Consortium
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of the X Consortium shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from the X Consortium.
25
26 * Copyright 1989 Prentice Hall
27 *
28 * Permission to use, copy, modify, and distribute this software for any
29 * purpose and without fee is hereby granted, provided that the above
30 * copyright notice appear in all copies and that both the copyright notice
31 * and this permission notice appear in supporting documentation.
32 *
33 * Prentice Hall and the authors disclaim all warranties with regard
34 * to this software, including all implied warranties of merchantability and
35 * fitness. In no event shall Prentice Hall or the authors be liable
36 * for any special, indirect or cosequential damages or any damages whatsoever
37 * resulting from loss of use, data or profits, whether in an action of
38 * contract, negligence or other tortious action, arising out of or in
39 * connection with the use or performance of this software.
40 *
41 * Authors: Jim Fulton, MIT X Consortium,
42 * based on a version by Douglas Young, Prentice Hall
43 *
44 * This widget is based on the Tree widget described on pages 397-419 of
45 * Douglas Young's book "The X Window System, Programming and Applications
46 * with Xt OSF/Motif Edition." The layout code has been rewritten to use
47 * additional blank space to make the structure of the graph easier to see
48 * as well as to support vertical trees.
49 */
50
51#ifdef HAVE_CONFIG_H1
52#include "config.h"
53#endif
54#include <X11/IntrinsicP.h>
55#include <X11/StringDefs.h>
56#include <X11/Xaw3d/XawInit.h>
57#include <X11/Xaw3d/Cardinals.h>
58#include <X11/Xaw3d/TreeP.h>
59
60#define IsHorizontal(tw)((tw)->tree.gravity == 4 || (tw)->tree.gravity == 6) ((tw)->tree.gravity == WestGravity4 || \
61 (tw)->tree.gravity == EastGravity6)
62
63
64 /* widget class method */
65static void ClassInitialize(void);
66static void Initialize(Widget, Widget, ArgList, Cardinal *);
67static void ConstraintInitialize(Widget, Widget, ArgList, Cardinal *);
68static void ConstraintDestroy(Widget);
69static Boolean ConstraintSetValues(Widget, Widget, Widget, ArgList, Cardinal *);
70static void Destroy(Widget);
71static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
72static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *, XtWidgetGeometry *);
73static void ChangeManaged(Widget);
74static void Redisplay(Widget, XEvent *, Region);
75static XtGeometryResult QueryGeometry(Widget, XtWidgetGeometry *, XtWidgetGeometry *);
76
77 /* utility routines */
78static void insert_node(Widget, Widget);
79static void delete_node(Widget, Widget);
80static void layout_tree(TreeWidget, Boolean);
81
82
83/*
84 * resources of the tree itself
85 */
86static XtResource resources[] = {
87 { XtNautoReconfigure"autoReconfigure", XtCAutoReconfigure"AutoReconfigure", XtRBoolean((char*)&XtStrings[1561]), sizeof (Boolean),
88 XtOffsetOf(TreeRec, tree.auto_reconfigure)__builtin_offsetof(TreeRec, tree.auto_reconfigure), XtRImmediate((char*)&XtStrings[1695]),
89 (XtPointer) FALSE0 },
90 { XtNhSpace((char*)&XtStrings[251]), XtCHSpace((char*)&XtStrings[1058]), XtRDimension((char*)&XtStrings[1618]), sizeof (Dimension),
91 XtOffsetOf(TreeRec, tree.hpad)__builtin_offsetof(TreeRec, tree.hpad), XtRImmediate((char*)&XtStrings[1695]), (XtPointer) 0 },
92 { XtNvSpace((char*)&XtStrings[865]), XtCVSpace((char*)&XtStrings[1503]), XtRDimension((char*)&XtStrings[1618]), sizeof (Dimension),
93 XtOffsetOf(TreeRec, tree.vpad)__builtin_offsetof(TreeRec, tree.vpad), XtRImmediate((char*)&XtStrings[1695]), (XtPointer) 0 },
94 { XtNforeground((char*)&XtStrings[214]), XtCForeground((char*)&XtStrings[1022]), XtRPixel((char*)&XtStrings[1754]), sizeof (Pixel),
95 XtOffsetOf(TreeRec, tree.foreground)__builtin_offsetof(TreeRec, tree.foreground), XtRString((char*)&XtStrings[1797]),
96 XtDefaultForeground"XtDefaultForeground"},
97 { XtNlineWidth"lineWidth", XtCLineWidth"LineWidth", XtRDimension((char*)&XtStrings[1618]), sizeof (Dimension),
98 XtOffsetOf(TreeRec, tree.line_width)__builtin_offsetof(TreeRec, tree.line_width), XtRImmediate((char*)&XtStrings[1695]), (XtPointer) 0 },
99 { XtNgravity"gravity", XtCGravity"Gravity", XtRGravity((char*)&XtStrings[2042]), sizeof (XtGravity),
100 XtOffsetOf(TreeRec, tree.gravity)__builtin_offsetof(TreeRec, tree.gravity), XtRImmediate((char*)&XtStrings[1695]),
101 (XtPointer) WestGravity4 },
102};
103
104
105/*
106 * resources that are attached to all children of the tree
107 */
108static XtResource treeConstraintResources[] = {
109 { XtNtreeParent"treeParent", XtCTreeParent"TreeParent", XtRWidget((char*)&XtStrings[1865]), sizeof (Widget),
110 XtOffsetOf(TreeConstraintsRec, tree.parent)__builtin_offsetof(TreeConstraintsRec, tree.parent), XtRImmediate((char*)&XtStrings[1695]), NULL((void*)0) },
111 { XtNtreeGC"treeGC", XtCTreeGC"TreeGC", XtRGC"GC", sizeof(GC),
112 XtOffsetOf(TreeConstraintsRec, tree.gc)__builtin_offsetof(TreeConstraintsRec, tree.gc), XtRImmediate((char*)&XtStrings[1695]), NULL((void*)0) },
113};
114
115
116TreeClassRec treeClassRec = {
117 {
118 /* core_class fields */
119 (WidgetClass) &constraintClassRec, /* superclass */
120 "Tree", /* class_name */
121 sizeof(TreeRec), /* widget_size */
122 ClassInitialize, /* class_init */
123 NULL((void*)0), /* class_part_init */
124 FALSE0, /* class_inited */
125 Initialize, /* initialize */
126 NULL((void*)0), /* initialize_hook */
127 XtInheritRealize((XtRealizeProc) _XtInherit), /* realize */
128 NULL((void*)0), /* actions */
129 0, /* num_actions */
130 resources, /* resources */
131 XtNumber(resources)((Cardinal) (sizeof(resources) / sizeof(resources[0]))), /* num_resources */
132 NULLQUARK((XrmQuark) 0), /* xrm_class */
133 TRUE1, /* compress_motion */
134 TRUE1, /* compress_exposure */
135 TRUE1, /* compress_enterleave*/
136 TRUE1, /* visible_interest */
137 Destroy, /* destroy */
138 NULL((void*)0), /* resize */
139 Redisplay, /* expose */
140 SetValues, /* set_values */
141 NULL((void*)0), /* set_values_hook */
142 XtInheritSetValuesAlmost((XtAlmostProc) _XtInherit), /* set_values_almost */
143 NULL((void*)0), /* get_values_hook */
144 NULL((void*)0), /* accept_focus */
145 XtVersion(11 * 1000 + 6), /* version */
146 NULL((void*)0), /* callback_private */
147 NULL((void*)0), /* tm_table */
148 QueryGeometry, /* query_geometry */
149 NULL((void*)0), /* display_accelerator*/
150 NULL((void*)0), /* extension */
151 },
152 {
153 /* composite_class fields */
154 GeometryManager, /* geometry_manager */
155 ChangeManaged, /* change_managed */
156 XtInheritInsertChild((XtWidgetProc) _XtInherit), /* insert_child */
157 XtInheritDeleteChild((XtWidgetProc) _XtInherit), /* delete_child */
158 NULL((void*)0), /* extension */
159 },
160 {
161 /* constraint_class fields */
162 treeConstraintResources, /* subresources */
163 XtNumber(treeConstraintResources)((Cardinal) (sizeof(treeConstraintResources) / sizeof(treeConstraintResources
[0])))
, /* subresource_count */
164 sizeof(TreeConstraintsRec), /* constraint_size */
165 ConstraintInitialize, /* initialize */
166 ConstraintDestroy, /* destroy */
167 ConstraintSetValues, /* set_values */
168 NULL((void*)0), /* extension */
169 },
170 {
171 /* Tree class fields */
172 0, /* ignore */
173 }
174};
175
176WidgetClass treeWidgetClass = (WidgetClass) &treeClassRec;
177
178
179/*****************************************************************************
180 * *
181 * tree utility routines *
182 * *
183 *****************************************************************************/
184
185static void
186initialize_dimensions (Dimension **listp, int *sizep, int n)
187{
188 int i;
189 Dimension *l;
190
191 if (!*listp) {
192 *listp = (Dimension *) XtCalloc ((unsigned int) n,
193 (unsigned int) sizeof(Dimension));
194 *sizep = ((*listp) ? n : 0);
195 return;
196 }
197 if (n > *sizep) {
198 *listp = (Dimension *) XtRealloc((char *) *listp,
199 (unsigned int) (n*sizeof(Dimension)));
200 if (!*listp) {
201 *sizep = 0;
202 return;
203 }
204 for (i = *sizep, l = (*listp) + i; i < n; i++, l++) *l = 0;
205 *sizep = n;
206 }
207 return;
208}
209
210static GC
211get_tree_gc (TreeWidget w)
212{
213 XtGCMask valuemask = GCBackground(1L<<3) | GCForeground(1L<<2);
214 XGCValues values;
215
216 values.background = w->core.background_pixel;
217 values.foreground = w->tree.foreground;
218 if (w->tree.line_width != 0) {
219 valuemask |= GCLineWidth(1L<<4);
220 values.line_width = w->tree.line_width;
221 }
222
223 return XtGetGC ((Widget) w, valuemask, &values);
224}
225
226static void
227insert_node (Widget parent, Widget node)
228{
229 TreeConstraints pc;
230 TreeConstraints nc = TREE_CONSTRAINT(node)((TreeConstraints)((node)->core.constraints));
231 int nindex;
232
233 nc->tree.parent = parent;
234
235 if (parent == NULL((void*)0)) return;
236
237 /*
238 * If there isn't more room in the children array,
239 * allocate additional space.
240 */
241 pc = TREE_CONSTRAINT(parent)((TreeConstraints)((parent)->core.constraints));
242 nindex = pc->tree.n_children;
243
244 if (pc->tree.n_children == pc->tree.max_children) {
245 pc->tree.max_children += (pc->tree.max_children / 2) + 2;
246 pc->tree.children = (WidgetList) XtRealloc ((char *)pc->tree.children,
247 (unsigned int)
248 ((pc->tree.max_children) *
249 sizeof(Widget)));
250 }
251
252 /*
253 * Add the sub_node in the next available slot and
254 * increment the counter.
255 */
256 pc->tree.children[nindex] = node;
257 pc->tree.n_children++;
258}
259
260static void
261delete_node (Widget parent, Widget node)
262{
263 TreeConstraints pc;
264 int pos, i;
265
266 /*
267 * Make sure the parent exists.
268 */
269 if (!parent) return;
270
271 pc = TREE_CONSTRAINT(parent)((TreeConstraints)((parent)->core.constraints));
272
273 /*
274 * Find the sub_node on its parent's list.
275 */
276 for (pos = 0; pos < pc->tree.n_children; pos++)
277 if (pc->tree.children[pos] == node) break;
278
279 if (pos == pc->tree.n_children) return;
280
281 /*
282 * Decrement the number of children
283 */
284 pc->tree.n_children--;
285
286 /*
287 * Fill in the gap left by the sub_node.
288 * Zero the last slot for good luck.
289 */
290 for (i = pos; i < pc->tree.n_children; i++)
291 pc->tree.children[i] = pc->tree.children[i+1];
292
293 pc->tree.children[pc->tree.n_children]=0;
294}
295
296static void
297check_gravity (TreeWidget tw, XtGravity grav)
298{
299 switch (tw->tree.gravity) {
300 case WestGravity4: case NorthGravity2: case EastGravity6: case SouthGravity8:
301 break;
302 default:
303 tw->tree.gravity = grav;
304 break;
305 }
306}
307
308
309/*****************************************************************************
310 * *
311 * tree class methods *
312 * *
313 *****************************************************************************/
314
315static void
316ClassInitialize (void)
317{
318 XawInitializeWidgetSet();
319 XtAddConverter (XtRString((char*)&XtStrings[1797]), XtRGravity((char*)&XtStrings[2042]), XmuCvtStringToGravity,
320 (XtConvertArgList) NULL((void*)0), (Cardinal) 0);
321}
322
323
324/*ARGSUSED*/
325static void
326Initialize (Widget grequest, Widget gnew, ArgList args, Cardinal *num_args)
327{
328 TreeWidget request = (TreeWidget) grequest, new = (TreeWidget) gnew;
329 Arg arglist[2];
330
331 /*
332 * Make sure the widget's width and height are
333 * greater than zero.
334 */
335 if (request->core.width <= 0) new->core.width = 5;
336 if (request->core.height <= 0) new->core.height = 5;
337
338 /*
339 * Set the padding according to the orientation
340 */
341 if (request->tree.hpad == 0 && request->tree.vpad == 0) {
342 if (IsHorizontal (request)((request)->tree.gravity == 4 || (request)->tree.gravity
== 6)
) {
343 new->tree.hpad = TREE_HORIZONTAL_DEFAULT_SPACING20;
344 new->tree.vpad = TREE_VERTICAL_DEFAULT_SPACING6;
345 } else {
346 new->tree.hpad = TREE_VERTICAL_DEFAULT_SPACING6;
347 new->tree.vpad = TREE_HORIZONTAL_DEFAULT_SPACING20;
348 }
349 }
350
351 /*
352 * Create a graphics context for the connecting lines.
353 */
354 new->tree.gc = get_tree_gc (new);
355
356 /*
357 * Create the hidden root widget.
358 */
359 new->tree.tree_root = (Widget) NULL((void*)0);
360 XtSetArg(arglist[0], XtNwidth, 1)((void)( (arglist[0]).name = (((char*)&XtStrings[872])), (
arglist[0]).value = (XtArgVal)(1) ))
;
361 XtSetArg(arglist[1], XtNheight, 1)((void)( (arglist[1]).name = (((char*)&XtStrings[234])), (
arglist[1]).value = (XtArgVal)(1) ))
;
362 new->tree.tree_root = XtCreateWidget ("root", widgetClass, gnew,
363 arglist,TWO((Cardinal)2));
364
365 /*
366 * Allocate the array used to hold the widest values per depth
367 */
368 new->tree.largest = NULL((void*)0);
369 new->tree.n_largest = 0;
370 initialize_dimensions (&new->tree.largest, &new->tree.n_largest,
371 TREE_INITIAL_DEPTH10);
372
373 /*
374 * make sure that our gravity is one of the acceptable values
375 */
376 check_gravity (new, WestGravity4);
377}
378
379
380/* ARGSUSED */
381static void
382ConstraintInitialize (Widget request, Widget new, ArgList args, Cardinal *num_args)
383{
384 TreeConstraints tc = TREE_CONSTRAINT(new)((TreeConstraints)((new)->core.constraints));
385 TreeWidget tw = (TreeWidget) new->core.parent;
386
387 /*
388 * Initialize the widget to have no sub-nodes.
389 */
390 tc->tree.n_children = 0;
391 tc->tree.max_children = 0;
392 tc->tree.children = (Widget *) NULL((void*)0);
393 tc->tree.x = tc->tree.y = 0;
394 tc->tree.bbsubwidth = 0;
395 tc->tree.bbsubheight = 0;
396
397
398 /*
399 * If this widget has a super-node, add it to that
400 * widget' sub-nodes list. Otherwise make it a sub-node of
401 * the tree_root widget.
402 */
403 if (tc->tree.parent)
404 insert_node (tc->tree.parent, new);
405 else if (tw->tree.tree_root)
406 insert_node (tw->tree.tree_root, new);
407}
408
409
410/* ARGSUSED */
411static Boolean
412SetValues (Widget gcurrent, Widget grequest, Widget gnew, ArgList args, Cardinal *num_args)
413{
414 TreeWidget current = (TreeWidget) gcurrent, new = (TreeWidget) gnew;
415 Boolean redraw = FALSE0;
416
417 /*
418 * If the foreground color has changed, redo the GC's
419 * and indicate a redraw.
420 */
421 if (new->tree.foreground != current->tree.foreground ||
422 new->core.background_pixel != current->core.background_pixel ||
423 new->tree.line_width != current->tree.line_width) {
424 XtReleaseGC (gnew, new->tree.gc);
425 new->tree.gc = get_tree_gc (new);
426 redraw = TRUE1;
427 }
428
429 /*
430 * If the minimum spacing has changed, recalculate the
431 * tree layout. layout_tree() does a redraw, so we don't
432 * need SetValues to do another one.
433 */
434 if (new->tree.gravity != current->tree.gravity) {
435 check_gravity (new, current->tree.gravity);
436 }
437
438 if (IsHorizontal(new)((new)->tree.gravity == 4 || (new)->tree.gravity == 6) != IsHorizontal(current)((current)->tree.gravity == 4 || (current)->tree.gravity
== 6)
) {
439 if (new->tree.vpad == current->tree.vpad &&
440 new->tree.hpad == current->tree.hpad) {
441 new->tree.vpad = current->tree.hpad;
442 new->tree.hpad = current->tree.vpad;
443 }
444 }
445
446 if (new->tree.vpad != current->tree.vpad ||
447 new->tree.hpad != current->tree.hpad ||
448 new->tree.gravity != current->tree.gravity) {
449 layout_tree (new, TRUE1);
450 redraw = FALSE0;
451 }
452 return redraw;
453}
454
455
456/* ARGSUSED */
457static Boolean
458ConstraintSetValues (Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args)
459{
460 TreeConstraints newc = TREE_CONSTRAINT(new)((TreeConstraints)((new)->core.constraints));
461 TreeConstraints curc = TREE_CONSTRAINT(current)((TreeConstraints)((current)->core.constraints));
462 TreeWidget tw = (TreeWidget) new->core.parent;
463
464 /*
465 * If the parent field has changed, remove the widget
466 * from the old widget's children list and add it to the
467 * new one.
468 */
469 if (curc->tree.parent != newc->tree.parent){
470 if (curc->tree.parent)
471 delete_node (curc->tree.parent, new);
472 if (newc->tree.parent)
473 insert_node(newc->tree.parent, new);
474
475 /*
476 * If the Tree widget has been realized,
477 * compute new layout.
478 */
479 if (XtIsRealized((Widget)tw)(XtWindowOfObject((Widget)tw) != 0L))
480 layout_tree (tw, FALSE0);
481 }
482 return False0;
483}
484
485
486static void
487ConstraintDestroy (Widget w)
488{
489 TreeConstraints tc = TREE_CONSTRAINT(w)((TreeConstraints)((w)->core.constraints));
490 TreeWidget tw = (TreeWidget) XtParent(w)((w)->core.parent);
491 int i;
492
493 /*
494 * Remove the widget from its parent's sub-nodes list and
495 * make all this widget's sub-nodes sub-nodes of the parent.
496 */
497
498 if (tw->tree.tree_root == w) {
499 if (tc->tree.n_children > 0)
500 tw->tree.tree_root = tc->tree.children[0];
501 else
502 tw->tree.tree_root = NULL((void*)0);
503 }
504
505 delete_node (tc->tree.parent, (Widget) w);
506 for (i = 0; i< tc->tree.n_children; i++)
507 insert_node (tc->tree.parent, tc->tree.children[i]);
508
509 layout_tree ((TreeWidget) (w->core.parent), FALSE0);
510}
511
512/* ARGSUSED */
513static XtGeometryResult
514GeometryManager (Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
515{
516
517 TreeWidget tw = (TreeWidget) w->core.parent;
518
519 /*
520 * No position changes allowed!.
521 */
522 if ((request->request_mode & CWX(1<<0) && request->x!=w->core.x)
523 ||(request->request_mode & CWY(1<<1) && request->y!=w->core.y))
524 return (XtGeometryNo);
525
526 /*
527 * Allow all resize requests.
528 */
529
530 if (request->request_mode & CWWidth(1<<2))
531 w->core.width = request->width;
532 if (request->request_mode & CWHeight(1<<3))
533 w->core.height = request->height;
534 if (request->request_mode & CWBorderWidth(1<<4))
535 w->core.border_width = request->border_width;
536
537 if (tw->tree.auto_reconfigure) layout_tree (tw, FALSE0);
538 return (XtGeometryYes);
539}
540
541static void
542ChangeManaged (Widget gw)
543{
544 layout_tree ((TreeWidget) gw, FALSE0);
1
Calling 'layout_tree'
545}
546
547
548static void
549Destroy (Widget gw)
550{
551 TreeWidget w = (TreeWidget) gw;
552
553 XtReleaseGC (gw, w->tree.gc);
554 if (w->tree.largest) XtFree ((char *) w->tree.largest);
555}
556
557
558/* ARGSUSED */
559static void
560Redisplay (Widget gw, XEvent *event, Region region)
561{
562 TreeWidget tw = (TreeWidget) gw;
563
564 /*
565 * If the Tree widget is visible, visit each managed child.
566 */
567 if (tw->core.visible) {
568 int i, j;
569 Display *dpy = XtDisplay (tw)(((tw)->core.screen)->display);
570 Window w = XtWindow (tw)((tw)->core.window);
571
572 for (i = 0; i < tw->composite.num_children; i++) {
573 Widget child = tw->composite.children[i];
574 TreeConstraints tc = TREE_CONSTRAINT(child)((TreeConstraints)((child)->core.constraints));
575
576 /*
577 * Don't draw lines from the fake tree_root.
578 */
579 if (child != tw->tree.tree_root && tc->tree.n_children) {
580 int srcx = child->core.x + child->core.border_width;
581 int srcy = child->core.y + child->core.border_width;
582
583 switch (tw->tree.gravity) {
584 case WestGravity4:
585 srcx += child->core.width + child->core.border_width;
586 /* fall through */
587 case EastGravity6:
588 srcy += child->core.height / 2;
589 break;
590
591 case NorthGravity2:
592 srcy += child->core.height + child->core.border_width;
593 /* fall through */
594 case SouthGravity8:
595 srcx += child->core.width / 2;
596 break;
597 }
598
599 for (j = 0; j < tc->tree.n_children; j++) {
600 Widget k = tc->tree.children[j];
601 GC gc = (tc->tree.gc ? tc->tree.gc : tw->tree.gc);
602
603 switch (tw->tree.gravity) {
604 case WestGravity4:
605 /*
606 * right center to left center
607 */
608 XDrawLine (dpy, w, gc, srcx, srcy,
609 (int) k->core.x,
610 (k->core.y + ((int) k->core.border_width) +
611 ((int) k->core.height) / 2));
612 break;
613
614 case NorthGravity2:
615 /*
616 * bottom center to top center
617 */
618 XDrawLine (dpy, w, gc, srcx, srcy,
619 (k->core.x + ((int) k->core.border_width) +
620 ((int) k->core.width) / 2),
621 (int) k->core.y);
622 break;
623
624 case EastGravity6:
625 /*
626 * left center to right center
627 */
628 XDrawLine (dpy, w, gc, srcx, srcy,
629 (k->core.x +
630 (((int) k->core.border_width) << 1) +
631 (int) k->core.width),
632 (k->core.y + ((int) k->core.border_width) +
633 ((int) k->core.height) / 2));
634 break;
635
636 case SouthGravity8:
637 /*
638 * top center to bottom center
639 */
640 XDrawLine (dpy, w, gc, srcx, srcy,
641 (k->core.x + ((int) k->core.border_width) +
642 ((int) k->core.width) / 2),
643 (k->core.y +
644 (((int) k->core.border_width) << 1) +
645 (int) k->core.height));
646 break;
647 }
648 }
649 }
650 }
651 }
652}
653
654static XtGeometryResult
655QueryGeometry (Widget w, XtWidgetGeometry *intended, XtWidgetGeometry *preferred)
656{
657 TreeWidget tw = (TreeWidget) w;
658
659 preferred->request_mode = (CWWidth(1<<2) | CWHeight(1<<3));
660 preferred->width = tw->tree.maxwidth;
661 preferred->height = tw->tree.maxheight;
662
663 if (((intended->request_mode & (CWWidth(1<<2) | CWHeight(1<<3))) ==
664 (CWWidth(1<<2) | CWHeight(1<<3))) &&
665 intended->width == preferred->width &&
666 intended->height == preferred->height)
667 return XtGeometryYes;
668 else if (preferred->width == w->core.width &&
669 preferred->height == w->core.height)
670 return XtGeometryNo;
671 else
672 return XtGeometryAlmost;
673}
674
675
676/*****************************************************************************
677 * *
678 * tree layout algorithm *
679 * *
680 * Each node in the tree is "shrink-wrapped" with a minimal bounding *
681 * rectangle, laid next to its siblings (with a small about of padding in *
682 * between) and then wrapped with their parent. Parents are centered about *
683 * their children (or vice versa if the parent is larger than the children). *
684 * *
685 *****************************************************************************/
686
687static void
688compute_bounding_box_subtree (TreeWidget tree, Widget w, int depth)
689{
690 TreeConstraints tc = TREE_CONSTRAINT(w)((TreeConstraints)((w)->core.constraints)); /* info attached to all kids */
691 int i;
692 Boolint horiz = IsHorizontal (tree)((tree)->tree.gravity == 4 || (tree)->tree.gravity == 6
)
;
693 Dimension newwidth, newheight;
694 Dimension bw2 = w->core.border_width * 2;
695
696 /*
697 * Set the max-size per level.
698 */
699 if (depth >= tree->tree.n_largest) {
700 initialize_dimensions (&tree->tree.largest,
701 &tree->tree.n_largest, depth + 1);
702 }
703 newwidth = ((horiz ? w->core.width : w->core.height) + bw2);
704 if (tree->tree.largest[depth] < newwidth)
705 tree->tree.largest[depth] = newwidth;
706
707
708 /*
709 * initialize
710 */
711 tc->tree.bbwidth = w->core.width + bw2;
712 tc->tree.bbheight = w->core.height + bw2;
713
714 if (tc->tree.n_children == 0) return;
715
716 /*
717 * Figure the size of the opposite dimension (vertical if tree is
718 * horizontal, else vice versa). The other dimension will be set
719 * in the second pass once we know the maximum dimensions.
720 */
721 newwidth = 0;
722 newheight = 0;
723 for (i = 0; i < tc->tree.n_children; i++) {
724 Widget child = tc->tree.children[i];
725 TreeConstraints cc = TREE_CONSTRAINT(child)((TreeConstraints)((child)->core.constraints));
726
727 compute_bounding_box_subtree (tree, child, depth + 1);
728
729 if (horiz) {
730 if (newwidth < cc->tree.bbwidth) newwidth = cc->tree.bbwidth;
731 newheight += tree->tree.vpad + cc->tree.bbheight;
732 } else {
733 if (newheight < cc->tree.bbheight) newheight = cc->tree.bbheight;
734 newwidth += tree->tree.hpad + cc->tree.bbwidth;
735 }
736 }
737
738
739 tc->tree.bbsubwidth = newwidth;
740 tc->tree.bbsubheight = newheight;
741
742 /*
743 * Now fit parent onto side (or top) of bounding box and correct for
744 * extra padding. Be careful of unsigned arithmetic.
745 */
746 if (horiz) {
747 tc->tree.bbwidth += tree->tree.hpad + newwidth;
748 newheight -= tree->tree.vpad;
749 if (newheight > tc->tree.bbheight) tc->tree.bbheight = newheight;
750 } else {
751 tc->tree.bbheight += tree->tree.vpad + newheight;
752 newwidth -= tree->tree.hpad;
753 if (newwidth > tc->tree.bbwidth) tc->tree.bbwidth = newwidth;
754 }
755}
756
757
758static void
759set_positions (TreeWidget tw, Widget w, int level)
760{
761 int i;
762
763 if (w) {
764 TreeConstraints tc = TREE_CONSTRAINT(w)((TreeConstraints)((w)->core.constraints));
765
766 if (level > 0) {
767 /*
768 * mirror if necessary
769 */
770 switch (tw->tree.gravity) {
771 case EastGravity6:
772 tc->tree.x = (((Position) tw->tree.maxwidth) -
773 ((Position) w->core.width) - tc->tree.x);
774 break;
775
776 case SouthGravity8:
777 tc->tree.y = (((Position) tw->tree.maxheight) -
778 ((Position) w->core.height) - tc->tree.y);
779 break;
780 }
781
782 /*
783 * Move the widget into position.
784 */
785 XtMoveWidget (w, tc->tree.x, tc->tree.y);
786 }
787
788 /*
789 * Set the positions of all children.
790 */
791 for (i = 0; i < tc->tree.n_children; i++)
792 set_positions (tw, tc->tree.children[i], level + 1);
793 }
794}
795
796
797static void
798arrange_subtree (TreeWidget tree, Widget w, int depth, Position x, Position y)
799{
800 TreeConstraints tc = TREE_CONSTRAINT(w)((TreeConstraints)((w)->core.constraints)); /* info attached to all kids */
801 TreeConstraints firstcc, lastcc;
802 int i;
803 int newx, newy;
804 Boolint horiz = IsHorizontal (tree)((tree)->tree.gravity == 4 || (tree)->tree.gravity == 6
)
;
805 Widget child = NULL((void*)0);
5
'child' initialized to a null pointer value
806 Dimension tmp;
807 Dimension bw2 = w->core.border_width * 2;
808 Boolint relayout = True1;
809
810
811 /*
812 * If no children, then just lay out where requested.
813 */
814 tc->tree.x = x;
815 tc->tree.y = y;
816
817 if (horiz) {
6
Taking false branch
818 int myh = (w->core.height + bw2);
819
820 if (myh > (int)tc->tree.bbsubheight) {
821 y += (myh - (int)tc->tree.bbsubheight) / 2;
822 relayout = False0;
823 }
824 } else {
825 int myw = (w->core.width + bw2);
826
827 if (myw > (int)tc->tree.bbsubwidth) {
7
Taking false branch
828 x += (myw - (int)tc->tree.bbsubwidth) / 2;
829 relayout = False0;
830 }
831 }
832
833 if ((tmp = ((Dimension) x) + tc->tree.bbwidth) > tree->tree.maxwidth)
8
Taking false branch
834 tree->tree.maxwidth = tmp;
835 if ((tmp = ((Dimension) y) + tc->tree.bbheight) > tree->tree.maxheight)
9
Taking false branch
836 tree->tree.maxheight = tmp;
837
838 if (tc->tree.n_children == 0) return;
10
Taking false branch
839
840
841 /*
842 * Have children, so walk down tree laying out children, then laying
843 * out parents.
844 */
845 if (horiz) {
11
Taking false branch
846 newx = x + tree->tree.largest[depth];
847 if (depth > 0) newx += tree->tree.hpad;
848 newy = y;
849 } else {
850 newx = x;
851 newy = y + tree->tree.largest[depth];
852 if (depth > 0) newy += tree->tree.vpad;
12
Taking false branch
853 }
854
855 for (i = 0; i < tc->tree.n_children; i++) {
13
Loop condition is false. Execution continues on line 872
856 TreeConstraints cc;
857
858 child = tc->tree.children[i]; /* last value is used outside loop */
859 cc = TREE_CONSTRAINT(child)((TreeConstraints)((child)->core.constraints));
860
861 arrange_subtree (tree, child, depth + 1, newx, newy);
862 if (horiz) {
863 newy += tree->tree.vpad + cc->tree.bbheight;
864 } else {
865 newx += tree->tree.hpad + cc->tree.bbwidth;
866 }
867 }
868
869 /*
870 * now layout parent between first and last children
871 */
872 if (relayout) {
14
Taking true branch
873 Position adjusted;
874 firstcc = TREE_CONSTRAINT (tc->tree.children[0])((TreeConstraints)((tc->tree.children[0])->core.constraints
))
;
875 lastcc = TREE_CONSTRAINT (child)((TreeConstraints)((child)->core.constraints));
15
Within the expansion of the macro 'TREE_CONSTRAINT':
a
Dereference of null pointer
876
877 /* Adjustments are disallowed if they result in a position above
878 * or to the left of the originally requested position, because
879 * this could collide with the position of the previous sibling.
880 */
881 if (horiz) {
882 tc->tree.x = x;
883 adjusted = firstcc->tree.y +
884 ((lastcc->tree.y + (Position) child->core.height +
885 (Position) child->core.border_width * 2 -
886 firstcc->tree.y - (Position) w->core.height -
887 (Position) w->core.border_width * 2 + 1) / 2);
888 if (adjusted > tc->tree.y) tc->tree.y = adjusted;
889 } else {
890 adjusted = firstcc->tree.x +
891 ((lastcc->tree.x + (Position) child->core.width +
892 (Position) child->core.border_width * 2 -
893 firstcc->tree.x - (Position) w->core.width -
894 (Position) w->core.border_width * 2 + 1) / 2);
895 if (adjusted > tc->tree.x) tc->tree.x = adjusted;
896 tc->tree.y = y;
897 }
898 }
899}
900
901static void
902set_tree_size (TreeWidget tw, Boolean insetvalues, Dimension width, Dimension height)
903{
904 if (insetvalues) {
905 tw->core.width = width;
906 tw->core.height = height;
907 } else {
908 Dimension replyWidth = 0, replyHeight = 0;
909 XtGeometryResult result = XtMakeResizeRequest ((Widget) tw,
910 width, height,
911 &replyWidth,
912 &replyHeight);
913 /*
914 * Accept any compromise.
915 */
916 if (result == XtGeometryAlmost)
917 XtMakeResizeRequest ((Widget) tw, replyWidth, replyHeight,
918 (Dimension *) NULL((void*)0), (Dimension *) NULL((void*)0));
919 }
920 return;
921}
922
923static void
924layout_tree (TreeWidget tw, Boolean insetvalues)
925{
926 int i;
927 Dimension *dp;
928
929 /*
930 * Do a depth-first search computing the width and height of the bounding
931 * box for the tree at that position (and below). Then, walk again using
932 * this information to layout the children at each level.
933 */
934
935 if (tw->tree.tree_root == NULL((void*)0))
2
Taking false branch
936 return;
937
938 tw->tree.maxwidth = tw->tree.maxheight = 0;
939 for (i = 0, dp = tw->tree.largest; i < tw->tree.n_largest; i++, dp++)
3
Loop condition is false. Execution continues on line 941
940 *dp = 0;
941 initialize_dimensions (&tw->tree.largest, &tw->tree.n_largest,
942 tw->tree.n_largest);
943 compute_bounding_box_subtree (tw, tw->tree.tree_root, 0);
944
945 /*
946 * Second pass to do final layout. Each child's bounding box is stacked
947 * on top of (if horizontal, else next to) on top of its siblings. The
948 * parent is centered between the first and last children.
949 */
950 arrange_subtree (tw, tw->tree.tree_root, 0, 0, 0);
4
Calling 'arrange_subtree'
951
952 /*
953 * Move each widget into place.
954 */
955 set_tree_size (tw, insetvalues, tw->tree.maxwidth, tw->tree.maxheight);
956 set_positions (tw, tw->tree.tree_root, 0);
957
958 /*
959 * And redisplay.
960 */
961 if (XtIsRealized ((Widget) tw)(XtWindowOfObject((Widget) tw) != 0L)) {
962 XClearArea (XtDisplay(tw)(((tw)->core.screen)->display), XtWindow((Widget)tw)(((Widget)tw)->core.window), 0, 0, 0, 0, True1);
963 }
964}
965
966
967
968/*****************************************************************************
969 * *
970 * Public Routines *
971 * *
972 *****************************************************************************/
973
974void
975XawTreeForceLayout (Widget tree)
976{
977 layout_tree ((TreeWidget) tree, FALSE0);
978}
979