1 /**************************************************************************\
2  *
3  *  This file is part of the Coin 3D visualization library.
4  *  Copyright (C) by Kongsberg Oil & Gas Technologies.
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  ("GPL") version 2 as published by the Free Software Foundation.
9  *  See the file LICENSE.GPL at the root directory of this source
10  *  distribution for additional information about the GNU GPL.
11  *
12  *  For using Coin with software that can not be combined with the GNU
13  *  GPL, and for taking advantage of the additional benefits of our
14  *  support services, please contact Kongsberg Oil & Gas Technologies
15  *  about acquiring a Coin Professional Edition License.
16  *
17  *  See http://www.coin3d.org/ for more information.
18  *
19  *  Kongsberg Oil & Gas Technologies, Bygdoy Alle 5, 0257 Oslo, NORWAY.
20  *  http://www.sim.no/  sales@sim.no  coin-support@coin3d.org
21  *
22 \**************************************************************************/
23 
24 #if SOXT_DEBUG
25 static const char rcsid[] =
26   "$Id$";
27 #endif // SOXT_DEBUG
28 
29 // *************************************************************************
30 
31 /*!
32   \class SoXtResource Inventor/Xt/SoXtResource.h
33   \brief The SoXtResource class is a utility class for fetching X resource
34   values for widgets.  Special care is taken for SoXt components.
35   \ingroup misc
36 */
37 
38 // *************************************************************************
39 
40 #include <assert.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 
44 #include <X11/IntrinsicP.h>
45 #include <X11/CoreP.h>
46 
47 #include <Inventor/SoLists.h>
48 #include <Inventor/errors/SoDebugError.h>
49 
50 #include <soxtdefs.h>
51 #include <Inventor/Xt/SoXt.h>
52 #include <Inventor/Xt/SoXtComponent.h>
53 
54 #include <Inventor/Xt/SoXtResource.h>
55 
56 // *************************************************************************
57 
58 int icstrcmp(const char * str1, const char * str2);
59 
60 /*!
61   Constructor.   sets up the SoXtResource object to fetch resources for
62   the \a widget Widget.
63 */
64 
SoXtResource(const Widget widget)65 SoXtResource::SoXtResource(
66   const Widget widget)
67 {
68   static SbBool initialized = FALSE;
69   if (! initialized) {
70     XrmInitialize();
71     initialized = TRUE;
72   }
73 
74   this->hierarchy_depth = 0;
75 
76   if (! widget) {
77     this->name_hierarchy = NULL;
78     this->class_hierarchy = NULL;
79     this->display = SoXt::getDisplay();
80     return;
81   }
82 
83   this->display = XtDisplay(widget);
84 
85   SbIntList quarks;
86   Widget stop = NULL;
87 
88   SoXtComponent * component = SoXtComponent::getComponent(widget);
89   if (component != NULL) {
90     Widget cwidget = component->getBaseWidget();
91     if (cwidget != NULL)
92       stop = XtParent(cwidget);
93   }
94 
95   Widget w = widget;
96   while (w && w != stop) {
97     quarks.append(((CorePart *) w)->xrm_name);
98     quarks.append(((CoreClassPart *) XtClass(w))->xrm_class);
99     this->hierarchy_depth++;
100     if (XtIsShell(w))
101       break;
102     if ((component == NULL) &&
103          ((component = SoXtComponent::getComponent(w)) != NULL)) {
104       Widget cwidget = component->getWidget();
105       if (cwidget != NULL)
106         stop = XtParent(cwidget);
107     }
108     w = XtParent(w);
109   }
110 
111 #if SOXT_DEBUG
112   if (component == NULL)
113     SoDebugError::postInfo("SoXtResource",
114       "using SoXtResource for non-component widget (which is OK)");
115 #endif // SOXT_DEBUG
116 
117   this->name_hierarchy = new XrmQuark [ this->hierarchy_depth + 2];
118   this->class_hierarchy = new XrmQuark [ this->hierarchy_depth + 2];
119   int i;
120   for (i = 0; i < this->hierarchy_depth; i++) {
121     this->name_hierarchy[this->hierarchy_depth - i - 1] = quarks[i*2];
122     this->class_hierarchy[this->hierarchy_depth - i - 1] = quarks[i*2+1];
123   }
124   this->name_hierarchy[ this->hierarchy_depth ] = 0;
125   this->name_hierarchy[ this->hierarchy_depth + 1 ] = 0;
126   this->class_hierarchy[ this->hierarchy_depth ] = 0;
127   this->class_hierarchy[ this->hierarchy_depth + 1 ] = 0;
128 
129 #if SOXT_DEBUG && 0
130   this->DumpInternals();
131 #endif // SOXT_DEBUG
132 } // SoXtResource()
133 
134 /*!
135   Destructor.
136 */
137 
~SoXtResource(void)138 SoXtResource::~SoXtResource(
139   void)
140 {
141   delete [] this->name_hierarchy;
142   delete [] this->class_hierarchy;
143 } // ~SoXtResource()
144 
145 // *************************************************************************
146 
147 /*!
148   This method just dumps the name and class hierarchy of the widget the
149   SoXtResource object is set to.
150 */
151 
152 void
DumpInternals(void) const153 SoXtResource::DumpInternals(
154   void) const
155 {
156   SoDebugError::postInfo("SoXtResource::DumpInternals", "dumping");
157   fprintf(stdout, "Classes: ");
158   int i;
159   for (i = 0; i < this->hierarchy_depth; i++) {
160     fprintf(stdout, "%s", XrmQuarkToString(this->class_hierarchy[i]));
161     if (i < (this->hierarchy_depth - 1))
162       fprintf(stdout, ".");
163   }
164   fprintf(stdout, "\n");
165 
166   fprintf(stdout, "Names:  ");
167   for (i = 0; i < this->hierarchy_depth; i++) {
168     fprintf(stdout, "%s", XrmQuarkToString(this->name_hierarchy[i]));
169     if (i < (this->hierarchy_depth - 1))
170       fprintf(stdout, ".");
171   }
172   fprintf(stdout, "\n");
173 } // DumpInternals()
174 
175 // *************************************************************************
176 
177 #define GET_RESOURCE()                                                         \
178   XrmValue value;                                                              \
179   XrmRepresentation format;                                                    \
180   char * formatstr = NULL;                                                     \
181   do {                                                                         \
182     SbBool found = FALSE;                                                      \
183     XrmDatabase database = XrmGetDatabase(this->display);                    \
184     if (this->name_hierarchy != NULL) {                                      \
185       this->name_hierarchy[this->hierarchy_depth] = XrmStringToQuark(rname); \
186       this->class_hierarchy[this->hierarchy_depth] =                           \
187         XrmStringToQuark(rclass);                                            \
188       found = XrmQGetResource(database, this->name_hierarchy,                 \
189                 this->class_hierarchy, &format, &value) ? TRUE : FALSE;       \
190       this->name_hierarchy[this->hierarchy_depth] = 0;                         \
191       this->class_hierarchy[this->hierarchy_depth] = 0;                        \
192     }                                                                          \
193     if (! found)                                                             \
194       found = XrmGetResource(database, rname,                                 \
195                 rclass, &formatstr, &value) ? TRUE : FALSE;                   \
196     if (! found)                                                             \
197       return FALSE;                                                            \
198   } while (FALSE)
199 
200 // *************************************************************************
201 
202 /*!
203   This method retrieves the given X resource and puts it into the
204   SbColor object \a retval.
205 
206   TRUE is returned if the resource is found, and FALSE otherwise.
207 */
208 
209 SbBool
getResource(const char * const rname,const char * const rclass,SbColor & retval) const210 SoXtResource::getResource(
211   const char * const rname,
212   const char * const rclass,
213   SbColor & retval) const
214 {
215   GET_RESOURCE();
216   SOXT_STUB_ONCE();
217 
218   XrmQuark stringq = XrmStringToQuark(XmRString);
219 
220   if (formatstr != NULL)
221     format = XrmStringToQuark(formatstr);
222 
223   if (format == stringq) {
224     XColor exact, screen;
225     Display * dpy = SoXt::getDisplay();
226     Colormap cmap = 0; // = SoXt::getColormap();
227     if (XLookupColor(dpy, cmap, (char *) value.addr, &exact, &screen)) {
228       retval = SbColor(float(exact.red) / 65535.0f,
229         float(exact.green) / 65535.0f, float(exact.blue) / 65535.0f);
230       return TRUE;
231     }
232     return FALSE;
233   }
234 
235 #if SOXT_DEBUG
236   SoDebugError::postInfo("getResource",
237     "resource format \"%s\" not supported\n", XrmQuarkToString(format));
238 #endif // SOXT_DEBUG
239   return FALSE;
240 } // getResource()
241 
242 // *************************************************************************
243 
244 /*!
245   This method retrieves the given X resource and puts it into the
246   short \a retval.
247 
248   TRUE is returned if the resource is found, and FALSE otherwise.
249 */
250 
251 SbBool
getResource(const char * const rname,const char * const rclass,short & retval) const252 SoXtResource::getResource(
253   const char * const rname,
254   const char * const rclass,
255   short & retval) const
256 {
257   GET_RESOURCE();
258 
259   XrmQuark shortq = XrmStringToQuark(XmRShort);
260   XrmQuark stringq = XrmStringToQuark(XmRString);
261 
262   if (formatstr != NULL)
263     format = XrmStringToQuark(formatstr);
264 
265   if (format == shortq) {
266     retval = *((short *) value.addr);
267     return TRUE;
268   }
269   if (format == stringq) {
270     retval = atoi((char *) value.addr);
271     return TRUE;
272   }
273 
274 #if SOXT_DEBUG
275   SoDebugError::postInfo("getResource",
276     "resource format \"%s\" not supported\n", XrmQuarkToString(format));
277 #endif // SOXT_DEBUG
278   return FALSE;
279 } // getResource()
280 
281 // *************************************************************************
282 
283 /*!
284   This method retrieves the given X resource and puts it into the
285   unsigned short \a retval.
286 
287   TRUE is returned if the resource is found, and FALSE otherwise.
288 */
289 
290 SbBool
getResource(const char * const rname,const char * const rclass,unsigned short & retval) const291 SoXtResource::getResource(
292   const char * const rname,
293   const char * const rclass,
294   unsigned short & retval) const
295 {
296   GET_RESOURCE();
297 
298   XrmQuark stringq = XrmStringToQuark(XmRString);
299   XrmQuark shortq = XrmStringToQuark(XmRShort);
300 
301   if (formatstr != NULL)
302     format = XrmStringToQuark(formatstr);
303 
304   if (format == shortq) {
305     retval = *((unsigned short *) value.addr);
306     return TRUE;
307   }
308 
309   if (format == stringq) {
310     retval = atoi((char *) value.addr);
311     return TRUE;
312   }
313 
314 #if SOXT_DEBUG
315   SoDebugError::postInfo("getResource",
316     "resource format \"%s\" not supported\n", XrmQuarkToString(format));
317 #endif // SOXT_DEBUG
318   return FALSE;
319 } // getResource()
320 
321 // *************************************************************************
322 
323 /*!
324   This method retrieves the given X resource and points the \a retval
325   pointer to it's data.
326 
327   TRUE is returned if the resource is found, and FALSE otherwise.
328 */
329 
330 SbBool
getResource(const char * const rname,const char * const rclass,char * & retval) const331 SoXtResource::getResource(
332   const char * const rname,
333   const char * const rclass,
334   char * & retval) const
335 {
336   GET_RESOURCE();
337 
338   XrmQuark stringq = XrmStringToQuark(XmRString);
339 
340   if (formatstr != NULL)
341     format = XrmStringToQuark(formatstr);
342 
343   if (format == stringq) {
344     retval = (char *) value.addr;
345     return TRUE;
346   }
347 
348 #if SOXT_DEBUG
349   SoDebugError::postInfo("getResource",
350     "resource format \"%s\" not supported\n", XrmQuarkToString(format));
351 #endif // SOXT_DEBUG
352   return FALSE;
353 } // getResource()
354 
355 // *************************************************************************
356 
357 /*!
358   This method retrieves the given X resource and puts it into the
359   SbBool \a retval.
360 
361   TRUE is returned if the resource is found, and FALSE otherwise.
362 */
363 
364 SbBool
getResource(const char * const rname,const char * const rclass,SbBool & retval) const365 SoXtResource::getResource(
366   const char * const rname,
367   const char * const rclass,
368   SbBool & retval) const
369 {
370   GET_RESOURCE();
371 
372   XrmQuark stringq = XrmStringToQuark(XmRString);
373   XrmQuark booleanq = XrmStringToQuark(XmRBoolean);
374 
375   if (formatstr != NULL)
376     format = XrmStringToQuark(formatstr);
377 
378   if (format == booleanq) {
379     retval = *((Boolean *) value.addr) ? TRUE : FALSE;
380     return TRUE;
381   }
382 
383   if (format == stringq) {
384     if (icstrcmp((const char *) value.addr, "true") == 0 ||
385          icstrcmp((const char *) value.addr, "on") == 0 ||
386          icstrcmp((const char *) value.addr, "yes") == 0 ||
387          icstrcmp((const char *) value.addr, "enable") == 0 ||
388          icstrcmp((const char *) value.addr, "enabled") == 0 ||
389          icstrcmp((const char *) value.addr, "set") == 0 ||
390          icstrcmp((const char *) value.addr, "1") == 0) {
391       retval = TRUE;
392       return TRUE;
393     } else if (icstrcmp((const char *) value.addr, "false") == 0 ||
394                 icstrcmp((const char *) value.addr, "off") == 0 ||
395                 icstrcmp((const char *) value.addr, "no") == 0 ||
396                 icstrcmp((const char *) value.addr, "disable") == 0 ||
397                 icstrcmp((const char *) value.addr, "disabled") == 0 ||
398                 icstrcmp((const char *) value.addr, "unset") == 0 ||
399                 icstrcmp((const char *) value.addr, "0") == 0) {
400       retval = FALSE;
401       return TRUE;
402     } else {
403       SoDebugError::postWarning("getResource",
404         "string \"%s\" not understood", (char *) value.addr);
405       return FALSE;
406     }
407   }
408 
409 #if SOXT_DEBUG
410   SoDebugError::postInfo("getResource",
411     "resource format \"%s\" not supported\n", XrmQuarkToString(format));
412 #endif // SOXT_DEBUG
413   return FALSE;
414 } // getResource()
415 
416 // *************************************************************************
417 
418 /*!
419   This method retrieves the given X resource and puts it into the
420   float \a retval.
421 
422   TRUE is returned if the resource is found, and FALSE otherwise.
423 */
424 
425 SbBool
getResource(const char * const rname,const char * const rclass,float & retval) const426 SoXtResource::getResource(
427   const char * const rname,
428   const char * const rclass,
429   float & retval) const
430 {
431   GET_RESOURCE();
432 
433   XrmQuark stringq = XrmStringToQuark(XmRString);
434   XrmQuark floatq = XrmStringToQuark(XmRFloat);
435 
436   if (formatstr != NULL)
437     format = XrmStringToQuark(formatstr);
438 
439   if (format == floatq) {
440     retval = *((float *) value.addr);
441     return TRUE;
442   }
443 
444   if (format == stringq) {
445     retval = atof((char *) value.addr);
446     return TRUE;
447   }
448 
449 #if SOXT_DEBUG
450   SoDebugError::postInfo("getResource",
451     "resource format \"%s\" not supported\n", XrmQuarkToString(format));
452 #endif // SOXT_DEBUG
453   return FALSE;
454 } // getResource()
455 
456 // *************************************************************************
457 
upcase(char letter)458 inline char upcase(char letter) {
459   if (letter >= 'a' && letter <= 'z')
460     return letter - 'a' + 'A';
461   return letter;
462 }
463 
464 int
icstrcmp(const char * str1,const char * str2)465 icstrcmp(
466   const char * str1,
467   const char * str2)
468 {
469   int i = 0;
470   while (str1[i] && (upcase(str1[i]) == upcase(str2[i]))) i++;
471   return str2[i] - str1[i];
472 } // icstrcmp()
473 
474 // *************************************************************************
475 
476 #if SOXT_DEBUG
getSoXtResourceRCSId(void)477 static const char * getSoXtResourceRCSId(void) { return rcsid; }
478 #endif // SOXT_DEBUG
479 
480