Xft support under OpenMotif 2.3.3 - I've been using this for quite a while on
[nedit.git] / Xlt / BubbleButton.c
blob9034cfad4b2ccf4225ffcea23a4c4ab374e4041a
1 /**
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.
24 **/
26 #ifdef HAVE_CONFIG_H
27 #include "../config.h"
28 #endif
30 #include <unistd.h>
31 #include <stdio.h>
33 #include <X11/StringDefs.h>
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>
44 #include "BubbleButtonP.h"
45 #include "SlideC.h"
47 #include "../util/misc.h"
49 #ifdef WITH_DMALLOC
50 #include <dmalloc.h>
51 #endif
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[] =
122 XltNbubbleString,
123 sizeof(XmString), Offset(BubbleString),
124 _XmExportLabelString, NULL
127 #undef Offset
130 Widget class record
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},
142 /* *INDENT-OFF* */
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,
174 /* tm_table */ 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,
194 /* extension */ NULL
196 /* PushButton Class part */
198 /* extension */ NULL
200 /* BubbleButton Class part */
202 /* leave_time */ 0,
203 /* extension */ NULL
206 /* *INDENT-ON* */
210 WidgetClass xrwsBubbleButtonWidgetClass = (WidgetClass)&xrwsBubbleButtonClassRec;
213 Helper routines
217 Widget methods
220 static void
221 class_initialize(void)
223 xrwsBubbleButtonClassRec.bubble_button_class.leave_time = 0;
226 static void
227 class_part_initialize(WidgetClass widget_class)
231 static void
232 initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args)
234 Widget Shell;
235 Arg arg[10];
236 int argcnt = 0;
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)
249 BubbleButton_MouseOverString(new_w) = XmStringCopy(BubbleButton_MouseOverString(new_w));
251 if (BubbleButton_BubbleString(new_w) == NULL)
253 XmString xmstring;
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;
268 else
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,
277 NULL);
278 XtManageChild(BubbleButton_Label(new_w));
281 static void
282 destroy(Widget 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));
298 static Boolean
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),
312 NULL);
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);
323 return (False);
327 * Short-term solution. Doesn't belong here. See SF bug #923924.
329 extern XmString _XmStringCreateExternal(XmFontList fontlist, _XmString cs);
331 static void
332 _XmExportLabelString(Widget w, int offset, XtArgVal *value)
334 _XmString str;
335 XmString ret;
337 str = *(_XmString *)(((char *)w) + offset);
338 if (str)
340 if (XmIsLabel(w))
342 ret = _XmStringCreateExternal(Lab_Font(w), str);
344 else
346 ret = NULL;
349 else
351 ret = NULL;
354 *value = (XtArgVal)ret;
357 static void
358 fadeOutFinish(Widget slide, Widget w, XtPointer call_data)
360 BubbleButton_Slider(w) = NULL;
361 XtPopdown(XtParent(BubbleButton_Label(w)));
364 static void
365 UnpostIt(Widget 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,
374 NULL);
375 XtAddCallback(BubbleButton_Slider(w), XltNslideFinishCallback,
376 (XtCallbackProc)fadeOutFinish, w);
378 else
380 XtPopdown(XtParent(BubbleButton_Label(w)));
384 static void
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
398 static void
399 PostIt(Widget w)
401 int rx, ry, x, y;
402 unsigned int key;
403 Window root, child;
404 Dimension xPos, yPos;
405 XWindowAttributes screenAttr;
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)
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))
430 xPos = rx + 3;
431 yPos = ry + 15;
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)*/,
456 XmNheight, 1,
457 XmNwidth, 1 /*geo.width*/,
458 NULL);
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,
468 NULL);
469 XtAddCallback(BubbleButton_Slider(w), XltNslideFinishCallback, (XtCallbackProc)fadeInFinish, w);
471 else
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*/,
478 NULL);
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,
492 static void
493 SwapLabels(Widget w)
495 XmString tmp = NULL;
497 if (BubbleButton_MouseOverString(w))
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;
510 static void
511 SwapPixmaps(Widget w)
513 Pixmap tmp;
515 if (BubbleButton_MouseOverPixmap(w))
517 XtVaGetValues(w,
518 XmNlabelPixmap, &tmp,
519 NULL);
520 XtVaSetValues(w,
521 XmNlabelPixmap, BubbleButton_MouseOverPixmap(w),
522 NULL);
523 BubbleButton_MouseOverPixmap(w) = tmp;
527 static void
528 Swap(Widget w)
530 if (Lab_IsText(w))
532 SwapLabels(w);
534 else
536 SwapPixmaps(w);
538 BubbleButton_Swapped(w) = BubbleButton_Swapped(w) ? False : True;
541 static void
542 EnterWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
544 if (BubbleButton_ShowBubble(w) && !BubbleButton_Timer(w))
546 unsigned long delay;
548 if (event && (event->xcrossing.time - BubbleButtonClass_LeaveTime(w) < BubbleButton_Delay(w)))
550 delay = 0;
552 else
554 delay = BubbleButton_Delay(w);
556 BubbleButton_Timer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
557 delay,
558 (XtTimerCallbackProc)PostIt,
561 if (!BubbleButton_Swapped(w))
563 Swap(w);
567 static void
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;
575 else
577 if (BubbleButton_Slider(w) != NULL)
579 XtDestroyWidget(BubbleButton_Slider(w));
580 BubbleButton_Slider(w) = NULL;
582 XtPopdown(XtParent(BubbleButton_Label(w)));
583 if (event)
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))
598 Swap(w);
603 Public functions
606 Widget
607 XltCreateBubbleButton(Widget parent,
608 char *name,
609 Arg *arglist,
610 Cardinal argCount)
612 return XtCreateWidget(name, xrwsBubbleButtonWidgetClass, parent, arglist, argCount);