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