aboutsummaryrefslogtreecommitdiff
path: root/libXaw/src/Tip.c
diff options
context:
space:
mode:
Diffstat (limited to 'libXaw/src/Tip.c')
-rw-r--r--libXaw/src/Tip.c1274
1 files changed, 637 insertions, 637 deletions
diff --git a/libXaw/src/Tip.c b/libXaw/src/Tip.c
index 9f8b32ad3..bca994ca5 100644
--- a/libXaw/src/Tip.c
+++ b/libXaw/src/Tip.c
@@ -1,637 +1,637 @@
-/*
- * Copyright (c) 1999 by The XFree86 Project, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
- * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Except as contained in this notice, the name of the XFree86 Project shall
- * not be used in advertising or otherwise to promote the sale, use or other
- * dealings in this Software without prior written authorization from the
- * XFree86 Project.
- *
- * Author: Paulo César Pereira de Andrade
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <X11/IntrinsicP.h>
-#include <X11/StringDefs.h>
-#include <X11/Xos.h>
-#include <X11/Xaw/TipP.h>
-#include <X11/Xaw/XawInit.h>
-#include <X11/Xmu/Converters.h>
-#include "Private.h"
-
-#define TIP_EVENT_MASK (ButtonPressMask | \
- ButtonReleaseMask | \
- PointerMotionMask | \
- ButtonMotionMask | \
- KeyPressMask | \
- KeyReleaseMask | \
- EnterWindowMask | \
- LeaveWindowMask)
-
-/*
- * Types
- */
-typedef struct _XawTipInfo {
- Screen *screen;
- TipWidget tip;
- Widget widget;
- Bool mapped;
- struct _XawTipInfo *next;
-} XawTipInfo;
-
-/*
- * Class Methods
- */
-static void XawTipClassInitialize(void);
-static void XawTipInitialize(Widget, Widget, ArgList, Cardinal*);
-static void XawTipDestroy(Widget);
-static void XawTipExpose(Widget, XEvent*, Region);
-static void XawTipRealize(Widget, Mask*, XSetWindowAttributes*);
-static Boolean XawTipSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
-
-/*
- * Prototypes
- */
-static void TipEventHandler(Widget, XtPointer, XEvent*, Boolean*);
-static void TipShellEventHandler(Widget, XtPointer, XEvent*, Boolean*);
-static XawTipInfo *CreateTipInfo(Widget);
-static XawTipInfo *FindTipInfo(Widget);
-static void ResetTip(XawTipInfo*, Bool);
-static void TipTimeoutCallback(XtPointer, XtIntervalId*);
-static void TipLayout(XawTipInfo*);
-static void TipPosition(XawTipInfo*);
-
-/*
- * Initialization
- */
-#define offset(field) XtOffsetOf(TipRec, tip.field)
-static XtResource resources[] = {
- {
- XtNforeground,
- XtCForeground,
- XtRPixel,
- sizeof(Pixel),
- offset(foreground),
- XtRString,
- XtDefaultForeground,
- },
- {
- XtNfont,
- XtCFont,
- XtRFontStruct,
- sizeof(XFontStruct*),
- offset(font),
- XtRString,
- XtDefaultFont
- },
- {
- XtNfontSet,
- XtCFontSet,
- XtRFontSet,
- sizeof(XFontSet),
- offset(fontset),
- XtRString,
- XtDefaultFontSet
- },
- {
- XtNtopMargin,
- XtCVerticalMargins,
- XtRDimension,
- sizeof(Dimension),
- offset(top_margin),
- XtRImmediate,
- (XtPointer)2
- },
- {
- XtNbottomMargin,
- XtCVerticalMargins,
- XtRDimension,
- sizeof(Dimension),
- offset(bottom_margin),
- XtRImmediate,
- (XtPointer)2
- },
- {
- XtNleftMargin,
- XtCHorizontalMargins,
- XtRDimension,
- sizeof(Dimension),
- offset(left_margin),
- XtRImmediate,
- (XtPointer)6
- },
- {
- XtNrightMargin,
- XtCHorizontalMargins,
- XtRDimension,
- sizeof(Dimension),
- offset(right_margin),
- XtRImmediate,
- (XtPointer)6
- },
- {
- XtNbackingStore,
- XtCBackingStore,
- XtRBackingStore,
- sizeof(int),
- offset(backing_store),
- XtRImmediate,
- (XtPointer)(Always + WhenMapped + NotUseful)
- },
- {
- XtNtimeout,
- XtCTimeout,
- XtRInt,
- sizeof(int),
- offset(timeout),
- XtRImmediate,
- (XtPointer)500
- },
- {
- XawNdisplayList,
- XawCDisplayList,
- XawRDisplayList,
- sizeof(XawDisplayList*),
- offset(display_list),
- XtRImmediate,
- NULL
- },
-};
-#undef offset
-
-TipClassRec tipClassRec = {
- /* core */
- {
- (WidgetClass)&widgetClassRec, /* superclass */
- "Tip", /* class_name */
- sizeof(TipRec), /* widget_size */
- XawTipClassInitialize, /* class_initialize */
- NULL, /* class_part_initialize */
- False, /* class_inited */
- XawTipInitialize, /* initialize */
- NULL, /* initialize_hook */
- XawTipRealize, /* realize */
- NULL, /* actions */
- 0, /* num_actions */
- resources, /* resources */
- XtNumber(resources), /* num_resources */
- NULLQUARK, /* xrm_class */
- True, /* compress_motion */
- True, /* compress_exposure */
- True, /* compress_enterleave */
- False, /* visible_interest */
- XawTipDestroy, /* destroy */
- NULL, /* resize */
- XawTipExpose, /* expose */
- XawTipSetValues, /* set_values */
- NULL, /* set_values_hook */
- XtInheritSetValuesAlmost, /* set_values_almost */
- NULL, /* get_values_hook */
- NULL, /* accept_focus */
- XtVersion, /* version */
- NULL, /* callback_private */
- NULL, /* tm_table */
- XtInheritQueryGeometry, /* query_geometry */
- XtInheritDisplayAccelerator, /* display_accelerator */
- NULL, /* extension */
- },
- /* tip */
- {
- NULL, /* extension */
- },
-};
-
-WidgetClass tipWidgetClass = (WidgetClass)&tipClassRec;
-
-static XawTipInfo *first_tip;
-
-/*
- * Implementation
- */
-static void
-XawTipClassInitialize(void)
-{
- XawInitializeWidgetSet();
- XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
- NULL, 0);
- XtSetTypeConverter(XtRBackingStore, XtRString, XmuCvtBackingStoreToString,
- NULL, 0, XtCacheNone, NULL);
-}
-
-/*ARGSUSED*/
-static void
-XawTipInitialize(Widget req, Widget w, ArgList args, Cardinal *num_args)
-{
- TipWidget tip = (TipWidget)w;
- XGCValues values;
-
- if (!tip->tip.font) XtError("Aborting: no font found\n");
- if (tip->tip.international && !tip->tip.fontset)
- XtError("Aborting: no fontset found\n");
-
- tip->tip.timer = 0;
-
- values.foreground = tip->tip.foreground;
- values.background = tip->core.background_pixel;
- values.font = tip->tip.font->fid;
- values.graphics_exposures = False;
-
- tip->tip.gc = XtAllocateGC(w, 0, GCForeground | GCBackground | GCFont |
- GCGraphicsExposures, &values, GCFont, 0);
-}
-
-static void
-XawTipDestroy(Widget w)
-{
- XawTipInfo *info = FindTipInfo(w);
- TipWidget tip = (TipWidget)w;
-
- if (tip->tip.timer)
- XtRemoveTimeOut(tip->tip.timer);
-
- XtReleaseGC(w, tip->tip.gc);
-
- XtRemoveEventHandler(XtParent(w), KeyPressMask, False, TipShellEventHandler,
- (XtPointer)NULL);
- if (info == first_tip)
- first_tip = first_tip->next;
- else {
- XawTipInfo *p = first_tip;
-
- while (p && p->next != info)
- p = p->next;
- if (p)
- p->next = info->next;
- }
- XtFree((char*)info);
-}
-
-static void
-XawTipRealize(Widget w, Mask *mask, XSetWindowAttributes *attr)
-{
- TipWidget tip = (TipWidget)w;
-
- if (tip->tip.backing_store == Always ||
- tip->tip.backing_store == NotUseful ||
- tip->tip.backing_store == WhenMapped) {
- *mask |= CWBackingStore;
- attr->backing_store = tip->tip.backing_store;
- }
- else
- *mask &= ~CWBackingStore;
- *mask |= CWOverrideRedirect;
- attr->override_redirect = True;
-
- XtWindow(w) = XCreateWindow(DisplayOfScreen(XtScreen(w)),
- RootWindowOfScreen(XtScreen(w)),
- XtX(w), XtY(w),
- XtWidth(w) ? XtWidth(w) : 1,
- XtHeight(w) ? XtHeight(w) : 1,
- XtBorderWidth(w),
- DefaultDepthOfScreen(XtScreen(w)),
- InputOutput,
- (Visual *)CopyFromParent,
- *mask, attr);
-}
-
-static void
-XawTipExpose(Widget w, XEvent *event, Region region)
-{
- TipWidget tip = (TipWidget)w;
- GC gc = tip->tip.gc;
- char *nl, *label = tip->tip.label;
- Position y = tip->tip.top_margin + tip->tip.font->max_bounds.ascent;
- int len;
-
- if (tip->tip.display_list)
- XawRunDisplayList(w, tip->tip.display_list, event, region);
-
- if (tip->tip.international == True) {
- Position ksy = tip->tip.top_margin;
- XFontSetExtents *ext = XExtentsOfFontSet(tip->tip.fontset);
-
- ksy += XawAbs(ext->max_ink_extent.y);
-
- while ((nl = index(label, '\n')) != NULL) {
- XmbDrawString(XtDisplay(w), XtWindow(w), tip->tip.fontset,
- gc, tip->tip.left_margin, ksy, label,
- (int)(nl - label));
- ksy += ext->max_ink_extent.height;
- label = nl + 1;
- }
- len = strlen(label);
- if (len)
- XmbDrawString(XtDisplay(w), XtWindow(w), tip->tip.fontset, gc,
- tip->tip.left_margin, ksy, label, len);
- }
- else {
- while ((nl = index(label, '\n')) != NULL) {
- if (tip->tip.encoding)
- XDrawString16(XtDisplay(w), XtWindow(w), gc,
- tip->tip.left_margin, y,
- (XChar2b*)label, (int)(nl - label) >> 1);
- else
- XDrawString(XtDisplay(w), XtWindow(w), gc,
- tip->tip.left_margin, y, label, (int)(nl - label));
- y += tip->tip.font->max_bounds.ascent +
- tip->tip.font->max_bounds.descent;
- label = nl + 1;
- }
- len = strlen(label);
- if (len) {
- if (tip->tip.encoding)
- XDrawString16(XtDisplay(w), XtWindow(w), gc,
- tip->tip.left_margin, y, (XChar2b*)label, len >> 1);
- else
- XDrawString(XtDisplay(w), XtWindow(w), gc,
- tip->tip.left_margin, y, label, len);
- }
- }
-}
-
-/*ARGSUSED*/
-static Boolean
-XawTipSetValues(Widget current, Widget request, Widget cnew,
- ArgList args, Cardinal *num_args)
-{
- TipWidget curtip = (TipWidget)current;
- TipWidget newtip = (TipWidget)cnew;
- Boolean redisplay = False;
-
- if (curtip->tip.font->fid != newtip->tip.font->fid ||
- curtip->tip.foreground != newtip->tip.foreground) {
- XGCValues values;
-
- values.foreground = newtip->tip.foreground;
- values.background = newtip->core.background_pixel;
- values.font = newtip->tip.font->fid;
- values.graphics_exposures = False;
- XtReleaseGC(cnew, curtip->tip.gc);
- newtip->tip.gc = XtAllocateGC(cnew, 0, GCForeground | GCBackground |
- GCFont | GCGraphicsExposures, &values,
- GCFont, 0);
- redisplay = True;
- }
- if (curtip->tip.display_list != newtip->tip.display_list)
- redisplay = True;
-
- return (redisplay);
-}
-
-static void
-TipLayout(XawTipInfo *info)
-{
- XFontStruct *fs = info->tip->tip.font;
- int width = 0, height;
- char *nl, *label = info->tip->tip.label;
-
- if (info->tip->tip.international == True) {
- XFontSet fset = info->tip->tip.fontset;
- XFontSetExtents *ext = XExtentsOfFontSet(fset);
-
- height = ext->max_ink_extent.height;
- if ((nl = index(label, '\n')) != NULL) {
- /*CONSTCOND*/
- while (True) {
- int w = XmbTextEscapement(fset, label, (int)(nl - label));
-
- if (w > width)
- width = w;
- if (*nl == '\0')
- break;
- label = nl + 1;
- if (*label)
- height += ext->max_ink_extent.height;
- if ((nl = index(label, '\n')) == NULL)
- nl = index(label, '\0');
- }
- }
- else
- width = XmbTextEscapement(fset, label, strlen(label));
- }
- else {
- height = fs->max_bounds.ascent + fs->max_bounds.descent;
- if ((nl = index(label, '\n')) != NULL) {
- /*CONSTCOND*/
- while (True) {
- int w = info->tip->tip.encoding ?
- XTextWidth16(fs, (XChar2b*)label, (int)(nl - label) >> 1) :
- XTextWidth(fs, label, (int)(nl - label));
- if (w > width)
- width = w;
- if (*nl == '\0')
- break;
- label = nl + 1;
- if (*label)
- height += fs->max_bounds.ascent + fs->max_bounds.descent;
- if ((nl = index(label, '\n')) == NULL)
- nl = index(label, '\0');
- }
- }
- else
- width = info->tip->tip.encoding ?
- XTextWidth16(fs, (XChar2b*)label, strlen(label) >> 1) :
- XTextWidth(fs, label, strlen(label));
- }
- XtWidth(info->tip) = width + info->tip->tip.left_margin +
- info->tip->tip.right_margin;
- XtHeight(info->tip) = height + info->tip->tip.top_margin +
- info->tip->tip.bottom_margin;
-}
-
-#define DEFAULT_TIP_Y_OFFSET 12
-static void
-TipPosition(XawTipInfo *info)
-{
- Window r, c;
- int rx, ry, wx, wy;
- unsigned mask;
- Position x, y;
-
- XQueryPointer(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip),
- &r, &c, &rx, &ry, &wx, &wy, &mask);
- x = rx - (XtWidth(info->tip) >> 1);
- y = ry + DEFAULT_TIP_Y_OFFSET;
-
- if (x >= 0) {
- int scr_width = WidthOfScreen(XtScreen(info->tip));
-
- if (x + XtWidth(info->tip) + XtBorderWidth(info->tip) > scr_width)
- x = scr_width - XtWidth(info->tip) - XtBorderWidth(info->tip);
- }
- if (x < 0)
- x = 0;
- if (y >= 0) {
- int scr_height = HeightOfScreen(XtScreen(info->tip));
-
- if (y + XtHeight(info->tip) + XtBorderWidth(info->tip) > scr_height)
- y -= XtHeight(info->tip) + XtBorderWidth(info->tip) +
- (DEFAULT_TIP_Y_OFFSET << 1);
- }
- if (y < 0)
- y = 0;
-
- XMoveResizeWindow(XtDisplay(info->tip), XtWindow(info->tip),
- (int)(XtX(info->tip) = x), (int)(XtY(info->tip) = y),
- (unsigned)XtWidth(info->tip), (unsigned)XtHeight(info->tip));
-}
-
-static XawTipInfo *
-CreateTipInfo(Widget w)
-{
- XawTipInfo *info = XtNew(XawTipInfo);
- Widget shell = w;
-
- info->screen = XtScreen(w);
-
- while (XtParent(shell))
- shell = XtParent(shell);
-
- info->tip = (TipWidget)XtCreateWidget("tip", tipWidgetClass, shell, NULL, 0);
- XtRealizeWidget((Widget)info->tip);
- info->widget = NULL;
- info->mapped = False;
- info->next = NULL;
- XtAddEventHandler(shell, KeyPressMask, False, TipShellEventHandler,
- (XtPointer)NULL);
-
- return (info);
-}
-
-static XawTipInfo *
-FindTipInfo(Widget w)
-{
- XawTipInfo *ptip, *tip = first_tip;
- Screen *screen = XtScreenOfObject(w);
-
- if (tip == NULL)
- return (first_tip = tip = CreateTipInfo(w));
-
- for (ptip = tip; tip; ptip = tip, tip = tip->next)
- if (tip->screen == screen)
- return (tip);
-
- return (ptip->next = CreateTipInfo(w));
-}
-
-static void
-ResetTip(XawTipInfo *info, Bool add_timeout)
-{
- if (info->tip->tip.timer) {
- XtRemoveTimeOut(info->tip->tip.timer);
- info->tip->tip.timer = 0;
- }
- if (info->mapped) {
- XtRemoveGrab(XtParent((Widget)info->tip));
- XUnmapWindow(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip));
- info->mapped = False;
- }
- if (add_timeout) {
- info->tip->tip.timer =
- XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)info->tip),
- info->tip->tip.timeout, TipTimeoutCallback,
- (XtPointer)info);
- }
-}
-
-static void
-TipTimeoutCallback(XtPointer closure, XtIntervalId *id)
-{
- XawTipInfo *info = (XawTipInfo*)closure;
- Arg args[3];
-
- info->tip->tip.label = NULL;
- info->tip->tip.international = False;
- info->tip->tip.encoding = 0;
- info->tip->tip.timer = 0;
- XtSetArg(args[0], XtNtip, &info->tip->tip.label);
- XtSetArg(args[1], XtNinternational, &info->tip->tip.international);
- XtSetArg(args[2], XtNencoding, &info->tip->tip.encoding);
- XtGetValues(info->widget, args, 3);
-
- if (info->tip->tip.label) {
- TipLayout(info);
- TipPosition(info);
- XMapRaised(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip));
- XtAddGrab(XtParent((Widget)info->tip), True, True);
- info->mapped = True;
- }
-}
-
-/*ARGSUSED*/
-static void
-TipShellEventHandler(Widget w, XtPointer client_data, XEvent *event,
- Boolean *continue_to_dispatch)
-{
- ResetTip(FindTipInfo(w), False);
-}
-
-/*ARGSUSED*/
-static void
-TipEventHandler(Widget w, XtPointer client_data, XEvent *event,
- Boolean *continue_to_dispatch)
-{
- XawTipInfo *info = FindTipInfo(w);
- Boolean add_timeout;
-
- if (info->widget != w) {
- ResetTip(info, False);
- info->widget = w;
- }
-
- switch (event->type) {
- case EnterNotify:
- add_timeout = True;
- break;
- case MotionNotify:
- /* If any button is pressed, timer is 0 */
- if (info->mapped)
- return;
- add_timeout = info->tip->tip.timer != 0;
- break;
- default:
- add_timeout = False;
- break;
- }
- ResetTip(info, add_timeout);
-}
-
-/*
- * Public routines
- */
-void
-XawTipEnable(Widget w)
-{
- XtAddEventHandler(w, TIP_EVENT_MASK, False, TipEventHandler,
- (XtPointer)NULL);
-}
-
-void
-XawTipDisable(Widget w)
-{
- XawTipInfo *info = FindTipInfo(w);
-
- XtRemoveEventHandler(w, TIP_EVENT_MASK, False, TipEventHandler,
- (XtPointer)NULL);
- if (info->widget == w)
- ResetTip(info, False);
-}
+/*
+ * Copyright (c) 1999 by The XFree86 Project, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the XFree86 Project shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization from the
+ * XFree86 Project.
+ *
+ * Author: Paulo César Pereira de Andrade
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/TipP.h>
+#include <X11/Xaw/XawInit.h>
+#include <X11/Xmu/Converters.h>
+#include "Private.h"
+
+#define TIP_EVENT_MASK (ButtonPressMask | \
+ ButtonReleaseMask | \
+ PointerMotionMask | \
+ ButtonMotionMask | \
+ KeyPressMask | \
+ KeyReleaseMask | \
+ EnterWindowMask | \
+ LeaveWindowMask)
+
+/*
+ * Types
+ */
+typedef struct _XawTipInfo {
+ Screen *screen;
+ TipWidget tip;
+ Widget widget;
+ Bool mapped;
+ struct _XawTipInfo *next;
+} XawTipInfo;
+
+/*
+ * Class Methods
+ */
+static void XawTipClassInitialize(void);
+static void XawTipInitialize(Widget, Widget, ArgList, Cardinal*);
+static void XawTipDestroy(Widget);
+static void XawTipExpose(Widget, XEvent*, Region);
+static void XawTipRealize(Widget, Mask*, XSetWindowAttributes*);
+static Boolean XawTipSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
+
+/*
+ * Prototypes
+ */
+static void TipEventHandler(Widget, XtPointer, XEvent*, Boolean*);
+static void TipShellEventHandler(Widget, XtPointer, XEvent*, Boolean*);
+static XawTipInfo *CreateTipInfo(Widget);
+static XawTipInfo *FindTipInfo(Widget);
+static void ResetTip(XawTipInfo*, Bool);
+static void TipTimeoutCallback(XtPointer, XtIntervalId*);
+static void TipLayout(XawTipInfo*);
+static void TipPosition(XawTipInfo*);
+
+/*
+ * Initialization
+ */
+#define offset(field) XtOffsetOf(TipRec, tip.field)
+static XtResource resources[] = {
+ {
+ XtNforeground,
+ XtCForeground,
+ XtRPixel,
+ sizeof(Pixel),
+ offset(foreground),
+ XtRString,
+ XtDefaultForeground,
+ },
+ {
+ XtNfont,
+ XtCFont,
+ XtRFontStruct,
+ sizeof(XFontStruct*),
+ offset(font),
+ XtRString,
+ XtDefaultFont
+ },
+ {
+ XtNfontSet,
+ XtCFontSet,
+ XtRFontSet,
+ sizeof(XFontSet),
+ offset(fontset),
+ XtRString,
+ XtDefaultFontSet
+ },
+ {
+ XtNtopMargin,
+ XtCVerticalMargins,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(top_margin),
+ XtRImmediate,
+ (XtPointer)2
+ },
+ {
+ XtNbottomMargin,
+ XtCVerticalMargins,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(bottom_margin),
+ XtRImmediate,
+ (XtPointer)2
+ },
+ {
+ XtNleftMargin,
+ XtCHorizontalMargins,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(left_margin),
+ XtRImmediate,
+ (XtPointer)6
+ },
+ {
+ XtNrightMargin,
+ XtCHorizontalMargins,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(right_margin),
+ XtRImmediate,
+ (XtPointer)6
+ },
+ {
+ XtNbackingStore,
+ XtCBackingStore,
+ XtRBackingStore,
+ sizeof(int),
+ offset(backing_store),
+ XtRImmediate,
+ (XtPointer)(Always + WhenMapped + NotUseful)
+ },
+ {
+ XtNtimeout,
+ XtCTimeout,
+ XtRInt,
+ sizeof(int),
+ offset(timeout),
+ XtRImmediate,
+ (XtPointer)500
+ },
+ {
+ XawNdisplayList,
+ XawCDisplayList,
+ XawRDisplayList,
+ sizeof(XawDisplayList*),
+ offset(display_list),
+ XtRImmediate,
+ NULL
+ },
+};
+#undef offset
+
+TipClassRec tipClassRec = {
+ /* core */
+ {
+ (WidgetClass)&widgetClassRec, /* superclass */
+ "Tip", /* class_name */
+ sizeof(TipRec), /* widget_size */
+ XawTipClassInitialize, /* class_initialize */
+ NULL, /* class_part_initialize */
+ False, /* class_inited */
+ XawTipInitialize, /* initialize */
+ NULL, /* initialize_hook */
+ XawTipRealize, /* realize */
+ NULL, /* actions */
+ 0, /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ True, /* compress_motion */
+ True, /* compress_exposure */
+ True, /* compress_enterleave */
+ False, /* visible_interest */
+ XawTipDestroy, /* destroy */
+ NULL, /* resize */
+ XawTipExpose, /* expose */
+ XawTipSetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ NULL, /* tm_table */
+ XtInheritQueryGeometry, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator */
+ NULL, /* extension */
+ },
+ /* tip */
+ {
+ NULL, /* extension */
+ },
+};
+
+WidgetClass tipWidgetClass = (WidgetClass)&tipClassRec;
+
+static XawTipInfo *first_tip;
+
+/*
+ * Implementation
+ */
+static void
+XawTipClassInitialize(void)
+{
+ XawInitializeWidgetSet();
+ XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
+ NULL, 0);
+ XtSetTypeConverter(XtRBackingStore, XtRString, XmuCvtBackingStoreToString,
+ NULL, 0, XtCacheNone, NULL);
+}
+
+/*ARGSUSED*/
+static void
+XawTipInitialize(Widget req, Widget w, ArgList args, Cardinal *num_args)
+{
+ TipWidget tip = (TipWidget)w;
+ XGCValues values;
+
+ if (!tip->tip.font) XtError("Aborting: no font found\n");
+ if (tip->tip.international && !tip->tip.fontset)
+ XtError("Aborting: no fontset found\n");
+
+ tip->tip.timer = 0;
+
+ values.foreground = tip->tip.foreground;
+ values.background = tip->core.background_pixel;
+ values.font = tip->tip.font->fid;
+ values.graphics_exposures = False;
+
+ tip->tip.gc = XtAllocateGC(w, 0, GCForeground | GCBackground | GCFont |
+ GCGraphicsExposures, &values, GCFont, 0);
+}
+
+static void
+XawTipDestroy(Widget w)
+{
+ XawTipInfo *info = FindTipInfo(w);
+ TipWidget tip = (TipWidget)w;
+
+ if (tip->tip.timer)
+ XtRemoveTimeOut(tip->tip.timer);
+
+ XtReleaseGC(w, tip->tip.gc);
+
+ XtRemoveEventHandler(XtParent(w), KeyPressMask, False, TipShellEventHandler,
+ (XtPointer)NULL);
+ if (info == first_tip)
+ first_tip = first_tip->next;
+ else {
+ XawTipInfo *p = first_tip;
+
+ while (p && p->next != info)
+ p = p->next;
+ if (p)
+ p->next = info->next;
+ }
+ XtFree((char*)info);
+}
+
+static void
+XawTipRealize(Widget w, Mask *mask, XSetWindowAttributes *attr)
+{
+ TipWidget tip = (TipWidget)w;
+
+ if (tip->tip.backing_store == Always ||
+ tip->tip.backing_store == NotUseful ||
+ tip->tip.backing_store == WhenMapped) {
+ *mask |= CWBackingStore;
+ attr->backing_store = tip->tip.backing_store;
+ }
+ else
+ *mask &= ~CWBackingStore;
+ *mask |= CWOverrideRedirect;
+ attr->override_redirect = True;
+
+ XtWindow(w) = XCreateWindow(DisplayOfScreen(XtScreen(w)),
+ RootWindowOfScreen(XtScreen(w)),
+ XtX(w), XtY(w),
+ XtWidth(w) ? XtWidth(w) : 1,
+ XtHeight(w) ? XtHeight(w) : 1,
+ XtBorderWidth(w),
+ DefaultDepthOfScreen(XtScreen(w)),
+ InputOutput,
+ (Visual *)CopyFromParent,
+ *mask, attr);
+}
+
+static void
+XawTipExpose(Widget w, XEvent *event, Region region)
+{
+ TipWidget tip = (TipWidget)w;
+ GC gc = tip->tip.gc;
+ char *nl, *label = tip->tip.label;
+ Position y = tip->tip.top_margin + tip->tip.font->max_bounds.ascent;
+ int len;
+
+ if (tip->tip.display_list)
+ XawRunDisplayList(w, tip->tip.display_list, event, region);
+
+ if (tip->tip.international == True) {
+ Position ksy = tip->tip.top_margin;
+ XFontSetExtents *ext = XExtentsOfFontSet(tip->tip.fontset);
+
+ ksy += XawAbs(ext->max_ink_extent.y);
+
+ while ((nl = index(label, '\n')) != NULL) {
+ XmbDrawString(XtDisplay(w), XtWindow(w), tip->tip.fontset,
+ gc, tip->tip.left_margin, ksy, label,
+ (int)(nl - label));
+ ksy += ext->max_ink_extent.height;
+ label = nl + 1;
+ }
+ len = strlen(label);
+ if (len)
+ XmbDrawString(XtDisplay(w), XtWindow(w), tip->tip.fontset, gc,
+ tip->tip.left_margin, ksy, label, len);
+ }
+ else {
+ while ((nl = index(label, '\n')) != NULL) {
+ if (tip->tip.encoding)
+ XDrawString16(XtDisplay(w), XtWindow(w), gc,
+ tip->tip.left_margin, y,
+ (XChar2b*)label, (int)(nl - label) >> 1);
+ else
+ XDrawString(XtDisplay(w), XtWindow(w), gc,
+ tip->tip.left_margin, y, label, (int)(nl - label));
+ y += tip->tip.font->max_bounds.ascent +
+ tip->tip.font->max_bounds.descent;
+ label = nl + 1;
+ }
+ len = strlen(label);
+ if (len) {
+ if (tip->tip.encoding)
+ XDrawString16(XtDisplay(w), XtWindow(w), gc,
+ tip->tip.left_margin, y, (XChar2b*)label, len >> 1);
+ else
+ XDrawString(XtDisplay(w), XtWindow(w), gc,
+ tip->tip.left_margin, y, label, len);
+ }
+ }
+}
+
+/*ARGSUSED*/
+static Boolean
+XawTipSetValues(Widget current, Widget request, Widget cnew,
+ ArgList args, Cardinal *num_args)
+{
+ TipWidget curtip = (TipWidget)current;
+ TipWidget newtip = (TipWidget)cnew;
+ Boolean redisplay = False;
+
+ if (curtip->tip.font->fid != newtip->tip.font->fid ||
+ curtip->tip.foreground != newtip->tip.foreground) {
+ XGCValues values;
+
+ values.foreground = newtip->tip.foreground;
+ values.background = newtip->core.background_pixel;
+ values.font = newtip->tip.font->fid;
+ values.graphics_exposures = False;
+ XtReleaseGC(cnew, curtip->tip.gc);
+ newtip->tip.gc = XtAllocateGC(cnew, 0, GCForeground | GCBackground |
+ GCFont | GCGraphicsExposures, &values,
+ GCFont, 0);
+ redisplay = True;
+ }
+ if (curtip->tip.display_list != newtip->tip.display_list)
+ redisplay = True;
+
+ return (redisplay);
+}
+
+static void
+TipLayout(XawTipInfo *info)
+{
+ XFontStruct *fs = info->tip->tip.font;
+ int width = 0, height;
+ char *nl, *label = info->tip->tip.label;
+
+ if (info->tip->tip.international == True) {
+ XFontSet fset = info->tip->tip.fontset;
+ XFontSetExtents *ext = XExtentsOfFontSet(fset);
+
+ height = ext->max_ink_extent.height;
+ if ((nl = index(label, '\n')) != NULL) {
+ /*CONSTCOND*/
+ while (True) {
+ int w = XmbTextEscapement(fset, label, (int)(nl - label));
+
+ if (w > width)
+ width = w;
+ if (*nl == '\0')
+ break;
+ label = nl + 1;
+ if (*label)
+ height += ext->max_ink_extent.height;
+ if ((nl = index(label, '\n')) == NULL)
+ nl = index(label, '\0');
+ }
+ }
+ else
+ width = XmbTextEscapement(fset, label, strlen(label));
+ }
+ else {
+ height = fs->max_bounds.ascent + fs->max_bounds.descent;
+ if ((nl = index(label, '\n')) != NULL) {
+ /*CONSTCOND*/
+ while (True) {
+ int w = info->tip->tip.encoding ?
+ XTextWidth16(fs, (XChar2b*)label, (int)(nl - label) >> 1) :
+ XTextWidth(fs, label, (int)(nl - label));
+ if (w > width)
+ width = w;
+ if (*nl == '\0')
+ break;
+ label = nl + 1;
+ if (*label)
+ height += fs->max_bounds.ascent + fs->max_bounds.descent;
+ if ((nl = index(label, '\n')) == NULL)
+ nl = index(label, '\0');
+ }
+ }
+ else
+ width = info->tip->tip.encoding ?
+ XTextWidth16(fs, (XChar2b*)label, strlen(label) >> 1) :
+ XTextWidth(fs, label, strlen(label));
+ }
+ XtWidth(info->tip) = width + info->tip->tip.left_margin +
+ info->tip->tip.right_margin;
+ XtHeight(info->tip) = height + info->tip->tip.top_margin +
+ info->tip->tip.bottom_margin;
+}
+
+#define DEFAULT_TIP_Y_OFFSET 12
+static void
+TipPosition(XawTipInfo *info)
+{
+ Window r, c;
+ int rx, ry, wx, wy;
+ unsigned mask;
+ Position x, y;
+
+ XQueryPointer(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip),
+ &r, &c, &rx, &ry, &wx, &wy, &mask);
+ x = rx - (XtWidth(info->tip) >> 1);
+ y = ry + DEFAULT_TIP_Y_OFFSET;
+
+ if (x >= 0) {
+ int scr_width = WidthOfScreen(XtScreen(info->tip));
+
+ if (x + XtWidth(info->tip) + XtBorderWidth(info->tip) > scr_width)
+ x = scr_width - XtWidth(info->tip) - XtBorderWidth(info->tip);
+ }
+ if (x < 0)
+ x = 0;
+ if (y >= 0) {
+ int scr_height = HeightOfScreen(XtScreen(info->tip));
+
+ if (y + XtHeight(info->tip) + XtBorderWidth(info->tip) > scr_height)
+ y -= XtHeight(info->tip) + XtBorderWidth(info->tip) +
+ (DEFAULT_TIP_Y_OFFSET << 1);
+ }
+ if (y < 0)
+ y = 0;
+
+ XMoveResizeWindow(XtDisplay(info->tip), XtWindow(info->tip),
+ (int)(XtX(info->tip) = x), (int)(XtY(info->tip) = y),
+ (unsigned)XtWidth(info->tip), (unsigned)XtHeight(info->tip));
+}
+
+static XawTipInfo *
+CreateTipInfo(Widget w)
+{
+ XawTipInfo *info = XtNew(XawTipInfo);
+ Widget shell = w;
+
+ info->screen = XtScreen(w);
+
+ while (XtParent(shell))
+ shell = XtParent(shell);
+
+ info->tip = (TipWidget)XtCreateWidget("tip", tipWidgetClass, shell, NULL, 0);
+ XtRealizeWidget((Widget)info->tip);
+ info->widget = NULL;
+ info->mapped = False;
+ info->next = NULL;
+ XtAddEventHandler(shell, KeyPressMask, False, TipShellEventHandler,
+ (XtPointer)NULL);
+
+ return (info);
+}
+
+static XawTipInfo *
+FindTipInfo(Widget w)
+{
+ XawTipInfo *ptip, *tip = first_tip;
+ Screen *screen = XtScreenOfObject(w);
+
+ if (tip == NULL)
+ return (first_tip = tip = CreateTipInfo(w));
+
+ for (ptip = tip; tip; ptip = tip, tip = tip->next)
+ if (tip->screen == screen)
+ return (tip);
+
+ return (ptip->next = CreateTipInfo(w));
+}
+
+static void
+ResetTip(XawTipInfo *info, Bool add_timeout)
+{
+ if (info->tip->tip.timer) {
+ XtRemoveTimeOut(info->tip->tip.timer);
+ info->tip->tip.timer = 0;
+ }
+ if (info->mapped) {
+ XtRemoveGrab(XtParent((Widget)info->tip));
+ XUnmapWindow(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip));
+ info->mapped = False;
+ }
+ if (add_timeout) {
+ info->tip->tip.timer =
+ XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)info->tip),
+ info->tip->tip.timeout, TipTimeoutCallback,
+ (XtPointer)info);
+ }
+}
+
+static void
+TipTimeoutCallback(XtPointer closure, XtIntervalId *id)
+{
+ XawTipInfo *info = (XawTipInfo*)closure;
+ Arg args[3];
+
+ info->tip->tip.label = NULL;
+ info->tip->tip.international = False;
+ info->tip->tip.encoding = 0;
+ info->tip->tip.timer = 0;
+ XtSetArg(args[0], XtNtip, &info->tip->tip.label);
+ XtSetArg(args[1], XtNinternational, &info->tip->tip.international);
+ XtSetArg(args[2], XtNencoding, &info->tip->tip.encoding);
+ XtGetValues(info->widget, args, 3);
+
+ if (info->tip->tip.label) {
+ TipLayout(info);
+ TipPosition(info);
+ XMapRaised(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip));
+ XtAddGrab(XtParent((Widget)info->tip), True, True);
+ info->mapped = True;
+ }
+}
+
+/*ARGSUSED*/
+static void
+TipShellEventHandler(Widget w, XtPointer client_data, XEvent *event,
+ Boolean *continue_to_dispatch)
+{
+ ResetTip(FindTipInfo(w), False);
+}
+
+/*ARGSUSED*/
+static void
+TipEventHandler(Widget w, XtPointer client_data, XEvent *event,
+ Boolean *continue_to_dispatch)
+{
+ XawTipInfo *info = FindTipInfo(w);
+ Boolean add_timeout;
+
+ if (info->widget != w) {
+ ResetTip(info, False);
+ info->widget = w;
+ }
+
+ switch (event->type) {
+ case EnterNotify:
+ add_timeout = True;
+ break;
+ case MotionNotify:
+ /* If any button is pressed, timer is 0 */
+ if (info->mapped)
+ return;
+ add_timeout = info->tip->tip.timer != 0;
+ break;
+ default:
+ add_timeout = False;
+ break;
+ }
+ ResetTip(info, add_timeout);
+}
+
+/*
+ * Public routines
+ */
+void
+XawTipEnable(Widget w)
+{
+ XtAddEventHandler(w, TIP_EVENT_MASK, False, TipEventHandler,
+ (XtPointer)NULL);
+}
+
+void
+XawTipDisable(Widget w)
+{
+ XawTipInfo *info = FindTipInfo(w);
+
+ XtRemoveEventHandler(w, TIP_EVENT_MASK, False, TipEventHandler,
+ (XtPointer)NULL);
+ if (info->widget == w)
+ ResetTip(info, False);
+}