17a84e134Smrg/* 27a84e134Smrg * Copyright (c) 1999 by The XFree86 Project, Inc. 37a84e134Smrg * 47a84e134Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57a84e134Smrg * copy of this software and associated documentation files (the "Software"), 67a84e134Smrg * to deal in the Software without restriction, including without limitation 77a84e134Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87a84e134Smrg * and/or sell copies of the Software, and to permit persons to whom the 97a84e134Smrg * Software is furnished to do so, subject to the following conditions: 107a84e134Smrg * 117a84e134Smrg * The above copyright notice and this permission notice shall be included in 127a84e134Smrg * all copies or substantial portions of the Software. 137a84e134Smrg * 147a84e134Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 157a84e134Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 167a84e134Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 177a84e134Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 187a84e134Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 197a84e134Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 207a84e134Smrg * SOFTWARE. 217a84e134Smrg * 227a84e134Smrg * Except as contained in this notice, the name of the XFree86 Project shall 237a84e134Smrg * not be used in advertising or otherwise to promote the sale, use or other 247a84e134Smrg * dealings in this Software without prior written authorization from the 257a84e134Smrg * XFree86 Project. 267a84e134Smrg * 277a84e134Smrg * Author: Paulo César Pereira de Andrade 287a84e134Smrg */ 297a84e134Smrg 307a84e134Smrg#ifdef HAVE_CONFIG_H 317a84e134Smrg#include <config.h> 327a84e134Smrg#endif 337a84e134Smrg#include <X11/IntrinsicP.h> 347a84e134Smrg#include <X11/StringDefs.h> 357a84e134Smrg#include <X11/Xos.h> 367a84e134Smrg#include <X11/Xaw/TipP.h> 377a84e134Smrg#include <X11/Xaw/XawInit.h> 387a84e134Smrg#include <X11/Xmu/Converters.h> 397a84e134Smrg#include "Private.h" 407a84e134Smrg 417a84e134Smrg#define TIP_EVENT_MASK (ButtonPressMask | \ 427a84e134Smrg ButtonReleaseMask | \ 437a84e134Smrg PointerMotionMask | \ 447a84e134Smrg ButtonMotionMask | \ 457a84e134Smrg KeyPressMask | \ 467a84e134Smrg KeyReleaseMask | \ 477a84e134Smrg EnterWindowMask | \ 487a84e134Smrg LeaveWindowMask) 497a84e134Smrg 507a84e134Smrg/* 517a84e134Smrg * Types 527a84e134Smrg */ 537a84e134Smrgtypedef struct _XawTipInfo { 547a84e134Smrg Screen *screen; 557a84e134Smrg TipWidget tip; 567a84e134Smrg Widget widget; 577a84e134Smrg Bool mapped; 587a84e134Smrg struct _XawTipInfo *next; 597a84e134Smrg} XawTipInfo; 607a84e134Smrg 617a84e134Smrg/* 627a84e134Smrg * Class Methods 637a84e134Smrg */ 647a84e134Smrgstatic void XawTipClassInitialize(void); 657a84e134Smrgstatic void XawTipInitialize(Widget, Widget, ArgList, Cardinal*); 667a84e134Smrgstatic void XawTipDestroy(Widget); 677a84e134Smrgstatic void XawTipExpose(Widget, XEvent*, Region); 687a84e134Smrgstatic void XawTipRealize(Widget, Mask*, XSetWindowAttributes*); 697a84e134Smrgstatic Boolean XawTipSetValues(Widget, Widget, Widget, ArgList, Cardinal*); 707a84e134Smrg 717a84e134Smrg/* 727a84e134Smrg * Prototypes 737a84e134Smrg */ 747a84e134Smrgstatic void TipEventHandler(Widget, XtPointer, XEvent*, Boolean*); 757a84e134Smrgstatic void TipShellEventHandler(Widget, XtPointer, XEvent*, Boolean*); 767a84e134Smrgstatic XawTipInfo *CreateTipInfo(Widget); 777a84e134Smrgstatic XawTipInfo *FindTipInfo(Widget); 787a84e134Smrgstatic void ResetTip(XawTipInfo*, Bool); 797a84e134Smrgstatic void TipTimeoutCallback(XtPointer, XtIntervalId*); 807a84e134Smrgstatic void TipLayout(XawTipInfo*); 817a84e134Smrgstatic void TipPosition(XawTipInfo*); 827a84e134Smrg 837a84e134Smrg/* 847a84e134Smrg * Initialization 857a84e134Smrg */ 867a84e134Smrg#define offset(field) XtOffsetOf(TipRec, tip.field) 877a84e134Smrgstatic XtResource resources[] = { 887a84e134Smrg { 897a84e134Smrg XtNforeground, 907a84e134Smrg XtCForeground, 917a84e134Smrg XtRPixel, 927a84e134Smrg sizeof(Pixel), 937a84e134Smrg offset(foreground), 947a84e134Smrg XtRString, 955ec34c4cSmrg (XtPointer)XtDefaultForeground, 967a84e134Smrg }, 977a84e134Smrg { 987a84e134Smrg XtNfont, 997a84e134Smrg XtCFont, 1007a84e134Smrg XtRFontStruct, 1017a84e134Smrg sizeof(XFontStruct*), 1027a84e134Smrg offset(font), 1037a84e134Smrg XtRString, 1045ec34c4cSmrg (XtPointer)XtDefaultFont 1057a84e134Smrg }, 1067a84e134Smrg { 1077a84e134Smrg XtNfontSet, 1087a84e134Smrg XtCFontSet, 1097a84e134Smrg XtRFontSet, 1107a84e134Smrg sizeof(XFontSet), 1117a84e134Smrg offset(fontset), 1127a84e134Smrg XtRString, 1135ec34c4cSmrg (XtPointer)XtDefaultFontSet 1147a84e134Smrg }, 1157a84e134Smrg { 1167a84e134Smrg XtNtopMargin, 1177a84e134Smrg XtCVerticalMargins, 1187a84e134Smrg XtRDimension, 1197a84e134Smrg sizeof(Dimension), 1207a84e134Smrg offset(top_margin), 1217a84e134Smrg XtRImmediate, 1227a84e134Smrg (XtPointer)2 1237a84e134Smrg }, 1247a84e134Smrg { 1257a84e134Smrg XtNbottomMargin, 1267a84e134Smrg XtCVerticalMargins, 1277a84e134Smrg XtRDimension, 1287a84e134Smrg sizeof(Dimension), 1297a84e134Smrg offset(bottom_margin), 1307a84e134Smrg XtRImmediate, 1317a84e134Smrg (XtPointer)2 1327a84e134Smrg }, 1337a84e134Smrg { 1347a84e134Smrg XtNleftMargin, 1357a84e134Smrg XtCHorizontalMargins, 1367a84e134Smrg XtRDimension, 1377a84e134Smrg sizeof(Dimension), 1387a84e134Smrg offset(left_margin), 1397a84e134Smrg XtRImmediate, 1407a84e134Smrg (XtPointer)6 1417a84e134Smrg }, 1427a84e134Smrg { 1437a84e134Smrg XtNrightMargin, 1447a84e134Smrg XtCHorizontalMargins, 1457a84e134Smrg XtRDimension, 1467a84e134Smrg sizeof(Dimension), 1477a84e134Smrg offset(right_margin), 1487a84e134Smrg XtRImmediate, 1497a84e134Smrg (XtPointer)6 1507a84e134Smrg }, 1517a84e134Smrg { 1527a84e134Smrg XtNbackingStore, 1537a84e134Smrg XtCBackingStore, 1547a84e134Smrg XtRBackingStore, 1557a84e134Smrg sizeof(int), 1567a84e134Smrg offset(backing_store), 1577a84e134Smrg XtRImmediate, 1587a84e134Smrg (XtPointer)(Always + WhenMapped + NotUseful) 1597a84e134Smrg }, 1607a84e134Smrg { 1617a84e134Smrg XtNtimeout, 1627a84e134Smrg XtCTimeout, 1637a84e134Smrg XtRInt, 1647a84e134Smrg sizeof(int), 1657a84e134Smrg offset(timeout), 1667a84e134Smrg XtRImmediate, 1677a84e134Smrg (XtPointer)500 1687a84e134Smrg }, 1697a84e134Smrg { 1707a84e134Smrg XawNdisplayList, 1717a84e134Smrg XawCDisplayList, 1727a84e134Smrg XawRDisplayList, 1737a84e134Smrg sizeof(XawDisplayList*), 1747a84e134Smrg offset(display_list), 1757a84e134Smrg XtRImmediate, 1767a84e134Smrg NULL 1777a84e134Smrg }, 1787a84e134Smrg}; 1797a84e134Smrg#undef offset 1807a84e134Smrg 1817a84e134SmrgTipClassRec tipClassRec = { 1827a84e134Smrg /* core */ 1837a84e134Smrg { 1847a84e134Smrg (WidgetClass)&widgetClassRec, /* superclass */ 1857a84e134Smrg "Tip", /* class_name */ 1867a84e134Smrg sizeof(TipRec), /* widget_size */ 1877a84e134Smrg XawTipClassInitialize, /* class_initialize */ 1887a84e134Smrg NULL, /* class_part_initialize */ 1897a84e134Smrg False, /* class_inited */ 1907a84e134Smrg XawTipInitialize, /* initialize */ 1917a84e134Smrg NULL, /* initialize_hook */ 1927a84e134Smrg XawTipRealize, /* realize */ 1937a84e134Smrg NULL, /* actions */ 1947a84e134Smrg 0, /* num_actions */ 1957a84e134Smrg resources, /* resources */ 1967a84e134Smrg XtNumber(resources), /* num_resources */ 1977a84e134Smrg NULLQUARK, /* xrm_class */ 1987a84e134Smrg True, /* compress_motion */ 1997a84e134Smrg True, /* compress_exposure */ 2007a84e134Smrg True, /* compress_enterleave */ 2017a84e134Smrg False, /* visible_interest */ 2027a84e134Smrg XawTipDestroy, /* destroy */ 2037a84e134Smrg NULL, /* resize */ 2047a84e134Smrg XawTipExpose, /* expose */ 2057a84e134Smrg XawTipSetValues, /* set_values */ 2067a84e134Smrg NULL, /* set_values_hook */ 2077a84e134Smrg XtInheritSetValuesAlmost, /* set_values_almost */ 2087a84e134Smrg NULL, /* get_values_hook */ 2097a84e134Smrg NULL, /* accept_focus */ 2107a84e134Smrg XtVersion, /* version */ 2117a84e134Smrg NULL, /* callback_private */ 2127a84e134Smrg NULL, /* tm_table */ 2137a84e134Smrg XtInheritQueryGeometry, /* query_geometry */ 2147a84e134Smrg XtInheritDisplayAccelerator, /* display_accelerator */ 2157a84e134Smrg NULL, /* extension */ 2167a84e134Smrg }, 2177a84e134Smrg /* tip */ 2187a84e134Smrg { 2197a84e134Smrg NULL, /* extension */ 2207a84e134Smrg }, 2217a84e134Smrg}; 2227a84e134Smrg 2237a84e134SmrgWidgetClass tipWidgetClass = (WidgetClass)&tipClassRec; 2247a84e134Smrg 2257a84e134Smrgstatic XawTipInfo *first_tip; 2267a84e134Smrg 2277a84e134Smrg/* 2287a84e134Smrg * Implementation 2297a84e134Smrg */ 2307a84e134Smrgstatic void 2317a84e134SmrgXawTipClassInitialize(void) 2327a84e134Smrg{ 2337a84e134Smrg XawInitializeWidgetSet(); 2347a84e134Smrg XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore, 2357a84e134Smrg NULL, 0); 2367a84e134Smrg XtSetTypeConverter(XtRBackingStore, XtRString, XmuCvtBackingStoreToString, 2377a84e134Smrg NULL, 0, XtCacheNone, NULL); 2387a84e134Smrg} 2397a84e134Smrg 2407a84e134Smrg/*ARGSUSED*/ 2417a84e134Smrgstatic void 2425ec34c4cSmrgXawTipInitialize(Widget req _X_UNUSED, Widget w _X_UNUSED, ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 2437a84e134Smrg{ 2447a84e134Smrg TipWidget tip = (TipWidget)w; 2457a84e134Smrg XGCValues values; 2467a84e134Smrg 2477a84e134Smrg if (!tip->tip.font) XtError("Aborting: no font found\n"); 2487a84e134Smrg if (tip->tip.international && !tip->tip.fontset) 2497a84e134Smrg XtError("Aborting: no fontset found\n"); 250421c997bSmrg 2517a84e134Smrg tip->tip.timer = 0; 2527a84e134Smrg 2537a84e134Smrg values.foreground = tip->tip.foreground; 2547a84e134Smrg values.background = tip->core.background_pixel; 2557a84e134Smrg values.font = tip->tip.font->fid; 2567a84e134Smrg values.graphics_exposures = False; 2577a84e134Smrg 2587a84e134Smrg tip->tip.gc = XtAllocateGC(w, 0, GCForeground | GCBackground | GCFont | 2597a84e134Smrg GCGraphicsExposures, &values, GCFont, 0); 2607a84e134Smrg} 2617a84e134Smrg 2627a84e134Smrgstatic void 2637a84e134SmrgXawTipDestroy(Widget w) 2647a84e134Smrg{ 2657a84e134Smrg XawTipInfo *info = FindTipInfo(w); 2667a84e134Smrg TipWidget tip = (TipWidget)w; 2677a84e134Smrg 2687a84e134Smrg if (tip->tip.timer) 2697a84e134Smrg XtRemoveTimeOut(tip->tip.timer); 2707a84e134Smrg 2717a84e134Smrg XtReleaseGC(w, tip->tip.gc); 2727a84e134Smrg 2737a84e134Smrg XtRemoveEventHandler(XtParent(w), KeyPressMask, False, TipShellEventHandler, 2747a84e134Smrg (XtPointer)NULL); 2757a84e134Smrg if (info == first_tip) 2767a84e134Smrg first_tip = first_tip->next; 2777a84e134Smrg else { 2787a84e134Smrg XawTipInfo *p = first_tip; 2797a84e134Smrg 2807a84e134Smrg while (p && p->next != info) 2817a84e134Smrg p = p->next; 2827a84e134Smrg if (p) 2837a84e134Smrg p->next = info->next; 2847a84e134Smrg } 2857a84e134Smrg XtFree((char*)info); 2867a84e134Smrg} 2877a84e134Smrg 2887a84e134Smrgstatic void 2897a84e134SmrgXawTipRealize(Widget w, Mask *mask, XSetWindowAttributes *attr) 2907a84e134Smrg{ 2917a84e134Smrg TipWidget tip = (TipWidget)w; 2927a84e134Smrg 2937a84e134Smrg if (tip->tip.backing_store == Always || 2947a84e134Smrg tip->tip.backing_store == NotUseful || 2957a84e134Smrg tip->tip.backing_store == WhenMapped) { 2967a84e134Smrg *mask |= CWBackingStore; 2977a84e134Smrg attr->backing_store = tip->tip.backing_store; 2987a84e134Smrg } 2997a84e134Smrg else 3005ec34c4cSmrg *mask &= (Mask)(~CWBackingStore); 3017a84e134Smrg *mask |= CWOverrideRedirect; 3027a84e134Smrg attr->override_redirect = True; 3037a84e134Smrg 3047a84e134Smrg XtWindow(w) = XCreateWindow(DisplayOfScreen(XtScreen(w)), 3057a84e134Smrg RootWindowOfScreen(XtScreen(w)), 3067a84e134Smrg XtX(w), XtY(w), 3077a84e134Smrg XtWidth(w) ? XtWidth(w) : 1, 3087a84e134Smrg XtHeight(w) ? XtHeight(w) : 1, 3097a84e134Smrg XtBorderWidth(w), 3107a84e134Smrg DefaultDepthOfScreen(XtScreen(w)), 3117a84e134Smrg InputOutput, 312775e7de9Smrg (Visual *)CopyFromParent, 3137a84e134Smrg *mask, attr); 3147a84e134Smrg} 3157a84e134Smrg 3167a84e134Smrgstatic void 3177a84e134SmrgXawTipExpose(Widget w, XEvent *event, Region region) 3187a84e134Smrg{ 3197a84e134Smrg TipWidget tip = (TipWidget)w; 3207a84e134Smrg GC gc = tip->tip.gc; 3215ec34c4cSmrg char *nl; 3225ec34c4cSmrg _Xconst char * label = tip->tip.label; 3235ec34c4cSmrg Position y = (Position)(tip->tip.top_margin + tip->tip.font->max_bounds.ascent); 3247a84e134Smrg int len; 3257a84e134Smrg 3267a84e134Smrg if (tip->tip.display_list) 3277a84e134Smrg XawRunDisplayList(w, tip->tip.display_list, event, region); 3287a84e134Smrg 3297a84e134Smrg if (tip->tip.international == True) { 3305ec34c4cSmrg Position ksy = (Position)tip->tip.top_margin; 3317a84e134Smrg XFontSetExtents *ext = XExtentsOfFontSet(tip->tip.fontset); 3327a84e134Smrg 333efbcb2bfSmrg ksy = (Position) (ksy + XawAbs(ext->max_ink_extent.y)); 3347a84e134Smrg 3355b16253fSmrg while ((nl = strchr(label, '\n')) != NULL) { 3367a84e134Smrg XmbDrawString(XtDisplay(w), XtWindow(w), tip->tip.fontset, 3377a84e134Smrg gc, tip->tip.left_margin, ksy, label, 3387a84e134Smrg (int)(nl - label)); 339efbcb2bfSmrg ksy = (Position) (ksy + ext->max_ink_extent.height); 3407a84e134Smrg label = nl + 1; 3417a84e134Smrg } 3425ec34c4cSmrg len = (int)strlen(label); 3437a84e134Smrg if (len) 3447a84e134Smrg XmbDrawString(XtDisplay(w), XtWindow(w), tip->tip.fontset, gc, 3457a84e134Smrg tip->tip.left_margin, ksy, label, len); 3467a84e134Smrg } 3477a84e134Smrg else { 3485b16253fSmrg while ((nl = strchr(label, '\n')) != NULL) { 3497a84e134Smrg if (tip->tip.encoding) 3507a84e134Smrg XDrawString16(XtDisplay(w), XtWindow(w), gc, 3517a84e134Smrg tip->tip.left_margin, y, 3525ec34c4cSmrg (_Xconst XChar2b*)label, (int)(nl - label) >> 1); 3537a84e134Smrg else 3547a84e134Smrg XDrawString(XtDisplay(w), XtWindow(w), gc, 3557a84e134Smrg tip->tip.left_margin, y, label, (int)(nl - label)); 3565ec34c4cSmrg y = (Position)(y + (tip->tip.font->max_bounds.ascent + 3575ec34c4cSmrg tip->tip.font->max_bounds.descent)); 3587a84e134Smrg label = nl + 1; 3597a84e134Smrg } 3605ec34c4cSmrg len = (int)strlen(label); 3617a84e134Smrg if (len) { 3627a84e134Smrg if (tip->tip.encoding) 3637a84e134Smrg XDrawString16(XtDisplay(w), XtWindow(w), gc, 3645ec34c4cSmrg tip->tip.left_margin, y, (_Xconst XChar2b*)label, len >> 1); 3657a84e134Smrg else 3667a84e134Smrg XDrawString(XtDisplay(w), XtWindow(w), gc, 3677a84e134Smrg tip->tip.left_margin, y, label, len); 3687a84e134Smrg } 3697a84e134Smrg } 3707a84e134Smrg} 3717a84e134Smrg 3727a84e134Smrg/*ARGSUSED*/ 3737a84e134Smrgstatic Boolean 3745ec34c4cSmrgXawTipSetValues(Widget current, Widget request _X_UNUSED, Widget cnew, 3755ec34c4cSmrg ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 3767a84e134Smrg{ 3777a84e134Smrg TipWidget curtip = (TipWidget)current; 3787a84e134Smrg TipWidget newtip = (TipWidget)cnew; 3797a84e134Smrg Boolean redisplay = False; 3807a84e134Smrg 3817a84e134Smrg if (curtip->tip.font->fid != newtip->tip.font->fid || 3827a84e134Smrg curtip->tip.foreground != newtip->tip.foreground) { 383efbcb2bfSmrg XGCValues values = { 384efbcb2bfSmrg .foreground = newtip->tip.foreground, 385efbcb2bfSmrg .background = newtip->core.background_pixel, 386efbcb2bfSmrg .font = newtip->tip.font->fid, 387efbcb2bfSmrg .graphics_exposures = False 388efbcb2bfSmrg }; 3897a84e134Smrg 3907a84e134Smrg XtReleaseGC(cnew, curtip->tip.gc); 3917a84e134Smrg newtip->tip.gc = XtAllocateGC(cnew, 0, GCForeground | GCBackground | 3927a84e134Smrg GCFont | GCGraphicsExposures, &values, 3937a84e134Smrg GCFont, 0); 3947a84e134Smrg redisplay = True; 3957a84e134Smrg } 3967a84e134Smrg if (curtip->tip.display_list != newtip->tip.display_list) 3977a84e134Smrg redisplay = True; 3987a84e134Smrg 3997a84e134Smrg return (redisplay); 4007a84e134Smrg} 4017a84e134Smrg 4027a84e134Smrgstatic void 4037a84e134SmrgTipLayout(XawTipInfo *info) 4047a84e134Smrg{ 4057a84e134Smrg XFontStruct *fs = info->tip->tip.font; 4067a84e134Smrg int width = 0, height; 4075ec34c4cSmrg char *nl; 4085ec34c4cSmrg _Xconst char *label = info->tip->tip.label; 4097a84e134Smrg 4107a84e134Smrg if (info->tip->tip.international == True) { 4117a84e134Smrg XFontSet fset = info->tip->tip.fontset; 4127a84e134Smrg XFontSetExtents *ext = XExtentsOfFontSet(fset); 4137a84e134Smrg 4147a84e134Smrg height = ext->max_ink_extent.height; 4155b16253fSmrg if ((nl = strchr(label, '\n')) != NULL) { 4167a84e134Smrg /*CONSTCOND*/ 4177a84e134Smrg while (True) { 4187a84e134Smrg int w = XmbTextEscapement(fset, label, (int)(nl - label)); 4197a84e134Smrg 4207a84e134Smrg if (w > width) 4217a84e134Smrg width = w; 4227a84e134Smrg if (*nl == '\0') 4237a84e134Smrg break; 4247a84e134Smrg label = nl + 1; 4257a84e134Smrg if (*label) 4267a84e134Smrg height += ext->max_ink_extent.height; 4275b16253fSmrg if ((nl = strchr(label, '\n')) == NULL) 4285b16253fSmrg nl = strchr(label, '\0'); 4297a84e134Smrg } 4307a84e134Smrg } 4317a84e134Smrg else 4325ec34c4cSmrg width = XmbTextEscapement(fset, label, (int)strlen(label)); 4337a84e134Smrg } 4347a84e134Smrg else { 4357a84e134Smrg height = fs->max_bounds.ascent + fs->max_bounds.descent; 4365b16253fSmrg if ((nl = strchr(label, '\n')) != NULL) { 4377a84e134Smrg /*CONSTCOND*/ 4387a84e134Smrg while (True) { 4397a84e134Smrg int w = info->tip->tip.encoding ? 4405ec34c4cSmrg XTextWidth16(fs, (_Xconst XChar2b*)label, (int)(nl - label) >> 1) : 4417a84e134Smrg XTextWidth(fs, label, (int)(nl - label)); 4427a84e134Smrg if (w > width) 4437a84e134Smrg width = w; 4447a84e134Smrg if (*nl == '\0') 4457a84e134Smrg break; 4467a84e134Smrg label = nl + 1; 4477a84e134Smrg if (*label) 4487a84e134Smrg height += fs->max_bounds.ascent + fs->max_bounds.descent; 4495b16253fSmrg if ((nl = strchr(label, '\n')) == NULL) 4505b16253fSmrg nl = strchr(label, '\0'); 4517a84e134Smrg } 4527a84e134Smrg } 4537a84e134Smrg else 4547a84e134Smrg width = info->tip->tip.encoding ? 4555ec34c4cSmrg XTextWidth16(fs, (_Xconst XChar2b*)label, (int)(strlen(label) >> 1)) : 4565ec34c4cSmrg XTextWidth(fs, label, (int)strlen(label)); 4577a84e134Smrg } 458efbcb2bfSmrg XtWidth(info->tip) = (Dimension) (width + info->tip->tip.left_margin + 459efbcb2bfSmrg info->tip->tip.right_margin); 460efbcb2bfSmrg XtHeight(info->tip) = (Dimension) (height + info->tip->tip.top_margin + 461efbcb2bfSmrg info->tip->tip.bottom_margin); 4627a84e134Smrg} 4637a84e134Smrg 4647a84e134Smrg#define DEFAULT_TIP_Y_OFFSET 12 4657a84e134Smrgstatic void 4667a84e134SmrgTipPosition(XawTipInfo *info) 4677a84e134Smrg{ 4687a84e134Smrg Window r, c; 4697a84e134Smrg int rx, ry, wx, wy; 4707a84e134Smrg unsigned mask; 4717a84e134Smrg Position x, y; 4727a84e134Smrg 4737a84e134Smrg XQueryPointer(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip), 4747a84e134Smrg &r, &c, &rx, &ry, &wx, &wy, &mask); 4755ec34c4cSmrg x = (Position)(rx - (XtWidth(info->tip) >> 1)); 4765ec34c4cSmrg y = (Position)(ry + DEFAULT_TIP_Y_OFFSET); 4777a84e134Smrg 4787a84e134Smrg if (x >= 0) { 4797a84e134Smrg int scr_width = WidthOfScreen(XtScreen(info->tip)); 4807a84e134Smrg 4817a84e134Smrg if (x + XtWidth(info->tip) + XtBorderWidth(info->tip) > scr_width) 4825ec34c4cSmrg x = (Position)(scr_width - XtWidth(info->tip) - XtBorderWidth(info->tip)); 4837a84e134Smrg } 4847a84e134Smrg if (x < 0) 4857a84e134Smrg x = 0; 4867a84e134Smrg if (y >= 0) { 4877a84e134Smrg int scr_height = HeightOfScreen(XtScreen(info->tip)); 4887a84e134Smrg 4897a84e134Smrg if (y + XtHeight(info->tip) + XtBorderWidth(info->tip) > scr_height) 4905ec34c4cSmrg y = (Position)(y - (XtHeight(info->tip) + XtBorderWidth(info->tip) + 4915ec34c4cSmrg (DEFAULT_TIP_Y_OFFSET << 1))); 4927a84e134Smrg } 4937a84e134Smrg if (y < 0) 4947a84e134Smrg y = 0; 4957a84e134Smrg 4967a84e134Smrg XMoveResizeWindow(XtDisplay(info->tip), XtWindow(info->tip), 4977a84e134Smrg (int)(XtX(info->tip) = x), (int)(XtY(info->tip) = y), 4987a84e134Smrg (unsigned)XtWidth(info->tip), (unsigned)XtHeight(info->tip)); 4997a84e134Smrg} 5007a84e134Smrg 5017a84e134Smrgstatic XawTipInfo * 5027a84e134SmrgCreateTipInfo(Widget w) 5037a84e134Smrg{ 5047a84e134Smrg XawTipInfo *info = XtNew(XawTipInfo); 5057a84e134Smrg Widget shell = w; 5067a84e134Smrg 5077a84e134Smrg info->screen = XtScreen(w); 5087a84e134Smrg 5097a84e134Smrg while (XtParent(shell)) 5107a84e134Smrg shell = XtParent(shell); 5117a84e134Smrg 5127a84e134Smrg info->tip = (TipWidget)XtCreateWidget("tip", tipWidgetClass, shell, NULL, 0); 5137a84e134Smrg XtRealizeWidget((Widget)info->tip); 5147a84e134Smrg info->widget = NULL; 5157a84e134Smrg info->mapped = False; 5167a84e134Smrg info->next = NULL; 5177a84e134Smrg XtAddEventHandler(shell, KeyPressMask, False, TipShellEventHandler, 5187a84e134Smrg (XtPointer)NULL); 5197a84e134Smrg 5207a84e134Smrg return (info); 5217a84e134Smrg} 5227a84e134Smrg 5237a84e134Smrgstatic XawTipInfo * 5247a84e134SmrgFindTipInfo(Widget w) 5257a84e134Smrg{ 5267a84e134Smrg XawTipInfo *ptip, *tip = first_tip; 5277a84e134Smrg Screen *screen = XtScreenOfObject(w); 5287a84e134Smrg 5297a84e134Smrg if (tip == NULL) 530efbcb2bfSmrg return (first_tip = CreateTipInfo(w)); 5317a84e134Smrg 5327a84e134Smrg for (ptip = tip; tip; ptip = tip, tip = tip->next) 5337a84e134Smrg if (tip->screen == screen) 5347a84e134Smrg return (tip); 5357a84e134Smrg 5367a84e134Smrg return (ptip->next = CreateTipInfo(w)); 5377a84e134Smrg} 5387a84e134Smrg 5397a84e134Smrgstatic void 5407a84e134SmrgResetTip(XawTipInfo *info, Bool add_timeout) 5417a84e134Smrg{ 5427a84e134Smrg if (info->tip->tip.timer) { 5437a84e134Smrg XtRemoveTimeOut(info->tip->tip.timer); 5447a84e134Smrg info->tip->tip.timer = 0; 5457a84e134Smrg } 5467a84e134Smrg if (info->mapped) { 5477a84e134Smrg XtRemoveGrab(XtParent((Widget)info->tip)); 5487a84e134Smrg XUnmapWindow(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip)); 5497a84e134Smrg info->mapped = False; 5507a84e134Smrg } 5517a84e134Smrg if (add_timeout) { 5527a84e134Smrg info->tip->tip.timer = 5537a84e134Smrg XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)info->tip), 5545ec34c4cSmrg (unsigned long)info->tip->tip.timeout, 5555ec34c4cSmrg TipTimeoutCallback, 5567a84e134Smrg (XtPointer)info); 5577a84e134Smrg } 5587a84e134Smrg} 5597a84e134Smrg 5607a84e134Smrgstatic void 5615ec34c4cSmrgTipTimeoutCallback(XtPointer closure, XtIntervalId *id _X_UNUSED) 5627a84e134Smrg{ 5637a84e134Smrg XawTipInfo *info = (XawTipInfo*)closure; 5647a84e134Smrg Arg args[3]; 5657a84e134Smrg 5667a84e134Smrg info->tip->tip.label = NULL; 5677a84e134Smrg info->tip->tip.international = False; 5687a84e134Smrg info->tip->tip.encoding = 0; 569e1e1713cSmrg info->tip->tip.timer = 0; 5707a84e134Smrg XtSetArg(args[0], XtNtip, &info->tip->tip.label); 5717a84e134Smrg XtSetArg(args[1], XtNinternational, &info->tip->tip.international); 5727a84e134Smrg XtSetArg(args[2], XtNencoding, &info->tip->tip.encoding); 5737a84e134Smrg XtGetValues(info->widget, args, 3); 5747a84e134Smrg 5757a84e134Smrg if (info->tip->tip.label) { 5767a84e134Smrg TipLayout(info); 5777a84e134Smrg TipPosition(info); 5787a84e134Smrg XMapRaised(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip)); 5797a84e134Smrg XtAddGrab(XtParent((Widget)info->tip), True, True); 5807a84e134Smrg info->mapped = True; 5817a84e134Smrg } 5827a84e134Smrg} 5837a84e134Smrg 5847a84e134Smrg/*ARGSUSED*/ 5857a84e134Smrgstatic void 5865ec34c4cSmrgTipShellEventHandler(Widget w, XtPointer client_data _X_UNUSED, XEvent *event _X_UNUSED, 5875ec34c4cSmrg Boolean *continue_to_dispatch _X_UNUSED) 5887a84e134Smrg{ 5897a84e134Smrg ResetTip(FindTipInfo(w), False); 5907a84e134Smrg} 5917a84e134Smrg 5927a84e134Smrg/*ARGSUSED*/ 5937a84e134Smrgstatic void 5945ec34c4cSmrgTipEventHandler(Widget w, XtPointer client_data _X_UNUSED, XEvent *event, 5955ec34c4cSmrg Boolean *continue_to_dispatch _X_UNUSED) 5967a84e134Smrg{ 5977a84e134Smrg XawTipInfo *info = FindTipInfo(w); 5987a84e134Smrg Boolean add_timeout; 5997a84e134Smrg 6007a84e134Smrg if (info->widget != w) { 6017a84e134Smrg ResetTip(info, False); 6027a84e134Smrg info->widget = w; 6037a84e134Smrg } 6047a84e134Smrg 6057a84e134Smrg switch (event->type) { 6067a84e134Smrg case EnterNotify: 6077a84e134Smrg add_timeout = True; 6087a84e134Smrg break; 6097a84e134Smrg case MotionNotify: 6107a84e134Smrg /* If any button is pressed, timer is 0 */ 6117a84e134Smrg if (info->mapped) 6127a84e134Smrg return; 6137a84e134Smrg add_timeout = info->tip->tip.timer != 0; 6147a84e134Smrg break; 6157a84e134Smrg default: 6167a84e134Smrg add_timeout = False; 6177a84e134Smrg break; 6187a84e134Smrg } 6197a84e134Smrg ResetTip(info, add_timeout); 6207a84e134Smrg} 6217a84e134Smrg 6227a84e134Smrg/* 6237a84e134Smrg * Public routines 6247a84e134Smrg */ 6257a84e134Smrgvoid 6267a84e134SmrgXawTipEnable(Widget w) 6277a84e134Smrg{ 6287a84e134Smrg XtAddEventHandler(w, TIP_EVENT_MASK, False, TipEventHandler, 6297a84e134Smrg (XtPointer)NULL); 6307a84e134Smrg} 6317a84e134Smrg 6327a84e134Smrgvoid 6337a84e134SmrgXawTipDisable(Widget w) 6347a84e134Smrg{ 6357a84e134Smrg XawTipInfo *info = FindTipInfo(w); 6367a84e134Smrg 6377a84e134Smrg XtRemoveEventHandler(w, TIP_EVENT_MASK, False, TipEventHandler, 6387a84e134Smrg (XtPointer)NULL); 6397a84e134Smrg if (info->widget == w) 6407a84e134Smrg ResetTip(info, False); 6417a84e134Smrg} 642