Tip.c revision 775e7de9
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/* $XFree86: xc/lib/Xaw/Tip.c,v 1.4 1999/07/11 08:49:16 dawes Exp $ */ 317a84e134Smrg 327a84e134Smrg#ifdef HAVE_CONFIG_H 337a84e134Smrg#include <config.h> 347a84e134Smrg#endif 357a84e134Smrg#include <X11/IntrinsicP.h> 367a84e134Smrg#include <X11/StringDefs.h> 377a84e134Smrg#include <X11/Xos.h> 387a84e134Smrg#include <X11/Xaw/TipP.h> 397a84e134Smrg#include <X11/Xaw/XawInit.h> 407a84e134Smrg#include <X11/Xmu/Converters.h> 417a84e134Smrg#include "Private.h" 427a84e134Smrg 437a84e134Smrg#define TIP_EVENT_MASK (ButtonPressMask | \ 447a84e134Smrg ButtonReleaseMask | \ 457a84e134Smrg PointerMotionMask | \ 467a84e134Smrg ButtonMotionMask | \ 477a84e134Smrg KeyPressMask | \ 487a84e134Smrg KeyReleaseMask | \ 497a84e134Smrg EnterWindowMask | \ 507a84e134Smrg LeaveWindowMask) 517a84e134Smrg 527a84e134Smrg/* 537a84e134Smrg * Types 547a84e134Smrg */ 557a84e134Smrgtypedef struct _XawTipInfo { 567a84e134Smrg Screen *screen; 577a84e134Smrg TipWidget tip; 587a84e134Smrg Widget widget; 597a84e134Smrg Bool mapped; 607a84e134Smrg struct _XawTipInfo *next; 617a84e134Smrg} XawTipInfo; 627a84e134Smrg 637a84e134Smrg/* 647a84e134Smrg * Class Methods 657a84e134Smrg */ 667a84e134Smrgstatic void XawTipClassInitialize(void); 677a84e134Smrgstatic void XawTipInitialize(Widget, Widget, ArgList, Cardinal*); 687a84e134Smrgstatic void XawTipDestroy(Widget); 697a84e134Smrgstatic void XawTipExpose(Widget, XEvent*, Region); 707a84e134Smrgstatic void XawTipRealize(Widget, Mask*, XSetWindowAttributes*); 717a84e134Smrgstatic Boolean XawTipSetValues(Widget, Widget, Widget, ArgList, Cardinal*); 727a84e134Smrg 737a84e134Smrg/* 747a84e134Smrg * Prototypes 757a84e134Smrg */ 767a84e134Smrgstatic void TipEventHandler(Widget, XtPointer, XEvent*, Boolean*); 777a84e134Smrgstatic void TipShellEventHandler(Widget, XtPointer, XEvent*, Boolean*); 787a84e134Smrgstatic XawTipInfo *CreateTipInfo(Widget); 797a84e134Smrgstatic XawTipInfo *FindTipInfo(Widget); 807a84e134Smrgstatic void ResetTip(XawTipInfo*, Bool); 817a84e134Smrgstatic void TipTimeoutCallback(XtPointer, XtIntervalId*); 827a84e134Smrgstatic void TipLayout(XawTipInfo*); 837a84e134Smrgstatic void TipPosition(XawTipInfo*); 847a84e134Smrg 857a84e134Smrg/* 867a84e134Smrg * Initialization 877a84e134Smrg */ 887a84e134Smrg#define offset(field) XtOffsetOf(TipRec, tip.field) 897a84e134Smrgstatic XtResource resources[] = { 907a84e134Smrg { 917a84e134Smrg XtNforeground, 927a84e134Smrg XtCForeground, 937a84e134Smrg XtRPixel, 947a84e134Smrg sizeof(Pixel), 957a84e134Smrg offset(foreground), 967a84e134Smrg XtRString, 977a84e134Smrg XtDefaultForeground, 987a84e134Smrg }, 997a84e134Smrg { 1007a84e134Smrg XtNfont, 1017a84e134Smrg XtCFont, 1027a84e134Smrg XtRFontStruct, 1037a84e134Smrg sizeof(XFontStruct*), 1047a84e134Smrg offset(font), 1057a84e134Smrg XtRString, 1067a84e134Smrg XtDefaultFont 1077a84e134Smrg }, 1087a84e134Smrg { 1097a84e134Smrg XtNfontSet, 1107a84e134Smrg XtCFontSet, 1117a84e134Smrg XtRFontSet, 1127a84e134Smrg sizeof(XFontSet), 1137a84e134Smrg offset(fontset), 1147a84e134Smrg XtRString, 1157a84e134Smrg XtDefaultFontSet 1167a84e134Smrg }, 1177a84e134Smrg { 1187a84e134Smrg XtNtopMargin, 1197a84e134Smrg XtCVerticalMargins, 1207a84e134Smrg XtRDimension, 1217a84e134Smrg sizeof(Dimension), 1227a84e134Smrg offset(top_margin), 1237a84e134Smrg XtRImmediate, 1247a84e134Smrg (XtPointer)2 1257a84e134Smrg }, 1267a84e134Smrg { 1277a84e134Smrg XtNbottomMargin, 1287a84e134Smrg XtCVerticalMargins, 1297a84e134Smrg XtRDimension, 1307a84e134Smrg sizeof(Dimension), 1317a84e134Smrg offset(bottom_margin), 1327a84e134Smrg XtRImmediate, 1337a84e134Smrg (XtPointer)2 1347a84e134Smrg }, 1357a84e134Smrg { 1367a84e134Smrg XtNleftMargin, 1377a84e134Smrg XtCHorizontalMargins, 1387a84e134Smrg XtRDimension, 1397a84e134Smrg sizeof(Dimension), 1407a84e134Smrg offset(left_margin), 1417a84e134Smrg XtRImmediate, 1427a84e134Smrg (XtPointer)6 1437a84e134Smrg }, 1447a84e134Smrg { 1457a84e134Smrg XtNrightMargin, 1467a84e134Smrg XtCHorizontalMargins, 1477a84e134Smrg XtRDimension, 1487a84e134Smrg sizeof(Dimension), 1497a84e134Smrg offset(right_margin), 1507a84e134Smrg XtRImmediate, 1517a84e134Smrg (XtPointer)6 1527a84e134Smrg }, 1537a84e134Smrg { 1547a84e134Smrg XtNbackingStore, 1557a84e134Smrg XtCBackingStore, 1567a84e134Smrg XtRBackingStore, 1577a84e134Smrg sizeof(int), 1587a84e134Smrg offset(backing_store), 1597a84e134Smrg XtRImmediate, 1607a84e134Smrg (XtPointer)(Always + WhenMapped + NotUseful) 1617a84e134Smrg }, 1627a84e134Smrg { 1637a84e134Smrg XtNtimeout, 1647a84e134Smrg XtCTimeout, 1657a84e134Smrg XtRInt, 1667a84e134Smrg sizeof(int), 1677a84e134Smrg offset(timeout), 1687a84e134Smrg XtRImmediate, 1697a84e134Smrg (XtPointer)500 1707a84e134Smrg }, 1717a84e134Smrg { 1727a84e134Smrg XawNdisplayList, 1737a84e134Smrg XawCDisplayList, 1747a84e134Smrg XawRDisplayList, 1757a84e134Smrg sizeof(XawDisplayList*), 1767a84e134Smrg offset(display_list), 1777a84e134Smrg XtRImmediate, 1787a84e134Smrg NULL 1797a84e134Smrg }, 1807a84e134Smrg}; 1817a84e134Smrg#undef offset 1827a84e134Smrg 1837a84e134SmrgTipClassRec tipClassRec = { 1847a84e134Smrg /* core */ 1857a84e134Smrg { 1867a84e134Smrg (WidgetClass)&widgetClassRec, /* superclass */ 1877a84e134Smrg "Tip", /* class_name */ 1887a84e134Smrg sizeof(TipRec), /* widget_size */ 1897a84e134Smrg XawTipClassInitialize, /* class_initialize */ 1907a84e134Smrg NULL, /* class_part_initialize */ 1917a84e134Smrg False, /* class_inited */ 1927a84e134Smrg XawTipInitialize, /* initialize */ 1937a84e134Smrg NULL, /* initialize_hook */ 1947a84e134Smrg XawTipRealize, /* realize */ 1957a84e134Smrg NULL, /* actions */ 1967a84e134Smrg 0, /* num_actions */ 1977a84e134Smrg resources, /* resources */ 1987a84e134Smrg XtNumber(resources), /* num_resources */ 1997a84e134Smrg NULLQUARK, /* xrm_class */ 2007a84e134Smrg True, /* compress_motion */ 2017a84e134Smrg True, /* compress_exposure */ 2027a84e134Smrg True, /* compress_enterleave */ 2037a84e134Smrg False, /* visible_interest */ 2047a84e134Smrg XawTipDestroy, /* destroy */ 2057a84e134Smrg NULL, /* resize */ 2067a84e134Smrg XawTipExpose, /* expose */ 2077a84e134Smrg XawTipSetValues, /* set_values */ 2087a84e134Smrg NULL, /* set_values_hook */ 2097a84e134Smrg XtInheritSetValuesAlmost, /* set_values_almost */ 2107a84e134Smrg NULL, /* get_values_hook */ 2117a84e134Smrg NULL, /* accept_focus */ 2127a84e134Smrg XtVersion, /* version */ 2137a84e134Smrg NULL, /* callback_private */ 2147a84e134Smrg NULL, /* tm_table */ 2157a84e134Smrg XtInheritQueryGeometry, /* query_geometry */ 2167a84e134Smrg XtInheritDisplayAccelerator, /* display_accelerator */ 2177a84e134Smrg NULL, /* extension */ 2187a84e134Smrg }, 2197a84e134Smrg /* tip */ 2207a84e134Smrg { 2217a84e134Smrg NULL, /* extension */ 2227a84e134Smrg }, 2237a84e134Smrg}; 2247a84e134Smrg 2257a84e134SmrgWidgetClass tipWidgetClass = (WidgetClass)&tipClassRec; 2267a84e134Smrg 2277a84e134Smrgstatic XawTipInfo *first_tip; 2287a84e134Smrg 2297a84e134Smrg/* 2307a84e134Smrg * Implementation 2317a84e134Smrg */ 2327a84e134Smrgstatic void 2337a84e134SmrgXawTipClassInitialize(void) 2347a84e134Smrg{ 2357a84e134Smrg XawInitializeWidgetSet(); 2367a84e134Smrg XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore, 2377a84e134Smrg NULL, 0); 2387a84e134Smrg XtSetTypeConverter(XtRBackingStore, XtRString, XmuCvtBackingStoreToString, 2397a84e134Smrg NULL, 0, XtCacheNone, NULL); 2407a84e134Smrg} 2417a84e134Smrg 2427a84e134Smrg/*ARGSUSED*/ 2437a84e134Smrgstatic void 2447a84e134SmrgXawTipInitialize(Widget req, Widget w, ArgList args, Cardinal *num_args) 2457a84e134Smrg{ 2467a84e134Smrg TipWidget tip = (TipWidget)w; 2477a84e134Smrg XGCValues values; 2487a84e134Smrg 2497a84e134Smrg if (!tip->tip.font) XtError("Aborting: no font found\n"); 2507a84e134Smrg if (tip->tip.international && !tip->tip.fontset) 2517a84e134Smrg XtError("Aborting: no fontset found\n"); 2527a84e134Smrg 2537a84e134Smrg tip->tip.timer = 0; 2547a84e134Smrg 2557a84e134Smrg values.foreground = tip->tip.foreground; 2567a84e134Smrg values.background = tip->core.background_pixel; 2577a84e134Smrg values.font = tip->tip.font->fid; 2587a84e134Smrg values.graphics_exposures = False; 2597a84e134Smrg 2607a84e134Smrg tip->tip.gc = XtAllocateGC(w, 0, GCForeground | GCBackground | GCFont | 2617a84e134Smrg GCGraphicsExposures, &values, GCFont, 0); 2627a84e134Smrg} 2637a84e134Smrg 2647a84e134Smrgstatic void 2657a84e134SmrgXawTipDestroy(Widget w) 2667a84e134Smrg{ 2677a84e134Smrg XawTipInfo *info = FindTipInfo(w); 2687a84e134Smrg TipWidget tip = (TipWidget)w; 2697a84e134Smrg 2707a84e134Smrg if (tip->tip.timer) 2717a84e134Smrg XtRemoveTimeOut(tip->tip.timer); 2727a84e134Smrg 2737a84e134Smrg XtReleaseGC(w, tip->tip.gc); 2747a84e134Smrg 2757a84e134Smrg XtRemoveEventHandler(XtParent(w), KeyPressMask, False, TipShellEventHandler, 2767a84e134Smrg (XtPointer)NULL); 2777a84e134Smrg if (info == first_tip) 2787a84e134Smrg first_tip = first_tip->next; 2797a84e134Smrg else { 2807a84e134Smrg XawTipInfo *p = first_tip; 2817a84e134Smrg 2827a84e134Smrg while (p && p->next != info) 2837a84e134Smrg p = p->next; 2847a84e134Smrg if (p) 2857a84e134Smrg p->next = info->next; 2867a84e134Smrg } 2877a84e134Smrg XtFree((char*)info); 2887a84e134Smrg} 2897a84e134Smrg 2907a84e134Smrgstatic void 2917a84e134SmrgXawTipRealize(Widget w, Mask *mask, XSetWindowAttributes *attr) 2927a84e134Smrg{ 2937a84e134Smrg TipWidget tip = (TipWidget)w; 2947a84e134Smrg 2957a84e134Smrg if (tip->tip.backing_store == Always || 2967a84e134Smrg tip->tip.backing_store == NotUseful || 2977a84e134Smrg tip->tip.backing_store == WhenMapped) { 2987a84e134Smrg *mask |= CWBackingStore; 2997a84e134Smrg attr->backing_store = tip->tip.backing_store; 3007a84e134Smrg } 3017a84e134Smrg else 3027a84e134Smrg *mask &= ~CWBackingStore; 3037a84e134Smrg *mask |= CWOverrideRedirect; 3047a84e134Smrg attr->override_redirect = True; 3057a84e134Smrg 3067a84e134Smrg XtWindow(w) = XCreateWindow(DisplayOfScreen(XtScreen(w)), 3077a84e134Smrg RootWindowOfScreen(XtScreen(w)), 3087a84e134Smrg XtX(w), XtY(w), 3097a84e134Smrg XtWidth(w) ? XtWidth(w) : 1, 3107a84e134Smrg XtHeight(w) ? XtHeight(w) : 1, 3117a84e134Smrg XtBorderWidth(w), 3127a84e134Smrg DefaultDepthOfScreen(XtScreen(w)), 3137a84e134Smrg InputOutput, 314775e7de9Smrg (Visual *)CopyFromParent, 3157a84e134Smrg *mask, attr); 3167a84e134Smrg} 3177a84e134Smrg 3187a84e134Smrgstatic void 3197a84e134SmrgXawTipExpose(Widget w, XEvent *event, Region region) 3207a84e134Smrg{ 3217a84e134Smrg TipWidget tip = (TipWidget)w; 3227a84e134Smrg GC gc = tip->tip.gc; 3237a84e134Smrg char *nl, *label = tip->tip.label; 3247a84e134Smrg Position y = tip->tip.top_margin + tip->tip.font->max_bounds.ascent; 3257a84e134Smrg int len; 3267a84e134Smrg 3277a84e134Smrg if (tip->tip.display_list) 3287a84e134Smrg XawRunDisplayList(w, tip->tip.display_list, event, region); 3297a84e134Smrg 3307a84e134Smrg if (tip->tip.international == True) { 3317a84e134Smrg Position ksy = tip->tip.top_margin; 3327a84e134Smrg XFontSetExtents *ext = XExtentsOfFontSet(tip->tip.fontset); 3337a84e134Smrg 3347a84e134Smrg ksy += XawAbs(ext->max_ink_extent.y); 3357a84e134Smrg 3367a84e134Smrg while ((nl = index(label, '\n')) != NULL) { 3377a84e134Smrg XmbDrawString(XtDisplay(w), XtWindow(w), tip->tip.fontset, 3387a84e134Smrg gc, tip->tip.left_margin, ksy, label, 3397a84e134Smrg (int)(nl - label)); 3407a84e134Smrg ksy += ext->max_ink_extent.height; 3417a84e134Smrg label = nl + 1; 3427a84e134Smrg } 3437a84e134Smrg len = strlen(label); 3447a84e134Smrg if (len) 3457a84e134Smrg XmbDrawString(XtDisplay(w), XtWindow(w), tip->tip.fontset, gc, 3467a84e134Smrg tip->tip.left_margin, ksy, label, len); 3477a84e134Smrg } 3487a84e134Smrg else { 3497a84e134Smrg while ((nl = index(label, '\n')) != NULL) { 3507a84e134Smrg if (tip->tip.encoding) 3517a84e134Smrg XDrawString16(XtDisplay(w), XtWindow(w), gc, 3527a84e134Smrg tip->tip.left_margin, y, 3537a84e134Smrg (XChar2b*)label, (int)(nl - label) >> 1); 3547a84e134Smrg else 3557a84e134Smrg XDrawString(XtDisplay(w), XtWindow(w), gc, 3567a84e134Smrg tip->tip.left_margin, y, label, (int)(nl - label)); 3577a84e134Smrg y += tip->tip.font->max_bounds.ascent + 3587a84e134Smrg tip->tip.font->max_bounds.descent; 3597a84e134Smrg label = nl + 1; 3607a84e134Smrg } 3617a84e134Smrg len = strlen(label); 3627a84e134Smrg if (len) { 3637a84e134Smrg if (tip->tip.encoding) 3647a84e134Smrg XDrawString16(XtDisplay(w), XtWindow(w), gc, 3657a84e134Smrg tip->tip.left_margin, y, (XChar2b*)label, len >> 1); 3667a84e134Smrg else 3677a84e134Smrg XDrawString(XtDisplay(w), XtWindow(w), gc, 3687a84e134Smrg tip->tip.left_margin, y, label, len); 3697a84e134Smrg } 3707a84e134Smrg } 3717a84e134Smrg} 3727a84e134Smrg 3737a84e134Smrg/*ARGSUSED*/ 3747a84e134Smrgstatic Boolean 3757a84e134SmrgXawTipSetValues(Widget current, Widget request, Widget cnew, 3767a84e134Smrg ArgList args, Cardinal *num_args) 3777a84e134Smrg{ 3787a84e134Smrg TipWidget curtip = (TipWidget)current; 3797a84e134Smrg TipWidget newtip = (TipWidget)cnew; 3807a84e134Smrg Boolean redisplay = False; 3817a84e134Smrg 3827a84e134Smrg if (curtip->tip.font->fid != newtip->tip.font->fid || 3837a84e134Smrg curtip->tip.foreground != newtip->tip.foreground) { 3847a84e134Smrg XGCValues values; 3857a84e134Smrg 3867a84e134Smrg values.foreground = newtip->tip.foreground; 3877a84e134Smrg values.background = newtip->core.background_pixel; 3887a84e134Smrg values.font = newtip->tip.font->fid; 3897a84e134Smrg values.graphics_exposures = False; 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; 4077a84e134Smrg char *nl, *label = info->tip->tip.label; 4087a84e134Smrg 4097a84e134Smrg if (info->tip->tip.international == True) { 4107a84e134Smrg XFontSet fset = info->tip->tip.fontset; 4117a84e134Smrg XFontSetExtents *ext = XExtentsOfFontSet(fset); 4127a84e134Smrg 4137a84e134Smrg height = ext->max_ink_extent.height; 4147a84e134Smrg if ((nl = index(label, '\n')) != NULL) { 4157a84e134Smrg /*CONSTCOND*/ 4167a84e134Smrg while (True) { 4177a84e134Smrg int w = XmbTextEscapement(fset, label, (int)(nl - label)); 4187a84e134Smrg 4197a84e134Smrg if (w > width) 4207a84e134Smrg width = w; 4217a84e134Smrg if (*nl == '\0') 4227a84e134Smrg break; 4237a84e134Smrg label = nl + 1; 4247a84e134Smrg if (*label) 4257a84e134Smrg height += ext->max_ink_extent.height; 4267a84e134Smrg if ((nl = index(label, '\n')) == NULL) 4277a84e134Smrg nl = index(label, '\0'); 4287a84e134Smrg } 4297a84e134Smrg } 4307a84e134Smrg else 4317a84e134Smrg width = XmbTextEscapement(fset, label, strlen(label)); 4327a84e134Smrg } 4337a84e134Smrg else { 4347a84e134Smrg height = fs->max_bounds.ascent + fs->max_bounds.descent; 4357a84e134Smrg if ((nl = index(label, '\n')) != NULL) { 4367a84e134Smrg /*CONSTCOND*/ 4377a84e134Smrg while (True) { 4387a84e134Smrg int w = info->tip->tip.encoding ? 4397a84e134Smrg XTextWidth16(fs, (XChar2b*)label, (int)(nl - label) >> 1) : 4407a84e134Smrg XTextWidth(fs, label, (int)(nl - label)); 4417a84e134Smrg if (w > width) 4427a84e134Smrg width = w; 4437a84e134Smrg if (*nl == '\0') 4447a84e134Smrg break; 4457a84e134Smrg label = nl + 1; 4467a84e134Smrg if (*label) 4477a84e134Smrg height += fs->max_bounds.ascent + fs->max_bounds.descent; 4487a84e134Smrg if ((nl = index(label, '\n')) == NULL) 4497a84e134Smrg nl = index(label, '\0'); 4507a84e134Smrg } 4517a84e134Smrg } 4527a84e134Smrg else 4537a84e134Smrg width = info->tip->tip.encoding ? 4547a84e134Smrg XTextWidth16(fs, (XChar2b*)label, strlen(label) >> 1) : 4557a84e134Smrg XTextWidth(fs, label, strlen(label)); 4567a84e134Smrg } 4577a84e134Smrg XtWidth(info->tip) = width + info->tip->tip.left_margin + 4587a84e134Smrg info->tip->tip.right_margin; 4597a84e134Smrg XtHeight(info->tip) = height + info->tip->tip.top_margin + 4607a84e134Smrg info->tip->tip.bottom_margin; 4617a84e134Smrg} 4627a84e134Smrg 4637a84e134Smrg#define DEFAULT_TIP_Y_OFFSET 12 4647a84e134Smrgstatic void 4657a84e134SmrgTipPosition(XawTipInfo *info) 4667a84e134Smrg{ 4677a84e134Smrg Window r, c; 4687a84e134Smrg int rx, ry, wx, wy; 4697a84e134Smrg unsigned mask; 4707a84e134Smrg Position x, y; 4717a84e134Smrg 4727a84e134Smrg XQueryPointer(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip), 4737a84e134Smrg &r, &c, &rx, &ry, &wx, &wy, &mask); 4747a84e134Smrg x = rx - (XtWidth(info->tip) >> 1); 4757a84e134Smrg y = ry + DEFAULT_TIP_Y_OFFSET; 4767a84e134Smrg 4777a84e134Smrg if (x >= 0) { 4787a84e134Smrg int scr_width = WidthOfScreen(XtScreen(info->tip)); 4797a84e134Smrg 4807a84e134Smrg if (x + XtWidth(info->tip) + XtBorderWidth(info->tip) > scr_width) 4817a84e134Smrg x = scr_width - XtWidth(info->tip) - XtBorderWidth(info->tip); 4827a84e134Smrg } 4837a84e134Smrg if (x < 0) 4847a84e134Smrg x = 0; 4857a84e134Smrg if (y >= 0) { 4867a84e134Smrg int scr_height = HeightOfScreen(XtScreen(info->tip)); 4877a84e134Smrg 4887a84e134Smrg if (y + XtHeight(info->tip) + XtBorderWidth(info->tip) > scr_height) 4897a84e134Smrg y -= XtHeight(info->tip) + XtBorderWidth(info->tip) + 4907a84e134Smrg (DEFAULT_TIP_Y_OFFSET << 1); 4917a84e134Smrg } 4927a84e134Smrg if (y < 0) 4937a84e134Smrg y = 0; 4947a84e134Smrg 4957a84e134Smrg XMoveResizeWindow(XtDisplay(info->tip), XtWindow(info->tip), 4967a84e134Smrg (int)(XtX(info->tip) = x), (int)(XtY(info->tip) = y), 4977a84e134Smrg (unsigned)XtWidth(info->tip), (unsigned)XtHeight(info->tip)); 4987a84e134Smrg} 4997a84e134Smrg 5007a84e134Smrgstatic XawTipInfo * 5017a84e134SmrgCreateTipInfo(Widget w) 5027a84e134Smrg{ 5037a84e134Smrg XawTipInfo *info = XtNew(XawTipInfo); 5047a84e134Smrg Widget shell = w; 5057a84e134Smrg 5067a84e134Smrg info->screen = XtScreen(w); 5077a84e134Smrg 5087a84e134Smrg while (XtParent(shell)) 5097a84e134Smrg shell = XtParent(shell); 5107a84e134Smrg 5117a84e134Smrg info->tip = (TipWidget)XtCreateWidget("tip", tipWidgetClass, shell, NULL, 0); 5127a84e134Smrg XtRealizeWidget((Widget)info->tip); 5137a84e134Smrg info->widget = NULL; 5147a84e134Smrg info->mapped = False; 5157a84e134Smrg info->next = NULL; 5167a84e134Smrg XtAddEventHandler(shell, KeyPressMask, False, TipShellEventHandler, 5177a84e134Smrg (XtPointer)NULL); 5187a84e134Smrg 5197a84e134Smrg return (info); 5207a84e134Smrg} 5217a84e134Smrg 5227a84e134Smrgstatic XawTipInfo * 5237a84e134SmrgFindTipInfo(Widget w) 5247a84e134Smrg{ 5257a84e134Smrg XawTipInfo *ptip, *tip = first_tip; 5267a84e134Smrg Screen *screen = XtScreenOfObject(w); 5277a84e134Smrg 5287a84e134Smrg if (tip == NULL) 5297a84e134Smrg return (first_tip = tip = CreateTipInfo(w)); 5307a84e134Smrg 5317a84e134Smrg for (ptip = tip; tip; ptip = tip, tip = tip->next) 5327a84e134Smrg if (tip->screen == screen) 5337a84e134Smrg return (tip); 5347a84e134Smrg 5357a84e134Smrg return (ptip->next = CreateTipInfo(w)); 5367a84e134Smrg} 5377a84e134Smrg 5387a84e134Smrgstatic void 5397a84e134SmrgResetTip(XawTipInfo *info, Bool add_timeout) 5407a84e134Smrg{ 5417a84e134Smrg if (info->tip->tip.timer) { 5427a84e134Smrg XtRemoveTimeOut(info->tip->tip.timer); 5437a84e134Smrg info->tip->tip.timer = 0; 5447a84e134Smrg } 5457a84e134Smrg if (info->mapped) { 5467a84e134Smrg XtRemoveGrab(XtParent((Widget)info->tip)); 5477a84e134Smrg XUnmapWindow(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip)); 5487a84e134Smrg info->mapped = False; 5497a84e134Smrg } 5507a84e134Smrg if (add_timeout) { 5517a84e134Smrg info->tip->tip.timer = 5527a84e134Smrg XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)info->tip), 5537a84e134Smrg info->tip->tip.timeout, TipTimeoutCallback, 5547a84e134Smrg (XtPointer)info); 5557a84e134Smrg } 5567a84e134Smrg} 5577a84e134Smrg 5587a84e134Smrgstatic void 5597a84e134SmrgTipTimeoutCallback(XtPointer closure, XtIntervalId *id) 5607a84e134Smrg{ 5617a84e134Smrg XawTipInfo *info = (XawTipInfo*)closure; 5627a84e134Smrg Arg args[3]; 5637a84e134Smrg 5647a84e134Smrg info->tip->tip.label = NULL; 5657a84e134Smrg info->tip->tip.international = False; 5667a84e134Smrg info->tip->tip.encoding = 0; 5677a84e134Smrg XtSetArg(args[0], XtNtip, &info->tip->tip.label); 5687a84e134Smrg XtSetArg(args[1], XtNinternational, &info->tip->tip.international); 5697a84e134Smrg XtSetArg(args[2], XtNencoding, &info->tip->tip.encoding); 5707a84e134Smrg XtGetValues(info->widget, args, 3); 5717a84e134Smrg 5727a84e134Smrg if (info->tip->tip.label) { 5737a84e134Smrg TipLayout(info); 5747a84e134Smrg TipPosition(info); 5757a84e134Smrg XMapRaised(XtDisplay((Widget)info->tip), XtWindow((Widget)info->tip)); 5767a84e134Smrg XtAddGrab(XtParent((Widget)info->tip), True, True); 5777a84e134Smrg info->mapped = True; 5787a84e134Smrg } 5797a84e134Smrg} 5807a84e134Smrg 5817a84e134Smrg/*ARGSUSED*/ 5827a84e134Smrgstatic void 5837a84e134SmrgTipShellEventHandler(Widget w, XtPointer client_data, XEvent *event, 5847a84e134Smrg Boolean *continue_to_dispatch) 5857a84e134Smrg{ 5867a84e134Smrg ResetTip(FindTipInfo(w), False); 5877a84e134Smrg} 5887a84e134Smrg 5897a84e134Smrg/*ARGSUSED*/ 5907a84e134Smrgstatic void 5917a84e134SmrgTipEventHandler(Widget w, XtPointer client_data, XEvent *event, 5927a84e134Smrg Boolean *continue_to_dispatch) 5937a84e134Smrg{ 5947a84e134Smrg XawTipInfo *info = FindTipInfo(w); 5957a84e134Smrg Boolean add_timeout; 5967a84e134Smrg 5977a84e134Smrg if (info->widget != w) { 5987a84e134Smrg ResetTip(info, False); 5997a84e134Smrg info->widget = w; 6007a84e134Smrg } 6017a84e134Smrg 6027a84e134Smrg switch (event->type) { 6037a84e134Smrg case EnterNotify: 6047a84e134Smrg add_timeout = True; 6057a84e134Smrg break; 6067a84e134Smrg case MotionNotify: 6077a84e134Smrg /* If any button is pressed, timer is 0 */ 6087a84e134Smrg if (info->mapped) 6097a84e134Smrg return; 6107a84e134Smrg add_timeout = info->tip->tip.timer != 0; 6117a84e134Smrg break; 6127a84e134Smrg default: 6137a84e134Smrg add_timeout = False; 6147a84e134Smrg break; 6157a84e134Smrg } 6167a84e134Smrg ResetTip(info, add_timeout); 6177a84e134Smrg} 6187a84e134Smrg 6197a84e134Smrg/* 6207a84e134Smrg * Public routines 6217a84e134Smrg */ 6227a84e134Smrgvoid 6237a84e134SmrgXawTipEnable(Widget w) 6247a84e134Smrg{ 6257a84e134Smrg XtAddEventHandler(w, TIP_EVENT_MASK, False, TipEventHandler, 6267a84e134Smrg (XtPointer)NULL); 6277a84e134Smrg} 6287a84e134Smrg 6297a84e134Smrgvoid 6307a84e134SmrgXawTipDisable(Widget w) 6317a84e134Smrg{ 6327a84e134Smrg XawTipInfo *info = FindTipInfo(w); 6337a84e134Smrg 6347a84e134Smrg XtRemoveEventHandler(w, TIP_EVENT_MASK, False, TipEventHandler, 6357a84e134Smrg (XtPointer)NULL); 6367a84e134Smrg if (info->widget == w) 6377a84e134Smrg ResetTip(info, False); 6387a84e134Smrg} 639