1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 #ifdef HAVE_CONFIG_H
27 #include "../config.h"
28 #endif
29
30 #include <unistd.h>
31 #include <stdio.h>
32
33 #include <X11/StringDefs.h>
34
35 #include <Xm/XmosP.h>
36 #include <Xm/MessageB.h>
37 #include <Xm/Form.h>
38 #include <Xm/TextF.h>
39 #include <Xm/LabelP.h>
40 #include <Xm/DialogS.h>
41 #include <Xm/MenuShell.h>
42 #include <Xm/Display.h>
43
44 #include "BubbleButtonP.h"
45 #include "SlideC.h"
46
47 #include "../util/misc.h"
48
49 #ifdef WITH_DMALLOC
50 #include <dmalloc.h>
51 #endif
52
53 static const char rcsid[] =
"$Id: BubbleButton.c,v 1.9 2005/12/01 14:31:43 tringali Exp $";
54
55
56
57
58
59 static void class_initialize(
void);
60 static void class_part_initialize(WidgetClass widget_class);
61 static void initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args);
62 static void destroy(Widget w);
63 static Boolean set_values(Widget old, Widget request, Widget new_w, ArgList args, Cardinal *num_args);
64 static void _XmExportLabelString(Widget w,
int offset, XtArgVal *value);
65
66
67
68
69
70
71
72
73
74 #define Offset(field) XtOffsetOf(XltBubbleButtonRec, bubble_button.field)
75 static XtResource resources[] =
76 {
77 {
78 XltNbubbleString, XltCBubbleString, XmRXmString,
79 sizeof(XmString), Offset(BubbleString),
80 XmRImmediate, (XtPointer)
NULL
81 },
82 {
83 XltNshowBubble, XltCShowBubble, XmRBoolean,
84 sizeof(Boolean), Offset(show_bubble),
85 XmRImmediate, (XtPointer)True
86 },
87 {
88 XltNdelay, XltCDelay, XtRInt,
89 sizeof(
int), Offset(Delay),
90 XtRImmediate, (XtPointer)
1000
91 },
92 {
93 XltNmouseOverString, XltCMouseOverString, XmRXmString,
94 sizeof(XmString), Offset(MouseOverString),
95 XtRImmediate, (XtPointer)
NULL
96 },
97 {
98 XltNmouseOverPixmap, XltCMouseOverPixmap, XmRPrimForegroundPixmap,
99 sizeof(Pixmap), Offset(MouseOverPixmap),
100 XtRImmediate, (XtPointer)None
101 },
102 {
103 XltNbubbleDuration, XltCBubbleDuration, XtRInt,
104 sizeof(
int), Offset(Duration),
105 XtRImmediate, (XtPointer)
0
106 },
107 {
108 XltNslidingBubble, XltCslidingBubble, XmRBoolean,
109 sizeof(Boolean), Offset(slidingBubble),
110 XmRImmediate, (XtPointer)True
111 },
112 {
113 XltNautoParkBubble, XltCautoParkBubble, XmRBoolean,
114 sizeof(Boolean), Offset(autoParkBubble),
115 XmRImmediate, (XtPointer)False
116 },
117 };
118
119 static XmSyntheticResource syn_resources[] =
120 {
121 {
122 XltNbubbleString,
123 sizeof(XmString), Offset(BubbleString),
124 _XmExportLabelString,
NULL
125 }
126 };
127 #undef Offset
128
129
130
131
132
133 static void EnterWindow(Widget w, XEvent *event, String *params, Cardinal *num_params);
134 static void LeaveWindow(Widget w, XEvent *event, String *params, Cardinal *num_params);
135
136 static XtActionsRec actions[] =
137 {
138 {
"Enter", EnterWindow},
139 {
"Leave", LeaveWindow},
140 };
141
142
143 XltBubbleButtonClassRec xrwsBubbleButtonClassRec = {
144
145 {
146 (WidgetClass) &xmPushButtonClassRec,
147 "XltBubbleButton",
148 sizeof(XltBubbleButtonRec),
149 class_initialize,
150 class_part_initialize,
151 False,
152 initialize,
153 NULL,
154 XtInheritRealize,
155 actions,
156 XtNumber(actions),
157 resources,
158 XtNumber(resources),
159 NULLQUARK,
160 True,
161 XtExposeCompressMaximal,
162 True,
163 False,
164 destroy,
165 XtInheritResize,
166 XtInheritExpose,
167 set_values,
168 NULL,
169 XtInheritSetValuesAlmost,
170 NULL,
171 NULL,
172 XtVersion,
173 NULL,
174 NULL,
175 XtInheritQueryGeometry,
176 NULL,
177 (XtPointer)
NULL
178 },
179
180 {
181 XmInheritBorderHighlight,
182 XmInheritBorderUnhighlight,
183 XtInheritTranslations,
184 XmInheritArmAndActivate,
185 syn_resources,
186 XtNumber(syn_resources),
187 (XtPointer)
NULL
188 },
189
190 {
191 XmInheritSetOverrideCallback,
192 XmInheritMenuProc,
193 XtInheritTranslations,
194 NULL
195 },
196
197 {
198 NULL
199 },
200
201 {
202 0,
203 NULL
204 }
205 };
206
207
208
209
210 WidgetClass xrwsBubbleButtonWidgetClass = (WidgetClass)&xrwsBubbleButtonClassRec;
211
212
213
214
215
216
217
218
219
220 static void
221 class_initialize(
void)
222 {
223 xrwsBubbleButtonClassRec.bubble_button_class.leave_time =
0;
224 }
225
226 static void
227 class_part_initialize(WidgetClass widget_class)
228 {
229 }
230
231 static void
232 initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args)
233 {
234 Widget Shell;
235 Arg arg[
10];
236 int argcnt =
0;
237
238 BubbleButton_Timer(new_w) = (XtIntervalId)
NULL;
239 BubbleButton_DurationTimer(new_w) = (XtIntervalId)
NULL;
240 BubbleButton_Swapped(new_w) = False;
241 BubbleButton_Slider(new_w) =
NULL;
242 Shell = CreatePopupShellWithBestVis(
"BubbleShell",
243 transientShellWidgetClass, new_w, arg, argcnt);
244 XtVaSetValues(Shell,
245 XmNoverrideRedirect, True,
246 NULL);
247 if (BubbleButton_MouseOverString(new_w) !=
NULL)
248 {
249 BubbleButton_MouseOverString(new_w) = XmStringCopy(BubbleButton_MouseOverString(new_w));
250 }
251 if (BubbleButton_BubbleString(new_w) ==
NULL)
252 {
253 XmString xmstring;
254
255 #if XmVERSION >=
2
256 xmstring = XmeGetLocalizedString((
char *)
NULL,
257 new_w,
258 XmNlabelString,
259 XtName(new_w));
260 #else
261 xmstring = _XmOSGetLocalizedString((
char *)
NULL,
262 new_w,
263 XmNlabelString,
264 XtName(new_w));
265 #endif
266 BubbleButton_BubbleString(new_w) = xmstring;
267 }
268 else
269 {
270 BubbleButton_BubbleString(new_w) = XmStringCopy(BubbleButton_BubbleString(new_w));
271 }
272 BubbleButton_Label(new_w) = XmCreateLabel(Shell,
"BubbleLabel",
NULL,
0);
273 XtVaSetValues(BubbleButton_Label(new_w),
274 XmNlabelString, BubbleButton_BubbleString(new_w),
275 XmNforeground, ((XltBubbleButtonWidget)new_w)->core.background_pixel,
276 XmNbackground, ((XltBubbleButtonWidget)new_w)->primitive.foreground,
277 NULL);
278 XtManageChild(BubbleButton_Label(new_w));
279 }
280
281 static void
282 destroy(Widget w)
283 {
284 if (BubbleButton_MouseOverString(w))
285 {
286 XmStringFree(BubbleButton_MouseOverString(w));
287 }
288 if (BubbleButton_Timer(w))
289 {
290 XtRemoveTimeOut(BubbleButton_Timer(w));
291 }
292 if (BubbleButton_DurationTimer(w))
293 {
294 XtRemoveTimeOut(BubbleButton_DurationTimer(w));
295 }
296 }
297
298 static Boolean
299 set_values(Widget old, Widget request, Widget new_w, ArgList args, Cardinal *num_args)
300 {
301 if (BubbleButton_MouseOverString(new_w) != BubbleButton_MouseOverString(old))
302 {
303 XmStringFree(BubbleButton_MouseOverString(old));
304 BubbleButton_MouseOverString(new_w) = XmStringCopy(BubbleButton_MouseOverString(new_w));
305 }
306 if (BubbleButton_BubbleString(new_w) != BubbleButton_BubbleString(old))
307 {
308 XmStringFree(BubbleButton_BubbleString(old));
309 BubbleButton_BubbleString(new_w) = XmStringCopy(BubbleButton_BubbleString(new_w));
310 XtVaSetValues(BubbleButton_Label(new_w),
311 XmNlabelString, BubbleButton_BubbleString(new_w),
312 NULL);
313 }
314 if (XtIsSensitive(old) != XtIsSensitive(new_w))
315 {
316 if (!XtIsSensitive(new_w))
317 {
318 Cardinal num_params =
0;
319
320 LeaveWindow(new_w,
NULL,
NULL, &num_params);
321 }
322 }
323 return (False);
324 }
325
326
327
328
329 extern XmString _XmStringCreateExternal(XmFontList fontlist, _XmString cs);
330
331 static void
332 _XmExportLabelString(Widget w,
int offset, XtArgVal *value)
333 {
334 _XmString str;
335 XmString ret;
336
337 str = *(_XmString *)(((
char *)w) + offset);
338 if (str)
339 {
340 if (XmIsLabel(w))
341 {
342 ret = _XmStringCreateExternal(Lab_Font(w), str);
343 }
344 else
345 {
346 ret =
NULL;
347 }
348 }
349 else
350 {
351 ret =
NULL;
352 }
353
354 *value = (XtArgVal)ret;
355 }
356
357 static void
358 fadeOutFinish(Widget slide, Widget w, XtPointer call_data)
359 {
360 BubbleButton_Slider(w) =
NULL;
361 XtPopdown(XtParent(BubbleButton_Label(w)));
362 }
363
364 static void
365 UnpostIt(Widget w)
366 {
367 BubbleButton_DurationTimer(w) = (XtIntervalId)
NULL;
368 if (BubbleButton_SlidingBubble(w))
369 {
370 BubbleButton_Slider(w) = XtVaCreateWidget(
"Slide", xltSlideContextWidgetClass,
371 XmGetXmDisplay(XtDisplay(w)),
372 XltNslideWidget, XtParent(BubbleButton_Label(w)),
373 XltNslideDestHeight,
1,
374 NULL);
375 XtAddCallback(BubbleButton_Slider(w), XltNslideFinishCallback,
376 (XtCallbackProc)fadeOutFinish, w);
377 }
378 else
379 {
380 XtPopdown(XtParent(BubbleButton_Label(w)));
381 }
382 }
383
384 static void
385 fadeInFinish(Widget slide, Widget w, XtPointer call_data)
386 {
387 BubbleButton_Slider(w) =
NULL;
388 if (BubbleButton_Duration(w) >
0)
389 {
390 BubbleButton_DurationTimer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
391 BubbleButton_Duration(w),
392 (XtTimerCallbackProc)UnpostIt,
393 w);
394 }
395 }
396
397 #define TOOLTIP_EDGE_GUARD 5
398 static void
399 PostIt(Widget w)
400 {
401 int rx, ry, x, y;
402 unsigned int key;
403 Window root, child;
404 Dimension xPos, yPos;
405 XWindowAttributes screenAttr;
406
407 BubbleButton_Timer(w) = (XtIntervalId)
NULL;
408 XQueryPointer(XtDisplay(w),
409 XtWindow(w),
410 &root,
411 &child,
412 &rx, &ry,
413 &x, &y,
414 &key);
415 if (BubbleButton_DurationTimer(w) != (XtIntervalId)
NULL)
416 {
417 XtRemoveTimeOut(BubbleButton_DurationTimer(w));
418 BubbleButton_DurationTimer(w) = (XtIntervalId)
NULL;
419 }
420 {
421 XtWidgetGeometry geo;
422
423 XtQueryGeometry(BubbleButton_Label(w),
NULL, &geo);
424
425 xPos = rx - x + XtWidth(w) /
2 ;
426 yPos = ry - y + XtHeight(w);
427
428 if (BubbleButton_AutoParkBubble(w))
429 {
430 xPos = rx +
3;
431 yPos = ry +
15;
432
433
434 XGetWindowAttributes(XtDisplay(w),
435 RootWindowOfScreen(XtScreen(w)), &screenAttr);
436
437 if (xPos + geo.width >= screenAttr.width -
TOOLTIP_EDGE_GUARD)
438 xPos = screenAttr.width - geo.width -
TOOLTIP_EDGE_GUARD;
439
440 if (yPos + geo.height >= screenAttr.height -
TOOLTIP_EDGE_GUARD)
441 yPos = ry -
15 - geo.height;
442 }
443
444
445 if (BubbleButton_SlidingBubble(w))
446 {
447 int xAdjust, yAdjust;
448
449
450 xAdjust = rx < xPos?
1 : -
1;
451 yAdjust = ry < yPos?
1 : - geo.height/
2;
452
453 XtVaSetValues(XtParent(BubbleButton_Label(w)),
454 XmNx, rx + xAdjust ,
455 XmNy, ry + yAdjust ,
456 XmNheight,
1,
457 XmNwidth,
1 ,
458 NULL);
459 XtPopup(XtParent(BubbleButton_Label(w)), XtGrabNone);
460
461 BubbleButton_Slider(w) = XtVaCreateWidget(
"Slide", xltSlideContextWidgetClass,
462 XmGetXmDisplay(XtDisplay(w)),
463 XltNslideWidget, XtParent(BubbleButton_Label(w)),
464 XltNslideDestX, xPos,
465 XltNslideDestY, yPos,
466 XltNslideDestWidth, geo.width,
467 XltNslideDestHeight, geo.height,
468 NULL);
469 XtAddCallback(BubbleButton_Slider(w), XltNslideFinishCallback, (XtCallbackProc)fadeInFinish, w);
470 }
471 else
472 {
473 XtVaSetValues(XtParent(BubbleButton_Label(w)),
474 XmNx, xPos ,
475 XmNy, yPos ,
476 XmNheight, geo.height,
477 XmNwidth, geo.width ,
478 NULL);
479 XtPopup(XtParent(BubbleButton_Label(w)), XtGrabNone);
480
481 if (BubbleButton_Duration(w) >
0)
482 {
483 BubbleButton_DurationTimer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
484 BubbleButton_Duration(w),
485 (XtTimerCallbackProc)UnpostIt,
486 w);
487 }
488 }
489 }
490 }
491
492 static void
493 SwapLabels(Widget w)
494 {
495 XmString tmp =
NULL;
496
497 if (BubbleButton_MouseOverString(w))
498 {
499 XtVaGetValues(w,
500 XmNlabelString, &tmp,
501 NULL);
502 XtVaSetValues(w,
503 XmNlabelString, BubbleButton_MouseOverString(w),
504 NULL);
505 XmStringFree(BubbleButton_MouseOverString(w));
506 BubbleButton_MouseOverString(w) = tmp;
507 }
508 }
509
510 static void
511 SwapPixmaps(Widget w)
512 {
513 Pixmap tmp;
514
515 if (BubbleButton_MouseOverPixmap(w))
516 {
517 XtVaGetValues(w,
518 XmNlabelPixmap, &tmp,
519 NULL);
520 XtVaSetValues(w,
521 XmNlabelPixmap, BubbleButton_MouseOverPixmap(w),
522 NULL);
523 BubbleButton_MouseOverPixmap(w) = tmp;
524 }
525 }
526
527 static void
528 Swap(Widget w)
529 {
530 if (Lab_IsText(w))
531 {
532 SwapLabels(w);
533 }
534 else
535 {
536 SwapPixmaps(w);
537 }
538 BubbleButton_Swapped(w) = BubbleButton_Swapped(w) ? False : True;
539 }
540
541 static void
542 EnterWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
543 {
544 if (BubbleButton_ShowBubble(w) && !BubbleButton_Timer(w))
545 {
546 unsigned long delay;
547
548 if (event && (event->xcrossing.time - BubbleButtonClass_LeaveTime(w) < BubbleButton_Delay(w)))
549 {
550 delay =
0;
551 }
552 else
553 {
554 delay = BubbleButton_Delay(w);
555 }
556 BubbleButton_Timer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
557 delay,
558 (XtTimerCallbackProc)PostIt,
559 w);
560 }
561 if (!BubbleButton_Swapped(w))
562 {
563 Swap(w);
564 }
565 }
566
567 static void
568 LeaveWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
569 {
570 if (BubbleButton_Timer(w))
571 {
572 XtRemoveTimeOut(BubbleButton_Timer(w));
573 BubbleButton_Timer(w) = (XtIntervalId)
NULL;
574 }
575 else
576 {
577 if (BubbleButton_Slider(w) !=
NULL)
578 {
579 XtDestroyWidget(BubbleButton_Slider(w));
580 BubbleButton_Slider(w) =
NULL;
581 }
582 XtPopdown(XtParent(BubbleButton_Label(w)));
583 if (event)
584 {
585 if (BubbleButton_DurationTimer(w) || BubbleButton_Duration(w) ==
0)
586 {
587 BubbleButtonClass_LeaveTime(w) = event->xcrossing.time;
588 }
589 }
590 }
591 if (BubbleButton_DurationTimer(w))
592 {
593 XtRemoveTimeOut(BubbleButton_DurationTimer(w));
594 BubbleButton_DurationTimer(w) = (XtIntervalId)
NULL;
595 }
596 if (BubbleButton_Swapped(w))
597 {
598 Swap(w);
599 }
600 }
601
602
603
604
605
606 Widget
607 XltCreateBubbleButton(Widget parent,
608 char *name,
609 Arg *arglist,
610 Cardinal argCount)
611 {
612 return XtCreateWidget(name, xrwsBubbleButtonWidgetClass, parent, arglist, argCount);
613 }
614
615