/*
* Motif
*
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <Xm/LabelP.h>
#include <Xm/VendorSEP.h>
#include <Xm/GadgetP.h>
#include <Xm/SlideC.h>
#include <Xm/TraitP.h>
#include <Xm/ToolTipCT.h>
#include <Xm/ToolTipT.h>
#include "BaseClassI.h"
#include "ToolTipI.h"
#include "XmI.h"
#ifdef FIX_1388
static void ToolTipLabelDestroyCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
XmToolTipConfigTrait ttcp;
ttcp = (XmToolTipConfigTrait) XmeTraitGet(w, XmQTtoolTipConfig);
if (ttcp != NULL)
if (ttcp->label != NULL) {
Widget shell = XtParent(ttcp->label);
XtDestroyWidget(ttcp->label);
ttcp->label = NULL;
XtDestroyWidget(shell);
}
}
#endif /* FIX_1388 */
static XmToolTipConfigTrait
ToolTipGetData (Widget w)
{
Widget top = w;
XmToolTipConfigTrait ttp;
while (XtParent (top))
{
top = XtParent (top);
}
ttp = (XmToolTipConfigTrait) XmeTraitGet (top, XmQTtoolTipConfig);
if (ttp != NULL && ttp->label == NULL && !top->core.being_destroyed)
{
Widget shell;
shell = XtVaCreateWidget ("TipShell",
transientShellWidgetClass, top,
XmNoverrideRedirect, True, NULL);
ttp->label = XmCreateLabel (shell, "TipLabel", NULL, 0);
XtManageChild (ttp->label);
#ifdef FIX_1388
XtAddCallback(top, XmNdestroyCallback, (XtCallbackProc) ToolTipLabelDestroyCallback, (XtPointer) NULL);
#endif
}
return ttp;
}
static void
ToolTipUnpost (XtPointer client_data,
XtIntervalId * id)
{
XmToolTipConfigTrait ttp;
ttp = (XmToolTipConfigTrait) client_data;
if (ttp->duration_timer)
{
if (!id || (id && (*id != ttp->duration_timer)))
{
XtRemoveTimeOut (ttp->duration_timer);
}
ttp->duration_timer = (XtIntervalId) NULL;
}
if (ttp->slider)
{
XtDestroyWidget (ttp->slider);
ttp->slider = NULL;
}
if (ttp->label != NULL && !XtParent (ttp->label)->core.being_destroyed)
{
XtPopdown (XtParent (ttp->label));
}
}
static void
ToolTipPostFinish (Widget slide,
XtPointer client_data,
XtPointer call_data)
{
XmToolTipConfigTrait ttp;
ttp = (XmToolTipConfigTrait) client_data;
if (ttp == NULL)
{
XtWarning ("ToolTipPostFinish() - ttp==NULL");
return;
}
ttp->slider = NULL;
if (ttp->post_duration > 0)
{
ttp->duration_timer =
XtAppAddTimeOut (XtWidgetToApplicationContext (ttp->label),
(unsigned long) ttp->post_duration,
(XtTimerCallbackProc) ToolTipUnpost, client_data);
}
}
static void
ToolTipPost (XtPointer client_data,
XtIntervalId * id)
{
Widget w = (Widget) client_data;
int rx,
ry,
x,
y;
unsigned int key;
Window root,
child;
XtWidgetGeometry geo;
Position destX,
destY;
XmToolTipConfigTrait ttp; /* ToolTip pointer */
ttp = ToolTipGetData (w);
if (ttp == NULL)
{
XtWarning ("ToolTipGetData() returned NULL in ToolTipPost()");
return;
}
ttp->timer = (XtIntervalId) NULL;
XQueryPointer (XtDisplay (w),
XtWindow (w), &root, &child, &rx, &ry, &x, &y, &key);
if (ttp->duration_timer != (XtIntervalId) NULL)
{
XtRemoveTimeOut (ttp->duration_timer);
ttp->duration_timer = (XtIntervalId) NULL;
}
if (XmIsPrimitive(w) || XmIsGadget(w))
{
XtVaSetValues (ttp->label,
XmNlabelString,
XmGetToolTipString(w),
NULL);
}
else
{
XmString string;
string = XmStringCreateLocalized (XtName (w));
XtVaSetValues (ttp->label, XmNlabelString, string, NULL);
XmStringFree (string);
}
XtQueryGeometry (ttp->label, NULL, &geo);
/* rws 25 Feb 2001
Fix for Bug #1153
Don't let the tip be off the right/bottom of the screen
*/
destX = rx + (XmIsGadget (w) ? XtX (w) : 0) - x + XtWidth (w) / 2;
if (destX + geo.width > WidthOfScreen (XtScreen (w)))
{
destX = WidthOfScreen (XtScreen (w)) - geo.width;
}
destY = ry + (XmIsGadget (w) ? XtY (w) : 0) - y + XtHeight (w);
if (destY + geo.height > HeightOfScreen (XtScreen (w)))
{
destY = ry + (XmIsGadget (w) ? XtY (w) : 0) - y - geo.height;
}
XtVaSetValues (XtParent (ttp->label),
XmNx, rx + 1,
XmNy, ry + 1, XmNwidth, 1, XmNheight, 1, NULL);
ttp->slider =
XtVaCreateWidget ("ToolTipSlider", xmSlideContextWidgetClass,
XmGetXmDisplay (XtDisplay (w)), XmNslideWidget,
XtParent (ttp->label),
XmNslideDestX, destX,
XmNslideDestY, destY,
XmNslideDestWidth, geo.width,
XmNslideDestHeight, geo.height, NULL);
XtAddCallback (ttp->slider, XmNslideFinishCallback,
(XtCallbackProc) ToolTipPostFinish, ttp);
XtPopup (XtParent (ttp->label), XtGrabNone);
}
/*
=====================================
Publically available functions follow
=====================================
*/
void
_XmToolTipEnter (Widget wid,
XEvent * event,
String * params,
Cardinal * num_params)
{
XmToolTipConfigTrait ttp; /* ToolTip pointer */
ttp = ToolTipGetData (wid);
if (ttp == NULL)
{
XtWarning ("ToolTipGetData() returned NULL in _XmToolTipEnter()");
return;
}
if ((XmIsPrimitive (wid) || XmIsGadget(wid)) && XmGetToolTipString(wid))
{
if (ttp->enable && !ttp->timer)
{
unsigned long delay;
if (event &&
(event->xcrossing.time - ttp->leave_time < ttp->post_delay))
{
delay = 0;
}
else
{
delay = (unsigned long) ttp->post_delay;
}
if (ttp->duration_timer)
{
XtRemoveTimeOut (ttp->duration_timer);
ttp->duration_timer = (XtIntervalId) NULL;
}
ttp->timer =
XtAppAddTimeOut (XtWidgetToApplicationContext (wid), delay,
(XtTimerCallbackProc) ToolTipPost, wid);
}
}
}
void
_XmToolTipLeave (Widget w,
XEvent * event,
String * params,
Cardinal * num_params)
{
XmToolTipConfigTrait ttp = ToolTipGetData (w);
if (!ttp)
{
XtWarning ("_XmToolTipLeave() - ttp == NULL.");
return;
}
if (ttp->timer)
{
XtRemoveTimeOut (ttp->timer);
ttp->timer = (XtIntervalId) NULL;
}
else
{
if (event && (ttp->duration_timer || ttp->post_duration == 0))
{
ttp->leave_time = event->xcrossing.time;
}
ToolTipUnpost (ttp, NULL);
}
}
#ifdef FIX_1388
void _XmToolTipRemove(Widget w)
{
XmToolTipTrait ttp;
_XmToolTipLeave(w, NULL, NULL, NULL);
ttp = (XmToolTipTrait) XmeTraitGet(w, XmQTtoolTip);
if (ttp != NULL) {
XmStringFree(ttp->tool_tip_string);
XmeTraitSet(w, XmQTtoolTip, (XtPointer) NULL);
XtFree((char*)ttp);
}
}
#endif /* FIX_1388 */
Widget
XmToolTipGetLabel(Widget wid)
{
XmToolTipConfigTrait TipData = ToolTipGetData(wid);
#ifdef BUG1232
/* rws 25 Sep 2003
protect against NULL TipData
*/
#endif
return(TipData ? TipData->label : NULL);
}
XmString
XmGetToolTipString (Widget w)
{
XmToolTipTrait ttp;
ttp = (XmToolTipTrait)XmeTraitGet(w, XmQTtoolTip);
return ttp ? ttp->tool_tip_string : NULL;
}
void
XmSetToolTipString (Widget w,
XmString s)
{
XmToolTipTrait ttp;
ttp = (XmToolTipTrait)XmeTraitGet(w, XmQTtoolTip);
if (!ttp) {
ttp = (XmToolTipTrait)XtCalloc(1, sizeof(XmToolTipTraitRec));
XmeTraitSet(w, XmQTtoolTip, ttp);
}
if (ttp->tool_tip_string)
XmStringFree(ttp->tool_tip_string);
ttp->tool_tip_string = XmStringCopy(s);
}