1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10 #include <defines.h>
11
12
13
14
15 #include <X11/Intrinsic.h>
16 #include <Xm/Xm.h>
17 #include <Xm/Label.h>
18 #include <Xm/Text.h>
19 #include <Xm/TextF.h>
20 #include <string.h>
21
22 #include "UIComponent.h"
23 #include "Application.h"
24 #include "WarningDialogManager.h"
25 #include "WarningDialogManager.h"
26 #include "DXStrings.h"
27
28 #if defined(HAVE_XINERAMA)
29 #include <X11/extensions/Xinerama.h>
30 #endif
31
32 // SUITS to allow turn-off of stippled drawing on slow devices
33 #define RES_CONVERT(res, str) XtVaTypedArg, res, XmRString, str, strlen(str)+1
34
35 //
36 // The following are constant understood by setGeometry() and used by
37 // setXYPosition() and setXYSize() and subclasses.
38 //
39 const int UIComponent::UnspecifiedPosition = 32767;
40 const int UIComponent::UnspecifiedDimension = 32767;
41
42 XtIntervalId UIComponent::BubbleTimer = 0;
43
UIComponent_WidgetDestroyCB(Widget,XtPointer clientData,XtPointer)44 extern "C" void UIComponent_WidgetDestroyCB(Widget /* widget */,
45 XtPointer clientData,
46 XtPointer /* callData */)
47 {
48 UIComponent* component;
49
50 ASSERT(clientData);
51
52 //
53 // Convert the client data into the UIComponent instance pointer it is.
54 //
55 component = (UIComponent*)clientData;
56
57 //
58 // Notify the component that its widget is being destroyed.
59 //
60 component->widgetDestroyed();
61 }
62
UIComponent_ComponentHelpCB(Widget,XtPointer clientData,XtPointer)63 extern "C" void UIComponent_ComponentHelpCB(Widget /* widget */,
64 XtPointer clientData,
65 XtPointer /* callData */)
66 {
67 UIComponent* component;
68
69 ASSERT(clientData);
70
71 //
72 // Convert the client data into the UIComponent instance pointer it is.
73 //
74 component = (UIComponent*)clientData;
75
76 //
77 // Notify the component that its widget is being destroyed.
78 //
79 component->componentHelp();
80 }
81
82
UIComponent(const char * name)83 UIComponent::UIComponent(const char* name)
84 {
85 unsigned int i;
86
87 ASSERT(name);
88 for(i = 0; i < STRLEN(name); i++)
89 {
90 if( name[i] == ' ' ||
91 name[i] == '\t' ||
92 name[i] == '.' ||
93 name[i] == '*')
94 {
95 WarningMessage("UIComponent questionable name: %s", name);
96 }
97 }
98 this->root = NUL(Widget);
99 this->name = DuplicateString(name);
100 this->active = TRUE;
101 this->help_msg = NUL(char*);
102 this->inactive_help_msg = NUL(char*);
103 this->help_widget = NUL(Widget);
104 this->deactivated = FALSE;
105 this->xtt = NULL;
106 this->fg = ((Pixel)-1);
107 }
108
109
~UIComponent()110 UIComponent::~UIComponent()
111 {
112 //
113 // Remove destroy callback so Xt Intrinsics canot call the
114 // callback with a pointer to an object that has already
115 // been freed.
116 //
117 if (this->root)
118 {
119 XtRemoveCallback
120 (this->root,
121 XmNdestroyCallback,
122 (XtCallbackProc)UIComponent_WidgetDestroyCB,
123 (XtPointer)this);
124 }
125
126 //
127 // Destroy the widget tree, if it still exists;
128 // delete the name string.
129 //
130 if (this->root)
131 {
132 XtDestroyWidget(this->root);
133 }
134
135 if (this->name)
136 delete[] this->name;
137
138 if (this->help_msg)
139 delete[] this->help_msg;
140
141 if (this->inactive_help_msg)
142 delete[] this->inactive_help_msg;
143 }
144
clearRootWidget()145 void UIComponent::clearRootWidget()
146 {
147 this->root = NULL;
148 }
setRootWidget(Widget root,boolean standardDestroy)149 void UIComponent::setRootWidget(Widget root, boolean standardDestroy)
150 {
151 if (this->root)
152 {
153 XtRemoveCallback
154 (this->root,
155 XmNdestroyCallback,
156 (XtCallbackProc)UIComponent_WidgetDestroyCB,
157 (XtPointer)this);
158 this->removeComponentHelpCallback();
159 }
160
161 this->root = root;
162
163 if (standardDestroy) {
164 XtAddCallback
165 (this->root,
166 XmNdestroyCallback,
167 (XtCallbackProc)UIComponent_WidgetDestroyCB,
168 (XtPointer)this);
169 }
170 this->installComponentHelpCallback();
171 }
172
setBubbleHelp(const char * msg,Widget w,boolean active_help)173 void UIComponent::setBubbleHelp (const char *msg, Widget w, boolean active_help)
174 {
175 if (active_help) {
176 if (this->help_msg) delete[] this->help_msg;
177 this->help_msg = NUL(char*);
178 if ((!msg) || (!msg[0])) return ;
179 this->help_msg = DuplicateString(msg);
180 } else {
181 if (this->inactive_help_msg) delete[] this->inactive_help_msg;
182 this->inactive_help_msg = NUL(char*);
183 if ((!msg) || (!msg[0])) return ;
184 this->inactive_help_msg = DuplicateString(msg);
185 }
186
187 if (this->help_widget) {
188 XtRemoveEventHandler (this->help_widget, EnterWindowMask|LeaveWindowMask,
189 True, (XtEventHandler)UIComponent_BubbleEH, (XtPointer)this);
190 }
191 this->help_widget = w;
192 if (this->help_widget) {
193 XtAddEventHandler (this->help_widget, EnterWindowMask|LeaveWindowMask,
194 False, (XtEventHandler)UIComponent_BubbleEH, (XtPointer)this);
195 }
196 }
197
198
widgetDestroyed()199 void UIComponent::widgetDestroyed()
200 {
201 this->root = NUL(Widget);
202 }
203
204
getResources(const XtPointer resourceBase,const XtResourceList resourceList,const int numResources)205 void UIComponent::getResources(const XtPointer resourceBase,
206 const XtResourceList resourceList,
207 const int numResources)
208 {
209 Widget parent;
210
211 ASSERT(resourceBase);
212 ASSERT(resourceList);
213 ASSERT(numResources > 0);
214
215 ASSERT(this->root);
216 ASSERT(this->name);
217
218 parent = XtParent(this->root);
219 //
220 // Use XtGetSubresources() to retrieve the resources
221 // for a component with a parent.
222 //
223 XtGetSubresources
224 (parent ? parent : this->root,
225 resourceBase,
226 this->name,
227 this->getClassName(),
228 resourceList,
229 numResources,
230 NUL(ArgList),
231 0);
232 }
233
234
setDefaultResources(const Widget widget,const String * resourceSpec)235 void UIComponent::setDefaultResources(const Widget widget,
236 const String* resourceSpec)
237 {
238 XrmDatabase resourceDatabase;
239 Display* display;
240 int i;
241 char buffer[4096];
242 char prepend[1024];
243
244 ASSERT(widget);
245 ASSERT(resourceSpec);
246
247 display = XtDisplay(widget);
248 resourceDatabase = XrmGetStringDatabase("");
249
250 String name,classname;
251 XtGetApplicationNameAndClass(display,&name,&classname);
252
253 // Determine the base name of the application (i.e. ./dx -> dx)
254 #ifdef DXD_NON_UNIX_DIR_SEPARATOR
255 char *p = this->name;
256 for (int j=strlen(this->name)-1; j>=0; j--) {
257 if ((this->name[j] == '\\') || (this->name[j] == '/') || (this->name[j] == ':')) {
258 p = &this->name[j+1];
259 break;
260 }
261 }
262 #else
263 char *p = strrchr(this->name,'/');
264 p = ( !p ? this->name : p+1);
265 #endif
266
267 if (EqualString(name,p)) { // Global resources
268 // Replace the resource name with the class name when the resources
269 // are for the top level component.
270 strcpy(prepend,classname);
271 } else {
272 // Prepend the classname and the component's name
273 sprintf(prepend,"%s*%s",classname,this->name);
274 }
275
276
277 ASSERT(STRLEN(prepend) < 1024);
278
279 i = 0;
280 while(resourceSpec[i] != NUL(char*))
281 {
282 sprintf(buffer, "%s%s", prepend, resourceSpec[i++]);
283 ASSERT(STRLEN(buffer) < 4096);
284 XrmPutLineResource(&resourceDatabase, buffer);
285 }
286
287 //
288 // Merge the rosources into the Xt database with lowest precedence.
289 //
290 if (resourceDatabase)
291 {
292 #if defined XlibSpecificationRelease && XlibSpecificationRelease > 4
293 XrmDatabase db = XrmGetDatabase(display);
294 XrmCombineDatabase(resourceDatabase, &db, False);
295 #else
296 XrmMergeDatabases(display->db, &resourceDatabase);
297 display->db = resourceDatabase;
298 #endif
299 }
300 }
301
302
manage()303 void UIComponent::manage()
304 {
305 ASSERT(this->root);
306
307 //
308 // Check to see that a destroy callback has been installed.
309 //
310 ASSERT(XtHasCallbacks(this->root, XmNdestroyCallback) == XtCallbackHasSome);
311
312 //
313 // Manage the root widget.
314 //
315 XtManageChild(this->root);
316 }
317
318
isManaged()319 boolean UIComponent::isManaged()
320 {
321 if (!this->root)
322 return FALSE;
323 return XtIsManaged(this->root);
324 }
325
unmanage()326 void UIComponent::unmanage()
327 {
328 ASSERT(this->root);
329 XtUnmanageChild(this->root);
330 }
331
332
activate()333 void UIComponent::activate()
334 {
335 if (this->root)
336 {
337 if (!theApplication->bubbleHelpEnabled())
338 XtSetSensitive(this->root, TRUE);
339 else {
340 if(deactivated)
341 {
342 if(xtt)
343 XtAugmentTranslations(this->root, xtt);
344 XtVaSetValues(this->root, XmNforeground, this->fg, NULL);
345 deactivated = FALSE;
346 }
347 }
348 }
349 this->active = TRUE;
350 if (this->inactive_help_msg) {
351 delete[] this->inactive_help_msg;
352 this->inactive_help_msg = NUL(char*);
353 }
354 }
355
356
deactivate(const char * inactive_help)357 void UIComponent::deactivate(const char * inactive_help)
358 {
359 if (this->root)
360 {
361 if (!theApplication->bubbleHelpEnabled())
362 XtSetSensitive(this->root, FALSE);
363 else {
364 if(!deactivated)
365 {
366 XtVaGetValues(this->root, XmNtranslations, &xtt, NULL);
367 XtVaGetValues(this->root, XmNforeground, &this->fg, NULL);
368 XtUninstallTranslations(this->root);
369 XtVaSetValues(this->root,
370 RES_CONVERT(XmNforeground, "gray50"), NULL);
371 deactivated = TRUE;
372 }
373 }
374 }
375 this->active = FALSE;
376 if ((this->inactive_help_msg) || (inactive_help))
377 this->setBubbleHelp (inactive_help, this->help_widget, FALSE);
378 }
379
380 //
381 // Set the size of this component
382 //
setXYSize(int x,int y)383 void UIComponent::setXYSize(int x, int y)
384 {
385 this->setGeometry(UIComponent::UnspecifiedPosition,
386 UIComponent::UnspecifiedPosition,
387 x,y);
388 }
389 //
390 // Get the size of this component
391 //
getXYSize(int * x,int * y)392 void UIComponent::getXYSize(int *x, int *y)
393 {
394 int a, b;
395 this->getGeometry(&a, &b, x, y);
396 }
397 //
398 // Get the position of this component
399 //
getXYPosition(int * x,int * y)400 void UIComponent::getXYPosition(int *x, int *y)
401 {
402 int a, b;
403 this->getGeometry(x,y, &a, &b);
404 }
405 //
406 // Set the position of this component
407 //
setXYPosition(int x,int y)408 void UIComponent::setXYPosition(int x, int y)
409 {
410 this->setGeometry(x,y, UIComponent::UnspecifiedDimension,
411 UIComponent::UnspecifiedDimension);
412 }
413
414 //
415 // Get the size and dimensions.
416 // Return TRUE if all return values are valid.
417 //
getGeometry(int * x,int * y,int * width,int * height)418 boolean UIComponent::getGeometry(int *x, int *y, int *width, int *height)
419 {
420 Position a,b;
421 Dimension w,h;
422
423 ASSERT(this->root);
424
425 XtVaGetValues(this->root,
426 XmNx, &a,
427 XmNy, &b,
428 XmNwidth, &w,
429 XmNheight, &h,
430 NULL);
431
432 *x = a;
433 *y = b;
434 *width = w;
435 *height = h;
436
437 return TRUE;
438 }
439 //
440 // Set the size and dimensions.
441 //
setGeometry(int x,int y,int width,int height)442 void UIComponent::setGeometry(int x, int y, int width, int height)
443 {
444 ASSERT(this->root);
445 Arg wargs[4];
446 int n = 0;
447
448 #if 1
449 if (x != UIComponent::UnspecifiedPosition)
450 { XtSetArg(wargs[n],XmNx,x); n++; }
451 if (y != UIComponent::UnspecifiedPosition)
452 { XtSetArg(wargs[n],XmNy,y); n++; }
453 if (width != UIComponent::UnspecifiedDimension)
454 { XtSetArg(wargs[n],XmNwidth,width); n++; }
455 if (height != UIComponent::UnspecifiedDimension)
456 { XtSetArg(wargs[n],XmNheight,height); n++; }
457 if (n > 0)
458 XtSetValues(this->root,wargs,n);
459 #else
460 XtWidgetGeometry req;
461
462 req.x = x; req.y = y; req.width = width; req.height = height;
463 req.request_mode = 0;
464 if (x != UIComponent::UnspecifiedPosition) req.request_mode|= CWX;
465 if (y != UIComponent::UnspecifiedPosition) req.request_mode|= CWY;
466 if (width != UIComponent::UnspecifiedDimension) req.request_mode|= CWWidth;
467 if (height != UIComponent::UnspecifiedDimension) req.request_mode|= CWHeight;
468 if (req.request_mode)
469 XtMakeGeometryRequest (this->root, &req, NULL);
470 #endif
471 }
472
473
474
installComponentHelpCallback(Widget widget)475 void UIComponent::installComponentHelpCallback(Widget widget)
476 {
477
478 if (!widget)
479 widget = this->root;
480 ASSERT(widget);
481
482 if (XtHasCallbacks(widget, XmNhelpCallback) != XtCallbackNoList)
483 {
484 // Ensure that only one copy of the help callback is installed.
485 XtRemoveCallback
486 (widget,
487 XmNhelpCallback,
488 (XtCallbackProc)UIComponent_ComponentHelpCB,
489 (XtPointer)this);
490 XtAddCallback
491 (widget,
492 XmNhelpCallback,
493 (XtCallbackProc)UIComponent_ComponentHelpCB,
494 (XtPointer)this);
495 }
496 }
497
removeComponentHelpCallback(Widget widget)498 void UIComponent::removeComponentHelpCallback(Widget widget)
499 {
500
501 if (!widget)
502 widget = this->root;
503 ASSERT(widget);
504
505 if (XtHasCallbacks(widget, XmNhelpCallback) != XtCallbackNoList)
506 XtRemoveCallback
507 (widget,
508 XmNhelpCallback,
509 (XtCallbackProc)UIComponent_ComponentHelpCB,
510 (XtPointer)this);
511 }
512
513
getComponentHelpTopic()514 const char *UIComponent::getComponentHelpTopic()
515 {
516 return this->name;
517 }
componentHelp()518 void UIComponent::componentHelp()
519 {
520 theApplication->helpOn(this->getComponentHelpTopic());
521 }
setLocalData(void * data)522 void UIComponent::setLocalData(void *data)
523 {
524 ASSERT(this->root);
525 Arg arg[1];
526 XtSetArg(arg[0], XmNuserData, (XtPointer)data);
527 XtSetValues(this->root, arg,1);
528 }
529
getLocalData()530 void *UIComponent::getLocalData()
531 {
532 void *data;
533 ASSERT(this->root);
534 Arg arg[1];
535 XtSetArg(arg[0], XmNuserData, (XtPointer)&data);
536 XtGetValues(this->root, arg,1);
537 return data;
538 }
539
540 /*
541 ParseGeometryComment actually performs the Window placement and
542 Window sizing for shell windows such as the ImageWindow and
543 Control Panels. The network saves the placement as a normalized
544 vector of where and what size it was on the authors screen
545 and then tries to replicate that to fit the screen of others.
546 This becomes a real problem when Xinerama comes into play. For example,
547 the width/height ratio changes significantly and makes ImageWindows
548 very wide when reconstructing them if the Xinerama environment is
549 in place. For example DisplayWidth may be 2560 and Height may only
550 be 1024. But the original developer was on a system of 1280 x 1024.
551 The resulting image doesn't look anything like the authors.
552
553 The fix for placement is to check for Xinerama and replicate on
554 the dominate screen. Then this also needs to be fixed in PrintGeometryComment
555 as well.
556
557 It will not be possible to replicate the multiple screen geometry
558 unless the support for Xinerama is turned off. For example: two
559 identical screens side by side. If the user builds with the VPE on
560 the primary screen, and puts the Image Window on the secondary screen,
561 when the Editor is re-opened and executed, the Image Window will
562 appear on the primary screen. The only way to fix this would be
563 to append the screen number in the GeometryComment
564 */
565
PrintGeometryComment(FILE * f,int xpos,int ypos,int xsize,int ysize,const char * tag,const char * indent)566 boolean UIComponent::PrintGeometryComment(FILE *f, int xpos, int ypos,
567 int xsize, int ysize, const char *tag,
568 const char *indent)
569 {
570 float norm_xsize, norm_ysize, norm_xpos, norm_ypos;
571
572 if (!tag)
573 tag = "window";
574
575 if (!indent)
576 indent = "";
577
578 Display *disp = theApplication->getDisplay();
579 int width = DisplayWidth(disp,0);
580 int height = DisplayHeight(disp,0);
581 int x=0, y=0;
582 int screen = -1;
583
584 #if defined(HAVE_XINERAMA)
585 // Do some Xinerama Magic to use the largest main screen.
586 int dummy_a, dummy_b;
587 int screens;
588 XineramaScreenInfo *screeninfo = NULL;
589
590 if ((XineramaQueryExtension (disp, &dummy_a, &dummy_b)) &&
591 (screeninfo = XineramaQueryScreens(disp, &screens))) {
592 // Xinerama Detected
593
594 if (XineramaIsActive(disp)) {
595 width = 0; height = 0;
596 int i = dummy_a;
597 while ( i < screens ) {
598 if(xpos > screeninfo[i].x_org &&
599 xpos < screeninfo[i].x_org+screeninfo[i].width &&
600 ypos > screeninfo[i].y_org &&
601 ypos < screeninfo[i].y_org+screeninfo[i].height ) {
602 screen = i;
603 width = screeninfo[i].width;
604 height = screeninfo[i].height;
605 x = screeninfo[i].x_org;
606 y = screeninfo[i].y_org;
607 }
608 i++;
609 }
610 }
611 }
612 #endif
613
614 norm_xsize = (float) xsize/width;
615 norm_ysize = (float) ysize/height;
616 norm_xpos = (float) (xpos - x)/width;
617 norm_ypos = (float) (ypos - y)/height;
618 if(screen != -1) {
619 if (fprintf(f,
620 "%s// %s: position = (%6.4f,%6.4f), size = %6.4fx%6.4f, screen = %d\n",
621 indent, tag, norm_xpos,norm_ypos,norm_xsize,norm_ysize,screen) < 0)
622 return FALSE;
623 } else {
624 if (fprintf(f,
625 "%s// %s: position = (%6.4f,%6.4f), size = %6.4fx%6.4f\n",
626 indent, tag, norm_xpos,norm_ypos,norm_xsize,norm_ysize) < 0)
627 return FALSE;
628 }
629
630 return TRUE;
631 }
632
ParseGeometryComment(const char * line,const char * file,int lineno,int * xpos,int * ypos,int * xsize,int * ysize,const char * tag)633 boolean UIComponent::ParseGeometryComment(const char *line, const char *file,
634 int lineno, int *xpos, int *ypos,
635 int *xsize, int *ysize, const char *tag)
636 {
637 char format[1024];
638 int items;
639 float norm_xsize, norm_ysize, norm_xpos, norm_ypos;
640 int screen = -1;
641 int display_xsize, display_ysize;
642
643 if (!tag)
644 tag = "window";
645
646 int taglen = STRLEN(tag);
647 sprintf(format," %s: position = (%%f,%%f), size = %%fx%%f, screen = %%d",tag);
648
649 // 15 = strlen(" ") + strlen(": position = (")
650 if (!EqualSubstring(line,format,taglen+15))
651 return FALSE;
652
653 items = sscanf(line,format,&norm_xpos,&norm_ypos,&norm_xsize,&norm_ysize,&screen);
654
655 if (items == 4 || items == 5) {
656 // If the size when printed was UIComponent::UnspecifiedPosition
657 // then the normalized value will be greater than 3, so ignore it.
658 if ((norm_xsize < 3) && (norm_ysize < 3)) {
659
660 int x=0, y=0, width=0, height=0;
661 Display *disp = theApplication->getDisplay();
662 width = DisplayWidth(disp,0);
663 height = DisplayHeight(disp,0);
664
665 #if defined(HAVE_XINERAMA)
666 // Do some Xinerama Magic to use the largest main screen.
667 int dummy_a, dummy_b;
668 int screens;
669 XineramaScreenInfo *screeninfo = NULL;
670
671 if ((XineramaQueryExtension (disp, &dummy_a, &dummy_b)) &&
672 (screeninfo = XineramaQueryScreens(disp, &screens))) {
673 // Xinerama Detected
674 //fprintf(stderr, "screens = %d, screen = %d, \nline = %s\n", screens, screen, line);
675 if (XineramaIsActive(disp)) {
676 width = 0; height = 0;
677 int i = dummy_a;
678 if(screen != -1 && screen <= screens) {
679 width = screeninfo[screen].width;
680 height = screeninfo[screen].height;
681 x = screeninfo[screen].x_org;
682 y = screeninfo[screen].y_org;
683 } else
684 while ( i < screens ) {
685 if(screeninfo[i].width > width) {
686 width = screeninfo[i].width;
687 height = screeninfo[i].height;
688 x = screeninfo[i].x_org;
689 y = screeninfo[i].y_org;
690 }
691 i++;
692 }
693 }
694 }
695 #endif
696 *xpos = (int) (width * norm_xpos + .5 + x);
697 *ypos = (int) (height * norm_ypos + .5 + y);
698 *xsize = (int) (width * norm_xsize + .5);
699 *ysize = (int) (height * norm_ysize + .5);
700 } else {
701 *xpos = UIComponent::UnspecifiedPosition;
702 *ypos = UIComponent::UnspecifiedPosition;
703 *xsize = UIComponent::UnspecifiedDimension;
704 *ysize = UIComponent::UnspecifiedDimension;
705 }
706 } else {
707 WarningMessage("Bad comment found in file '%s' line %d (ignoring)",
708 file,lineno);
709 }
710
711 return TRUE;
712 }
713
714 extern "C" void
UIComponent_InstallBubbleTP(XtPointer cData,XtIntervalId * id)715 UIComponent_InstallBubbleTP (XtPointer cData, XtIntervalId *id)
716 {
717 UIComponent *uic = (UIComponent*)cData;
718 uic->showBubbleHelp();
719 UIComponent::BubbleTimer = 0;
720 }
721
722 extern "C" void
UIComponent_BubbleEH(Widget w,XtPointer cData,XEvent * xev,Boolean * doit)723 UIComponent_BubbleEH (Widget w, XtPointer cData, XEvent* xev, Boolean* doit)
724 {
725 *doit = True;
726 UIComponent *uic = (UIComponent*)cData;
727 if (xev->type == EnterNotify) {
728 if (UIComponent::BubbleTimer)
729 XtRemoveTimeOut (UIComponent::BubbleTimer);
730 UIComponent::BubbleTimer =
731 XtAppAddTimeOut (theApplication->getApplicationContext(),
732 (unsigned long)100, (XtTimerCallbackProc)UIComponent_InstallBubbleTP,
733 (XtPointer)uic);
734 //uic->showBubbleHelp();
735 } else if (xev->type == LeaveNotify) {
736 if (UIComponent::BubbleTimer)
737 XtRemoveTimeOut (UIComponent::BubbleTimer);
738 else
739 uic->eraseBubbleHelp();
740 }
741 }
742
743 void
showBubbleHelp()744 UIComponent::showBubbleHelp()
745 {
746 if (!theApplication->bubbleHelpEnabled()) return ;
747
748 Widget help_viewer = theApplication->getHelpViewer();
749 if (!help_viewer) return ;
750
751 char *help_msg;
752 if ((this->inactive_help_msg) && (!this->active))
753 help_msg = this->inactive_help_msg;
754 else
755 help_msg = this->help_msg;
756 if (!help_msg) return ;
757
758 if (XtIsSubclass(help_viewer, xmLabelWidgetClass)) {
759 XmString xmstr = XmStringCreateLtoR (help_msg, "small_normal");
760 XtVaSetValues (help_viewer, XmNlabelString, xmstr, NULL);
761 XmStringFree(xmstr);
762 } else if (XtIsSubclass(help_viewer, xmTextWidgetClass)) {
763 XtVaSetValues (help_viewer, XmNvalue, help_msg, NULL);
764 } else if (XtIsSubclass(help_viewer, xmTextFieldWidgetClass)) {
765 XtVaSetValues (help_viewer, XmNvalue, help_msg, NULL);
766 } else ASSERT(0);
767 }
768
769 void
eraseBubbleHelp()770 UIComponent::eraseBubbleHelp()
771 {
772 if (!theApplication->bubbleHelpEnabled()) return ;
773
774 Widget help_viewer = theApplication->getHelpViewer();
775 if (!help_viewer) return ;
776
777 if (XtIsSubclass(help_viewer, xmLabelWidgetClass)) {
778 XmString xmstr = XmStringCreateLtoR ("", "small_normal");
779 XtVaSetValues (help_viewer, XmNlabelString, xmstr, NULL);
780 XmStringFree(xmstr);
781 } else if (XtIsSubclass(help_viewer, xmTextWidgetClass)) {
782 XtVaSetValues (help_viewer, XmNvalue, "", NULL);
783 } else if (XtIsSubclass(help_viewer, xmTextFieldWidgetClass)) {
784 XtVaSetValues (help_viewer, XmNvalue, "", NULL);
785 } else ASSERT(0);
786 }
787
788