viewres.c revision 67f05d30
1/*
2 * $XConsortium: viewres.c,v 1.74 94/04/17 20:43:24 converse Exp $
3 *
4 *
5Copyright (c) 1989  X Consortium
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of the X Consortium shall not be
25used in advertising or otherwise to promote the sale, use or other dealings
26in this Software without prior written authorization from the X Consortium.
27 * *
28 * Author:  Jim Fulton, MIT X Consortium
29 */
30/* $XFree86: xc/programs/viewres/viewres.c,v 1.6 2003/05/27 22:26:58 tsi Exp $ */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <X11/StringDefs.h>
35#include <X11/IntrinsicP.h>
36#include <X11/Xaw/Cardinals.h>
37#include <X11/Xaw/Box.h>
38#include <X11/Xaw/Form.h>
39#include <X11/Xaw/Command.h>
40#include <X11/Xaw/MenuButton.h>
41#include <X11/Xaw/SimpleMenu.h>
42#include <X11/Xaw/Sme.h>
43#include <X11/Xaw/SmeBSB.h>
44#include <X11/Xaw/SmeLine.h>
45#include <X11/Xaw/Paned.h>
46#include <X11/Xaw/Porthole.h>
47#include <X11/Xaw/Toggle.h>
48#include <X11/Xaw/Text.h>
49#include <X11/Xaw/List.h>
50#include <X11/Xaw/Scrollbar.h>
51#include <X11/Xaw/Panner.h>
52#include <X11/Xaw/Tree.h>
53#include <X11/Xmu/Converters.h>
54#include <X11/Xmu/CharSet.h>
55#include <X11/Xmu/WidgetNode.h>
56#include <X11/Xaw/AllWidgets.h>
57
58#define widget_list XawWidgetArray  /* or motif or ol or ... */
59#define nwidgets XawWidgetCount
60
61typedef struct {
62    const char **resource_labels;	/* names of res added by widget */
63    Cardinal nnewresources;		/* number res added by widget */
64    Cardinal nnewconstraints;		/* number res added by widget */
65    Cardinal nnew;			/* number new */
66    Widget instance;			/* Label widget in box in tree */
67    Widget resource_lw;			/* List widget showing resources */
68    int selection_index;		/* -1 or index into selection_list */
69} ViewresData;
70
71#define VData(node) ((ViewresData *) (node)->data)
72
73
74#define IsShowing(node) (VData(node)->resource_lw && \
75			 XtIsManaged(VData(node)->resource_lw))
76
77
78struct {
79    int n_elements;
80    int max_elements;
81    XmuWidgetNode **elements;
82} selected_list = { 0, 0, (XmuWidgetNode **) NULL };
83
84#define INSERT_NODE(node,i) \
85  selected_list.elements[VData(node)->selection_index = (i)] = (node)
86
87#define REMOVE_NODE(node) \
88  selected_list.elements[VData(node)->selection_index] = \
89  (XmuWidgetNode *) NULL; VData(node)->selection_index = (-1)
90
91const char *ProgramName;
92static int NumberShowing = 0;
93
94static Arg sensitiveargs[2] = {{ XtNsensitive, (XtArgVal) FALSE },
95			       { XtNsensitive, (XtArgVal) TRUE }};
96
97static const char *help_message[] = {
98    "-top name        object to be top of tree",
99    "-variable        show variable name instead of class name",
100    "-vertical        list the tree vertically",
101    NULL
102};
103
104static XrmOptionDescRec Options[] = {
105    { "-top", "*topObject", XrmoptionSepArg, (XPointer) NULL },
106    { "-variable", "*showVariable", XrmoptionNoArg, (XPointer) "on" },
107    { "-vertical", "*Tree.Gravity", XrmoptionNoArg, (XPointer) "north" }
108};
109
110
111typedef struct {
112    char *top_object;
113    Boolean show_variable;
114} OptionsRec;
115
116static OptionsRec options;
117
118#define Offset(field) XtOffsetOf(OptionsRec, field)
119
120static XtResource Resources[] = {
121    { "topObject", "TopObject", XtRString, sizeof(char *),
122	Offset(top_object), XtRString, (XtPointer) "object" },
123    { "showVariable", "ShowVariable", XtRBoolean, sizeof(Boolean),
124	Offset(show_variable), XtRImmediate, (XtPointer) FALSE },
125};
126
127#undef Offset
128
129static const char *fallback_resources[] = {
130    "*allowShellResize: true",
131    "*Porthole.top: ChainTop",
132    "*Porthole.left: ChainLeft",
133    "*Porthole.bottom: ChainBottom",
134    "*Porthole.right:  ChainRight",
135    "*Porthole.resizable: on",
136    "*Panner.top: ChainTop",
137    "*Panner.left: ChainLeft",
138    "*Panner.bottom: ChainTop",
139    "*Panner.right:  ChainLeft",
140    "*Panner.resizable: on",
141    "*Tree*ShapeStyle: rectangle",
142    "*Tree*Toggle*BorderWidth: 0",
143    "*Porthole*Box.BorderWidth: 0",
144    "*Porthole*Box.HSpace: 0",
145    "*Porthole*Box.VSpace: 0",
146    "*Paned*allowResize: true",
147    "*buttonbox.quit.Translations:  #override \\n <Btn1Down>,<Btn1Up>: Quit() unset()",
148    "*Toggle.Translations: #augment \\n <Btn2Down>,<Btn2Up>: set() notify() Resources(toggle)",
149    NULL
150};
151
152static void ActionQuit(Widget, XEvent *, String *, Cardinal *);
153static void ActionSetLableType(Widget, XEvent *, String *, Cardinal *);
154static void ActionSetOrientation(Widget, XEvent *, String *, Cardinal *);
155static void ActionSelect(Widget, XEvent *, String *, Cardinal *);
156static void ActionResources(Widget, XEvent *, String *, Cardinal *);
157static void set_labeltype_menu(Boolean, Boolean);
158static void set_orientation_menu(XtGravity, Boolean);
159static void build_tree(XmuWidgetNode *, Widget, Widget);
160static void set_node_labels(XmuWidgetNode *, int);
161
162static XtActionsRec viewres_actions[] = {
163    { "Quit", ActionQuit },
164    { "SetLabelType", ActionSetLableType },
165    { "SetOrientation", ActionSetOrientation },
166    { "Select", ActionSelect },
167    { "Resources", ActionResources },
168};
169
170static Atom wm_delete_window;
171
172#define BOOL_OFF 0
173#define BOOL_ON 1
174#define BOOL_TOGGLE 2
175
176#define VIEW_HORIZONTAL 0
177#define VIEW_VERTICAL 1
178#define VIEW_VARIABLES 2
179#define VIEW_CLASSES 3
180#define VIEW_SHOW_RESOURCES 4
181#define VIEW_HIDE_RESOURCES 5
182#define VIEW_number 6
183
184#define SELECT_NOTHING 0
185#define SELECT_ALL 1
186#define SELECT_INVERT 2
187#define SELECT_PARENT 3
188#define SELECT_ANCESTORS 4
189#define SELECT_CHILDREN 5
190#define SELECT_DESCENDANTS 6
191#define SELECT_HAS_RESOURCES 7
192#define SELECT_SHOWN_RESOURCES 8
193#define SELECT_number 9
194
195static struct _nametable {
196    const char *name;
197    int value;
198} select_nametable[] = {
199    { "nothing", SELECT_NOTHING },
200    { "all", SELECT_ALL },
201    { "invert", SELECT_INVERT },
202    { "parent", SELECT_PARENT },
203    { "ancestors", SELECT_ANCESTORS },
204    { "children", SELECT_CHILDREN },
205    { "descendants", SELECT_DESCENDANTS },
206    { "resources", SELECT_HAS_RESOURCES },
207    { "shown", SELECT_SHOWN_RESOURCES },
208}, boolean_nametable[] = {
209    { "off", BOOL_OFF },
210    { "false", BOOL_OFF },
211    { "no", BOOL_OFF },
212    { "on", BOOL_ON },
213    { "true", BOOL_ON },
214    { "yes", BOOL_ON },
215    { "toggle", BOOL_TOGGLE },
216};
217
218static Widget treeWidget;
219static Widget viewButton, viewMenu, selectButton, selectMenu;
220static Widget view_widgets[VIEW_number];
221static Widget select_widgets[SELECT_number];
222static XmuWidgetNode *topnode;
223
224static Arg false_args[1] = {{ XtNstate, (XtArgVal) FALSE }};
225static Arg true_args[1] = {{ XtNstate, (XtArgVal) TRUE }};
226
227
228/*
229 * routines
230 */
231static void
232usage (void)
233{
234    const char **cpp;
235    fprintf (stderr, "usage:  %s [-options...]\n", ProgramName);
236    fprintf(stderr, "\nwhere options include:\n");
237    for (cpp = help_message; *cpp; cpp++) {
238	fprintf (stderr, "    %s\n", *cpp);
239    }
240    fprintf(stderr, "\n");
241    exit (1);
242}
243
244
245static XmuWidgetNode *
246widget_to_node (Widget gw)
247{
248    XmuWidgetNode *node;
249    int i;
250
251    if (XtIsSubclass (gw, toggleWidgetClass)) {
252	for (i = 0, node = widget_list; i < nwidgets; i++, node++) {
253	    if (VData(node)->instance == gw) return node;
254	}
255    } else if (XtIsSubclass (gw, listWidgetClass)) {
256	for (i = 0, node = widget_list; i < nwidgets; i++, node++) {
257	    if (VData(node)->resource_lw == gw) return node;
258	}
259    }
260    return (XmuWidgetNode *) NULL;
261}
262
263
264static void
265initialize_widgetnode_list (XmuWidgetNode ***listp, int *sizep, int n)
266{
267    int i;
268    XmuWidgetNode **l;
269
270    if (!*listp) {
271        *listp = (XmuWidgetNode **)
272	  XtCalloc ((unsigned int) n, (unsigned int)sizeof(XmuWidgetNode **));
273        *sizep = ((*listp) ? n : 0);
274        return;
275    }
276    if (n > *sizep) {
277        *listp = (XmuWidgetNode **) XtRealloc ((char *) *listp,
278					       (unsigned int)
279					       (n * sizeof(XmuWidgetNode **)));
280	if (!*listp) {
281	    *sizep = 0;
282	    return;
283	}
284	for (i = *sizep, l = (*listp) + i; i < n; i++, l++) *l =
285	  (XmuWidgetNode *) NULL;
286	*sizep = n;
287    }
288    return;
289}
290
291
292static Boolean
293set_resource_labels (XmuWidgetNode *node)
294{
295    int i;
296    const char **cur;
297    XtResourceList res;
298    XmuWidgetNode **wn;
299    ViewresData *d = VData(node);
300
301    if (!d->resource_labels) {
302	d->resource_labels =
303	  (const char **) calloc ((unsigned) d->nnew * 3,
304				  (unsigned) sizeof (const char *));
305	if (!d->resource_labels) return FALSE;
306    }
307
308    cur = d->resource_labels;
309    res = node->resources;
310    wn = node->resourcewn;
311    for (i = 0; i < node->nresources; i++, res++, wn++) {
312	if (*wn == node) {		/* should match nnew */
313	    *cur++ = res->resource_name;
314	    *cur++ = res->resource_class;
315	    *cur++ = res->resource_type;
316	}
317    }
318    if (d->nnewconstraints > 0) {
319	const char *s;
320
321	*cur++ = s = "";
322	*cur++ = s;
323	*cur++ = s;
324    }
325    res = node->constraints;
326    wn = node->constraintwn;
327    for (i = 0; i < node->nconstraints; i++, res++, wn++) {
328	if (*wn == node) {		/* should match nnew */
329	    *cur++ = res->resource_name;
330	    *cur++ = res->resource_class;
331	    *cur++ = res->resource_type;
332	}
333    }
334    return TRUE;
335}
336
337
338static ViewresData *
339create_viewres_data (XmuWidgetNode *node)
340{
341    ViewresData *d =
342      (ViewresData *) malloc ((unsigned) sizeof(ViewresData));
343
344    if (d) {
345	d->resource_labels = NULL;
346	d->nnewresources = XmuWnCountOwnedResources (node, node, False);
347	d->nnewconstraints = XmuWnCountOwnedResources (node, node, True);
348	d->nnew = (d->nnewresources + (d->nnewconstraints
349				       ? d->nnewconstraints + 1 : 0));
350	d->instance = (Widget) NULL;
351	d->resource_lw = (Widget) NULL;
352	d->selection_index = -1;
353    }
354    return d;
355}
356
357static int
358copydown (int start)
359{
360    XmuWidgetNode **src = &selected_list.elements[start];
361    XmuWidgetNode **dst = src;
362    int cur;
363
364    for (cur = start; start < selected_list.n_elements; start++, src++) {
365	if (*src) {
366	    VData((*src))->selection_index = cur++;
367	    *dst++ = *src;
368	}
369    }
370    return (start - cur);
371}
372
373
374static void
375add_to_selected_list (XmuWidgetNode *node, Boolean updatewidget)
376{
377    ViewresData *d = VData(node);
378    if (!d->instance || d->selection_index >= 0) return;
379
380    if (selected_list.n_elements >= selected_list.max_elements) {
381	initialize_widgetnode_list (&selected_list.elements,
382				    &selected_list.max_elements,
383				    (selected_list.max_elements * 3) / 2);
384    }
385    INSERT_NODE (node, selected_list.n_elements);
386    selected_list.n_elements++;
387
388    if (updatewidget) XtSetValues (d->instance, true_args, ONE);
389}
390
391static Boolean
392remove_from_selected_list (XmuWidgetNode *node, Boolean updatewidget)
393{
394    int i, skips;
395    ViewresData *d = VData(node);
396
397    if ((i = d->selection_index) < 0) return FALSE;
398
399    REMOVE_NODE (node);
400
401    /* copy down */
402    if (selected_list.n_elements > 1) {
403	skips = copydown (i);
404    } else {
405	skips = 1;
406    }
407    selected_list.n_elements -= skips;
408
409    if (updatewidget) XtSetValues (d->instance, false_args, ONE);
410    return TRUE;
411}
412
413static void
414remove_nodes_from_selected_list (int start, int count, Boolean updatewidget)
415{
416    int i;
417
418    for (i = 0; i < count; i++) {
419	XmuWidgetNode *p = selected_list.elements[start+i];
420	ViewresData *d = VData(p);
421	REMOVE_NODE (p);
422	if (updatewidget) XtSetValues (d->instance, false_args, ONE);
423    }
424    selected_list.n_elements -= copydown (start);
425}
426
427static void
428add_subtree_to_selected_list (XmuWidgetNode *node, Boolean updatewidget)
429{
430    if (!node) return;
431
432    add_to_selected_list (node, updatewidget);
433    for (node = node->children; node; node = node->siblings) {
434	add_subtree_to_selected_list (node, updatewidget);
435    }
436}
437
438
439/* ARGSUSED */
440static void
441variable_labeltype_callback (Widget gw,
442    XtPointer closure,		/* TRUE or FALSE */
443    XtPointer data)
444{
445    set_labeltype_menu ((Boolean) (long) closure, True);
446}
447
448/* ARGSUSED */
449static void
450gravity_callback (Widget gw,
451    XtPointer closure,		/* TRUE or FALSE */
452    XtPointer data)
453{
454    set_orientation_menu ((XtGravity) (long) closure, True);
455}
456
457
458static Boolean
459create_resource_lw (XmuWidgetNode *node)
460{
461    Arg args[4];
462    Cardinal n;
463    ViewresData *d = VData(node);
464
465    if (d->nnew == 0) return FALSE;
466
467    if (!d->resource_labels &&
468	!set_resource_labels (node)) return FALSE;
469
470    n = 0;
471    XtSetArg (args[n], XtNnumberStrings, 3 * d->nnew); n++;
472    XtSetArg (args[n], XtNlist, d->resource_labels); n++;
473    XtSetArg (args[n], XtNdefaultColumns, 3); n++;
474    XtSetArg (args[n], XtNforceColumns, TRUE); n++;
475    d->resource_lw = XtCreateManagedWidget (node->label, listWidgetClass,
476					    XtParent(d->instance),
477					    args, n);
478    XtRealizeWidget (d->resource_lw);
479    return TRUE;
480}
481
482static void
483update_selection_items (void)
484{
485    int i;
486    static Arg args[1] = {{ XtNsensitive, (XtArgVal) FALSE }};
487    Boolean show = FALSE, hide = FALSE, ancestors = FALSE;
488    Boolean descendants = FALSE;
489
490    for (i = 0; i < selected_list.n_elements; i++) {
491	XmuWidgetNode *node = selected_list.elements[i];
492	ViewresData *d = VData(node);
493
494	/*
495	 * If node has any new resources then may be shown (if not
496	 * already being shown).  If node has widget and is managed,
497	 * then may be hidden.
498	 */
499	if (d->nnew > 0) {
500	    if (IsShowing(node)) {
501		hide = TRUE;
502	    } else {
503		show = TRUE;
504	    }
505	}
506	if (node != topnode) ancestors = TRUE;
507	if (node->children) descendants = TRUE;
508    }
509
510    args[0].value = (XtArgVal) show;
511    XtSetValues (view_widgets[VIEW_SHOW_RESOURCES], args, ONE);
512    args[0].value = (XtArgVal) hide;
513    XtSetValues (view_widgets[VIEW_HIDE_RESOURCES], args, ONE);
514    args[0].value = (XtArgVal) (selected_list.n_elements > 0 ? TRUE : FALSE);
515    XtSetValues (select_widgets[SELECT_NOTHING], args, ONE);
516    args[0].value = (XtArgVal) ancestors;
517    XtSetValues (select_widgets[SELECT_PARENT], args, ONE);
518    XtSetValues (select_widgets[SELECT_ANCESTORS], args, ONE);
519    args[0].value = (XtArgVal) descendants;
520    XtSetValues (select_widgets[SELECT_CHILDREN], args, ONE);
521    XtSetValues (select_widgets[SELECT_DESCENDANTS], args, ONE);
522    args[0].value = (XtArgVal) ((Boolean) (NumberShowing > 0));
523    XtSetValues (select_widgets[SELECT_SHOWN_RESOURCES], args, ONE);
524}
525
526
527static void
528do_resources (XmuWidgetNode *node, Boolean op, Boolean updatewidget)
529{
530    ViewresData *d = VData(node);
531    if (op == BOOL_TOGGLE) op = (IsShowing(node) ? BOOL_OFF : BOOL_ON);
532
533    if (op == BOOL_ON) {
534	if (d->resource_lw) {		/* if already created */
535	    if (!XtIsManaged(d->resource_lw)) {
536		NumberShowing++;
537		XtManageChild (d->resource_lw);
538	    }				/* else ignore it */
539	} else if (create_resource_lw (node))	/* create it */
540	  NumberShowing++;
541    } else if (d->resource_lw) {		/* if already created */
542	if (XtIsManaged (d->resource_lw)) {
543	    NumberShowing--;
544	    XtUnmanageChild (d->resource_lw);
545	    XawListUnhighlight (d->resource_lw);
546	    if (updatewidget) remove_from_selected_list (node, TRUE);
547	}				/* else ignore it */
548    }
549}
550
551
552
553/* ARGSUSED */
554static void
555show_resources_callback (
556    Widget gw,				/* menu or toggle button */
557    XtPointer closure,			/* BOOL_OFF, BOOL_ON, BOOL_TOGGLE */
558    XtPointer data)			/* undefined */
559{
560    int op = (long) closure;
561    XmuWidgetNode *node = widget_to_node (gw);
562
563    if (node) {
564	XUnmapWindow (XtDisplay(treeWidget), XtWindow(treeWidget));
565	do_resources (node, op, TRUE);
566    } else if (selected_list.n_elements <= 0) {
567	return;
568    } else {
569	int i;
570
571	XUnmapWindow (XtDisplay(treeWidget), XtWindow(treeWidget));
572	for (i = 0; i < selected_list.n_elements; i++) {
573	    do_resources (selected_list.elements[i], op, FALSE);
574	}
575    }
576    XawTreeForceLayout (treeWidget);
577    XMapWindow (XtDisplay(treeWidget), XtWindow(treeWidget));
578    update_selection_items ();
579}
580
581
582/* ARGSUSED */
583static void
584select_callback (
585    Widget gw,				/* entry widget */
586    XtPointer closure,			/* TRUE or FALSE */
587    XtPointer data)			/* undefined */
588{
589    int i;
590    int nselected = selected_list.n_elements;
591    XmuWidgetNode *node;
592
593    switch ((long) closure) {
594      case SELECT_NOTHING:		/* clear selection_list */
595	remove_nodes_from_selected_list (0, nselected, True);
596	break;
597
598      case SELECT_ALL:			/* put everything on selection_list */
599	add_subtree_to_selected_list (topnode, TRUE);
600	break;
601
602      case SELECT_INVERT:		/* toggle selection state */
603	for (i = 0, node = widget_list; i < nwidgets; i++, node++) {
604	    ViewresData *d = VData(node);
605	    if (d->selection_index < 0) add_to_selected_list (node, TRUE);
606	}
607	remove_nodes_from_selected_list (0, nselected, True);
608	break;
609
610
611      case SELECT_PARENT:		/* choose immediate parent */
612	node = widget_to_node (gw);
613	if (node) {
614	    if (node->superclass)
615	      add_to_selected_list (node->superclass, TRUE);
616	} else {
617	    for (i = 0; i < nselected; i++) {
618		XmuWidgetNode *node = selected_list.elements[i];
619		if (node->superclass)
620		  add_to_selected_list (node->superclass, TRUE);
621	    }
622	}
623	break;
624
625      case SELECT_ANCESTORS:		/* chain up adding to selection_list */
626	node = widget_to_node (gw);
627	if (node) {
628	    do {
629		add_to_selected_list (node, TRUE);
630	    } while ((node = node->superclass) != NULL);
631	} else {
632	    for (i = 0; i < nselected; i++) {
633		XmuWidgetNode *parent = selected_list.elements[i];
634
635		/*
636		 * chain up the tree, but stop if we get to nodes that
637		 * are already in the selected list.
638		 */
639		while ((parent = parent->superclass) != NULL) {
640		    if (VData(parent)->selection_index >= 0) break;
641		    add_to_selected_list (parent, TRUE);
642		}
643	    }
644	}
645	break;
646
647      case SELECT_CHILDREN:		/* all direct sub nodes */
648	node = widget_to_node (gw);
649	if (node) {
650	    add_to_selected_list (node, TRUE);
651	    for (node = node->children; node; node = node->siblings) {
652		add_to_selected_list (node, TRUE);
653	    }
654	} else {
655	    for (i = 0; i < nselected; i++) {
656		XmuWidgetNode *node = selected_list.elements[i];
657
658		add_to_selected_list (node, TRUE);
659		for (node = node->children; node; node = node->siblings) {
660		    add_to_selected_list (node, TRUE);
661		}
662	    }
663	}
664	break;
665
666      case SELECT_DESCENDANTS:		/* all sub nodes */
667	node = widget_to_node (gw);
668	if (node) {
669	    add_subtree_to_selected_list (node, TRUE);
670	} else {
671	    for (i = 0; i < nselected; i++) {
672		XmuWidgetNode *parent = selected_list.elements[i];
673
674		add_subtree_to_selected_list (parent, TRUE);
675	    }
676	}
677	break;
678
679      case SELECT_HAS_RESOURCES:	/* put all w/ rescnt > 0 on sel_list */
680	for (i = 0, node = widget_list; i < nwidgets; i++, node++) {
681	    if (VData(node)->nnew > 0)
682	      add_to_selected_list (node, TRUE);
683	}
684	break;
685
686      case SELECT_SHOWN_RESOURCES:
687	for (i = 0, node = widget_list; i < nwidgets; i++, node++) {
688	    if (IsShowing(node)) add_to_selected_list (node, TRUE);
689	}
690	break;
691
692      default:				/* error!!! */
693	XBell (XtDisplay(gw), 0);
694	return;
695    }
696
697    update_selection_items ();
698}
699
700/* ARGSUSED */
701static void
702toggle_callback (Widget gw,
703    XtPointer closure,		/* XmuWidgetNode for this widget */
704    XtPointer data)		/* on or off */
705{
706    XmuWidgetNode *node = (XmuWidgetNode *) closure;
707    Boolean selected = (Boolean) (long) data;
708
709    if (selected) {
710	add_to_selected_list (node, FALSE);
711    } else {
712	(void) remove_from_selected_list (node, FALSE);
713    }
714
715    update_selection_items ();
716}
717
718
719/*
720 * panner/porthole controls - called when the other changes
721 */
722/* ARGSUSED */
723static void
724panner_callback (
725    Widget gw,				/* panner widget */
726    XtPointer closure,			/* porthole widget */
727    XtPointer data)			/* report */
728{
729    XawPannerReport *rep = (XawPannerReport *) data;
730    Arg args[2];
731
732    if (!treeWidget) return;
733
734    XtSetArg (args[0], XtNx, -rep->slider_x);
735    XtSetArg (args[1], XtNy, -rep->slider_y);
736    XtSetValues (treeWidget, args, TWO);	/* just assume... */
737}
738
739/* ARGSUSED */
740static void
741porthole_callback (
742    Widget gw,				/* porthole widget */
743    XtPointer closure,			/* panner widget */
744    XtPointer data)			/* report */
745{
746    Widget panner = (Widget) closure;
747    XawPannerReport *rep = (XawPannerReport *) data;
748    Arg args[6];
749    Cardinal n = TWO;
750
751    XtSetArg (args[0], XtNsliderX, rep->slider_x);
752    XtSetArg (args[1], XtNsliderY, rep->slider_y);
753    if (rep->changed != (XawPRSliderX | XawPRSliderY)) {
754	XtSetArg (args[2], XtNsliderWidth, rep->slider_width);
755	XtSetArg (args[3], XtNsliderHeight, rep->slider_height);
756	XtSetArg (args[4], XtNcanvasWidth, rep->canvas_width);
757	XtSetArg (args[5], XtNcanvasHeight, rep->canvas_height);
758	n = SIX;
759    }
760    XtSetValues (panner, args, n);
761}
762
763
764
765static void
766build_tree (XmuWidgetNode *node, Widget tree, Widget super)
767{
768    ViewresData *d = VData (node);
769    Widget box, w;			/* widget for this Class */
770    XmuWidgetNode *child;			/* iterator over children */
771    Arg args[3];			/* need to set super node */
772    Cardinal n;				/* count of args */
773    static XtCallbackRec callback_rec[2] = {{ toggle_callback, NULL },
774					     { NULL, NULL }};
775
776
777    n = 0;
778    XtSetArg (args[n], XtNtreeParent, super); n++;
779    box = XtCreateManagedWidget (node->label, boxWidgetClass, tree, args, n);
780
781    n = 0;
782    XtSetArg (args[n], XtNlabel, (options.show_variable ?
783				  node->label : XmuWnClassname(node))); n++;
784    XtSetArg (args[n], XtNcallback, callback_rec); n++;
785
786    callback_rec[0].closure = (XtPointer) node;
787    w = XtCreateManagedWidget (node->label, toggleWidgetClass, box, args, n);
788    d->instance = w;
789
790    /*
791     * recursively build the rest of the tree
792     */
793    for (child = node->children; child; child = child->siblings) {
794	build_tree (child, tree, box);
795    }
796}
797
798
799static void
800set_node_labels (XmuWidgetNode *node, int depth)
801{
802    Arg args[1];
803    XmuWidgetNode *child;
804    ViewresData *d = VData(node);
805
806    if (!node) return;
807    XtSetArg (args[0], XtNlabel, (options.show_variable ?
808				  node->label : XmuWnClassname(node)));
809    XtSetValues (d->instance, args, ONE);
810
811    for (child = node->children; child; child = child->siblings) {
812	set_node_labels (child, depth + 1);
813    }
814}
815
816
817static void
818oneof_sensitive (Boolean choosea, Widget a, Widget b)
819{
820    static Arg args[1] = { { XtNsensitive, (XtArgVal) NULL } };
821
822    args[0].value = (XtArgVal) TRUE;
823    XtSetValues (choosea ? a : b, args, ONE);
824    args[0].value = (XtArgVal) FALSE;
825    XtSetValues (choosea ? b : a, args, ONE);
826}
827
828static void
829set_labeltype_menu (Boolean isvar, Boolean doall)
830{
831    options.show_variable = isvar;
832    oneof_sensitive (isvar, view_widgets[VIEW_CLASSES],
833		     view_widgets[VIEW_VARIABLES]);
834
835    if (doall) {
836	XUnmapWindow (XtDisplay(treeWidget), XtWindow(treeWidget));
837	set_node_labels (topnode, 0);
838	XawTreeForceLayout (treeWidget);
839	XMapWindow (XtDisplay(treeWidget), XtWindow(treeWidget));
840    }
841}
842
843static void
844set_orientation_menu (XtGravity grav, Boolean dosetvalues)
845{
846#define CHOOSE(val) (sensitiveargs + (grav != (val)))
847    XtSetValues (view_widgets[VIEW_HORIZONTAL], CHOOSE(WestGravity), ONE);
848    XtSetValues (view_widgets[VIEW_VERTICAL], CHOOSE(NorthGravity), ONE);
849#undef CHOOSE
850
851    if (dosetvalues) {
852	Arg args[1];
853
854	XtSetArg (args[0], XtNgravity, grav);
855	XUnmapWindow (XtDisplay(treeWidget), XtWindow(treeWidget));
856 	XtSetValues (treeWidget, args, ONE);
857	XMapWindow (XtDisplay(treeWidget), XtWindow(treeWidget));
858    }
859}
860
861
862/*****************************************************************************
863 *                                                                           *
864 *		     viewres - visual class browser for Xt                   *
865 *                                                                           *
866 *****************************************************************************/
867
868int
869main (int argc, char *argv[])
870{
871    Widget toplevel, pane, box, dummy, porthole, panner, form;
872    XmuWidgetNode *rootNode; /* always the root of the resource hierarchy */
873    XtAppContext app_con;
874    Arg args[6];
875    Dimension canvasWidth, canvasHeight, sliderWidth, sliderHeight;
876    static XtCallbackRec callback_rec[2] = {{ NULL, NULL }, { NULL, NULL }};
877    XtGravity grav;
878    int i;
879
880    ProgramName = argv[0];
881
882    XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL);
883
884    toplevel = XtAppInitialize (&app_con, "Viewres",
885				Options, XtNumber (Options),
886				&argc, argv, (char **) fallback_resources,
887				(ArgList) NULL, ZERO);
888    if (argc != 1) usage ();
889
890    initialize_widgetnode_list (&selected_list.elements,
891				&selected_list.max_elements, 10);
892
893    XtGetApplicationResources (toplevel, (XtPointer) &options,
894			       Resources, XtNumber(Resources), NULL, ZERO);
895    XmuWnInitializeNodes (widget_list, nwidgets);
896
897    topnode = XmuWnNameToNode (widget_list, nwidgets, options.top_object);
898    if (!topnode) {
899	fprintf(stderr, "%s: no widget with name \"%s\" found.\n",
900		ProgramName, options.top_object);
901	exit(1);
902    }
903
904    XtAppAddActions (app_con, viewres_actions, XtNumber (viewres_actions));
905    XtOverrideTranslations
906	(toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()"));
907
908    /*
909     * create dummy widgets to initialize resources
910     */
911    XtSetArg (args[0], XtNwidth, 1);
912    XtSetArg (args[1], XtNheight, 1);
913    dummy = XtCreateWidget ("dummy", widgetClass, toplevel, args, TWO);
914    rootNode = XmuWnNameToNode(widget_list, nwidgets, "Object");
915    for (i = 0; i < nwidgets; i++) {
916	XmuWidgetNode *node = &widget_list[i];
917	XmuWnFetchResources (node, dummy, rootNode);
918	node->data = (XtPointer) create_viewres_data (node);
919    }
920    XtDestroyWidget (dummy);
921
922    pane = XtCreateManagedWidget ("pane", panedWidgetClass, toplevel,
923				  (ArgList) NULL, ZERO);
924
925    box = XtCreateManagedWidget ("buttonbox", boxWidgetClass, pane,
926				 (ArgList) NULL, ZERO);
927    (void) XtCreateManagedWidget ("quit", commandWidgetClass, box,
928				  (ArgList) NULL, ZERO);
929
930    /*
931     * Format menu
932     */
933    XtSetArg (args[0], XtNmenuName, "viewMenu");
934    viewButton = XtCreateManagedWidget ("view", menuButtonWidgetClass, box,
935					args, ONE);
936    viewMenu = XtCreatePopupShell ("viewMenu", simpleMenuWidgetClass,
937				   viewButton, (ArgList) NULL, ZERO);
938    XtSetArg (args[0], XtNcallback, callback_rec);
939
940#define MAKE_VIEW(n,v,name) \
941    callback_rec[0].closure = (XtPointer) v; \
942    view_widgets[n] = XtCreateManagedWidget (name, smeBSBObjectClass, \
943					     viewMenu, args, ONE)
944    callback_rec[0].callback = (XtCallbackProc) gravity_callback;
945    MAKE_VIEW (VIEW_HORIZONTAL, WestGravity, "layoutHorizontal");
946    MAKE_VIEW (VIEW_VERTICAL, NorthGravity, "layoutVertical");
947
948    (void) XtCreateManagedWidget ("line1", smeLineObjectClass, viewMenu,
949				  (ArgList) NULL, ZERO);
950
951    callback_rec[0].callback = (XtCallbackProc) variable_labeltype_callback;
952    MAKE_VIEW (VIEW_VARIABLES, TRUE, "namesVariable");
953    MAKE_VIEW (VIEW_CLASSES, FALSE, "namesClass");
954
955    (void) XtCreateManagedWidget ("line2", smeLineObjectClass, viewMenu,
956				  (ArgList) NULL, ZERO);
957
958    callback_rec[0].callback = (XtCallbackProc) show_resources_callback;
959    MAKE_VIEW (VIEW_SHOW_RESOURCES, BOOL_ON, "viewResources");
960    MAKE_VIEW (VIEW_HIDE_RESOURCES, BOOL_OFF, "viewNoResources");
961#undef MAKE_VIEW
962
963    /*
964     * Select menu
965     */
966    XtSetArg (args[0], XtNmenuName, "selectMenu");
967    selectButton = XtCreateManagedWidget ("select", menuButtonWidgetClass, box,
968					  args, ONE);
969    selectMenu = XtCreatePopupShell ("selectMenu", simpleMenuWidgetClass,
970				     selectButton, (ArgList) NULL, ZERO);
971    XtSetArg (args[0], XtNcallback, callback_rec);
972    callback_rec[0].callback = (XtCallbackProc) select_callback;
973#define MAKE_SELECT(n,name) \
974    callback_rec[0].closure = (XtPointer) n; \
975    select_widgets[n] = XtCreateManagedWidget (name, smeBSBObjectClass, \
976					       selectMenu, args, ONE)
977    MAKE_SELECT (SELECT_NOTHING, "unselect");
978    MAKE_SELECT (SELECT_ALL, "selectAll");
979    MAKE_SELECT (SELECT_INVERT, "selectInvert");
980    (void) XtCreateManagedWidget ("line1", smeLineObjectClass, selectMenu,
981				  (ArgList) NULL, ZERO);
982    MAKE_SELECT (SELECT_PARENT, "selectParent");
983    MAKE_SELECT (SELECT_ANCESTORS, "selectAncestors");
984    MAKE_SELECT (SELECT_CHILDREN, "selectChildren");
985    MAKE_SELECT (SELECT_DESCENDANTS, "selectDescendants");
986    (void) XtCreateManagedWidget ("line2", smeLineObjectClass, selectMenu,
987				  (ArgList) NULL, ZERO);
988    MAKE_SELECT (SELECT_HAS_RESOURCES, "selectHasResources");
989    MAKE_SELECT (SELECT_SHOWN_RESOURCES, "selectShownResources");
990#undef MAKE_SELECT
991
992    form = XtCreateManagedWidget ("treeform", formWidgetClass, pane,
993				  (ArgList) NULL, ZERO);
994    /*
995     * create the panner and the porthole and then connect them with the
996     * callbacks (passing the other widget each callback)
997     */
998    XtSetArg (args[0], XtNbackgroundPixmap, None);  /* faster updates */
999    porthole = XtCreateManagedWidget ("porthole", portholeWidgetClass, form,
1000				      args, ONE);
1001    panner = XtCreateManagedWidget ("panner", pannerWidgetClass, form,
1002				    (ArgList) NULL, ZERO);
1003
1004    XtSetArg (args[0], XtNreportCallback, callback_rec);
1005    callback_rec[0].callback = (XtCallbackProc) panner_callback;
1006    callback_rec[0].closure = (XtPointer) porthole;
1007    XtSetValues (panner, args, ONE);
1008
1009    callback_rec[0].callback = (XtCallbackProc) porthole_callback;
1010    callback_rec[0].closure = (XtPointer) panner;
1011    XtSetValues (porthole, args, ONE);
1012
1013    /*
1014     * now that the panner and porthole are set up, insert the tree and
1015     * fix up the menu, fill in the nodes
1016     */
1017    treeWidget = XtCreateManagedWidget ("tree", treeWidgetClass,
1018					porthole, (ArgList) NULL, ZERO);
1019
1020    set_labeltype_menu (options.show_variable, FALSE);
1021    XtSetArg (args[0], XtNgravity, &grav);
1022    XtGetValues (treeWidget, args, ONE);
1023    set_orientation_menu (grav, FALSE);
1024    update_selection_items ();
1025    build_tree (topnode, treeWidget, (Widget) NULL);
1026
1027    /*
1028     * Realize the tree, but do not map it (we set mappedWhenManaged to
1029     * false up above).  Get the initial size of the tree so that we can
1030     * size the panner appropriately.
1031     */
1032    XtRealizeWidget (toplevel);
1033
1034    wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
1035				   False);
1036    (void) XSetWMProtocols (XtDisplay(toplevel), XtWindow(toplevel),
1037                            &wm_delete_window, 1);
1038
1039    XtSetArg (args[0], XtNwidth, &canvasWidth);
1040    XtSetArg (args[1], XtNheight, &canvasHeight);
1041    XtGetValues (treeWidget, args, TWO);
1042
1043    XtSetArg (args[0], XtNwidth, &sliderWidth);
1044    XtSetArg (args[1], XtNheight, &sliderHeight);
1045    XtGetValues (porthole, args, TWO);
1046
1047    XtSetArg (args[0], XtNcanvasWidth, canvasWidth);
1048    XtSetArg (args[1], XtNcanvasHeight, canvasHeight);
1049    XtSetArg (args[2], XtNsliderWidth, sliderWidth);
1050    XtSetArg (args[3], XtNsliderHeight, sliderHeight);
1051    XtSetValues (panner, args, FOUR);
1052
1053    XRaiseWindow (XtDisplay(panner), XtWindow(panner));
1054    XtAppMainLoop (app_con);
1055
1056    return 0;
1057}
1058
1059
1060
1061/*****************************************************************************
1062 *                                                                           *
1063 *		   viewres translation table action routines                 *
1064 *                                                                           *
1065 *****************************************************************************/
1066
1067/* ARGSUSED */
1068static void
1069ActionQuit (Widget w, XEvent *event,
1070    String *params, Cardinal *num_params)
1071{
1072    exit (0);
1073}
1074
1075/* ARGSUSED */
1076static void
1077ActionSetLableType (Widget w, XEvent *event,
1078    String *params, Cardinal *num_params)
1079{
1080    const char *cmd;
1081    Boolean oldvar = options.show_variable, newvar;
1082
1083    switch (*num_params) {
1084      case 0:
1085	cmd = "toggle";
1086	break;
1087      case 1:
1088	cmd = params[0];
1089	break;
1090      default:
1091	XBell (XtDisplay(w), 0);
1092	return;
1093    }
1094
1095    if (XmuCompareISOLatin1 (cmd, "toggle") == 0) {
1096	newvar = !oldvar;
1097    } else if (XmuCompareISOLatin1 (cmd, "variable") == 0) {
1098	newvar = TRUE;
1099    } else if (XmuCompareISOLatin1 (cmd, "class") == 0) {
1100	newvar = FALSE;
1101    } else {
1102	XBell (XtDisplay(w), 0);
1103	return;
1104    }
1105
1106    if (newvar != oldvar) set_labeltype_menu (newvar, TRUE);
1107    return;
1108}
1109
1110/* ARGSUSED */
1111static void
1112ActionSetOrientation (Widget w, XEvent *event,
1113    String *params, Cardinal *num_params)
1114{
1115    XtGravity newgrav = ForgetGravity;
1116
1117    if (*num_params < 1) {
1118	Arg arg;
1119	XtGravity oldgrav = ForgetGravity;
1120
1121	XtSetArg (arg, XtNgravity, &oldgrav);
1122	XtGetValues (treeWidget, &arg, ONE);
1123	switch (oldgrav) {
1124	  case WestGravity:  newgrav = NorthGravity; break;
1125	  case NorthGravity:  newgrav = WestGravity; break;
1126	  case EastGravity:  newgrav = SouthGravity; break;
1127	  case SouthGravity:  newgrav = EastGravity; break;
1128	  default:
1129	    return;
1130	}
1131    } else {
1132	XrmValue fromval, toval;
1133
1134	fromval.size = sizeof (String);
1135	fromval.addr = (XPointer) params[0];
1136	toval.size = sizeof (XtGravity);
1137	toval.addr = (XPointer) &newgrav;
1138	XtConvertAndStore (treeWidget, XtRString, &fromval,
1139			   XtRGravity, &toval);
1140    }
1141
1142    switch (newgrav) {
1143      case WestGravity: case NorthGravity: case EastGravity: case SouthGravity:
1144	break;
1145      default:
1146	XBell (XtDisplay(w), 0);
1147	return;
1148    }
1149
1150    set_orientation_menu (newgrav, TRUE);
1151    return;
1152}
1153
1154
1155static void
1156do_single_arg (Widget w, String *params, Cardinal nparams,
1157    struct _nametable table[] , int nentries, XtCallbackProc proc)
1158{
1159    int obj;
1160    int i;
1161
1162    if (nparams != 1) {
1163	XBell (XtDisplay(w), 0);
1164	return;
1165    }
1166
1167    for (i = 0; i < nentries; i++) {
1168	if (XmuCompareISOLatin1 (params[0], table[i].name) == 0) {
1169	    obj = table[i].value;
1170	    goto found;
1171	}
1172    }
1173    XBell (XtDisplay(w), 0);
1174    return;
1175
1176  found:
1177    /*
1178     * use any old widget
1179     */
1180    (*proc) (w, (XtPointer) (long) obj, (XtPointer) NULL);
1181}
1182
1183
1184/* ARGSUSED */
1185static void
1186ActionSelect (Widget w, XEvent *event,
1187    String *params, Cardinal *num_params)
1188{
1189    do_single_arg (w, params, *num_params, select_nametable,
1190		   (int) XtNumber(select_nametable), select_callback);
1191}
1192
1193
1194/* ARGSUSED */
1195static void ActionResources (Widget w, XEvent *event,
1196    String *params, Cardinal *num_params)
1197{
1198    if (*num_params == 0) {
1199	show_resources_callback (w, (XtPointer) BOOL_TOGGLE, (XtPointer) NULL);
1200    } else {
1201	do_single_arg (w, params, *num_params, boolean_nametable,
1202		       (int) XtNumber(boolean_nametable),
1203		       show_resources_callback);
1204    }
1205}
1206
1207