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