1 /* 2 LiteClue.c - LiteClue widget 3 See LiteClue documentation 4 Version 1.4 5 6 Copyright 1996 COMPUTER GENERATION, INC., 7 8 The software is provided "as is", without warranty of any kind, express 9 or implied, including but not limited to the warranties of 10 merchantability, fitness for a particular purpose and noninfringement. 11 In no event shall Computer Generation, inc. nor the author be liable for 12 any claim, damages or other liability, whether in an action of contract, 13 tort or otherwise, arising from, out of or in connection with the 14 software or the use or other dealings in the software. 15 16 Permission to use, copy, modify, and distribute this software and its 17 documentation for any purpose and without fee is hereby granted, 18 provided that the above copyright notice appear in all copies and that 19 both that copyright notice and this permission notice appear in 20 supporting documentation. 21 22 Author: 23 Gary Aviv 24 Computer Generation, Inc., 25 gary@compgen.com 26 www.compgen.com/widgets 27 28 Thanks to Contributers: 29 J Satchell, Eric Marttila 30 */ 31 /* Revision History: 32 $Log: LiteClue.c,v $ 33 Revision 1.16 1998/09/07 14:06:19 gary 34 Added const to prototype of XcgLiteClueAddWidget at request from user 35 36 Revision 1.15 1998/07/30 16:05:16 gary 37 Add NO_FONT_SET to usr FontStruct rather than FontSet 38 39 Revision 1.14 1998/01/06 15:30:33 gary 40 If font specified by resource can not be converted, use fixed 41 font as fallback. If no font at all can be converted, prevent 42 crash, just disable widget entirely. 43 44 Revision 1.13 1997/07/07 14:55:04 gary 45 Cancel timeouts when XcgLiteClueDeleteWidget is called to prevent 46 errant timeout event on deleted widget. 47 48 Revision 1.12 1997/06/20 20:09:09 gary 49 Add XcgLiteClueDispatchEvent to enable clues for insensitive widgets. 50 51 Revision 1.11 1997/06/15 14:10:24 gary 52 Add XcgLiteClueDispatchEvent to enable clues for insensitive widgets. 53 54 Revision 1.10 1997/04/14 13:02:33 gary 55 Attempt to fix problem when we get multiple enter events bu no leave event. 56 57 Revision 1.9 1997/03/10 14:42:41 gary 58 Attempt to fix problem when we get multiple enter events bu no leave event. 59 Add C++ wrapper to allow linking with C++ programs. (In HView.h) 60 61 Revision 1.8 1997/01/17 13:44:14 gary 62 Support of cancelWaitPeriod resource: this is a period from the point 63 a help popdown occurs in which the normal waitPeriod is suspended 64 for the next popup 65 66 Revision 1.7 1996/12/16 22:35:38 gary 67 Fix double entry problem 68 69 Revision 1.6 1996/11/18 14:52:21 gary 70 remove some compile warnings pointed out by a user 71 72 Revision 1.5 1996/11/12 20:56:43 gary 73 remove some compile warnings 74 75 Revision 1.4 1996/10/20 13:38:16 gary 76 Version 1.2 freeze 77 78 Revision 1.3 1996/10/19 16:16:30 gary 79 Compile warning removed with cast 80 81 Revision 1.2 1996/10/19 16:07:38 gary 82 a) R4 back compatibility 83 b) Delay before pop up of help, waitPeriod resource (def 500 ms). 84 Thanks to J Satchell for this. 85 c) Button press in watched widget pops down help 86 87 Revision 1.1 1996/10/18 23:14:58 gary 88 Initial 89 90 91 $log 92 Added const to prototype of XcgLiteClueAddWidget at request from user 93 $log 94 */ 95 #include <unistd.h> 96 #include <signal.h> 97 /* #include <Xm/XmP.h> */ 98 #include <X11/IntrinsicP.h> 99 #include <X11/StringDefs.h> 100 101 #include "LiteClueP.h" 102 103 #include <stdio.h> 104 105 #define CheckWidgetClass(routine) \ 106 if (XtClass(w) != xcgLiteClueWidgetClass) \ 107 wrong_widget(routine) 108 109 110 static Boolean setValues( Widget _current, Widget _request, Widget _new, ArgList args, Cardinal * num_args); 111 static void Initialize(Widget treq, Widget tnew, ArgList args, Cardinal *num_args); 112 struct liteClue_context_str * alloc_liteClue_context(void); 113 static void popdown_timeout_event( XtPointer client_data, XtIntervalId *id); 114 115 /* keep information about each widget we are keeping track of */ 116 struct liteClue_context_str 117 { 118 ListThread next; /* next in list */ 119 Widget watched_w; /* the widget we are watching */ 120 XcgLiteClueWidget cw; /* pointer back to the liteClue widget */ 121 Position abs_x, abs_y; 122 Boolean sensitive; /* if False, liteClue is suppressed */ 123 char * text; /* text to display */ 124 short text_size; /* its size */ 125 }; 126 127 void free_widget_context(XcgLiteClueWidget cw, struct liteClue_context_str * obj); 128 /* 129 Widget resources: eg to set LiteClue box background: 130 *XcgLiteClue.background: yellow 131 132 */ 133 #define offset(field) XtOffsetOf(LiteClueRec, field) 134 static XtResource LC_resources[] = 135 { 136 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), 137 offset(liteClue.foreground), XtRString, "black"}, 138 #if XtSpecificationRelease < 5 || defined(NO_FONT_SET) 139 {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), 140 offset(liteClue.fontset), XtRString, 141 "-adobe-new century schoolbook-bold-r-normal-*-14-*-*-*-*-*-*-*"}, 142 #else 143 {XtNfontSet, XtCFontSet, XtRFontSet, sizeof(XFontSet), 144 offset(liteClue.fontset), XtRString, "-adobe-new century schoolbook-bold-r-normal-*-12-*"}, 145 #endif 146 {XgcNwaitPeriod, XgcCWaitPeriod, XtRInt , sizeof(int), 147 offset(liteClue.waitPeriod),XtRString, "500" }, 148 149 {XgcNwaitPeriod2, XgcCWaitPeriod, XtRInt , sizeof(int), 150 offset(liteClue.waitPeriod2),XtRString, "2000" }, 151 152 {XgcNcancelWaitPeriod, XgcCCancelWaitPeriod, XtRInt , sizeof(int), 153 offset(liteClue.cancelWaitPeriod),XtRString, "2000" }, 154 }; 155 156 #undef offset 157 158 #if 0 159 static XtActionsRec actions[] = 160 }; /* actions */ 161 #endif 162 163 164 LiteClueClassRec xcgLiteClueClassRec = 165 { 166 { 167 (WidgetClass)&overrideShellClassRec, /* superclass */ 168 "XcgLiteClue", /* class_name */ 169 (Cardinal)sizeof(LiteClueRec), /* widget size */ 170 NULL, /* class_init */ 171 (XtWidgetClassProc)NULL, /* class_part_init */ 172 (XtEnum)FALSE, /* class_inited */ 173 (XtInitProc)Initialize, /* initialize */ 174 (XtArgsProc)NULL, /* init_hook */ 175 XtInheritRealize, /* realize */ 176 (XtActionList)0, /* actions */ 177 (Cardinal)0, /* num_actions */ 178 (XtResourceList)LC_resources, /* resources */ 179 (Cardinal)XtNumber(LC_resources), /* num_resources */ 180 NULLQUARK, /* xrm_class */ 181 TRUE, /* compress_motion */ 182 (XtEnum)FALSE, /* compress_exposur */ 183 TRUE, /* compress enterleave */ 184 FALSE, /* visibility_interest */ 185 (XtWidgetProc)NULL, /* destroy */ 186 XtInheritResize, 187 XtInheritExpose, /* expose, */ 188 (XtSetValuesFunc)setValues, /* set_values */ 189 (XtArgsFunc)NULL, /* set_values_hook */ 190 XtInheritSetValuesAlmost, /* set_values_almost */ 191 (XtArgsProc)NULL, /* get_values_hook */ 192 XtInheritAcceptFocus, /* accept_focus */ 193 XtVersion, /* version */ 194 (XtPointer)NULL, /* callback_private */ 195 XtInheritTranslations, 196 XtInheritQueryGeometry, /* query_geometry */ 197 XtInheritDisplayAccelerator, /* display_accelerator */ 198 (XtPointer)0, /* extension */ 199 }, 200 { /*** composite-Class ***/ 201 XtInheritGeometryManager, /* geometry_manager */ 202 XtInheritChangeManaged, /* change_managed */ 203 XtInheritInsertChild, /* insert_child */ 204 XtInheritDeleteChild, /* delete_child */ 205 NULL /* extension */ 206 }, 207 { /* Shell */ 208 (XtPointer) NULL, /* pointer to extension record */ 209 }, 210 /* Override Shell */ 211 { 212 0, 213 }, 214 /* LiteClue */ 215 { 216 0, 217 }, 218 }; 219 220 WidgetClass xcgLiteClueWidgetClass = (WidgetClass) & xcgLiteClueClassRec; 221 222 /* doubly linked list processing */ 223 224 /* 225 initialize header - both pointers point to it 226 */ 227 static void xcgListInit(ListThread *newbuf) 228 { 229 newbuf->back = newbuf; 230 newbuf->forw = newbuf; 231 } 232 233 234 /* 235 insert newbuf before posbuf 236 */ 237 static void xcgListInsertBefore(ListThread *newlist, ListThread *poslist) 238 { 239 ListThread *prevbuf; 240 241 prevbuf = poslist->back; 242 243 poslist->back = newlist; 244 newlist->forw = poslist; 245 newlist->back = prevbuf; 246 prevbuf->forw = newlist; 247 } 248 249 250 /* 251 remove rembuf from queue 252 */ 253 static ListThread * xcgListRemove(ListThread *rembuf) 254 { 255 ListThread *prevbuf, *nextbuf; 256 257 prevbuf = rembuf->back; 258 nextbuf = rembuf->forw; 259 260 prevbuf->forw = nextbuf; 261 nextbuf->back = prevbuf; 262 263 rembuf->back = (ListThread *) NULL; /* for safety to cause trap if ..*/ 264 rembuf->forw = (ListThread *) NULL; /* .. mistakenly refed */ 265 return rembuf; 266 } 267 268 /* 269 The font_information is derived 270 */ 271 272 #if XtSpecificationRelease < 5 || defined(NO_FONT_SET) 273 274 /* R4 and below code */ 275 /* 276 Return XFontSet for passed font_string. 277 return status 278 */ 279 static int string_to_FontSet (XcgLiteClueWidget cw, char * font_string, XFontStruct ** out) 280 { 281 Boolean sts; 282 XrmValue from; 283 XrmValue to; 284 285 to.size = sizeof(out); 286 to.addr = (void *) out; 287 from.size = strlen(from.addr = font_string ); 288 sts = XtConvertAndStore((Widget) cw, XtRString, &from, XtRFontStruct, &to); 289 return sts; 290 } 291 292 static void compute_font_info(XcgLiteClueWidget cw) 293 { 294 int direction_return; 295 int font_ascent_return, font_descent_return; 296 XCharStruct oret; 297 if (!cw->liteClue.fontset) 298 string_to_FontSet(cw, "fixed", &cw->liteClue.fontset) ; 299 if (!cw->liteClue.fontset) 300 { 301 fprintf(stderr,"LiteClue: can not find resource font nor fallback fixed font\n"); 302 return; 303 } 304 XTextExtents( cw->liteClue.fontset, "1", 1, 305 &direction_return, 306 &font_ascent_return, &font_descent_return, &oret); 307 308 cw->liteClue.font_baseline = oret.ascent; /* y offset from top to baseline, 309 don't know why this is returned as negative */ 310 cw->liteClue.font_width = oret.width; /* the width and height of the object */ 311 cw->liteClue.font_height = oret.ascent+oret.descent; 312 } 313 314 #else 315 /* 316 Return XFontSet for passed font_string. 317 return status 318 */ 319 static int string_to_FontSet (XcgLiteClueWidget cw, char * font_string, XFontSet * out) 320 { 321 Boolean sts; 322 XrmValue from; 323 XrmValue to; 324 325 to.size = sizeof(out); 326 to.addr = (void *) out; 327 from.size = strlen(from.addr = font_string ); 328 sts = XtConvertAndStore((Widget) cw, XtRString, &from, XtRFontSet, &to); 329 return sts; 330 } 331 332 /* R5 and above code */ 333 static void compute_font_info(XcgLiteClueWidget cw) 334 { 335 XRectangle ink; 336 XRectangle logical; 337 338 if (!cw->liteClue.fontset) 339 string_to_FontSet(cw, "fixed", &cw->liteClue.fontset) ; 340 if (!cw->liteClue.fontset) 341 { 342 fprintf(stderr,"LiteClue: can not find resource font nor fallback fixed font\n"); 343 return; 344 } 345 XmbTextExtents(cw->liteClue.fontset, "1", 1,&ink, &logical); 346 347 cw->liteClue.font_baseline = -logical.y; /* y offset from top to baseline, 348 don't know why this is returned as negative */ 349 cw->liteClue.font_width = logical.width; /* the width and height of the object */ 350 cw->liteClue.font_height = logical.height; 351 } 352 #endif 353 354 /* 355 Creates the various graphic contexts we will need 356 */ 357 static void create_GC(XcgLiteClueWidget cw ) 358 { 359 XtGCMask valuemask; 360 XGCValues myXGCV; 361 362 363 valuemask = GCForeground | GCBackground | GCFillStyle ; 364 myXGCV.foreground = cw->liteClue.foreground; 365 myXGCV.background = cw->core.background_pixel; 366 myXGCV.fill_style = FillSolid; 367 368 #if XtSpecificationRelease < 5 || defined(NO_FONT_SET) 369 valuemask |= GCFont ; 370 myXGCV.font = cw->liteClue.fontset->fid; 371 #endif /* end R4 hack */ 372 373 if (cw->liteClue.text_GC ) 374 XtReleaseGC((Widget) cw, cw->liteClue.text_GC ); 375 cw->liteClue.text_GC = XtGetGC((Widget)cw, valuemask, &myXGCV); 376 } 377 378 379 /* a routine to halt execution and force 380 a core dump for debugging analysis 381 when a public routine is called with the wrong class of widget 382 */ 383 static void wrong_widget(char * routine) 384 { 385 int mypid = getpid(); 386 fprintf(stderr, "Wrong class of widget passed to %s\n", routine); 387 fflush(stderr); 388 kill(mypid, SIGABRT); 389 } 390 391 /* 392 Find the target in the widget list. Return context pointer if found, 393 NULL if not 394 */ 395 static struct liteClue_context_str * find_watched_widget(XcgLiteClueWidget cw, 396 Widget target) 397 { 398 struct liteClue_context_str * obj; 399 400 for (obj = (struct liteClue_context_str *) cw->liteClue.widget_list.forw; 401 obj != (struct liteClue_context_str *) & cw->liteClue.widget_list; 402 obj = (struct liteClue_context_str *)obj->next.forw ) 403 { 404 if (target == obj->watched_w) 405 return obj; 406 } 407 return NULL; 408 } 409 410 /* 411 allocate and initialize a widget context 412 */ 413 struct liteClue_context_str * alloc_liteClue_context(void) 414 { 415 struct liteClue_context_str * out; 416 out = (struct liteClue_context_str *) XtMalloc(sizeof(struct liteClue_context_str)); 417 memset(out, 0, sizeof(struct liteClue_context_str)); 418 xcgListInit(&out->next); 419 return out ; 420 } 421 422 /* 423 allocate, initialize and link a liteClue context to the list 424 */ 425 static struct liteClue_context_str * alloc_link_liteClue_context(XcgLiteClueWidget cw ) 426 { 427 struct liteClue_context_str * out = alloc_liteClue_context(); 428 429 /* link as new last */ 430 xcgListInsertBefore(&out->next, &cw->liteClue.widget_list); 431 out->cw = cw; /* initialize this emeber - its always the same */ 432 return out; 433 } 434 435 /* 436 free a widget context 437 */ 438 void free_widget_context(XcgLiteClueWidget cw, struct liteClue_context_str * obj) 439 { 440 xcgListRemove((ListThread *)obj); 441 /* free up all things object points to */ 442 obj->sensitive = False; 443 if (obj->text ) 444 XtFree(obj->text); 445 XtFree((char *) obj); 446 } 447 448 449 /* -------------------- Widget Methods ---------------------- */ 450 /* Initialize method */ 451 static void Initialize(Widget treq, Widget tnew, ArgList args, 452 Cardinal *num_args) 453 { 454 XcgLiteClueWidget cw = (XcgLiteClueWidget) tnew; 455 456 457 cw->liteClue.text_GC = NULL; 458 cw->liteClue.HelpIsUp = False; 459 cw->liteClue.HelpPopDownTime = 0; 460 cw->liteClue.interval_id = (XtIntervalId)0; 461 cw->liteClue.interval_id2 = (XtIntervalId)0; 462 xcgListInit(&cw->liteClue.widget_list); /* initialize empty list */ 463 compute_font_info(cw); 464 create_GC(cw ); 465 } 466 467 static Boolean setValues( Widget _current, Widget _request, Widget _new, ArgList args, Cardinal * num_args) 468 { 469 XcgLiteClueWidget cw_new = (XcgLiteClueWidget) _new; 470 XcgLiteClueWidget cw_cur = (XcgLiteClueWidget) _current; 471 472 /* values of cw_new->liteClue.cancelWaitPeriod and 473 cw_new->liteClue.waitPeriod are accepted without checking */ 474 475 if (cw_new->liteClue.foreground != cw_cur->liteClue.foreground 476 || cw_new->core.background_pixel != cw_cur->core.background_pixel ) 477 { 478 create_GC(cw_new); 479 } 480 481 return FALSE; 482 } 483 484 /* ----------------- Event handlers ------------------------*/ 485 486 /* At this point the help may be popup 487 */ 488 static void timeout_event( XtPointer client_data, XtIntervalId *id) 489 { 490 #define BorderPix 2 491 struct liteClue_context_str * obj = (struct liteClue_context_str *) client_data; 492 XcgLiteClueWidget cw = obj->cw; 493 494 XRectangle ink; 495 XRectangle logical; 496 Widget w; 497 Window rwin, cld; 498 int rx, ry, wx, wy, width, height; 499 unsigned int mask; 500 Display *dpy; 501 int scr; 502 503 if (cw->liteClue.interval_id == (XtIntervalId)0) 504 return; /* timeout was removed but callback happened anyway */ 505 cw->liteClue.interval_id = (XtIntervalId)0; 506 if (obj->sensitive == False) 507 return; 508 509 w = obj->watched_w; 510 511 #if XtSpecificationRelease < 5 || defined(NO_FONT_SET) 512 { 513 int direction_return; 514 int font_ascent_return, font_descent_return; 515 XCharStruct oret; 516 XTextExtents( cw->liteClue.fontset ,obj->text , obj->text_size, 517 &direction_return, 518 &font_ascent_return, &font_descent_return, &oret); 519 logical.width = oret.width; 520 } 521 #else 522 XmbTextExtents(cw->liteClue.fontset, obj->text , obj->text_size ,&ink, &logical); 523 #endif 524 525 dpy = XtDisplay((Widget) cw); 526 XQueryPointer(dpy, DefaultRootWindow(dpy), 527 &rwin, &cld, &rx, &ry, &wx, &wy, &mask); 528 scr = DefaultScreen(dpy); 529 rx += 3; 530 ry += 15; 531 wx = DisplayWidth(dpy, scr); 532 wy = DisplayHeight(dpy, scr); 533 width = 2*BorderPix +logical.width; 534 height = 2*BorderPix + cw->liteClue.font_height; 535 536 if(rx+width > wx) 537 rx = wx - width; 538 if(ry+height > wy) 539 ry = wy - height; 540 541 XtResizeWidget((Widget) cw, width, height, cw->core.border_width ); 542 543 XtMoveWidget((Widget) cw, rx, ry); 544 XtPopup((Widget) cw, XtGrabNone); 545 cw->liteClue.HelpIsUp = True; 546 547 cw->liteClue.interval_id2 = XtAppAddTimeOut( 548 XtWidgetToApplicationContext(w), 549 cw->liteClue.waitPeriod2, 550 popdown_timeout_event, client_data); 551 552 #if XtSpecificationRelease < 5 || defined(NO_FONT_SET) 553 XDrawImageString(XtDisplay((Widget) cw), XtWindow((Widget) cw), 554 cw->liteClue.text_GC , BorderPix, 555 BorderPix + cw->liteClue.font_baseline, obj->text , obj->text_size); 556 #else 557 XmbDrawImageString(XtDisplay((Widget) cw), XtWindow((Widget) cw), 558 cw->liteClue.fontset, 559 cw->liteClue.text_GC , BorderPix, 560 BorderPix + cw->liteClue.font_baseline, obj->text , obj->text_size); 561 #endif 562 } 563 564 /* 565 Pointer enters watched widget, set a timer at which time it will 566 popup the help 567 */ 568 static void Enter_event(Widget w, XtPointer client_data, XEvent * xevent, Boolean * continue_to_dispatch ) 569 { 570 struct liteClue_context_str * obj = (struct liteClue_context_str *) client_data; 571 XcgLiteClueWidget cw = obj->cw; 572 XEnterWindowEvent * event = & xevent->xcrossing; 573 int current_waitPeriod ; 574 575 if (obj->sensitive == False || !cw->liteClue.fontset) 576 return; 577 /* check for two enters in a row - happens when widget is 578 exposed under a pop-up */ 579 if (cw->liteClue.interval_id != (XtIntervalId)0) 580 return; 581 if(event->mode != NotifyNormal) 582 return; 583 584 /* if a help was recently popped down, don't delay in poping up 585 help for next watched widget 586 */ 587 if ((event->time - cw->liteClue.HelpPopDownTime) > 588 cw->liteClue.cancelWaitPeriod ) 589 current_waitPeriod = cw->liteClue.waitPeriod,timeout_event; 590 else 591 current_waitPeriod = 0; 592 593 cw->liteClue.interval_id = XtAppAddTimeOut( 594 XtWidgetToApplicationContext(w), 595 current_waitPeriod, timeout_event, client_data); 596 } 597 598 /* 599 Remove timer, if its pending. Then popdown help. 600 */ 601 static void Leave_event(Widget w, XtPointer client_data, XEvent * xevent, Boolean * continue_to_dispatch ) 602 { 603 XEnterWindowEvent *event = NULL; 604 struct liteClue_context_str * obj = (struct liteClue_context_str *) client_data; 605 XcgLiteClueWidget cw = obj->cw; 606 607 if(xevent) 608 event = & xevent->xcrossing; 609 610 if (cw->liteClue.interval_id != (XtIntervalId)0) 611 { 612 XtRemoveTimeOut(cw->liteClue.interval_id); 613 cw->liteClue.interval_id= (XtIntervalId)0; 614 } 615 616 if (cw->liteClue.interval_id2 != (XtIntervalId)0) 617 { 618 XtRemoveTimeOut(cw->liteClue.interval_id2); 619 cw->liteClue.interval_id2= (XtIntervalId)0; 620 } 621 622 if (obj->sensitive == False) 623 return; 624 if (cw->liteClue.HelpIsUp) 625 { 626 XtPopdown((Widget) cw); 627 cw->liteClue.HelpIsUp = False; 628 if(xevent) 629 cw->liteClue.HelpPopDownTime = event->time; 630 else 631 cw->liteClue.HelpPopDownTime = 0; 632 } 633 } 634 635 static void popdown_timeout_event( XtPointer client_data, XtIntervalId *id) 636 { 637 Boolean dummy; 638 639 Leave_event(NULL, client_data, NULL, &dummy); 640 } 641 642 /* ---------------- Widget API ---------------------------- */ 643 644 /* 645 ;+ 646 XcgLiteClueAddWidget -- Add a widget to be watched. LiteClue will be given for this widget 647 648 Func: A widget will be added to the LiteClue watched list. Clues are given for 649 sensitive watched widgets when the pointer enters its window. If the 650 widget is already watched, the passed text replaces its current clue 651 text. If text is null, the widget is still added, if it is not already 652 in the list, but no clue will appear. Text may be specified with 653 XcgLiteClueAddWidget in a subsequent call. When text is null and the 654 widget is already in the list, its text is not changed. When a widget 655 will is added to the watched list, it automatically becomes sensitive. 656 Otherwise, its sensitivity is not changed. A watched widget which is not 657 sensitive retains its context but clues are suppressed. 658 None of this affects the behaviour of the watched widget itself. 659 LiteClue monitors enter and leave events of the watched widget's 660 window passively. 661 662 Input: w - LiteClue widget 663 watch - the widget to give liteClues for 664 text - pointer to liteClue text. (May be NULL) 665 size - size of text. May be zero 666 in which case a strlen will be done. 667 option - option mask, future use, zero for now. 668 Output: 669 670 Return: 671 672 ;- 673 */ 674 void XcgLiteClueAddWidget(Widget w, Widget watch, const char * text, int size, int option ) 675 { 676 # define ROUTINE "XcgLiteClueAddWidget" 677 XcgLiteClueWidget cw = (XcgLiteClueWidget) w; 678 struct liteClue_context_str * obj; 679 Boolean exists = False; 680 681 CheckWidgetClass(ROUTINE); /* make sure we are called with a LiteClue widget */ 682 683 obj = find_watched_widget(cw, watch); 684 if (obj) 685 { 686 exists = True; 687 if (text) 688 { 689 if(obj->text) 690 XtFree(obj->text); 691 obj->text = NULL; 692 } 693 } 694 else 695 { 696 obj = alloc_link_liteClue_context(cw ); 697 obj->watched_w = watch; 698 } 699 if (text && !(obj->text)) 700 { 701 if (!size) 702 size = strlen(text); 703 obj->text = XtMalloc(size+1); 704 memcpy(obj->text, text, size); 705 obj->text[size] = 0; 706 obj->text_size = size; 707 } 708 if (!exists) /* was created */ 709 { 710 XtAddEventHandler(watch, EnterWindowMask, False, 711 Enter_event, (XtPointer) obj); 712 XtAddEventHandler(watch, LeaveWindowMask|ButtonPressMask, 713 False, Leave_event, (XtPointer) obj); 714 715 obj->sensitive = True; 716 } 717 718 # undef ROUTINE 719 } 720 721 722 /* 723 ;+ 724 XcgLiteClueDeleteWidget -- Delete a widget that is watched. 725 726 Func: A widget is deleted from the watched list and its resources are 727 freed. LiteClue is no longer given for the widget. 728 If the widget is not watched, nothing is done. 729 730 Input: w - LiteClue widget 731 watch - the widget to delete 732 Output: 733 734 Return: 735 736 ;- 737 */ 738 void XcgLiteClueDeleteWidget(Widget w, Widget watch) 739 { 740 # define ROUTINE "XcgLiteClueDeleteWidget" 741 XcgLiteClueWidget cw = (XcgLiteClueWidget) w; 742 struct liteClue_context_str * obj; 743 744 CheckWidgetClass(ROUTINE); /* make sure we are called with a LiteClue widget */ 745 obj = find_watched_widget(cw, watch); 746 if (obj) 747 { 748 XtRemoveEventHandler(watch, EnterWindowMask, False, 749 Enter_event, (XtPointer) obj); 750 XtRemoveEventHandler(watch, LeaveWindowMask|ButtonPressMask, 751 False, Leave_event, (XtPointer) obj); 752 if (cw->liteClue.interval_id != (XtIntervalId)0) 753 { 754 XtRemoveTimeOut(cw->liteClue.interval_id); 755 cw->liteClue.interval_id= (XtIntervalId)0; 756 } 757 free_widget_context(cw, obj); 758 } 759 760 # undef ROUTINE 761 } 762 763 764 /* 765 ;+ 766 XcgLiteClueSetSensitive -- Enable/disable sensitivity for watched widget. 767 768 Func: When a watched widget is sensitive, a clue is poped up when the pointer 769 enters its window. When a watched widget is insensitive, the widget is 770 retained in the watched list but no clue is poped. The sensitivity of a 771 watched widget relative to clues is set or reset by this function. The 772 Xt sensitivity of the watched widget is not altered by this function. 773 774 Input: w - LiteClue widget 775 watch - the widget to make sensitive or insensitive or NULL 776 to change all watched widgets 777 sensitive - True or False 778 Output: 779 780 Return: 781 782 ;- 783 */ 784 void XcgLiteClueSetSensitive(Widget w, Widget watch, Boolean sensitive) 785 { 786 # define ROUTINE "XcgLiteClueSetSensitive" 787 XcgLiteClueWidget cw = (XcgLiteClueWidget) w; 788 struct liteClue_context_str * obj; 789 790 CheckWidgetClass(ROUTINE); /* make sure we are called with a LiteClue widget */ 791 if (watch) 792 { 793 obj = find_watched_widget(cw, watch); 794 if (obj) 795 { 796 obj->sensitive = sensitive; 797 return; 798 } 799 else 800 return; 801 } 802 803 /* do them all */ 804 for (obj = (struct liteClue_context_str *) cw->liteClue.widget_list.forw; 805 obj != (struct liteClue_context_str *) & cw->liteClue.widget_list; 806 obj = (struct liteClue_context_str *)obj->next.forw ) 807 { 808 obj->sensitive = sensitive; 809 } 810 811 # undef ROUTINE 812 } 813 814 /* 815 ;+ 816 XcgLiteClueGetSensitive -- Get sensitivity mode for watched widget. 817 818 Func: When a watched widget is sensitive, a clue is poped up when the pointer 819 enters its window. When a watched widget is insensitive, the widget is 820 retained in the watched list but no clue is poped. The sensitivity state 821 of a watched widget relative to clues is returned by this function. The 822 Xt sensitivity of a widget is a totally independent concept. 823 824 Input: w - LiteClue widget 825 watch - the widget for which to get sensitivity state. If NULL 826 first watched widget is used. If there are no watched widgets, 827 False is returned. 828 Output: 829 830 Return: sensitive - True or False 831 832 ;- 833 */ 834 Boolean XcgLiteClueGetSensitive(Widget w, Widget watch) 835 { 836 # define ROUTINE "XcgLiteClueGetSensitive" 837 838 XcgLiteClueWidget cw = (XcgLiteClueWidget) w; 839 struct liteClue_context_str * obj; 840 841 CheckWidgetClass(ROUTINE); /* make sure we are called with a LiteClue widget */ 842 if (watch) 843 { 844 obj = find_watched_widget(cw, watch); 845 if (obj) 846 return obj->sensitive; 847 else 848 return False; 849 } 850 /* do the first one */ 851 obj = (struct liteClue_context_str *) cw->liteClue.widget_list.forw; 852 if (obj != (struct liteClue_context_str *) & cw->liteClue.widget_list) 853 return obj->sensitive; 854 else 855 return False; 856 857 # undef ROUTINE 858 } 859 860 861 /* 862 ;+ 863 XcgLiteClueDispatchEvent -- Dispatch event from main X event loop 864 865 Func: This function may be used to enable clues for insensitive 866 watched widgets. Normally, XtAppMainLoop (which calls 867 XtDispatchEvent) will not deliver EnterNotify and LeaveNotify 868 events to widgets that are not sensitive (XtSetSensitive). This 869 prevents clues from poping up for these widgets. To bypass this 870 limitation, you can break out XtAppMainLoop and add a call to 871 XcgLiteClueDispatchEvent ass follows: 872 873 MyXtAppMainLoop(XtAppContext app) 874 { 875 XEvent event; 876 877 for (;;) { 878 XtAppNextEvent(app, &event); 879 XcgLiteClueDispatchEvent(w, event) ; 880 XtDispatchEvent(&event); 881 } 882 } 883 884 Input: w - LiteClue widget 885 event - received event, normally from call to XtAppNextEvent. 886 887 Output: void 888 889 Return: True - event was dispatched to non-sensitive watched widget. 890 False - not a EnterNotify or LeaveNotify event or window in 891 event is not a non-sensitive watched widget. 892 893 ;- 894 */ 895 Boolean XcgLiteClueDispatchEvent(Widget w, XEvent *event) 896 { 897 # define ROUTINE "XcgLiteClueDispatchEvent" 898 899 XcgLiteClueWidget cw = (XcgLiteClueWidget) w; 900 struct liteClue_context_str * obj; 901 Boolean continue_to_dispatch; 902 903 if (event->type != EnterNotify && event->type != LeaveNotify) 904 return False; 905 CheckWidgetClass(ROUTINE); /* make sure we are called with a LiteClue widget */ 906 907 /* scan list */ 908 for (obj = (struct liteClue_context_str *) cw->liteClue.widget_list.forw; 909 obj != (struct liteClue_context_str *) & cw->liteClue.widget_list; 910 obj = (struct liteClue_context_str *)obj->next.forw ) 911 { 912 if ((XtWindow(obj->watched_w) != event->xany.window) 913 || (XtIsSensitive(obj->watched_w)) ) 914 continue; 915 /* found one */ 916 if (event->type == EnterNotify ) 917 Enter_event(obj->watched_w, (XtPointer)obj, event, &continue_to_dispatch); 918 else 919 Leave_event(obj->watched_w, (XtPointer)obj, event, &continue_to_dispatch); 920 return True; 921 } 922 return False; 923 924 # undef ROUTINE 925 } 926 927