1/* 2 3Copyright 1987, 1988, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25*/ 26/***************************************************************** 27 28(C) COPYRIGHT International Business Machines Corp. 1992,1997 29 All Rights Reserved 30 31Permission is hereby granted, free of charge, to any person obtaining a copy 32of this software and associated documentation files (the "Software"), to deal 33in the Software without restriction, including without limitation the rights 34to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 35copies of the Software. 36 37The above copyright notice and this permission notice shall be included in 38all copies or substantial portions of the Software. 39 40THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 43THE IBM CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, 44BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, 45WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 46IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 47 48Except as contained in this notice, the name of the IBM Corporation shall 49not be used in advertising or otherwise to promote the sale, use or other 50dealings in this Software without prior written authorization from the IBM 51Corporation. 52 53******************************************************************/ 54 55#ifdef HAVE_CONFIG_H 56#include <config.h> 57#endif 58#include "Intrinsic.h" 59#include "IntrinsicI.h" 60#include "Core.h" 61#include "CoreP.h" 62#include "ShellP.h" 63#include "StringDefs.h" 64#include "ResConfigP.h" 65#include <X11/Xatom.h> 66#include <stdio.h> 67#include <stdlib.h> 68 69#define MAX_BUFFER 512 70 71static void _search_child(Widget, char *, char *, char *, char *, char, char *); 72static void _set_and_search(Widget, char *, char *, char *, char *, char, 73 char *); 74static int _locate_children(Widget, Widget **); 75 76/* 77 * NAME: _set_resource_values 78 * 79 * FUNCTION: 80 * This function sets the value on the widget. It must first determine 81 * if the last part is a valid resource for that widget. (eg. 82 * labelString is a valid resource for label but not for bulletin board) 83 * It must also add the resource to the application's resource database 84 * and then query it out using specific resource strings that it builds 85 * from the widget information. This ensures that a customizing tool 86 * on-the-fly paradigm is followed: an application that is 87 * instantaneously updated should look the same as one that is restarted 88 * and uses the .Xdefaults file. 89 * 90 * PARAMETERS: 91 * w the widget to match 92 * resource the resource string to be matched 93 * value the value to be set 94 * last_part the last resource part (e.g. *background) 95 * 96 * RETURN VALUES: void 97 * 98 * ERRORS: none 99 */ 100static void 101_set_resource_values(Widget w, char *resource, char *value, char *last_part) 102{ 103 XrmDatabase db = NULL; 104 char *resource_name = NULL; 105 char *resource_class = NULL; 106 char *return_type; 107 XrmValue return_value; 108 char *resource_value; 109 Widget cur = w; 110 char *temp; 111 XtResourceList resources_return = NULL; 112 Cardinal num_resources_return = 0; 113 Cardinal res_index; 114 Boolean found_resource = False; 115 Display *dpy; 116 XrmDatabase tmp_db; 117 118 if (last_part == NULL) 119 return; 120 121 if (!XtIsWidget(w)) { 122 if (w == 0 || w->core.parent == 0) 123 return; 124 dpy = XtDisplay(w->core.parent); 125 } 126 else { 127 dpy = XtDisplay(w); 128 } 129 tmp_db = XtDatabase(dpy); 130 131 /* 132 * get a list of all the valid resources for this widget 133 */ 134 XtGetResourceList(w->core.widget_class, 135 &resources_return, &num_resources_return); 136 137 /* 138 * try to match the last_part of the resource string with 139 * a resource in this resource list 140 */ 141 for (res_index = 0; res_index < num_resources_return; res_index++) { 142 if ((strcmp(last_part, 143 resources_return[res_index].resource_name) == 0) || 144 (strcmp(last_part, 145 resources_return[res_index].resource_class) == 0)) { 146 found_resource = True; 147 break; 148 } 149 } 150 151 /* 152 * if resource is not a valid resource for this widget 153 * or the resource name or class are NULL 154 * then exit this function 155 */ 156 if (!found_resource 157 || !resources_return[res_index].resource_name 158 || !resources_return[res_index].resource_class) { 159 XtFree((char *) resources_return); 160 return; 161 } 162 163 /* 164 * build the full resource name and class specifications so 165 * that you can query the resource database 166 * eg: .app.button1.foreground 167 * .App.XmPushButton.Foreground 168 */ 169 while (cur != NULL) { 170 /* 171 * create resource name string 172 */ 173 if (resource_name) { 174 XtAsprintf(&temp, ".%s%s", cur->core.name, resource_name); 175 XtFree(resource_name); 176 } 177 else if (!XtIsWidget(cur) || !cur->core.name) { 178 cur = XtParent(cur); 179 continue; 180 } 181 else { 182 XtAsprintf(&temp, ".%s", cur->core.name); 183 } 184 resource_name = temp; 185 186 /* 187 * create resource class string 188 */ 189 if ((XtIsTopLevelShell(cur)) && (XtParent(cur) == NULL)) { 190 ApplicationShellWidget top = (ApplicationShellWidget) (cur); 191 192 if (resource_class) { 193 XtAsprintf(&temp, ".%s%s", 194 top->application.class, resource_class); 195 } 196 else { 197 XtAsprintf(&temp, ".%s", top->application.class); 198 } 199 } 200 else { 201 if (resource_class) { 202 XtAsprintf(&temp, ".%s%s", 203 cur->core.widget_class->core_class.class_name, 204 resource_class); 205 } 206 else { 207 XtAsprintf(&temp, ".%s", 208 cur->core.widget_class->core_class.class_name); 209 } 210 } 211 212 XtFree(resource_class); 213 resource_class = temp; 214 215 cur = XtParent(cur); 216 } 217 218 /* 219 * add the resource name to the end of the resource name string 220 */ 221 XtAsprintf(&temp, "%s.%s", resource_name, 222 resources_return[res_index].resource_name); 223 224 XtFree(resource_name); 225 resource_name = temp; 226 227 /* 228 * add the resource class to the end of the resource class string 229 */ 230 XtAsprintf(&temp, "%s.%s", resource_class, 231 resources_return[res_index].resource_class); 232 233 XtFree(resource_class); 234 resource_class = temp; 235 236#ifdef DEBUG 237 fprintf(stderr, "resource_name = %s\n", resource_name); 238 fprintf(stderr, "resource_class = %s\n", resource_class); 239#endif 240 241 /* 242 * put the resource and its value in a resource database and 243 * then query it back out again using the specific name and 244 * class resource strings that were built above. This is 245 * necessary to maintain a precedence similar to the .Xdefaults 246 * file 247 */ 248 XrmPutStringResource(&db, resource, value); 249 XrmMergeDatabases(db, &tmp_db); 250 XrmGetResource(tmp_db, resource_name, resource_class, 251 &return_type, &return_value); 252 if (return_type) 253 resource_value = XtNewString(return_value.addr); 254 else 255 resource_value = XtNewString(value); 256 257#ifdef DEBUG 258 fprintf(stderr, 259 "Apply:\n\twidget = %s\n\tlast_part = %s\n\tvalue = %s\n", 260 (w->core.name == NULL) ? "NULL" : w->core.name, 261 resources_return[res_index].resource_name, resource_value); 262#endif 263 /* 264 * use XtVaSetValues with XtVaTypedArg to convert the value of 265 * type String the the same type as the resource (last_part). 266 * Then set the value. 267 */ 268 XtVaSetValues(w, 269 XtVaTypedArg, resources_return[res_index].resource_name, 270 XtRString, resource_value, strlen(resource_value) + 1, NULL); 271 272 XtFree((char *) resources_return); 273 XtFree(resource_name); 274 XtFree(resource_class); 275 XtFree(resource_value); 276} 277 278/* 279 * NAME: _apply_values_to_children 280 * 281 * FUNCTION: 282 * Once the resource string matches the value must be applied to 283 * all children if applicable. (eg. App*Form.background must apply 284 * background to all children of the Form widget) 285 * 286 * PARAMETERS: 287 * w the widget to match 288 * remainder the part of the resource string left over 289 * resource the resource string to be matched 290 * value the value to be set 291 * last_token the last * or . before the final resource part 292 * last_part the last resource part (e.g. *background) 293 * 294 * RETURN VALUES: void 295 * 296 * ERRORS: none 297 */ 298static void 299_apply_values_to_children(Widget w, 300 char *remainder, 301 char *resource, 302 char *value, 303 char last_token, 304 char *last_part) 305{ 306 int i; 307 int num_children; 308 Widget *children; 309 310 /* 311 * Recursively search through the children 312 */ 313 num_children = _locate_children(w, &children); 314 315 for (i = 0; i < num_children; i++) { 316 317#ifdef DEBUG 318 if (XtIsWidget(children[i]) && XtIsWidget(w)) 319 fprintf(stderr, "searching child %s of parent %s\n", 320 children[i]->core.name, w->core.name); 321 else 322 fprintf(stderr, "searching child (NULL) of parent %s\n", 323 w->core.name); 324 if (!XtIsWidget(children[i])) 325 fprintf(stderr, "children[%d] is NOT a widget\n", i); 326 if (!XtIsWidget(w)) 327 fprintf(stderr, "w is NOT a widget\n"); 328#endif 329 330 _set_resource_values(children[i], resource, value, last_part); 331 _apply_values_to_children(children[i], remainder, 332 resource, value, last_token, last_part); 333 } 334 335 XtFree((char *) children); 336} 337 338/* 339 * NAME: _search_child 340 * 341 * FUNCTION: 342 * descends through each child of the tree 343 * 344 * PARAMETERS: 345 * w the widget whose children are to be searched 346 * indx index into the resource string 347 * remainder the remaining part of the resource string 348 * resource the resource string to be matched 349 * value the value to be applied 350 * last_token the last * or . before the final resource part 351 * last_part the last resource part (e.g. *background) 352 * 353 * RETURN VALUES: none 354 * 355 * ERRORS: none 356 */ 357static void 358_search_child(Widget w, 359 char *indx, 360 char *remainder, 361 char *resource, 362 char *value, 363 char last_token, 364 char *last_part) 365{ 366 int i; 367 int num_children; 368 Widget *children; 369 370 /* 371 * Recursively search through the children 372 */ 373 num_children = _locate_children(w, &children); 374 for (i = 0; i < num_children; i++) { 375 _set_and_search(children[i], indx, remainder, resource, 376 value, last_token, last_part); 377 } 378 379 XtFree((char *) children); 380} 381 382/* 383 * NAME: _get_part 384 * 385 * FUNCTION: 386 * This routine will return the token and following part of the resource 387 * when given the current index it will update the index accordingly 388 * 389 * PARAMETERS: 390 * remainder the part of the resource string left over 391 * indx the index into the resource string 392 * part the parsed off part of the resource string 393 * 394 * RETURN VALUES: 395 * char the token (* or . or ?) preceding the resource part 396 * indx the index into the resource string 397 * part the parsed off part of the resource string 398 * 399 * ERRORS: none 400 */ 401static char 402_get_part(char *remainder _X_UNUSED, char **indx, char **part) 403{ 404 char buffer[MAX_BUFFER]; 405 char *buf_ptr; 406 char token = **indx; 407 int i = 0; 408 409 /* 410 * copy the remainder part into the buffer 411 */ 412 buf_ptr = buffer; 413 (*indx)++; /* get rid of the token */ 414 while (**indx && (**indx != '.') && (**indx != '*')) { 415 *buf_ptr++ = *(*indx)++; 416 if (++i >= MAX_BUFFER - 1) 417 break; 418 } 419 *buf_ptr = '\0'; 420 421 *part = XtNewString(buffer); /* return a new string to part */ 422 423 if (strcmp(*indx, "") == 0) 424 *indx = NULL; 425 426 return (token); /* return the token */ 427} 428 429/* 430 * NAME: _match_resource_to_widget 431 * 432 * FUNCTION: 433 * This function matches the resource part to the widget name or class 434 * 435 * PARAMETERS: 436 * w the widget to match 437 * part the parsed off part of the resource string 438 * 439 * RETURN VALUES: 440 * Boolean true if a match occurs 441 * 442 * ERRORS: none 443 */ 444static Boolean 445_match_resource_to_widget(Widget w, char *part) 446{ 447 /* 448 * Match any widget at this level if the ? is used 449 */ 450 if (strcmp(part, "?") == 0) 451 return (True); 452 453 /* 454 * if the object is really a widget then its name can be matched 455 * otherwise only use its class. Note that if you try to reference 456 * a widget name when the object is not a widget, you may get a 457 * core dump from an invalid pointer reference. 458 */ 459 if (XtIsWidget(w)) { 460 if ((strcmp(w->core.name, part) == 0) || 461 (strcmp(w->core.widget_class->core_class.class_name, part) == 0)) 462 return (True); 463 else 464 return (False); 465 } 466 else { 467 if ((strcmp(w->core.widget_class->core_class.class_name, part) == 0)) 468 return (True); 469 else 470 return (False); 471 } 472} 473 474/* 475 * NAME: _set_and_search 476 * 477 * FUNCTION: 478 * The algorithm to search the widget tree and apply a resource string 479 * 480 * PARAMETERS: 481 * w the widget to match 482 * indx the index into the resource string 483 * remainder the part of the resource string left over 484 * resource the resource string to be matched 485 * value the value to be set 486 * last_token the last * or . before the final resource part 487 * last_part the last resource part (e.g. *background) 488 * 489 * RETURN VALUES: none 490 * 491 * ERRORS: none 492 * 493 * ALGORITHM: 494 * loop (look at all children) 495 * if (resource segment and current widget match) 496 * if '.' 497 * if at end of resource string 498 * set values ( .=over all children 499 * *=this widget only) 500 * else 501 * descend the widget tree 502 * and parse off resource segment 503 * exit the loop 504 * if '*' 505 * if at end of resource string 506 * set values ( .=over all children 507 * *=this widget only) 508 * descend and parse 509 * else 510 * if '.' 511 * continue looping 512 * if '*' 513 * descend but don't parse 514 * continue looping 515 * end loop 516 * 517 * NOTE: the _set_resource_values routine will not allow a value to be 518 * set on a resource against the rules of the resource database manager 519 */ 520static void 521_set_and_search(Widget w, 522 char *indx, 523 char *remainder, 524 char *resource, 525 char *value, 526 char last_token, 527 char *last_part) 528{ 529 char *part; 530 char *local_index = indx; 531 char token; 532 533 /* 534 * parse off one part, return token and the new index 535 */ 536 token = _get_part(remainder, &local_index, &part); 537 538 if (_match_resource_to_widget(w, part)) { 539 if (token == '.') { 540 if (local_index == NULL) { 541 if (last_token == '.') { 542 _set_resource_values(w, resource, value, last_part); 543 } 544 else if (last_token == '*') { 545 _set_resource_values(w, resource, value, last_part); 546 _apply_values_to_children(w, 547 remainder, resource, value, 548 last_token, last_part); 549 } 550 } 551 else 552 _search_child(w, local_index, remainder, 553 resource, value, last_token, last_part); 554 XtFree(part); 555 return; 556 } 557 if (token == '*') { 558 if (local_index == NULL) { 559 if (last_token == '.') { 560 _set_resource_values(w, resource, value, last_part); 561 } 562 else if (last_token == '*') { 563 _set_resource_values(w, resource, value, last_part); 564 _apply_values_to_children(w, 565 remainder, resource, value, 566 last_token, last_part); 567 } 568 } 569 else 570 _search_child(w, local_index, remainder, 571 resource, value, last_token, last_part); 572 } 573 } 574 else { /* if the widget name and class don't match the part */ 575 /* if (token == '.') just continue looping */ 576 577 if (token == '*') { 578 _search_child(w, indx, remainder, resource, value, 579 last_token, last_part); 580 } 581 } 582 583 XtFree(part); 584} 585 586/* 587 * NAME: _get_last_part 588 * 589 * FUNCTION: 590 * This routine will parse off the last segment of a resource string 591 * and its token and return them. the remainder of resource is also 592 * returned. strcoll is used to guarantee no problems with 593 * international strings. 594 * 595 * PARAMETERS: 596 * remainder the part of the resource string left over 597 * part the parsed off part of the resource string 598 * 599 * RETURN VALUES: 600 * char the token (* or . or ?) preceding the resource part 601 * remainder the part of the resource string left over 602 * part the parsed off part of the resource string 603 * 604 * ERRORS: none 605 */ 606static char 607_get_last_part(char *remainder, char **part) 608{ 609 char *loose, *tight; 610 611 loose = strrchr(remainder, '*'); 612 tight = strrchr(remainder, '.'); 613 614 if ((loose == NULL) && (tight == NULL)) { 615 *part = XtNewString(remainder); 616 return ('.'); 617 } 618 if ((loose == NULL) || (tight && (strcoll(loose, tight) < 0))) { 619 *tight++ = '\0'; /* shorten the remainder string */ 620 *part = XtNewString(tight); 621 return ('.'); 622 } 623 if ((tight == NULL) || (strcoll(tight, loose) < 0)) { 624 *loose++ = '\0'; 625 *part = XtNewString(loose); 626 return ('*'); 627 } 628 *part = NULL; 629 630 return ('0'); /* error - return 0 */ 631} 632 633/* 634 * NAME: _search_widget_tree 635 * 636 * FUNCTION: 637 * This function tries to match a resource string to the widgets 638 * it applies to. The functions it invokes to do this then set 639 * the value for that resource to each widget. 640 * 641 * The resource string has to be parsed into the following format: 642 * resource = App*Form*button1.background 643 * remainder = *Form*button1 644 * last_part = background last_token = . 645 * As the widget tree is recursively descended, these variables are 646 * passed. The remainder is parsed at each level in the widget 647 * tree as the _set_and_search function attempts to match 648 * the resource part (eg. part = Form token = *) to a widget. When 649 * the entire resource string has been matched, the _set_resource_values 650 * functions is called to apply the value to the widget or widgets. 651 * 652 * PARAMETERS: 653 * w a widget from whose toplevel shell ancestor 654 * the search will start 655 * resource the resource string to match 656 * value the value to apply 657 * 658 * RETURN VALUES: none 659 * 660 * ERRORS: none 661 */ 662static void 663_search_widget_tree(Widget w, char *resource, char *value) 664{ 665 Widget parent = w; 666 char *last_part; 667 char *remainder = NULL; 668 char *loose, *tight; 669 int loose_len, tight_len; 670 671 if (resource == NULL) 672 return; 673 674 /* 675 * Find the root of the tree given any widget 676 */ 677 while (XtParent(parent) != NULL) { 678 parent = XtParent(parent); 679 } 680#ifdef DEBUG 681 if (XtIsWidget(w) && XtIsWidget(parent)) 682 fprintf(stderr, "widget = %s parent = %s\n", 683 w->core.name, parent->core.name); 684 else 685 fprintf(stderr, "widget = NULL parent = NULL\n"); 686#endif 687 688 /* 689 * parse off the Class name that was prepended to this string in 690 * a customizing tool 691 */ 692 loose = strchr(resource, '*'); 693 tight = strchr(resource, '.'); 694 if ((loose == NULL) && (tight == NULL)) 695 return; 696 697 loose_len = (loose) ? (int) strlen(loose) : 0; 698 tight_len = (tight) ? (int) strlen(tight) : 0; 699 700 if ((loose == NULL) || (tight_len > loose_len)) 701 remainder = XtNewString(tight); 702 else if ((tight == NULL) || (loose_len > tight_len)) 703 remainder = XtNewString(loose); 704 705 /* 706 * Parse last segment off of resource string, (eg. background, font, 707 * etc.) 708 */ 709 if (remainder) { 710 char last_token; 711 712 last_token = _get_last_part(remainder, &last_part); 713 /* 714 * this case covers resources of only one level (eg. *background) 715 */ 716 if (remainder[0] == 0) { 717 _set_resource_values(w, resource, value, last_part); 718 if (last_token == '*') 719 _apply_values_to_children(parent, remainder, resource, 720 value, last_token, last_part); 721 /* 722 * all other resource strings are recursively applied to the widget tree. 723 * Prepend a '.' to the remainder string if there is no leading token. 724 */ 725 } 726 else { 727 char *indx, *copy; 728 729 if (remainder[0] != '*' && remainder[0] != '.') { 730 XtAsprintf(©, ".%s", remainder); 731 XtFree(remainder); 732 remainder = copy; 733 } 734 indx = remainder; 735 _set_and_search(parent, indx, remainder, resource, value, 736 last_token, last_part); 737 } 738 739 XtFree(remainder); 740 XtFree(last_part); 741 } 742} 743 744/* 745 * NAME: _locate_children 746 * 747 * FUNCTION: 748 * returns a list of all of a widget's children 749 * 750 * PARAMETERS: 751 * w the parent to search for its children 752 * children the list of children that is created 753 * normal flag for normal children 754 * popup flag for popup children 755 * 756 * RETURN VALUES: 757 * int the number of children 758 * children the list of children found 759 * 760 * ERRORS: none 761 */ 762static int 763_locate_children(Widget parent, Widget **children) 764{ 765 CompositeWidget comp = (CompositeWidget) parent; 766 Cardinal i; 767 int num_children = 0; 768 int current = 0; 769 770 /* 771 * count the number of children 772 */ 773 if (XtIsWidget(parent)) 774 num_children = 775 (int) ((Cardinal) num_children + parent->core.num_popups); 776 if (XtIsComposite(parent)) 777 num_children = 778 (int) ((Cardinal) num_children + comp->composite.num_children); 779 if (num_children == 0) { 780 *children = NULL; 781 return (0); 782 } 783 784 *children = XtMallocArray((Cardinal)num_children, (Cardinal)sizeof(Widget)); 785 786 if (XtIsComposite(parent)) { 787 for (i = 0; i < comp->composite.num_children; i++) { 788 (*children)[current] = comp->composite.children[i]; 789 current++; 790 } 791 } 792 793 if (XtIsWidget(parent)) { 794 for (i = 0; i < parent->core.num_popups; i++) { 795 (*children)[current] = comp->core.popup_list[i]; 796 current++; 797 } 798 } 799 800 return (num_children); 801} 802 803#ifdef DEBUG 804/* 805 * NAME: dump_widget_tree 806 * 807 * FUNCTION: 808 * recursively printout entire widget tree 809 * 810 * PARAMETERS: 811 * w the widget to match 812 * indent the amount to indent each line 813 * 814 * RETURN VALUES: void 815 * 816 * ERRORS: none 817 */ 818static void 819dump_widget_tree(Widget w, int indent) 820{ 821 int i, j; 822 int num_children; 823 Widget *children; 824 825 /* 826 * Recursively search through the children 827 */ 828 num_children = _locate_children(w, &children); 829 indent += 2; 830 for (i = 0; i < num_children; i++) { 831 if (children[i] != NULL) { 832 for (j = 0; j < indent; j++) 833 fprintf(stderr, " "); 834 if (XtIsWidget(children[i])) { 835 fprintf(stderr, "(%s)\t", children[i]->core.name); 836 fprintf(stderr, "(%s)\n", 837 children[i]->core.widget_class->core_class.class_name); 838 } 839 else { 840 fprintf(stderr, "(NULL)\t"); 841 fprintf(stderr, "(%s)\n", 842 children[i]->core.widget_class->core_class.class_name); 843 } 844 } 845 dump_widget_tree(children[i], indent); 846 } 847 848 XtFree((char *) children); 849} 850#endif 851 852/* 853 * NAME: _XtResourceConfiguationEH 854 * 855 * FUNCTION: 856 * This function is the event handler for the on-the-fly communication 857 * with a resource customization tool. This event handler must be 858 * registered for the toplevel shell of each app. This is best done 859 * in the _XtCreatePopupShell and _XtAppCreateShell functions in Xt's 860 * Create.c source file. 861 * 862 * The property used to communicate with a customizing tool is 863 * placed on the toplevel shell window of the application. The 864 * customizing tool places a property on this window which causes 865 * this event handler to be invoked via the PropertyNotify event. 866 * This event handler reads the property and then deletes it from 867 * the server. The contents of the property are a resource string 868 * and value. The event handler then calls functions to walk the 869 * applications widget tree, determining which widgets are affected 870 * by the resource string, and then applying the value with XtSetValues. 871 * 872 * PARAMETERS: 873 * w the widget that invoked this event handler 874 * client_data not used 875 * event the event structure 876 * 877 * RETURN VALUES: none 878 * 879 * ERRORS: none 880 */ 881void 882_XtResourceConfigurationEH(Widget w, 883 XtPointer client_data _X_UNUSED, 884 XEvent *event, 885 Boolean *continue_to_dispatch _X_UNUSED) 886{ 887 Atom actual_type; 888 int actual_format; 889 unsigned long nitems; 890 unsigned long leftover; 891 char *data = NULL; 892 char *data_ptr; 893 894#ifdef DEBUG 895 int indent = 0; 896#endif 897 XtPerDisplay pd; 898 899#ifdef DEBUG 900 fprintf(stderr, "in _XtResourceConfiguationEH atom = %u\n", 901 (unsigned) event->xproperty.atom); 902 fprintf(stderr, " window = %x\n", (unsigned) XtWindow(w)); 903 if (XtIsWidget(w)) 904 fprintf(stderr, " widget = %zx name = %s\n", (size_t) w, 905 w->core.name); 906#endif 907 908 pd = _XtGetPerDisplay(XtDisplay(w)); 909 910 /* 911 * The window on which a customizing tool places the property 912 * is determined at this point. It should be the applications 913 * toplevel shell window. 914 * 915 * A customizing tool sends a "ping" to the application on 916 * the RCM_INIT property. The application answers the ping 917 * by deleting the property. 918 */ 919 if (event->xproperty.atom == pd->rcm_init) { 920 XDeleteProperty(XtDisplay(w), XtWindow(w), pd->rcm_init); 921 922#ifdef DEBUG 923 if (XtIsWidget(w)) 924 fprintf(stderr, "%s\n", w->core.name); 925 else 926 fprintf(stderr, "NULL name\n"); 927 dump_widget_tree(w, indent); 928 929 fprintf(stderr, "answer ping\n"); 930#endif 931 } 932 933 /* 934 * This event handler ignores any property notify events that 935 * are not RCM_INIT or RCM_DATA 936 */ 937 if (event->xproperty.atom != pd->rcm_data) 938 return; 939 940 /* 941 * Retrieve the data from the property 942 */ 943#ifdef DEBUG 944 fprintf(stderr, "receiving RCM_DATA property\n"); 945#endif 946 if (XGetWindowProperty(XtDisplay(w), 947 XtWindow(w), 948 pd->rcm_data, 0L, 8192L, 949 TRUE, XA_STRING, 950 &actual_type, &actual_format, &nitems, &leftover, 951 (unsigned char **) &data) == Success && 952 actual_type == XA_STRING && actual_format == 8) { 953 /* 954 * data format is: 955 * 956 * resource_length, resource, value 957 * 958 * convert the resource_length to a long, skip over it, put a 959 * zero byte at the end of the resource, and pick off the 960 * resource and value fields. 961 */ 962 if (data) { 963 char *data_end = data + nitems; 964 char *data_value; 965 unsigned long resource_len; 966 967 resource_len = strtoul(data, &data_ptr, 10); 968 969 if (data_ptr != (char *) data) { 970 data_ptr++; 971 data_value = data_ptr + resource_len; 972 } 973 else /* strtoul failed to convert a number */ 974 data_ptr = data_value = NULL; 975 976 if (data_value > data_ptr && data_value < data_end) { 977 char *resource; 978 char *value; 979 980 *data_value++ = '\0'; 981 982 resource = XtNewString(data_ptr); 983 value = XtNewString(data_value); 984#ifdef DEBUG 985 fprintf(stderr, "resource_len=%lu\n", resource_len); 986 fprintf(stderr, "resource = %s\t value = %s\n", 987 resource, value); 988#endif 989 /* 990 * descend the application widget tree and 991 * apply the value to the appropriate widgets 992 */ 993 _search_widget_tree(w, resource, value); 994 995 XtFree(resource); 996 XtFree(value); 997 } 998 } 999 } 1000 1001 XFree((char *) data); 1002} 1003