1444c061aSmrg/* 2444c061aSmrg 3444c061aSmrgCopyright 1987, 1988, 1998 The Open Group 4444c061aSmrg 5444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its 6444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that 7444c061aSmrgthe above copyright notice appear in all copies and that both that 8444c061aSmrgcopyright notice and this permission notice appear in supporting 9444c061aSmrgdocumentation. 10444c061aSmrg 11444c061aSmrgThe above copyright notice and this permission notice shall be included in 12444c061aSmrgall copies or substantial portions of the Software. 13444c061aSmrg 14444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20444c061aSmrg 21444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be 22444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings 23444c061aSmrgin this Software without prior written authorization from The Open Group. 24444c061aSmrg 25444c061aSmrg*/ 26444c061aSmrg/***************************************************************** 27444c061aSmrg 28444c061aSmrg(C) COPYRIGHT International Business Machines Corp. 1992,1997 29444c061aSmrg All Rights Reserved 30444c061aSmrg 31444c061aSmrgPermission is hereby granted, free of charge, to any person obtaining a copy 32444c061aSmrgof this software and associated documentation files (the "Software"), to deal 33444c061aSmrgin the Software without restriction, including without limitation the rights 34444c061aSmrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell 35444c061aSmrgcopies of the Software. 36444c061aSmrg 37444c061aSmrgThe above copyright notice and this permission notice shall be included in 38444c061aSmrgall copies or substantial portions of the Software. 39444c061aSmrg 40444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 43444c061aSmrgTHE IBM CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, 44444c061aSmrgBUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, 45444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 46444c061aSmrgIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 47444c061aSmrg 48444c061aSmrgExcept as contained in this notice, the name of the IBM Corporation shall 49444c061aSmrgnot be used in advertising or otherwise to promote the sale, use or other 50444c061aSmrgdealings in this Software without prior written authorization from the IBM 51444c061aSmrgCorporation. 52444c061aSmrg 53444c061aSmrg******************************************************************/ 54444c061aSmrg 55444c061aSmrg#ifdef HAVE_CONFIG_H 56444c061aSmrg#include <config.h> 57444c061aSmrg#endif 58444c061aSmrg#include "Intrinsic.h" 59444c061aSmrg#include "IntrinsicI.h" 60444c061aSmrg#include "Core.h" 61444c061aSmrg#include "CoreP.h" 62444c061aSmrg#include "ShellP.h" 63444c061aSmrg#include "StringDefs.h" 64444c061aSmrg#include "ResConfigP.h" 65444c061aSmrg#include <X11/Xatom.h> 66444c061aSmrg#include <stdio.h> 67444c061aSmrg#include <stdlib.h> 68444c061aSmrg 69444c061aSmrg#define MAX_BUFFER 512 70444c061aSmrg 71444c061aSmrgstatic void _search_child(Widget, char *, char *, char *, char *, char, char *); 72362b94d5Smrgstatic void _set_and_search(Widget, char *, char *, char *, char *, char, 73362b94d5Smrg char *); 74444c061aSmrgstatic int _locate_children(Widget, Widget **); 75444c061aSmrg 76444c061aSmrg/* 77444c061aSmrg * NAME: _set_resource_values 78444c061aSmrg * 79444c061aSmrg * FUNCTION: 80362b94d5Smrg * This function sets the value on the widget. It must first determine 81362b94d5Smrg * if the last part is a valid resource for that widget. (eg. 82362b94d5Smrg * labelString is a valid resource for label but not for bulletin board) 83362b94d5Smrg * It must also add the resource to the application's resource database 84362b94d5Smrg * and then query it out using specific resource strings that it builds 85362b94d5Smrg * from the widget information. This ensures that a customizing tool 86362b94d5Smrg * on-the-fly paradigm is followed: an application that is 87362b94d5Smrg * instantaneously updated should look the same as one that is restarted 88362b94d5Smrg * and uses the .Xdefaults file. 89444c061aSmrg * 90444c061aSmrg * PARAMETERS: 91362b94d5Smrg * w the widget to match 92362b94d5Smrg * resource the resource string to be matched 93362b94d5Smrg * value the value to be set 94362b94d5Smrg * last_part the last resource part (e.g. *background) 95444c061aSmrg * 96444c061aSmrg * RETURN VALUES: void 97444c061aSmrg * 98444c061aSmrg * ERRORS: none 99444c061aSmrg */ 100444c061aSmrgstatic void 101362b94d5Smrg_set_resource_values(Widget w, char *resource, char *value, char *last_part) 102444c061aSmrg{ 103362b94d5Smrg XrmDatabase db = NULL; 104362b94d5Smrg char *resource_name = NULL; 105362b94d5Smrg char *resource_class = NULL; 106362b94d5Smrg char *return_type; 107362b94d5Smrg XrmValue return_value; 108362b94d5Smrg char *resource_value; 109362b94d5Smrg Widget cur = w; 110362b94d5Smrg char *temp; 111362b94d5Smrg XtResourceList resources_return = NULL; 112362b94d5Smrg Cardinal num_resources_return = 0; 113362b94d5Smrg Cardinal res_index; 114362b94d5Smrg Boolean found_resource = False; 115362b94d5Smrg Display *dpy; 116362b94d5Smrg XrmDatabase tmp_db; 117362b94d5Smrg 118362b94d5Smrg if (last_part == NULL) 119362b94d5Smrg return; 120362b94d5Smrg 121362b94d5Smrg if (!XtIsWidget(w)) { 122362b94d5Smrg if (w == 0 || w->core.parent == 0) 123362b94d5Smrg return; 124362b94d5Smrg dpy = XtDisplay(w->core.parent); 125362b94d5Smrg } 126362b94d5Smrg else { 127362b94d5Smrg dpy = XtDisplay(w); 128362b94d5Smrg } 129362b94d5Smrg tmp_db = XtDatabase(dpy); 130362b94d5Smrg 131362b94d5Smrg /* 132362b94d5Smrg * get a list of all the valid resources for this widget 133362b94d5Smrg */ 134362b94d5Smrg XtGetResourceList(w->core.widget_class, 135362b94d5Smrg &resources_return, &num_resources_return); 136362b94d5Smrg 137362b94d5Smrg /* 138362b94d5Smrg * try to match the last_part of the resource string with 139362b94d5Smrg * a resource in this resource list 140362b94d5Smrg */ 141362b94d5Smrg for (res_index = 0; res_index < num_resources_return; res_index++) { 142362b94d5Smrg if ((strcmp(last_part, 143362b94d5Smrg resources_return[res_index].resource_name) == 0) || 144362b94d5Smrg (strcmp(last_part, 145362b94d5Smrg resources_return[res_index].resource_class) == 0)) { 146362b94d5Smrg found_resource = True; 147362b94d5Smrg break; 148362b94d5Smrg } 149362b94d5Smrg } 150362b94d5Smrg 151362b94d5Smrg /* 152362b94d5Smrg * if resource is not a valid resource for this widget 153362b94d5Smrg * or the resource name or class are NULL 154362b94d5Smrg * then exit this function 155362b94d5Smrg */ 156362b94d5Smrg if (!found_resource 157362b94d5Smrg || !resources_return[res_index].resource_name 158362b94d5Smrg || !resources_return[res_index].resource_class) { 159362b94d5Smrg XtFree((char *) resources_return); 160362b94d5Smrg return; 161362b94d5Smrg } 162362b94d5Smrg 163362b94d5Smrg /* 164362b94d5Smrg * build the full resource name and class specifications so 165362b94d5Smrg * that you can query the resource database 166362b94d5Smrg * eg: .app.button1.foreground 167362b94d5Smrg * .App.XmPushButton.Foreground 168362b94d5Smrg */ 169362b94d5Smrg while (cur != NULL) { 170362b94d5Smrg /* 171362b94d5Smrg * create resource name string 172362b94d5Smrg */ 173362b94d5Smrg if (resource_name) { 174362b94d5Smrg XtAsprintf(&temp, ".%s%s", cur->core.name, resource_name); 175362b94d5Smrg XtFree(resource_name); 176362b94d5Smrg } 177362b94d5Smrg else if (!XtIsWidget(cur) || !cur->core.name) { 178362b94d5Smrg cur = XtParent(cur); 179362b94d5Smrg continue; 180362b94d5Smrg } 181362b94d5Smrg else { 182362b94d5Smrg XtAsprintf(&temp, ".%s", cur->core.name); 183362b94d5Smrg } 184362b94d5Smrg resource_name = temp; 185362b94d5Smrg 186362b94d5Smrg /* 187362b94d5Smrg * create resource class string 188362b94d5Smrg */ 189362b94d5Smrg if ((XtIsTopLevelShell(cur)) && (XtParent(cur) == NULL)) { 190362b94d5Smrg ApplicationShellWidget top = (ApplicationShellWidget) (cur); 191362b94d5Smrg 192362b94d5Smrg if (resource_class) { 193362b94d5Smrg XtAsprintf(&temp, ".%s%s", 194362b94d5Smrg top->application.class, resource_class); 195362b94d5Smrg } 196362b94d5Smrg else { 197362b94d5Smrg XtAsprintf(&temp, ".%s", top->application.class); 198362b94d5Smrg } 199362b94d5Smrg } 200362b94d5Smrg else { 201362b94d5Smrg if (resource_class) { 202362b94d5Smrg XtAsprintf(&temp, ".%s%s", 203362b94d5Smrg cur->core.widget_class->core_class.class_name, 204362b94d5Smrg resource_class); 205362b94d5Smrg } 206362b94d5Smrg else { 207362b94d5Smrg XtAsprintf(&temp, ".%s", 208362b94d5Smrg cur->core.widget_class->core_class.class_name); 209362b94d5Smrg } 210362b94d5Smrg } 211362b94d5Smrg 212362b94d5Smrg XtFree(resource_class); 213362b94d5Smrg resource_class = temp; 214362b94d5Smrg 215362b94d5Smrg cur = XtParent(cur); 216362b94d5Smrg } 217362b94d5Smrg 218362b94d5Smrg /* 219362b94d5Smrg * add the resource name to the end of the resource name string 220362b94d5Smrg */ 221362b94d5Smrg XtAsprintf(&temp, "%s.%s", resource_name, 222362b94d5Smrg resources_return[res_index].resource_name); 223362b94d5Smrg 224362b94d5Smrg XtFree(resource_name); 225362b94d5Smrg resource_name = temp; 226362b94d5Smrg 227362b94d5Smrg /* 228362b94d5Smrg * add the resource class to the end of the resource class string 229362b94d5Smrg */ 230362b94d5Smrg XtAsprintf(&temp, "%s.%s", resource_class, 231362b94d5Smrg resources_return[res_index].resource_class); 232362b94d5Smrg 233362b94d5Smrg XtFree(resource_class); 234362b94d5Smrg resource_class = temp; 235444c061aSmrg 236444c061aSmrg#ifdef DEBUG 237362b94d5Smrg fprintf(stderr, "resource_name = %s\n", resource_name); 238362b94d5Smrg fprintf(stderr, "resource_class = %s\n", resource_class); 239444c061aSmrg#endif 240444c061aSmrg 241362b94d5Smrg /* 242362b94d5Smrg * put the resource and its value in a resource database and 243362b94d5Smrg * then query it back out again using the specific name and 244362b94d5Smrg * class resource strings that were built above. This is 245362b94d5Smrg * necessary to maintain a precedence similar to the .Xdefaults 246362b94d5Smrg * file 247362b94d5Smrg */ 248362b94d5Smrg XrmPutStringResource(&db, resource, value); 249362b94d5Smrg XrmMergeDatabases(db, &tmp_db); 250362b94d5Smrg XrmGetResource(tmp_db, resource_name, resource_class, 251362b94d5Smrg &return_type, &return_value); 252362b94d5Smrg if (return_type) 253362b94d5Smrg resource_value = XtNewString(return_value.addr); 254362b94d5Smrg else 255362b94d5Smrg resource_value = XtNewString(value); 256444c061aSmrg 257444c061aSmrg#ifdef DEBUG 258362b94d5Smrg fprintf(stderr, 259362b94d5Smrg "Apply:\n\twidget = %s\n\tlast_part = %s\n\tvalue = %s\n", 260362b94d5Smrg (w->core.name == NULL) ? "NULL" : w->core.name, 261362b94d5Smrg resources_return[res_index].resource_name, resource_value); 262444c061aSmrg#endif 263362b94d5Smrg /* 264362b94d5Smrg * use XtVaSetValues with XtVaTypedArg to convert the value of 265362b94d5Smrg * type String the the same type as the resource (last_part). 266362b94d5Smrg * Then set the value. 267362b94d5Smrg */ 268362b94d5Smrg XtVaSetValues(w, 269362b94d5Smrg XtVaTypedArg, resources_return[res_index].resource_name, 270362b94d5Smrg XtRString, resource_value, strlen(resource_value) + 1, NULL); 271362b94d5Smrg 272362b94d5Smrg XtFree((char *) resources_return); 273362b94d5Smrg XtFree(resource_name); 274362b94d5Smrg XtFree(resource_class); 275362b94d5Smrg XtFree(resource_value); 276444c061aSmrg} 277444c061aSmrg 278444c061aSmrg/* 279444c061aSmrg * NAME: _apply_values_to_children 280444c061aSmrg * 281444c061aSmrg * FUNCTION: 282362b94d5Smrg * Once the resource string matches the value must be applied to 283362b94d5Smrg * all children if applicable. (eg. App*Form.background must apply 284362b94d5Smrg * background to all children of the Form widget) 285444c061aSmrg * 286444c061aSmrg * PARAMETERS: 287362b94d5Smrg * w the widget to match 288362b94d5Smrg * remainder the part of the resource string left over 289362b94d5Smrg * resource the resource string to be matched 290362b94d5Smrg * value the value to be set 291a773ec55Smrg * last_token the last * or . before the final resource part 292362b94d5Smrg * last_part the last resource part (e.g. *background) 293444c061aSmrg * 294444c061aSmrg * RETURN VALUES: void 295444c061aSmrg * 296444c061aSmrg * ERRORS: none 297444c061aSmrg */ 298444c061aSmrgstatic void 299362b94d5Smrg_apply_values_to_children(Widget w, 300362b94d5Smrg char *remainder, 301362b94d5Smrg char *resource, 302362b94d5Smrg char *value, 303362b94d5Smrg char last_token, 304362b94d5Smrg char *last_part) 305444c061aSmrg{ 306362b94d5Smrg int i; 307362b94d5Smrg int num_children; 308362b94d5Smrg Widget *children; 309444c061aSmrg 310362b94d5Smrg /* 311362b94d5Smrg * Recursively search through the children 312362b94d5Smrg */ 313362b94d5Smrg num_children = _locate_children(w, &children); 314444c061aSmrg 315362b94d5Smrg for (i = 0; i < num_children; i++) { 316444c061aSmrg 317444c061aSmrg#ifdef DEBUG 318362b94d5Smrg if (XtIsWidget(children[i]) && XtIsWidget(w)) 319362b94d5Smrg fprintf(stderr, "searching child %s of parent %s\n", 320362b94d5Smrg children[i]->core.name, w->core.name); 321362b94d5Smrg else 322362b94d5Smrg fprintf(stderr, "searching child (NULL) of parent %s\n", 323362b94d5Smrg w->core.name); 324362b94d5Smrg if (!XtIsWidget(children[i])) 325362b94d5Smrg fprintf(stderr, "children[%d] is NOT a widget\n", i); 326362b94d5Smrg if (!XtIsWidget(w)) 327362b94d5Smrg fprintf(stderr, "w is NOT a widget\n"); 328444c061aSmrg#endif 329444c061aSmrg 330362b94d5Smrg _set_resource_values(children[i], resource, value, last_part); 331362b94d5Smrg _apply_values_to_children(children[i], remainder, 332362b94d5Smrg resource, value, last_token, last_part); 333362b94d5Smrg } 334444c061aSmrg 335362b94d5Smrg XtFree((char *) children); 336444c061aSmrg} 337444c061aSmrg 338444c061aSmrg/* 339444c061aSmrg * NAME: _search_child 340444c061aSmrg * 341444c061aSmrg * FUNCTION: 342362b94d5Smrg * descends through each child of the tree 343444c061aSmrg * 344444c061aSmrg * PARAMETERS: 345362b94d5Smrg * w the widget whose children are to be searched 346362b94d5Smrg * indx index into the resource string 347362b94d5Smrg * remainder the remaining part of the resource string 348362b94d5Smrg * resource the resource string to be matched 349362b94d5Smrg * value the value to be applied 350a773ec55Smrg * last_token the last * or . before the final resource part 351362b94d5Smrg * last_part the last resource part (e.g. *background) 352444c061aSmrg * 353444c061aSmrg * RETURN VALUES: none 354444c061aSmrg * 355444c061aSmrg * ERRORS: none 356444c061aSmrg */ 357444c061aSmrgstatic void 358362b94d5Smrg_search_child(Widget w, 359362b94d5Smrg char *indx, 360362b94d5Smrg char *remainder, 361362b94d5Smrg char *resource, 362362b94d5Smrg char *value, 363362b94d5Smrg char last_token, 364362b94d5Smrg char *last_part) 365444c061aSmrg{ 366362b94d5Smrg int i; 367362b94d5Smrg int num_children; 368362b94d5Smrg Widget *children; 369362b94d5Smrg 370362b94d5Smrg /* 371362b94d5Smrg * Recursively search through the children 372362b94d5Smrg */ 373362b94d5Smrg num_children = _locate_children(w, &children); 374362b94d5Smrg for (i = 0; i < num_children; i++) { 375362b94d5Smrg _set_and_search(children[i], indx, remainder, resource, 376362b94d5Smrg value, last_token, last_part); 377362b94d5Smrg } 378362b94d5Smrg 379362b94d5Smrg XtFree((char *) children); 380444c061aSmrg} 381444c061aSmrg 382444c061aSmrg/* 383444c061aSmrg * NAME: _get_part 384444c061aSmrg * 385444c061aSmrg * FUNCTION: 386362b94d5Smrg * This routine will return the token and following part of the resource 387362b94d5Smrg * when given the current index it will update the index accordingly 388444c061aSmrg * 389444c061aSmrg * PARAMETERS: 390362b94d5Smrg * remainder the part of the resource string left over 391362b94d5Smrg * indx the index into the resource string 392362b94d5Smrg * part the parsed off part of the resource string 393444c061aSmrg * 394444c061aSmrg * RETURN VALUES: 395362b94d5Smrg * char the token (* or . or ?) preceding the resource part 396362b94d5Smrg * indx the index into the resource string 397362b94d5Smrg * part the parsed off part of the resource string 398444c061aSmrg * 399444c061aSmrg * ERRORS: none 400444c061aSmrg */ 401444c061aSmrgstatic char 402362b94d5Smrg_get_part(char *remainder _X_UNUSED, char **indx, char **part) 403444c061aSmrg{ 404362b94d5Smrg char buffer[MAX_BUFFER]; 405362b94d5Smrg char *buf_ptr; 406362b94d5Smrg char token = **indx; 407362b94d5Smrg int i = 0; 408362b94d5Smrg 409362b94d5Smrg /* 410362b94d5Smrg * copy the remainder part into the buffer 411362b94d5Smrg */ 412362b94d5Smrg buf_ptr = buffer; 413362b94d5Smrg (*indx)++; /* get rid of the token */ 414362b94d5Smrg while (**indx && (**indx != '.') && (**indx != '*')) { 415362b94d5Smrg *buf_ptr++ = *(*indx)++; 416362b94d5Smrg if (++i >= MAX_BUFFER - 1) 417362b94d5Smrg break; 418362b94d5Smrg } 419362b94d5Smrg *buf_ptr = '\0'; 420362b94d5Smrg 421362b94d5Smrg *part = XtNewString(buffer); /* return a new string to part */ 422362b94d5Smrg 423362b94d5Smrg if (strcmp(*indx, "") == 0) 424362b94d5Smrg *indx = NULL; 425362b94d5Smrg 426362b94d5Smrg return (token); /* return the token */ 427444c061aSmrg} 428444c061aSmrg 429444c061aSmrg/* 430444c061aSmrg * NAME: _match_resource_to_widget 431444c061aSmrg * 432444c061aSmrg * FUNCTION: 433362b94d5Smrg * This function matches the resource part to the widget name or class 434444c061aSmrg * 435444c061aSmrg * PARAMETERS: 436362b94d5Smrg * w the widget to match 437362b94d5Smrg * part the parsed off part of the resource string 438444c061aSmrg * 439444c061aSmrg * RETURN VALUES: 440362b94d5Smrg * Boolean true if a match occurs 441444c061aSmrg * 442444c061aSmrg * ERRORS: none 443444c061aSmrg */ 444444c061aSmrgstatic Boolean 445362b94d5Smrg_match_resource_to_widget(Widget w, char *part) 446444c061aSmrg{ 447362b94d5Smrg /* 448362b94d5Smrg * Match any widget at this level if the ? is used 449362b94d5Smrg */ 450362b94d5Smrg if (strcmp(part, "?") == 0) 451362b94d5Smrg return (True); 452362b94d5Smrg 453362b94d5Smrg /* 454362b94d5Smrg * if the object is really a widget then its name can be matched 455362b94d5Smrg * otherwise only use its class. Note that if you try to reference 456362b94d5Smrg * a widget name when the object is not a widget, you may get a 457362b94d5Smrg * core dump from an invalid pointer reference. 458362b94d5Smrg */ 459362b94d5Smrg if (XtIsWidget(w)) { 460362b94d5Smrg if ((strcmp(w->core.name, part) == 0) || 461362b94d5Smrg (strcmp(w->core.widget_class->core_class.class_name, part) == 0)) 462362b94d5Smrg return (True); 463362b94d5Smrg else 464362b94d5Smrg return (False); 465362b94d5Smrg } 466362b94d5Smrg else { 467362b94d5Smrg if ((strcmp(w->core.widget_class->core_class.class_name, part) == 0)) 468362b94d5Smrg return (True); 469362b94d5Smrg else 470362b94d5Smrg return (False); 471362b94d5Smrg } 472444c061aSmrg} 473444c061aSmrg 474444c061aSmrg/* 475444c061aSmrg * NAME: _set_and_search 476444c061aSmrg * 477444c061aSmrg * FUNCTION: 478362b94d5Smrg * The algorithm to search the widget tree and apply a resource string 479444c061aSmrg * 480444c061aSmrg * PARAMETERS: 481362b94d5Smrg * w the widget to match 482362b94d5Smrg * indx the index into the resource string 483362b94d5Smrg * remainder the part of the resource string left over 484362b94d5Smrg * resource the resource string to be matched 485362b94d5Smrg * value the value to be set 486a773ec55Smrg * last_token the last * or . before the final resource part 487362b94d5Smrg * last_part the last resource part (e.g. *background) 488444c061aSmrg * 489444c061aSmrg * RETURN VALUES: none 490444c061aSmrg * 491444c061aSmrg * ERRORS: none 492444c061aSmrg * 493444c061aSmrg * ALGORITHM: 494444c061aSmrg * loop (look at all children) 495362b94d5Smrg * if (resource segment and current widget match) 496362b94d5Smrg * if '.' 497362b94d5Smrg * if at end of resource string 498362b94d5Smrg * set values ( .=over all children 499362b94d5Smrg * *=this widget only) 500362b94d5Smrg * else 501362b94d5Smrg * descend the widget tree 502362b94d5Smrg * and parse off resource segment 503362b94d5Smrg * exit the loop 504362b94d5Smrg * if '*' 505362b94d5Smrg * if at end of resource string 506362b94d5Smrg * set values ( .=over all children 507362b94d5Smrg * *=this widget only) 508362b94d5Smrg * descend and parse 509362b94d5Smrg * else 510362b94d5Smrg * if '.' 511362b94d5Smrg * continue looping 512362b94d5Smrg * if '*' 513362b94d5Smrg * descend but don't parse 514362b94d5Smrg * continue looping 515444c061aSmrg * end loop 516444c061aSmrg * 517444c061aSmrg * NOTE: the _set_resource_values routine will not allow a value to be 518362b94d5Smrg * set on a resource against the rules of the resource database manager 519444c061aSmrg */ 520444c061aSmrgstatic void 521362b94d5Smrg_set_and_search(Widget w, 522362b94d5Smrg char *indx, 523362b94d5Smrg char *remainder, 524362b94d5Smrg char *resource, 525362b94d5Smrg char *value, 526362b94d5Smrg char last_token, 527362b94d5Smrg char *last_part) 528444c061aSmrg{ 529362b94d5Smrg char *part; 530362b94d5Smrg char *local_index = indx; 531362b94d5Smrg char token; 532362b94d5Smrg 533362b94d5Smrg /* 534362b94d5Smrg * parse off one part, return token and the new index 535362b94d5Smrg */ 536362b94d5Smrg token = _get_part(remainder, &local_index, &part); 537362b94d5Smrg 538362b94d5Smrg if (_match_resource_to_widget(w, part)) { 539362b94d5Smrg if (token == '.') { 540362b94d5Smrg if (local_index == NULL) { 541362b94d5Smrg if (last_token == '.') { 542362b94d5Smrg _set_resource_values(w, resource, value, last_part); 543362b94d5Smrg } 544362b94d5Smrg else if (last_token == '*') { 545362b94d5Smrg _set_resource_values(w, resource, value, last_part); 546362b94d5Smrg _apply_values_to_children(w, 547362b94d5Smrg remainder, resource, value, 548362b94d5Smrg last_token, last_part); 549362b94d5Smrg } 550362b94d5Smrg } 551362b94d5Smrg else 552362b94d5Smrg _search_child(w, local_index, remainder, 553362b94d5Smrg resource, value, last_token, last_part); 554362b94d5Smrg XtFree(part); 555362b94d5Smrg return; 556362b94d5Smrg } 557362b94d5Smrg if (token == '*') { 558362b94d5Smrg if (local_index == NULL) { 559362b94d5Smrg if (last_token == '.') { 560362b94d5Smrg _set_resource_values(w, resource, value, last_part); 561362b94d5Smrg } 562362b94d5Smrg else if (last_token == '*') { 563362b94d5Smrg _set_resource_values(w, resource, value, last_part); 564362b94d5Smrg _apply_values_to_children(w, 565362b94d5Smrg remainder, resource, value, 566362b94d5Smrg last_token, last_part); 567362b94d5Smrg } 568362b94d5Smrg } 569362b94d5Smrg else 570362b94d5Smrg _search_child(w, local_index, remainder, 571362b94d5Smrg resource, value, last_token, last_part); 572362b94d5Smrg } 573362b94d5Smrg } 574362b94d5Smrg else { /* if the widget name and class don't match the part */ 575362b94d5Smrg /* if (token == '.') just continue looping */ 576362b94d5Smrg 577362b94d5Smrg if (token == '*') { 578362b94d5Smrg _search_child(w, indx, remainder, resource, value, 579362b94d5Smrg last_token, last_part); 580362b94d5Smrg } 581362b94d5Smrg } 582362b94d5Smrg 583362b94d5Smrg XtFree(part); 584444c061aSmrg} 585444c061aSmrg 586444c061aSmrg/* 587444c061aSmrg * NAME: _get_last_part 588444c061aSmrg * 589444c061aSmrg * FUNCTION: 590362b94d5Smrg * This routine will parse off the last segment of a resource string 591362b94d5Smrg * and its token and return them. the remainder of resource is also 592362b94d5Smrg * returned. strcoll is used to guarantee no problems with 593362b94d5Smrg * international strings. 594444c061aSmrg * 595444c061aSmrg * PARAMETERS: 596362b94d5Smrg * remainder the part of the resource string left over 597362b94d5Smrg * part the parsed off part of the resource string 598444c061aSmrg * 599444c061aSmrg * RETURN VALUES: 600362b94d5Smrg * char the token (* or . or ?) preceding the resource part 601362b94d5Smrg * remainder the part of the resource string left over 602362b94d5Smrg * part the parsed off part of the resource string 603444c061aSmrg * 604444c061aSmrg * ERRORS: none 605444c061aSmrg */ 606444c061aSmrgstatic char 607362b94d5Smrg_get_last_part(char *remainder, char **part) 608444c061aSmrg{ 609362b94d5Smrg char *loose, *tight; 610362b94d5Smrg 611362b94d5Smrg loose = strrchr(remainder, '*'); 612362b94d5Smrg tight = strrchr(remainder, '.'); 613362b94d5Smrg 614362b94d5Smrg if ((loose == NULL) && (tight == NULL)) { 615362b94d5Smrg *part = XtNewString(remainder); 616362b94d5Smrg return ('.'); 617362b94d5Smrg } 618362b94d5Smrg if ((loose == NULL) || (tight && (strcoll(loose, tight) < 0))) { 619362b94d5Smrg *tight++ = '\0'; /* shorten the remainder string */ 620362b94d5Smrg *part = XtNewString(tight); 621362b94d5Smrg return ('.'); 622362b94d5Smrg } 623a773ec55Smrg if ((tight == NULL) || (strcoll(tight, loose) < 0)) { 624362b94d5Smrg *loose++ = '\0'; 625362b94d5Smrg *part = XtNewString(loose); 626362b94d5Smrg return ('*'); 627362b94d5Smrg } 628362b94d5Smrg *part = NULL; 629362b94d5Smrg 630362b94d5Smrg return ('0'); /* error - return 0 */ 631444c061aSmrg} 632444c061aSmrg 633444c061aSmrg/* 634444c061aSmrg * NAME: _search_widget_tree 635444c061aSmrg * 636444c061aSmrg * FUNCTION: 637362b94d5Smrg * This function tries to match a resource string to the widgets 638362b94d5Smrg * it applies to. The functions it invokes to do this then set 639362b94d5Smrg * the value for that resource to each widget. 640362b94d5Smrg * 641362b94d5Smrg * The resource string has to be parsed into the following format: 642362b94d5Smrg * resource = App*Form*button1.background 643362b94d5Smrg * remainder = *Form*button1 644362b94d5Smrg * last_part = background last_token = . 645362b94d5Smrg * As the widget tree is recursively descended, these variables are 646362b94d5Smrg * passed. The remainder is parsed at each level in the widget 647362b94d5Smrg * tree as the _set_and_search function attempts to match 648362b94d5Smrg * the resource part (eg. part = Form token = *) to a widget. When 649362b94d5Smrg * the entire resource string has been matched, the _set_resource_values 650362b94d5Smrg * functions is called to apply the value to the widget or widgets. 651444c061aSmrg * 652444c061aSmrg * PARAMETERS: 653362b94d5Smrg * w a widget from whose toplevel shell ancestor 654362b94d5Smrg * the search will start 655362b94d5Smrg * resource the resource string to match 656362b94d5Smrg * value the value to apply 657444c061aSmrg * 658444c061aSmrg * RETURN VALUES: none 659444c061aSmrg * 660444c061aSmrg * ERRORS: none 661444c061aSmrg */ 662444c061aSmrgstatic void 663362b94d5Smrg_search_widget_tree(Widget w, char *resource, char *value) 664444c061aSmrg{ 665362b94d5Smrg Widget parent = w; 666362b94d5Smrg char *last_part; 667362b94d5Smrg char *remainder = NULL; 668362b94d5Smrg char *loose, *tight; 669362b94d5Smrg int loose_len, tight_len; 670362b94d5Smrg 671a773ec55Smrg if (resource == NULL) 672a773ec55Smrg return; 673a773ec55Smrg 674362b94d5Smrg /* 675362b94d5Smrg * Find the root of the tree given any widget 676362b94d5Smrg */ 677362b94d5Smrg while (XtParent(parent) != NULL) { 678362b94d5Smrg parent = XtParent(parent); 679362b94d5Smrg } 680444c061aSmrg#ifdef DEBUG 681362b94d5Smrg if (XtIsWidget(w) && XtIsWidget(parent)) 682362b94d5Smrg fprintf(stderr, "widget = %s parent = %s\n", 683362b94d5Smrg w->core.name, parent->core.name); 684362b94d5Smrg else 685362b94d5Smrg fprintf(stderr, "widget = NULL parent = NULL\n"); 686444c061aSmrg#endif 687444c061aSmrg 688362b94d5Smrg /* 689362b94d5Smrg * parse off the Class name that was prepended to this string in 690362b94d5Smrg * a customizing tool 691362b94d5Smrg */ 692362b94d5Smrg loose = strchr(resource, '*'); 693362b94d5Smrg tight = strchr(resource, '.'); 694362b94d5Smrg if ((loose == NULL) && (tight == NULL)) 695362b94d5Smrg return; 696362b94d5Smrg 697362b94d5Smrg loose_len = (loose) ? (int) strlen(loose) : 0; 698362b94d5Smrg tight_len = (tight) ? (int) strlen(tight) : 0; 699362b94d5Smrg 700362b94d5Smrg if ((loose == NULL) || (tight_len > loose_len)) 701362b94d5Smrg remainder = XtNewString(tight); 702362b94d5Smrg else if ((tight == NULL) || (loose_len > tight_len)) 703362b94d5Smrg remainder = XtNewString(loose); 704362b94d5Smrg 705362b94d5Smrg /* 706362b94d5Smrg * Parse last segment off of resource string, (eg. background, font, 707362b94d5Smrg * etc.) 708362b94d5Smrg */ 709362b94d5Smrg if (remainder) { 710a773ec55Smrg char last_token; 711a773ec55Smrg 712362b94d5Smrg last_token = _get_last_part(remainder, &last_part); 713362b94d5Smrg /* 714362b94d5Smrg * this case covers resources of only one level (eg. *background) 715362b94d5Smrg */ 716362b94d5Smrg if (remainder[0] == 0) { 717362b94d5Smrg _set_resource_values(w, resource, value, last_part); 718362b94d5Smrg if (last_token == '*') 719362b94d5Smrg _apply_values_to_children(parent, remainder, resource, 720362b94d5Smrg value, last_token, last_part); 721362b94d5Smrg /* 722362b94d5Smrg * all other resource strings are recursively applied to the widget tree. 723362b94d5Smrg * Prepend a '.' to the remainder string if there is no leading token. 724362b94d5Smrg */ 725362b94d5Smrg } 726362b94d5Smrg else { 727362b94d5Smrg char *indx, *copy; 728362b94d5Smrg 729362b94d5Smrg if (remainder[0] != '*' && remainder[0] != '.') { 730362b94d5Smrg XtAsprintf(©, ".%s", remainder); 731362b94d5Smrg XtFree(remainder); 732362b94d5Smrg remainder = copy; 733362b94d5Smrg } 734362b94d5Smrg indx = remainder; 735362b94d5Smrg _set_and_search(parent, indx, remainder, resource, value, 736362b94d5Smrg last_token, last_part); 737362b94d5Smrg } 738362b94d5Smrg 739362b94d5Smrg XtFree(remainder); 740362b94d5Smrg XtFree(last_part); 741362b94d5Smrg } 742444c061aSmrg} 743444c061aSmrg 744444c061aSmrg/* 745444c061aSmrg * NAME: _locate_children 746444c061aSmrg * 747444c061aSmrg * FUNCTION: 748362b94d5Smrg * returns a list of all of a widget's children 749444c061aSmrg * 750444c061aSmrg * PARAMETERS: 751362b94d5Smrg * w the parent to search for its children 752362b94d5Smrg * children the list of children that is created 753362b94d5Smrg * normal flag for normal children 754362b94d5Smrg * popup flag for popup children 755444c061aSmrg * 756444c061aSmrg * RETURN VALUES: 757362b94d5Smrg * int the number of children 758362b94d5Smrg * children the list of children found 759444c061aSmrg * 760444c061aSmrg * ERRORS: none 761444c061aSmrg */ 762444c061aSmrgstatic int 763362b94d5Smrg_locate_children(Widget parent, Widget **children) 764444c061aSmrg{ 765362b94d5Smrg CompositeWidget comp = (CompositeWidget) parent; 766362b94d5Smrg Cardinal i; 767362b94d5Smrg int num_children = 0; 768362b94d5Smrg int current = 0; 769362b94d5Smrg 770362b94d5Smrg /* 771362b94d5Smrg * count the number of children 772362b94d5Smrg */ 773362b94d5Smrg if (XtIsWidget(parent)) 774362b94d5Smrg num_children = 775362b94d5Smrg (int) ((Cardinal) num_children + parent->core.num_popups); 776362b94d5Smrg if (XtIsComposite(parent)) 777362b94d5Smrg num_children = 778362b94d5Smrg (int) ((Cardinal) num_children + comp->composite.num_children); 779362b94d5Smrg if (num_children == 0) { 780362b94d5Smrg *children = NULL; 781362b94d5Smrg return (0); 782362b94d5Smrg } 783362b94d5Smrg 784a773ec55Smrg *children = XtMallocArray((Cardinal)num_children, (Cardinal)sizeof(Widget)); 785362b94d5Smrg 786362b94d5Smrg if (XtIsComposite(parent)) { 787362b94d5Smrg for (i = 0; i < comp->composite.num_children; i++) { 788362b94d5Smrg (*children)[current] = comp->composite.children[i]; 789362b94d5Smrg current++; 790362b94d5Smrg } 791362b94d5Smrg } 792362b94d5Smrg 793362b94d5Smrg if (XtIsWidget(parent)) { 794362b94d5Smrg for (i = 0; i < parent->core.num_popups; i++) { 795362b94d5Smrg (*children)[current] = comp->core.popup_list[i]; 796362b94d5Smrg current++; 797362b94d5Smrg } 798362b94d5Smrg } 799362b94d5Smrg 800362b94d5Smrg return (num_children); 801444c061aSmrg} 802444c061aSmrg 803444c061aSmrg#ifdef DEBUG 804444c061aSmrg/* 805444c061aSmrg * NAME: dump_widget_tree 806444c061aSmrg * 807444c061aSmrg * FUNCTION: 808362b94d5Smrg * recursively printout entire widget tree 809444c061aSmrg * 810444c061aSmrg * PARAMETERS: 811362b94d5Smrg * w the widget to match 812362b94d5Smrg * indent the amount to indent each line 813444c061aSmrg * 814444c061aSmrg * RETURN VALUES: void 815444c061aSmrg * 816444c061aSmrg * ERRORS: none 817444c061aSmrg */ 818444c061aSmrgstatic void 819362b94d5Smrgdump_widget_tree(Widget w, int indent) 820444c061aSmrg{ 821362b94d5Smrg int i, j; 822362b94d5Smrg int num_children; 823362b94d5Smrg Widget *children; 824362b94d5Smrg 825362b94d5Smrg /* 826362b94d5Smrg * Recursively search through the children 827362b94d5Smrg */ 828362b94d5Smrg num_children = _locate_children(w, &children); 829362b94d5Smrg indent += 2; 830362b94d5Smrg for (i = 0; i < num_children; i++) { 831362b94d5Smrg if (children[i] != NULL) { 832362b94d5Smrg for (j = 0; j < indent; j++) 833362b94d5Smrg fprintf(stderr, " "); 834362b94d5Smrg if (XtIsWidget(children[i])) { 835362b94d5Smrg fprintf(stderr, "(%s)\t", children[i]->core.name); 836362b94d5Smrg fprintf(stderr, "(%s)\n", 837362b94d5Smrg children[i]->core.widget_class->core_class.class_name); 838362b94d5Smrg } 839362b94d5Smrg else { 840362b94d5Smrg fprintf(stderr, "(NULL)\t"); 841362b94d5Smrg fprintf(stderr, "(%s)\n", 842362b94d5Smrg children[i]->core.widget_class->core_class.class_name); 843362b94d5Smrg } 844362b94d5Smrg } 845362b94d5Smrg dump_widget_tree(children[i], indent); 846362b94d5Smrg } 847362b94d5Smrg 848362b94d5Smrg XtFree((char *) children); 849444c061aSmrg} 850444c061aSmrg#endif 851444c061aSmrg 852444c061aSmrg/* 853444c061aSmrg * NAME: _XtResourceConfiguationEH 854444c061aSmrg * 855444c061aSmrg * FUNCTION: 856362b94d5Smrg * This function is the event handler for the on-the-fly communication 857362b94d5Smrg * with a resource customization tool. This event handler must be 858444c061aSmrg * registered for the toplevel shell of each app. This is best done 859444c061aSmrg * in the _XtCreatePopupShell and _XtAppCreateShell functions in Xt's 860362b94d5Smrg * Create.c source file. 861362b94d5Smrg * 862362b94d5Smrg * The property used to communicate with a customizing tool is 863362b94d5Smrg * placed on the toplevel shell window of the application. The 864362b94d5Smrg * customizing tool places a property on this window which causes 865362b94d5Smrg * this event handler to be invoked via the PropertyNotify event. 866362b94d5Smrg * This event handler reads the property and then deletes it from 867362b94d5Smrg * the server. The contents of the property are a resource string 868362b94d5Smrg * and value. The event handler then calls functions to walk the 869362b94d5Smrg * applications widget tree, determining which widgets are affected 870362b94d5Smrg * by the resource string, and then applying the value with XtSetValues. 871444c061aSmrg * 872444c061aSmrg * PARAMETERS: 873362b94d5Smrg * w the widget that invoked this event handler 874362b94d5Smrg * client_data not used 875362b94d5Smrg * event the event structure 876444c061aSmrg * 877444c061aSmrg * RETURN VALUES: none 878444c061aSmrg * 879444c061aSmrg * ERRORS: none 880444c061aSmrg */ 881444c061aSmrgvoid 882362b94d5Smrg_XtResourceConfigurationEH(Widget w, 883362b94d5Smrg XtPointer client_data _X_UNUSED, 8847854a16aSmrg XEvent *event, 8857854a16aSmrg Boolean *continue_to_dispatch _X_UNUSED) 886444c061aSmrg{ 887362b94d5Smrg Atom actual_type; 888362b94d5Smrg int actual_format; 889362b94d5Smrg unsigned long nitems; 890362b94d5Smrg unsigned long leftover; 891362b94d5Smrg char *data = NULL; 892362b94d5Smrg char *data_ptr; 893362b94d5Smrg 894444c061aSmrg#ifdef DEBUG 895362b94d5Smrg int indent = 0; 896444c061aSmrg#endif 897362b94d5Smrg XtPerDisplay pd; 898444c061aSmrg 899444c061aSmrg#ifdef DEBUG 900362b94d5Smrg fprintf(stderr, "in _XtResourceConfiguationEH atom = %u\n", 901362b94d5Smrg (unsigned) event->xproperty.atom); 902362b94d5Smrg fprintf(stderr, " window = %x\n", (unsigned) XtWindow(w)); 903362b94d5Smrg if (XtIsWidget(w)) 904362b94d5Smrg fprintf(stderr, " widget = %zx name = %s\n", (size_t) w, 905362b94d5Smrg w->core.name); 906444c061aSmrg#endif 907444c061aSmrg 908362b94d5Smrg pd = _XtGetPerDisplay(XtDisplay(w)); 909444c061aSmrg 910362b94d5Smrg /* 911362b94d5Smrg * The window on which a customizing tool places the property 912362b94d5Smrg * is determined at this point. It should be the applications 913362b94d5Smrg * toplevel shell window. 914362b94d5Smrg * 915362b94d5Smrg * A customizing tool sends a "ping" to the application on 916362b94d5Smrg * the RCM_INIT property. The application answers the ping 917362b94d5Smrg * by deleting the property. 918362b94d5Smrg */ 919362b94d5Smrg if (event->xproperty.atom == pd->rcm_init) { 920362b94d5Smrg XDeleteProperty(XtDisplay(w), XtWindow(w), pd->rcm_init); 921444c061aSmrg 922444c061aSmrg#ifdef DEBUG 923362b94d5Smrg if (XtIsWidget(w)) 924362b94d5Smrg fprintf(stderr, "%s\n", w->core.name); 925362b94d5Smrg else 926362b94d5Smrg fprintf(stderr, "NULL name\n"); 927362b94d5Smrg dump_widget_tree(w, indent); 928444c061aSmrg 929362b94d5Smrg fprintf(stderr, "answer ping\n"); 930444c061aSmrg#endif 931362b94d5Smrg } 932362b94d5Smrg 933362b94d5Smrg /* 934362b94d5Smrg * This event handler ignores any property notify events that 935362b94d5Smrg * are not RCM_INIT or RCM_DATA 936362b94d5Smrg */ 937362b94d5Smrg if (event->xproperty.atom != pd->rcm_data) 938362b94d5Smrg return; 939362b94d5Smrg 940362b94d5Smrg /* 941362b94d5Smrg * Retrieve the data from the property 942362b94d5Smrg */ 943444c061aSmrg#ifdef DEBUG 944362b94d5Smrg fprintf(stderr, "receiving RCM_DATA property\n"); 945444c061aSmrg#endif 946362b94d5Smrg if (XGetWindowProperty(XtDisplay(w), 947362b94d5Smrg XtWindow(w), 948362b94d5Smrg pd->rcm_data, 0L, 8192L, 949362b94d5Smrg TRUE, XA_STRING, 950362b94d5Smrg &actual_type, &actual_format, &nitems, &leftover, 951362b94d5Smrg (unsigned char **) &data) == Success && 952362b94d5Smrg actual_type == XA_STRING && actual_format == 8) { 953362b94d5Smrg /* 954362b94d5Smrg * data format is: 955362b94d5Smrg * 956362b94d5Smrg * resource_length, resource, value 957362b94d5Smrg * 958362b94d5Smrg * convert the resource_length to a long, skip over it, put a 959362b94d5Smrg * zero byte at the end of the resource, and pick off the 960362b94d5Smrg * resource and value fields. 961362b94d5Smrg */ 962362b94d5Smrg if (data) { 963362b94d5Smrg char *data_end = data + nitems; 964362b94d5Smrg char *data_value; 965362b94d5Smrg unsigned long resource_len; 966362b94d5Smrg 967362b94d5Smrg resource_len = strtoul(data, &data_ptr, 10); 968362b94d5Smrg 969362b94d5Smrg if (data_ptr != (char *) data) { 970362b94d5Smrg data_ptr++; 971362b94d5Smrg data_value = data_ptr + resource_len; 972362b94d5Smrg } 973362b94d5Smrg else /* strtoul failed to convert a number */ 974362b94d5Smrg data_ptr = data_value = NULL; 975362b94d5Smrg 976362b94d5Smrg if (data_value > data_ptr && data_value < data_end) { 977362b94d5Smrg char *resource; 978362b94d5Smrg char *value; 979362b94d5Smrg 980362b94d5Smrg *data_value++ = '\0'; 981362b94d5Smrg 982362b94d5Smrg resource = XtNewString(data_ptr); 983362b94d5Smrg value = XtNewString(data_value); 984444c061aSmrg#ifdef DEBUG 985362b94d5Smrg fprintf(stderr, "resource_len=%lu\n", resource_len); 986362b94d5Smrg fprintf(stderr, "resource = %s\t value = %s\n", 987362b94d5Smrg resource, value); 988444c061aSmrg#endif 989362b94d5Smrg /* 990362b94d5Smrg * descend the application widget tree and 991362b94d5Smrg * apply the value to the appropriate widgets 992362b94d5Smrg */ 993362b94d5Smrg _search_widget_tree(w, resource, value); 994362b94d5Smrg 995362b94d5Smrg XtFree(resource); 996362b94d5Smrg XtFree(value); 997362b94d5Smrg } 998362b94d5Smrg } 999362b94d5Smrg } 1000362b94d5Smrg 1001362b94d5Smrg XFree((char *) data); 1002444c061aSmrg} 1003