3 * $Id: BubbleButton.c,v 1.9 2005/12/01 14:31:43 tringali Exp $
5 * Copyright (C) 1996 Free Software Foundation, Inc.
6 * Copyright © 1999-2001 by the LessTif developers.
8 * This file is part of the GNU LessTif Extension Library.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the Free
22 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "../config.h"
33 #include <X11/StringDefs.h>
36 #include <Xm/MessageB.h>
39 #include <Xm/LabelP.h>
40 #include <Xm/DialogS.h>
41 #include <Xm/MenuShell.h>
42 #include <Xm/Display.h>
44 #include "BubbleButtonP.h"
47 #include "../util/misc.h"
53 static const char rcsid
[] = "$Id: BubbleButton.c,v 1.9 2005/12/01 14:31:43 tringali Exp $";
56 Widget methods, forward declarations
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
);
67 Helper functions, forward declarations
71 Widget default resources
74 #define Offset(field) XtOffsetOf(XltBubbleButtonRec, bubble_button.field)
75 static XtResource resources
[] =
78 XltNbubbleString
, XltCBubbleString
, XmRXmString
,
79 sizeof(XmString
), Offset(BubbleString
),
80 XmRImmediate
, (XtPointer
)NULL
83 XltNshowBubble
, XltCShowBubble
, XmRBoolean
,
84 sizeof(Boolean
), Offset(show_bubble
),
85 XmRImmediate
, (XtPointer
)True
88 XltNdelay
, XltCDelay
, XtRInt
,
89 sizeof(int), Offset(Delay
),
90 XtRImmediate
, (XtPointer
)1000
93 XltNmouseOverString
, XltCMouseOverString
, XmRXmString
,
94 sizeof(XmString
), Offset(MouseOverString
),
95 XtRImmediate
, (XtPointer
)NULL
98 XltNmouseOverPixmap
, XltCMouseOverPixmap
, XmRPrimForegroundPixmap
,
99 sizeof(Pixmap
), Offset(MouseOverPixmap
),
100 XtRImmediate
, (XtPointer
)None
103 XltNbubbleDuration
, XltCBubbleDuration
, XtRInt
,
104 sizeof(int), Offset(Duration
),
105 XtRImmediate
, (XtPointer
)0
108 XltNslidingBubble
, XltCslidingBubble
, XmRBoolean
,
109 sizeof(Boolean
), Offset(slidingBubble
),
110 XmRImmediate
, (XtPointer
)True
113 XltNautoParkBubble
, XltCautoParkBubble
, XmRBoolean
,
114 sizeof(Boolean
), Offset(autoParkBubble
),
115 XmRImmediate
, (XtPointer
)False
119 static XmSyntheticResource syn_resources
[] =
123 sizeof(XmString
), Offset(BubbleString
),
124 _XmExportLabelString
, NULL
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
);
136 static XtActionsRec actions
[] =
138 {"Enter", EnterWindow
},
139 {"Leave", LeaveWindow
},
143 XltBubbleButtonClassRec xrwsBubbleButtonClassRec
= {
144 /* Core class part */
146 /* superclass */ (WidgetClass
) &xmPushButtonClassRec
,
147 /* class_name */ "XltBubbleButton",
148 /* widget_size */ sizeof(XltBubbleButtonRec
),
149 /* class_initialize */ class_initialize
,
150 /* class_part_initialize */ class_part_initialize
,
151 /* class_inited */ False
,
152 /* initialize */ initialize
,
153 /* initialize_hook */ NULL
,
154 /* realize */ XtInheritRealize
,
155 /* actions */ actions
,
156 /* num_actions */ XtNumber(actions
),
157 /* resources */ resources
,
158 /* num_resources */ XtNumber(resources
),
159 /* xrm_class */ NULLQUARK
,
160 /* compress_motion */ True
,
161 /* compress_exposure */ XtExposeCompressMaximal
,
162 /* compress_enterleave */ True
,
163 /* visible_interest */ False
,
164 /* destroy */ destroy
,
165 /* resize */ XtInheritResize
,
166 /* expose */ XtInheritExpose
,
167 /* set_values */ set_values
,
168 /* set_values_hook */ NULL
,
169 /* set_values_almost */ XtInheritSetValuesAlmost
,
170 /* get_values_hook */ NULL
,
171 /* accept_focus */ NULL
,
172 /* version */ XtVersion
,
173 /* callback offsets */ NULL
,
175 /* query_geometry */ XtInheritQueryGeometry
,
176 /* display_accelerator */ NULL
,
177 /* extension */ (XtPointer
)NULL
179 /* Primitive Class part */
181 /* border_highlight */ XmInheritBorderHighlight
,
182 /* border_unhighlight */ XmInheritBorderUnhighlight
,
183 /* translations */ XtInheritTranslations
,
184 /* arm_and_activate_proc */ XmInheritArmAndActivate
,
185 /* synthetic resources */ syn_resources
,
186 /* num syn res */ XtNumber(syn_resources
),
187 /* extension */ (XtPointer
)NULL
189 /* Label Class part */
191 /* setOverrideCallback */ XmInheritSetOverrideCallback
,
192 /* menuProcs */ XmInheritMenuProc
,
193 /* translations */ XtInheritTranslations
,
196 /* PushButton Class part */
200 /* BubbleButton Class part */
210 WidgetClass xrwsBubbleButtonWidgetClass
= (WidgetClass
)&xrwsBubbleButtonClassRec
;
221 class_initialize(void)
223 xrwsBubbleButtonClassRec
.bubble_button_class
.leave_time
= 0;
227 class_part_initialize(WidgetClass widget_class
)
232 initialize(Widget request
, Widget new_w
, ArgList args
, Cardinal
*num_args
)
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
);
245 XmNoverrideRedirect
, True
,
247 if (BubbleButton_MouseOverString(new_w
) != NULL
)
249 BubbleButton_MouseOverString(new_w
) = XmStringCopy(BubbleButton_MouseOverString(new_w
));
251 if (BubbleButton_BubbleString(new_w
) == NULL
)
256 xmstring
= XmeGetLocalizedString((char *)NULL
,
261 xmstring
= _XmOSGetLocalizedString((char *)NULL
,
266 BubbleButton_BubbleString(new_w
) = xmstring
;
270 BubbleButton_BubbleString(new_w
) = XmStringCopy(BubbleButton_BubbleString(new_w
));
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
,
278 XtManageChild(BubbleButton_Label(new_w
));
284 if (BubbleButton_MouseOverString(w
))
286 XmStringFree(BubbleButton_MouseOverString(w
));
288 if (BubbleButton_Timer(w
))
290 XtRemoveTimeOut(BubbleButton_Timer(w
));
292 if (BubbleButton_DurationTimer(w
))
294 XtRemoveTimeOut(BubbleButton_DurationTimer(w
));
299 set_values(Widget old
, Widget request
, Widget new_w
, ArgList args
, Cardinal
*num_args
)
301 if (BubbleButton_MouseOverString(new_w
) != BubbleButton_MouseOverString(old
))
303 XmStringFree(BubbleButton_MouseOverString(old
));
304 BubbleButton_MouseOverString(new_w
) = XmStringCopy(BubbleButton_MouseOverString(new_w
));
306 if (BubbleButton_BubbleString(new_w
) != BubbleButton_BubbleString(old
))
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
),
314 if (XtIsSensitive(old
) != XtIsSensitive(new_w
))
316 if (!XtIsSensitive(new_w
))
318 Cardinal num_params
= 0;
320 LeaveWindow(new_w
, NULL
, NULL
, &num_params
);
327 * Short-term solution. Doesn't belong here. See SF bug #923924.
329 extern XmString
_XmStringCreateExternal(XmFontList fontlist
, _XmString cs
);
332 _XmExportLabelString(Widget w
, int offset
, XtArgVal
*value
)
337 str
= *(_XmString
*)(((char *)w
) + offset
);
342 ret
= _XmStringCreateExternal(Lab_Font(w
), str
);
354 *value
= (XtArgVal
)ret
;
358 fadeOutFinish(Widget slide
, Widget w
, XtPointer call_data
)
360 BubbleButton_Slider(w
) = NULL
;
361 XtPopdown(XtParent(BubbleButton_Label(w
)));
367 BubbleButton_DurationTimer(w
) = (XtIntervalId
)NULL
;
368 if (BubbleButton_SlidingBubble(w
))
370 BubbleButton_Slider(w
) = XtVaCreateWidget("Slide", xltSlideContextWidgetClass
,
371 XmGetXmDisplay(XtDisplay(w
)),
372 XltNslideWidget
, XtParent(BubbleButton_Label(w
)),
373 XltNslideDestHeight
, 1,
375 XtAddCallback(BubbleButton_Slider(w
), XltNslideFinishCallback
,
376 (XtCallbackProc
)fadeOutFinish
, w
);
380 XtPopdown(XtParent(BubbleButton_Label(w
)));
385 fadeInFinish(Widget slide
, Widget w
, XtPointer call_data
)
387 BubbleButton_Slider(w
) = NULL
;
388 if (BubbleButton_Duration(w
) > 0)
390 BubbleButton_DurationTimer(w
) = XtAppAddTimeOut(XtWidgetToApplicationContext(w
),
391 BubbleButton_Duration(w
),
392 (XtTimerCallbackProc
)UnpostIt
,
397 #define TOOLTIP_EDGE_GUARD 5
404 Dimension xPos
, yPos
;
405 XWindowAttributes screenAttr
;
407 BubbleButton_Timer(w
) = (XtIntervalId
)NULL
;
408 XQueryPointer(XtDisplay(w
),
415 if (BubbleButton_DurationTimer(w
) != (XtIntervalId
)NULL
)
417 XtRemoveTimeOut(BubbleButton_DurationTimer(w
));
418 BubbleButton_DurationTimer(w
) = (XtIntervalId
)NULL
;
421 XtWidgetGeometry geo
;
423 XtQueryGeometry(BubbleButton_Label(w
), NULL
, &geo
);
425 xPos
= rx
- x
+ XtWidth(w
) / 2 ;
426 yPos
= ry
- y
+ XtHeight(w
);
428 if (BubbleButton_AutoParkBubble(w
))
433 /* keep tooltip within screen */
434 XGetWindowAttributes(XtDisplay(w
),
435 RootWindowOfScreen(XtScreen(w
)), &screenAttr
);
437 if (xPos
+ geo
.width
>= screenAttr
.width
- TOOLTIP_EDGE_GUARD
)
438 xPos
= screenAttr
.width
- geo
.width
- TOOLTIP_EDGE_GUARD
;
440 if (yPos
+ geo
.height
>= screenAttr
.height
- TOOLTIP_EDGE_GUARD
)
441 yPos
= ry
- 15 - geo
.height
;
445 if (BubbleButton_SlidingBubble(w
))
447 int xAdjust
, yAdjust
;
449 /* FIXME: slider must avoid pointer */
450 xAdjust
= rx
< xPos
? 1 : -1;
451 yAdjust
= ry
< yPos
? 1 : - geo
.height
/2;
453 XtVaSetValues(XtParent(BubbleButton_Label(w
)),
454 XmNx
, rx
+ xAdjust
/*- x + XtWidth(w) / 2*/,
455 XmNy
, ry
+ yAdjust
/*- y + XtHeight(w)*/,
457 XmNwidth
, 1 /*geo.width*/,
459 XtPopup(XtParent(BubbleButton_Label(w
)), XtGrabNone
);
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
,
469 XtAddCallback(BubbleButton_Slider(w
), XltNslideFinishCallback
, (XtCallbackProc
)fadeInFinish
, w
);
473 XtVaSetValues(XtParent(BubbleButton_Label(w
)),
474 XmNx
, xPos
/*- x + XtWidth(w) / 2*/,
475 XmNy
, yPos
/*- y + XtHeight(w)*/,
476 XmNheight
, geo
.height
,
477 XmNwidth
, geo
.width
/*geo.width*/,
479 XtPopup(XtParent(BubbleButton_Label(w
)), XtGrabNone
);
481 if (BubbleButton_Duration(w
) > 0)
483 BubbleButton_DurationTimer(w
) = XtAppAddTimeOut(XtWidgetToApplicationContext(w
),
484 BubbleButton_Duration(w
),
485 (XtTimerCallbackProc
)UnpostIt
,
497 if (BubbleButton_MouseOverString(w
))
500 XmNlabelString
, &tmp
,
503 XmNlabelString
, BubbleButton_MouseOverString(w
),
505 XmStringFree(BubbleButton_MouseOverString(w
));
506 BubbleButton_MouseOverString(w
) = tmp
;
511 SwapPixmaps(Widget w
)
515 if (BubbleButton_MouseOverPixmap(w
))
518 XmNlabelPixmap
, &tmp
,
521 XmNlabelPixmap
, BubbleButton_MouseOverPixmap(w
),
523 BubbleButton_MouseOverPixmap(w
) = tmp
;
538 BubbleButton_Swapped(w
) = BubbleButton_Swapped(w
) ? False
: True
;
542 EnterWindow(Widget w
, XEvent
*event
, String
*params
, Cardinal
*num_params
)
544 if (BubbleButton_ShowBubble(w
) && !BubbleButton_Timer(w
))
548 if (event
&& (event
->xcrossing
.time
- BubbleButtonClass_LeaveTime(w
) < BubbleButton_Delay(w
)))
554 delay
= BubbleButton_Delay(w
);
556 BubbleButton_Timer(w
) = XtAppAddTimeOut(XtWidgetToApplicationContext(w
),
558 (XtTimerCallbackProc
)PostIt
,
561 if (!BubbleButton_Swapped(w
))
568 LeaveWindow(Widget w
, XEvent
*event
, String
*params
, Cardinal
*num_params
)
570 if (BubbleButton_Timer(w
))
572 XtRemoveTimeOut(BubbleButton_Timer(w
));
573 BubbleButton_Timer(w
) = (XtIntervalId
)NULL
;
577 if (BubbleButton_Slider(w
) != NULL
)
579 XtDestroyWidget(BubbleButton_Slider(w
));
580 BubbleButton_Slider(w
) = NULL
;
582 XtPopdown(XtParent(BubbleButton_Label(w
)));
585 if (BubbleButton_DurationTimer(w
) || BubbleButton_Duration(w
) == 0)
587 BubbleButtonClass_LeaveTime(w
) = event
->xcrossing
.time
;
591 if (BubbleButton_DurationTimer(w
))
593 XtRemoveTimeOut(BubbleButton_DurationTimer(w
));
594 BubbleButton_DurationTimer(w
) = (XtIntervalId
)NULL
;
596 if (BubbleButton_Swapped(w
))
607 XltCreateBubbleButton(Widget parent
,
612 return XtCreateWidget(name
, xrwsBubbleButtonWidgetClass
, parent
, arglist
, argCount
);