#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include <unistd.h>
#include <stdio.h>
#include <X11/StringDefs.h>
#include <Xm/XmosP.h>
#include <Xm/MessageB.h>
#include <Xm/Form.h>
#include <Xm/TextF.h>
#include <Xm/LabelP.h>
#include <Xm/DialogS.h>
#include <Xm/MenuShell.h>
#include <Xm/Display.h>
#include "BubbleButtonP.h"
#include "SlideC.h"
#include "../util/misc.h"
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif
static const char rcsid[] =
"$Id: BubbleButton.c,v 1.9 2005/12/01 14:31:43 tringali Exp $";
static void class_initialize(
void);
static void class_part_initialize(WidgetClass widget_class);
static void initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args);
static void destroy(Widget w);
static Boolean set_values(Widget old, Widget request, Widget new_w, ArgList args, Cardinal *num_args);
static void _XmExportLabelString(Widget w,
int offset, XtArgVal *value);
#define Offset(field) XtOffsetOf(XltBubbleButtonRec, bubble_button.field)
static XtResource resources[] =
{
{
XltNbubbleString, XltCBubbleString, XmRXmString,
sizeof(XmString), Offset(BubbleString),
XmRImmediate, (XtPointer)
NULL
},
{
XltNshowBubble, XltCShowBubble, XmRBoolean,
sizeof(Boolean), Offset(show_bubble),
XmRImmediate, (XtPointer)True
},
{
XltNdelay, XltCDelay, XtRInt,
sizeof(
int), Offset(Delay),
XtRImmediate, (XtPointer)
1000
},
{
XltNmouseOverString, XltCMouseOverString, XmRXmString,
sizeof(XmString), Offset(MouseOverString),
XtRImmediate, (XtPointer)
NULL
},
{
XltNmouseOverPixmap, XltCMouseOverPixmap, XmRPrimForegroundPixmap,
sizeof(Pixmap), Offset(MouseOverPixmap),
XtRImmediate, (XtPointer)None
},
{
XltNbubbleDuration, XltCBubbleDuration, XtRInt,
sizeof(
int), Offset(Duration),
XtRImmediate, (XtPointer)
0
},
{
XltNslidingBubble, XltCslidingBubble, XmRBoolean,
sizeof(Boolean), Offset(slidingBubble),
XmRImmediate, (XtPointer)True
},
{
XltNautoParkBubble, XltCautoParkBubble, XmRBoolean,
sizeof(Boolean), Offset(autoParkBubble),
XmRImmediate, (XtPointer)False
},
};
static XmSyntheticResource syn_resources[] =
{
{
XltNbubbleString,
sizeof(XmString), Offset(BubbleString),
_XmExportLabelString,
NULL
}
};
#undef Offset
static void EnterWindow(Widget w, XEvent *event, String *params, Cardinal *num_params);
static void LeaveWindow(Widget w, XEvent *event, String *params, Cardinal *num_params);
static XtActionsRec actions[] =
{
{
"Enter", EnterWindow},
{
"Leave", LeaveWindow},
};
XltBubbleButtonClassRec xrwsBubbleButtonClassRec = {
{
(WidgetClass) &xmPushButtonClassRec,
"XltBubbleButton",
sizeof(XltBubbleButtonRec),
class_initialize,
class_part_initialize,
False,
initialize,
NULL,
XtInheritRealize,
actions,
XtNumber(actions),
resources,
XtNumber(resources),
NULLQUARK,
True,
XtExposeCompressMaximal,
True,
False,
destroy,
XtInheritResize,
XtInheritExpose,
set_values,
NULL,
XtInheritSetValuesAlmost,
NULL,
NULL,
XtVersion,
NULL,
NULL,
XtInheritQueryGeometry,
NULL,
(XtPointer)
NULL
},
{
XmInheritBorderHighlight,
XmInheritBorderUnhighlight,
XtInheritTranslations,
XmInheritArmAndActivate,
syn_resources,
XtNumber(syn_resources),
(XtPointer)
NULL
},
{
XmInheritSetOverrideCallback,
XmInheritMenuProc,
XtInheritTranslations,
NULL
},
{
NULL
},
{
0,
NULL
}
};
WidgetClass xrwsBubbleButtonWidgetClass = (WidgetClass)&xrwsBubbleButtonClassRec;
static void
class_initialize(
void)
{
xrwsBubbleButtonClassRec.bubble_button_class.leave_time =
0;
}
static void
class_part_initialize(WidgetClass widget_class)
{
}
static void
initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args)
{
Widget Shell;
Arg arg[
10];
int argcnt =
0;
BubbleButton_Timer(new_w) = (XtIntervalId)
NULL;
BubbleButton_DurationTimer(new_w) = (XtIntervalId)
NULL;
BubbleButton_Swapped(new_w) = False;
BubbleButton_Slider(new_w) =
NULL;
Shell = CreatePopupShellWithBestVis(
"BubbleShell",
transientShellWidgetClass, new_w, arg, argcnt);
XtVaSetValues(Shell,
XmNoverrideRedirect, True,
NULL);
if (BubbleButton_MouseOverString(new_w) !=
NULL)
{
BubbleButton_MouseOverString(new_w) = XmStringCopy(BubbleButton_MouseOverString(new_w));
}
if (BubbleButton_BubbleString(new_w) ==
NULL)
{
XmString xmstring;
#if XmVERSION >=
2
xmstring = XmeGetLocalizedString((
char *)
NULL,
new_w,
XmNlabelString,
XtName(new_w));
#else
xmstring = _XmOSGetLocalizedString((
char *)
NULL,
new_w,
XmNlabelString,
XtName(new_w));
#endif
BubbleButton_BubbleString(new_w) = xmstring;
}
else
{
BubbleButton_BubbleString(new_w) = XmStringCopy(BubbleButton_BubbleString(new_w));
}
BubbleButton_Label(new_w) = XmCreateLabel(Shell,
"BubbleLabel",
NULL,
0);
XtVaSetValues(BubbleButton_Label(new_w),
XmNlabelString, BubbleButton_BubbleString(new_w),
XmNforeground, ((XltBubbleButtonWidget)new_w)->core.background_pixel,
XmNbackground, ((XltBubbleButtonWidget)new_w)->primitive.foreground,
NULL);
XtManageChild(BubbleButton_Label(new_w));
}
static void
destroy(Widget w)
{
if (BubbleButton_MouseOverString(w))
{
XmStringFree(BubbleButton_MouseOverString(w));
}
if (BubbleButton_Timer(w))
{
XtRemoveTimeOut(BubbleButton_Timer(w));
}
if (BubbleButton_DurationTimer(w))
{
XtRemoveTimeOut(BubbleButton_DurationTimer(w));
}
}
static Boolean
set_values(Widget old, Widget request, Widget new_w, ArgList args, Cardinal *num_args)
{
if (BubbleButton_MouseOverString(new_w) != BubbleButton_MouseOverString(old))
{
XmStringFree(BubbleButton_MouseOverString(old));
BubbleButton_MouseOverString(new_w) = XmStringCopy(BubbleButton_MouseOverString(new_w));
}
if (BubbleButton_BubbleString(new_w) != BubbleButton_BubbleString(old))
{
XmStringFree(BubbleButton_BubbleString(old));
BubbleButton_BubbleString(new_w) = XmStringCopy(BubbleButton_BubbleString(new_w));
XtVaSetValues(BubbleButton_Label(new_w),
XmNlabelString, BubbleButton_BubbleString(new_w),
NULL);
}
if (XtIsSensitive(old) != XtIsSensitive(new_w))
{
if (!XtIsSensitive(new_w))
{
Cardinal num_params =
0;
LeaveWindow(new_w,
NULL,
NULL, &num_params);
}
}
return (False);
}
extern XmString _XmStringCreateExternal(XmFontList fontlist, _XmString cs);
static void
_XmExportLabelString(Widget w,
int offset, XtArgVal *value)
{
_XmString str;
XmString ret;
str = *(_XmString *)(((
char *)w) + offset);
if (str)
{
if (XmIsLabel(w))
{
ret = _XmStringCreateExternal(Lab_Font(w), str);
}
else
{
ret =
NULL;
}
}
else
{
ret =
NULL;
}
*value = (XtArgVal)ret;
}
static void
fadeOutFinish(Widget slide, Widget w, XtPointer call_data)
{
BubbleButton_Slider(w) =
NULL;
XtPopdown(XtParent(BubbleButton_Label(w)));
}
static void
UnpostIt(Widget w)
{
BubbleButton_DurationTimer(w) = (XtIntervalId)
NULL;
if (BubbleButton_SlidingBubble(w))
{
BubbleButton_Slider(w) = XtVaCreateWidget(
"Slide", xltSlideContextWidgetClass,
XmGetXmDisplay(XtDisplay(w)),
XltNslideWidget, XtParent(BubbleButton_Label(w)),
XltNslideDestHeight,
1,
NULL);
XtAddCallback(BubbleButton_Slider(w), XltNslideFinishCallback,
(XtCallbackProc)fadeOutFinish, w);
}
else
{
XtPopdown(XtParent(BubbleButton_Label(w)));
}
}
static void
fadeInFinish(Widget slide, Widget w, XtPointer call_data)
{
BubbleButton_Slider(w) =
NULL;
if (BubbleButton_Duration(w) >
0)
{
BubbleButton_DurationTimer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
BubbleButton_Duration(w),
(XtTimerCallbackProc)UnpostIt,
w);
}
}
#define TOOLTIP_EDGE_GUARD 5
static void
PostIt(Widget w)
{
int rx, ry, x, y;
unsigned int key;
Window root, child;
Dimension xPos, yPos;
XWindowAttributes screenAttr;
BubbleButton_Timer(w) = (XtIntervalId)
NULL;
XQueryPointer(XtDisplay(w),
XtWindow(w),
&root,
&child,
&rx, &ry,
&x, &y,
&key);
if (BubbleButton_DurationTimer(w) != (XtIntervalId)
NULL)
{
XtRemoveTimeOut(BubbleButton_DurationTimer(w));
BubbleButton_DurationTimer(w) = (XtIntervalId)
NULL;
}
{
XtWidgetGeometry geo;
XtQueryGeometry(BubbleButton_Label(w),
NULL, &geo);
xPos = rx - x + XtWidth(w) /
2 ;
yPos = ry - y + XtHeight(w);
if (BubbleButton_AutoParkBubble(w))
{
xPos = rx +
3;
yPos = ry +
15;
XGetWindowAttributes(XtDisplay(w),
RootWindowOfScreen(XtScreen(w)), &screenAttr);
if (xPos + geo.width >= screenAttr.width -
TOOLTIP_EDGE_GUARD)
xPos = screenAttr.width - geo.width -
TOOLTIP_EDGE_GUARD;
if (yPos + geo.height >= screenAttr.height -
TOOLTIP_EDGE_GUARD)
yPos = ry -
15 - geo.height;
}
if (BubbleButton_SlidingBubble(w))
{
int xAdjust, yAdjust;
xAdjust = rx < xPos?
1 : -
1;
yAdjust = ry < yPos?
1 : - geo.height/
2;
XtVaSetValues(XtParent(BubbleButton_Label(w)),
XmNx, rx + xAdjust ,
XmNy, ry + yAdjust ,
XmNheight,
1,
XmNwidth,
1 ,
NULL);
XtPopup(XtParent(BubbleButton_Label(w)), XtGrabNone);
BubbleButton_Slider(w) = XtVaCreateWidget(
"Slide", xltSlideContextWidgetClass,
XmGetXmDisplay(XtDisplay(w)),
XltNslideWidget, XtParent(BubbleButton_Label(w)),
XltNslideDestX, xPos,
XltNslideDestY, yPos,
XltNslideDestWidth, geo.width,
XltNslideDestHeight, geo.height,
NULL);
XtAddCallback(BubbleButton_Slider(w), XltNslideFinishCallback, (XtCallbackProc)fadeInFinish, w);
}
else
{
XtVaSetValues(XtParent(BubbleButton_Label(w)),
XmNx, xPos ,
XmNy, yPos ,
XmNheight, geo.height,
XmNwidth, geo.width ,
NULL);
XtPopup(XtParent(BubbleButton_Label(w)), XtGrabNone);
if (BubbleButton_Duration(w) >
0)
{
BubbleButton_DurationTimer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
BubbleButton_Duration(w),
(XtTimerCallbackProc)UnpostIt,
w);
}
}
}
}
static void
SwapLabels(Widget w)
{
XmString tmp =
NULL;
if (BubbleButton_MouseOverString(w))
{
XtVaGetValues(w,
XmNlabelString, &tmp,
NULL);
XtVaSetValues(w,
XmNlabelString, BubbleButton_MouseOverString(w),
NULL);
XmStringFree(BubbleButton_MouseOverString(w));
BubbleButton_MouseOverString(w) = tmp;
}
}
static void
SwapPixmaps(Widget w)
{
Pixmap tmp;
if (BubbleButton_MouseOverPixmap(w))
{
XtVaGetValues(w,
XmNlabelPixmap, &tmp,
NULL);
XtVaSetValues(w,
XmNlabelPixmap, BubbleButton_MouseOverPixmap(w),
NULL);
BubbleButton_MouseOverPixmap(w) = tmp;
}
}
static void
Swap(Widget w)
{
if (Lab_IsText(w))
{
SwapLabels(w);
}
else
{
SwapPixmaps(w);
}
BubbleButton_Swapped(w) = BubbleButton_Swapped(w) ? False : True;
}
static void
EnterWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
if (BubbleButton_ShowBubble(w) && !BubbleButton_Timer(w))
{
unsigned long delay;
if (event && (event->xcrossing.time - BubbleButtonClass_LeaveTime(w) < BubbleButton_Delay(w)))
{
delay =
0;
}
else
{
delay = BubbleButton_Delay(w);
}
BubbleButton_Timer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
delay,
(XtTimerCallbackProc)PostIt,
w);
}
if (!BubbleButton_Swapped(w))
{
Swap(w);
}
}
static void
LeaveWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
if (BubbleButton_Timer(w))
{
XtRemoveTimeOut(BubbleButton_Timer(w));
BubbleButton_Timer(w) = (XtIntervalId)
NULL;
}
else
{
if (BubbleButton_Slider(w) !=
NULL)
{
XtDestroyWidget(BubbleButton_Slider(w));
BubbleButton_Slider(w) =
NULL;
}
XtPopdown(XtParent(BubbleButton_Label(w)));
if (event)
{
if (BubbleButton_DurationTimer(w) || BubbleButton_Duration(w) ==
0)
{
BubbleButtonClass_LeaveTime(w) = event->xcrossing.time;
}
}
}
if (BubbleButton_DurationTimer(w))
{
XtRemoveTimeOut(BubbleButton_DurationTimer(w));
BubbleButton_DurationTimer(w) = (XtIntervalId)
NULL;
}
if (BubbleButton_Swapped(w))
{
Swap(w);
}
}
Widget
XltCreateBubbleButton(Widget parent,
char *name,
Arg *arglist,
Cardinal argCount)
{
return XtCreateWidget(name, xrwsBubbleButtonWidgetClass, parent, arglist, argCount);
}