chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / tooltips.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2009 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "E.h"
25 #include "aclass.h"
26 #include "conf.h"
27 #include "dialog.h"
28 #include "e16-ecore_list.h"
29 #include "emodule.h"
30 #include "eobj.h"
31 #include "iclass.h"
32 #include "settings.h"
33 #include "tclass.h"
34 #include "timers.h"
35 #include "tooltips.h"
36 #include "xwin.h"
37
38 static Ecore_List  *tt_list = NULL;
39 static Timer       *tt_timer = NULL;
40
41 static struct {
42    char                enable;
43    char                showroottooltip;
44    int                 delay;   /* milliseconds */
45 } Conf_tooltips;
46
47 static struct {
48    int                 inhibit;
49    char                root_motion_mask_set;
50    CB_GetAclass       *ac_func;
51    void               *ac_data;
52 } Mode_tooltips;
53
54 struct _tooltip {
55    const char         *name;
56    ImageClass         *iclass[5];
57    TextClass          *tclass;
58    int                 dist;
59    Win                 iwin;
60    EObj               *win[5];
61    char                visible;
62    ImageClass         *tooltippic;
63    unsigned int        ref_count;
64 };
65
66 #define TTWIN win[4]
67 #define TTICL iclass[4]
68
69 static void
70 TooltipRealize(ToolTip * tt)
71 {
72    int                 i, wh;
73    EObj               *eo;
74
75    for (i = 0; i < 5; i++)
76      {
77         if (!tt->iclass[i])
78            continue;
79
80         wh = (i + 1) * 8;
81         eo = EobjWindowCreate(EOBJ_TYPE_MISC, -50, -100, wh, wh, 1, tt->name);
82         eo->fade = eo->shadow = 1;
83         EobjChangeOpacity(eo, OpacityFromPercent(Conf.opacity.tooltips));
84         tt->win[i] = eo;
85      }
86    tt->iwin = ECreateWindow(EobjGetWin(tt->TTWIN), 0, 0, 1, 1, 0);
87 }
88
89 static ToolTip     *
90 TooltipCreate(const char *name, const char *ic0, const char *ic1,
91               const char *ic2, const char *ic3, const char *ic4,
92               const char *tclass, int dist, const char *tooltippic)
93 {
94    ToolTip            *tt;
95    ImageClass         *ic;
96
97    if (ic0 == NULL || tclass == NULL)
98       return NULL;
99
100    ic = ImageclassAlloc(ic0, 0);
101    if (!ic)
102       return NULL;
103
104    tt = ECALLOC(ToolTip, 1);
105    if (!tt)
106       return NULL;
107
108    tt->name = Estrdup(name);
109    tt->iclass[0] = ImageclassAlloc(ic1, 0);
110    tt->iclass[1] = ImageclassAlloc(ic2, 0);
111    tt->iclass[2] = ImageclassAlloc(ic3, 0);
112    tt->iclass[3] = ImageclassAlloc(ic4, 0);
113    tt->iclass[4] = ic;
114    tt->tclass = TextclassAlloc(tclass, 1);
115    tt->tooltippic = ImageclassAlloc(tooltippic, 0);
116
117    tt->dist = dist;
118
119    if (!tt_list)
120       tt_list = ecore_list_new();
121    ecore_list_prepend(tt_list, tt);
122
123    return tt;
124 }
125
126 #if 0                           /* Not used */
127 static void
128 TooltipDestroy(ToolTip * tt)
129 {
130    if (!tt)
131       return;
132
133    if (tt->ref_count > 0)
134      {
135         DialogOK("ToolTip Error!", _("%u references remain\n"), tt->ref_count);
136      }
137 }
138 #endif
139
140 int
141 TooltipConfigLoad(FILE * fs)
142 {
143    int                 err = 0;
144    char                s[FILEPATH_LEN_MAX];
145    char                s2[FILEPATH_LEN_MAX];
146    char                name[64];
147    char                iclass[64];
148    char                bubble1[64], bubble2[64], bubble3[64], bubble4[64];
149    char                tclass[64];
150    char                tooltiphelppic[64];
151    int                 i1;
152    int                 distance = 0;
153
154    name[0] = iclass[0] = tclass[0] = '\0';
155    bubble1[0] = bubble2[0] = bubble3[0] = bubble4[0] = '\0';
156    tooltiphelppic[0] = '\0';
157
158    while (GetLine(s, sizeof(s), fs))
159      {
160         i1 = ConfigParseline1(s, s2, NULL, NULL);
161         switch (i1)
162           {
163           case CONFIG_CLOSE:
164              if (iclass[0] && tclass[0] && name[0])
165                 TooltipCreate(name, iclass, bubble1, bubble2,
166                               bubble3, bubble4, tclass, distance,
167                               tooltiphelppic);
168              goto done;
169
170           case CONFIG_CLASSNAME:
171              if (TooltipFind(s2))
172                {
173                   SkipTillEnd(fs);
174                   goto done;
175                }
176              STRCPY(name, s2);
177              break;
178           case TOOLTIP_DRAWICLASS:
179           case CONFIG_IMAGECLASS:
180              STRCPY(iclass, s2);
181              break;
182           case TOOLTIP_BUBBLE1:
183              STRCPY(bubble1, s2);
184              break;
185           case TOOLTIP_BUBBLE2:
186              STRCPY(bubble2, s2);
187              break;
188           case TOOLTIP_BUBBLE3:
189              STRCPY(bubble3, s2);
190              break;
191           case TOOLTIP_BUBBLE4:
192              STRCPY(bubble4, s2);
193              break;
194           case CONFIG_TEXT:
195              STRCPY(tclass, s2);
196              break;
197           case TOOLTIP_DISTANCE:
198              distance = atoi(s2);
199              break;
200           case TOOLTIP_HELP_PIC:
201              STRCPY(tooltiphelppic, s2);
202              break;
203           default:
204              ConfigParseError("ToolTip", s);
205              break;
206           }
207      }
208    err = -1;
209
210  done:
211    return err;
212 }
213
214 static ImageClass  *
215 TooltipCreateIclass(const char *name, const char *file, int *pw, int *ph)
216 {
217    ImageClass         *ic;
218    EImage             *im;
219    int                 w, h;
220
221    ic = ImageclassFind(name, 0);
222    if (!ic)
223       ic = ImageclassCreateSimple(name, file);
224    im = ImageclassGetImage(ic, 0, 0, 0);
225
226    if (im)
227      {
228         EImageGetSize(im, &w, &h);
229         if (*pw < w)
230            *pw = w;
231         if (*ph < h)
232            *ph = h;
233      }
234
235    return ic;
236 }
237
238 static void
239 TooltipIclassPaste(ToolTip * tt, const char *ic_name, int x, int y, int *px)
240 {
241    ImageClass         *ic;
242    EImage             *im;
243    int                 w, h;
244
245    ic = ImageclassFind(ic_name, 0);
246    im = ImageclassGetImage(ic, 0, 0, 0);
247    if (!ic || !im)
248       return;
249
250    EImageGetSize(im, &w, &h);
251    EImageRenderOnDrawable(im, EobjGetWin(tt->TTWIN), None, EIMAGE_BLEND, x, y,
252                           w, h);
253
254    *px = x + w;
255 }
256
257 void
258 TooltipShow(ToolTip * tt, const char *text, ActionClass * ac, int x, int y)
259 {
260    int                 i, w, h, ix, iy, iw, ih, dx, dy, xx, yy;
261    int                 ww, hh, adx, ady, dist;
262    int                 headline_h = 0, headline_w = 0, icons_width =
263       0, labels_width = 0, double_w = 0;
264    EImage             *im;
265    int                *heights = NULL;
266    ImageClass         *ic;
267    EImageBorder       *pad;
268    int                 cols[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
269    int                 num, modifiers;
270    Action             *aa;
271    const char         *tts;
272    EObj               *eo;
273
274    if (!tt || Mode.mode != MODE_NONE)
275       return;
276
277    if (!tt->TTWIN)
278      {
279         TooltipRealize(tt);
280         if (!tt->TTWIN)
281            return;
282      }
283
284    /* if we get an actionclass, look for tooltip action texts */
285    h = 0;
286    if (ac)
287      {
288         num = ActionclassGetActionCount(ac);
289         heights = EMALLOC(int, num);
290
291         for (i = 0; i < num; i++)
292           {
293              int                 temp_w, temp_h;
294
295              temp_w = 0;
296              temp_h = 0;
297
298              aa = ActionclassGetAction(ac, i);
299              if (!aa)
300                 continue;
301
302              tts = ActionGetTooltipString(aa);
303              if (!tts)
304                 continue;
305              tts = _(tts);
306
307              TextSize(tt->tclass, 0, 0, STATE_NORMAL, tts, &temp_w, &temp_h,
308                       17);
309              if (temp_w > labels_width)
310                 labels_width = temp_w;
311              temp_w = 0;
312
313              if (ActionGetEvent(aa) == EVENT_DOUBLE_DOWN)
314                {
315                   TextSize(tt->tclass, 0, 0, STATE_NORMAL, "2x", &double_w,
316                            &temp_h, 17);
317                   if (cols[0] < double_w)
318                      cols[0] = double_w;
319                }
320
321              if (ActionGetAnybutton(aa))
322                {
323                   TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_ANY",
324                                       "pix/mouse_any.png", &cols[1], &temp_h);
325                }
326              else
327                 switch (ActionGetButton(aa))
328                   {
329                   case 1:
330                      ic = TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_1",
331                                               "pix/mouse_1.png", &cols[1],
332                                               &temp_h);
333                      break;
334                   case 2:
335                      ic = TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_2",
336                                               "pix/mouse_2.png", &cols[1],
337                                               &temp_h);
338                      break;
339                   case 3:
340                      ic = TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_3",
341                                               "pix/mouse_3.png", &cols[1],
342                                               &temp_h);
343                      break;
344                   case 4:
345                      ic = TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_4",
346                                               "pix/mouse_4.png", &cols[1],
347                                               &temp_h);
348                      break;
349                   case 5:
350                      ic = TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_5",
351                                               "pix/mouse_5.png", &cols[1],
352                                               &temp_h);
353                      break;
354                   case 0:
355                   default:
356                      break;
357                   }
358
359              modifiers = ActionGetModifiers(aa);
360              if (modifiers)
361                {
362                   if (modifiers & ShiftMask)
363                      ic = TooltipCreateIclass("TOOLTIP_KEY_SHIFT",
364                                               "pix/key_shift.png",
365                                               &cols[2], &temp_h);
366                   if (modifiers & LockMask)
367                      ic = TooltipCreateIclass("TOOLTIP_KEY_LOCK",
368                                               "pix/key_lock.png",
369                                               &cols[3], &temp_h);
370                   if (modifiers & ControlMask)
371                      ic = TooltipCreateIclass("TOOLTIP_KEY_CTRL",
372                                               "pix/key_ctrl.png",
373                                               &cols[4], &temp_h);
374                   if (modifiers & Mod1Mask)
375                      ic = TooltipCreateIclass("TOOLTIP_KEY_MOD1",
376                                               "pix/key_mod1.png",
377                                               &cols[5], &temp_h);
378                   if (modifiers & Mod2Mask)
379                      ic = TooltipCreateIclass("TOOLTIP_KEY_MOD2",
380                                               "pix/key_mod2.png",
381                                               &cols[6], &temp_h);
382                   if (modifiers & Mod3Mask)
383                      ic = TooltipCreateIclass("TOOLTIP_KEY_MOD3",
384                                               "pix/key_mod3.png",
385                                               &cols[7], &temp_h);
386                   if (modifiers & Mod4Mask)
387                      ic = TooltipCreateIclass("TOOLTIP_KEY_MOD4",
388                                               "pix/key_mod4.png",
389                                               &cols[8], &temp_h);
390                   if (modifiers & Mod5Mask)
391                      ic = TooltipCreateIclass("TOOLTIP_KEY_MOD5",
392                                               "pix/key_mod5.png",
393                                               &cols[9], &temp_h);
394                }
395
396              temp_w = cols[0] + cols[1] + cols[2] + cols[3] + cols[4] +
397                 cols[5] + cols[6] + cols[7] + cols[8] + cols[9];
398
399              if (temp_w > icons_width)
400                 icons_width = temp_w;
401              heights[i] = temp_h;
402              h += temp_h;
403           }
404      }
405
406    TextSize(tt->tclass, 0, 0, STATE_NORMAL, text, &headline_w, &headline_h, 17);
407    if (headline_w < icons_width + labels_width)
408       w = icons_width + labels_width;
409    else
410       w = headline_w;
411    h += headline_h;
412
413    ic = tt->TTICL;
414    pad = ImageclassGetPadding(ic);
415    iw = 0;
416    ih = 0;
417    if (tt->tooltippic)
418      {
419         im = ImageclassGetImage(tt->tooltippic, 0, 0, 0);
420         ix = 0;
421         iy = 0;
422         if (im)
423           {
424              EImageGetSize(im, &iw, &ih);
425              EImageFree(im);
426           }
427         w += iw;
428         if (h < ih)
429            h = ih;
430      }
431    w += pad->left + pad->right;
432    h += pad->top + pad->bottom;
433
434    if ((tt->tooltippic) && (iw > 0) && (ih > 0))
435      {
436         ix = pad->left;
437         iy = (h - ih) / 2;
438         EMoveResizeWindow(tt->iwin, ix, iy, iw, ih);
439         EMapWindow(tt->iwin);
440         ImageclassApply(tt->tooltippic, tt->iwin, 0, 0, STATE_NORMAL, ST_SOLID);
441      }
442    else
443       EUnmapWindow(tt->iwin);
444
445    dx = x - WinGetW(VROOT) / 2;
446    dy = y - WinGetH(VROOT) / 2;
447
448    if ((dy == 0) && (dx == 0))
449       dy = -1;
450
451    adx = dx;
452    if (adx < 0)
453       adx = -adx;
454    ady = dy;
455    if (ady < 0)
456       ady = -ady;
457    if (adx < ady)
458       /*   +-------+   */
459       /*   |\#####/|   */
460       /*   | \###/ |   */
461       /*   |  \#/  |   */
462       /*   |  /#\  |   */
463       /*   | /###\ |   */
464       /*   |/#####\|   */
465       /*   +-------+   */
466      {
467         if (dy == 0)
468           {
469              dy = 1;
470              ady = 1;
471           }
472         dist = tt->dist;
473         ady = ady / dy;
474
475         if (tt->win[0])
476           {
477              yy = y - ((ady * 10 * dist) / 100);
478              xx = x - (dist * 10 * dx) / (100 * WinGetW(VROOT) / 2);
479              EobjMove(tt->win[0], xx - 4, yy - 4);
480           }
481
482         if (tt->win[1])
483           {
484              yy = y - ((ady * 30 * dist) / 100);
485              xx = x - (dist * 30 * dx) / (100 * WinGetW(VROOT) / 2);
486              EobjMove(tt->win[1], xx - 8, yy - 8);
487           }
488
489         if (tt->win[2])
490           {
491              yy = y - ((ady * 50 * dist) / 100);
492              xx = x - (dist * 50 * dx) / (100 * WinGetW(VROOT) / 2);
493              EobjMove(tt->win[2], xx - 12, yy - 12);
494           }
495
496         if (tt->win[3])
497           {
498              yy = y - ((ady * 80 * dist) / 100);
499              xx = x - (dist * 80 * dx) / (100 * WinGetW(VROOT) / 2);
500              EobjMove(tt->win[3], xx - 16, yy - 16);
501           }
502
503         yy = y - ((ady * 100 * dist) / 100);
504         xx = x - (dist * 100 * dx) / (100 * WinGetW(VROOT) / 2);
505         if (ady < 0)
506            hh = 0;
507         else
508            hh = h;
509         ww = (w / 2) + ((dx * w) / (WinGetW(VROOT) / 2));
510      }
511    else
512       /*   +-------+   */
513       /*   |\     /|   */
514       /*   |#\   /#|   */
515       /*   |##\ /##|   */
516       /*   |##/ \##|   */
517       /*   |#/   \#|   */
518       /*   |/     \|   */
519       /*   +-------+   */
520      {
521         if (dx == 0)
522           {
523              dx = 1;
524              adx = 1;
525           }
526         dist = tt->dist;
527         adx = adx / dx;
528
529         if (tt->win[0])
530           {
531              xx = x - ((adx * 10 * dist) / 100);
532              yy = y - (dist * 10 * dy) / (100 * WinGetH(VROOT) / 2);
533              EobjMove(tt->win[0], xx - 4, yy - 4);
534           }
535
536         if (tt->win[1])
537           {
538              xx = x - ((adx * 30 * dist) / 100);
539              yy = y - (dist * 30 * dy) / (100 * WinGetH(VROOT) / 2);
540              EobjMove(tt->win[1], xx - 8, yy - 8);
541           }
542
543         if (tt->win[2])
544           {
545              xx = x - ((adx * 50 * dist) / 100);
546              yy = y - (dist * 50 * dy) / (100 * WinGetH(VROOT) / 2);
547              EobjMove(tt->win[2], xx - 12, yy - 12);
548           }
549
550         if (tt->win[3])
551           {
552              xx = x - ((adx * 80 * dist) / 100);
553              yy = y - (dist * 80 * dy) / (100 * WinGetH(VROOT) / 2);
554              EobjMove(tt->win[3], xx - 16, yy - 16);
555           }
556
557         xx = x - ((adx * 100 * dist) / 100);
558         yy = y - (dist * 100 * dy) / (100 * WinGetH(VROOT) / 2);
559         if (adx < 0)
560            ww = 0;
561         else
562            ww = w;
563         hh = (h / 2) + ((dy * h) / (WinGetH(VROOT) / 2));
564      }
565
566    EobjMoveResize(tt->TTWIN, xx - ww, yy - hh, w, h);
567
568    for (i = 0; i < 5; i++)
569      {
570         eo = tt->win[i];
571         if (!eo)
572            continue;
573         ImageclassApply(tt->iclass[i], EobjGetWin(eo), 0, 0, STATE_NORMAL,
574                         ST_TOOLTIP);
575         EobjShapeUpdate(eo, 0);
576         EobjMap(eo, 0);
577      }
578
579    xx = pad->left + iw;
580
581    /* draw the ordinary tooltip text */
582    TextDraw(tt->tclass, EobjGetWin(tt->TTWIN), None, 0, 0, STATE_NORMAL, text,
583             xx, pad->top, headline_w, headline_h, 17, 512);
584
585    /* draw the icons and labels, if any */
586    if (ac)
587      {
588         num = ActionclassGetActionCount(ac);
589         y = pad->top + headline_h;
590         xx = pad->left + double_w;
591
592         for (i = 0; i < num; i++)
593           {
594              x = xx + iw;
595
596              aa = ActionclassGetAction(ac, i);
597              if (!aa)
598                 continue;
599
600              tts = ActionGetTooltipString(aa);
601              if (!tts)
602                 continue;
603              tts = _(tts);
604
605              if (ActionGetEvent(aa) == EVENT_DOUBLE_DOWN)
606                {
607                   TextDraw(tt->tclass, EobjGetWin(tt->TTWIN), None, 0, 0,
608                            STATE_NORMAL, "2x", xx + iw - double_w, y, double_w,
609                            heights[i], 17, 0);
610                }
611
612              if (ActionGetAnybutton(aa))
613                {
614                   TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_ANY", x, y, &x);
615                }
616              else
617                 switch (ActionGetButton(aa))
618                   {
619                   case 1:
620                      TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_1", x, y, &x);
621                      break;
622                   case 2:
623                      TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_2", x, y, &x);
624                      break;
625                   case 3:
626                      TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_3", x, y, &x);
627                      break;
628                   case 4:
629                      TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_4", x, y, &x);
630                      break;
631                   case 5:
632                      TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_5", x, y, &x);
633                      break;
634                   default:
635                      break;
636                   }
637
638              modifiers = ActionGetModifiers(aa);
639              if (modifiers)
640                {
641                   if (modifiers & ShiftMask)
642                      TooltipIclassPaste(tt, "TOOLTIP_KEY_SHIFT", x, y, &x);
643                   if (modifiers & LockMask)
644                      TooltipIclassPaste(tt, "TOOLTIP_KEY_LOCK", x, y, &x);
645                   if (modifiers & ControlMask)
646                      TooltipIclassPaste(tt, "TOOLTIP_KEY_CTRL", x, y, &x);
647                   if (modifiers & Mod1Mask)
648                      TooltipIclassPaste(tt, "TOOLTIP_KEY_MOD1", x, y, &x);
649                   if (modifiers & Mod2Mask)
650                      TooltipIclassPaste(tt, "TOOLTIP_KEY_MOD2", x, y, &x);
651                   if (modifiers & Mod3Mask)
652                      TooltipIclassPaste(tt, "TOOLTIP_KEY_MOD3", x, y, &x);
653                   if (modifiers & Mod4Mask)
654                      TooltipIclassPaste(tt, "TOOLTIP_KEY_MOD4", x, y, &x);
655                   if (modifiers & Mod5Mask)
656                      TooltipIclassPaste(tt, "TOOLTIP_KEY_MOD5", x, y, &x);
657                }
658
659              TextDraw(tt->tclass, EobjGetWin(tt->TTWIN), None, 0, 0,
660                       STATE_NORMAL, tts, pad->left + icons_width + iw, y,
661                       labels_width, heights[i], 17, 0);
662              y += heights[i];
663
664           }
665      }
666
667    Efree(heights);
668 }
669
670 void
671 TooltipHide(ToolTip * tt)
672 {
673    int                 i;
674
675    if (!tt || !tt->TTWIN || !tt->TTWIN->shown)
676       return;
677
678    for (i = 4; i >= 0; i--)
679       if (tt->win[i])
680          EobjUnmap(tt->win[i]);
681 }
682
683 static int
684 _TooltipMatchName(const void *data, const void *match)
685 {
686    return strcmp(((const ToolTip *)data)->name, (const char *)match);
687 }
688
689 ToolTip            *
690 TooltipFind(const char *name)
691 {
692    return (ToolTip *) ecore_list_find(tt_list, _TooltipMatchName, name);
693 }
694
695 /*
696  * Tooltips
697  */
698
699 void
700 TooltipsHide(void)
701 {
702    ToolTip            *tt;
703
704    TooltipsSetPending(0, NULL, NULL);
705
706    ECORE_LIST_FOR_EACH(tt_list, tt) TooltipHide(tt);
707 }
708
709 void
710 TooltipsEnable(int enable)
711 {
712    if (enable)
713      {
714         if (Mode_tooltips.inhibit > 0)
715            Mode_tooltips.inhibit--;
716      }
717    else
718      {
719         Mode_tooltips.inhibit++;
720         TooltipsHide();
721      }
722 }
723
724 static ToolTip     *ttip = NULL;
725
726 static int
727 ToolTipTimeout(void *data __UNUSED__)
728 {
729    int                 x, y;
730    unsigned int        mask;
731    ActionClass        *ac;
732    const char         *tts;
733
734    if (!ttip)
735       ttip = TooltipFind("DEFAULT");
736    if (!ttip)
737       goto done;
738
739    /* In the case of multiple screens, check to make sure
740     * the root window is still where the mouse is... */
741    if (!EQueryPointer(NULL, &x, &y, NULL, &mask))
742       goto done;
743
744    /* In case this is a virtual root */
745    if (x < 0 || y < 0 || x >= WinGetW(VROOT) || y >= WinGetH(VROOT))
746       goto done;
747
748    /* dont pop up tooltip is mouse button down */
749    if (mask &
750        (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask))
751       goto done;
752
753    if (!Mode_tooltips.ac_func)
754       goto done;
755    ac = Mode_tooltips.ac_func(Mode_tooltips.ac_data);
756    if (!ac)
757       goto done;
758
759    tts = ActionclassGetTooltipString(ac);
760    if (!tts)
761       goto done;
762
763    TooltipShow(ttip, _(tts), ac, x, y);
764
765  done:
766    tt_timer = NULL;
767    return 0;
768 }
769
770 /*
771  * We want this on
772  * ButtonPress, ButtonRelease, MotionNotify, EnterNotify, LeaveNotify
773  */
774 void
775 TooltipsSetPending(int type, CB_GetAclass * func, void *data)
776 {
777    if (!Mode_tooltips.ac_func && !func)
778       return;
779
780    Mode_tooltips.ac_func = func;
781    Mode_tooltips.ac_data = data;
782
783    TooltipHide(ttip);
784
785    TIMER_DEL(tt_timer);
786
787    if (Conf_tooltips.showroottooltip)
788      {
789         if (!Mode_tooltips.root_motion_mask_set)
790           {
791              Mode_tooltips.root_motion_mask_set = 1;
792              ESelectInputChange(VROOT, PointerMotionMask, 0);
793           }
794      }
795    else
796      {
797         if (Mode_tooltips.root_motion_mask_set)
798           {
799              Mode_tooltips.root_motion_mask_set = 0;
800              ESelectInputChange(VROOT, 0, PointerMotionMask);
801           }
802      }
803
804    if (!func)
805       return;
806    if (Mode_tooltips.inhibit || !Conf_tooltips.enable)
807       return;
808    if (type && !Conf_tooltips.showroottooltip)
809       return;
810
811    TIMER_ADD(tt_timer, 0.001 * Conf_tooltips.delay, ToolTipTimeout, NULL);
812 }
813
814 /*
815  * Tooltips Module
816  */
817
818 static void
819 TooltipsSighan(int sig, void *prm __UNUSED__)
820 {
821    switch (sig)
822      {
823      case ESIGNAL_INIT:
824         memset(&Mode_tooltips, 0, sizeof(Mode_tooltips));
825         break;
826      case ESIGNAL_AREA_SWITCH_START:
827      case ESIGNAL_DESK_SWITCH_START:
828      case ESIGNAL_EWIN_CHANGE:
829         TooltipsHide();
830         break;
831      }
832 }
833
834 #if ENABLE_DIALOGS
835 /*
836  * Configuration dialog
837  */
838 static char         tmp_tooltips;
839 static int          tmp_tooltiptime;
840 static char         tmp_roottip;
841
842 static void
843 CB_ConfigureTooltips(Dialog * d __UNUSED__, int val, void *data __UNUSED__)
844 {
845    if (val < 2)
846      {
847         Conf_tooltips.enable = tmp_tooltips;
848         Conf_tooltips.delay = tmp_tooltiptime * 10;
849         Conf_tooltips.showroottooltip = tmp_roottip;
850      }
851    autosave();
852 }
853
854 static void
855 _DlgFillTooltips(Dialog * d __UNUSED__, DItem * table, void *data __UNUSED__)
856 {
857    DItem              *di;
858
859    tmp_tooltips = Conf_tooltips.enable;
860    tmp_tooltiptime = Conf_tooltips.delay / 10;
861    tmp_roottip = Conf_tooltips.showroottooltip;
862
863    DialogItemTableSetOptions(table, 2, 0, 0, 0);
864
865    di = DialogAddItem(table, DITEM_CHECKBUTTON);
866    DialogItemSetColSpan(di, 2);
867    DialogItemSetText(di, _("Display Tooltips"));
868    DialogItemCheckButtonSetPtr(di, &tmp_tooltips);
869
870    di = DialogAddItem(table, DITEM_CHECKBUTTON);
871    DialogItemSetColSpan(di, 2);
872    DialogItemSetText(di, _("Display Root Window Tips"));
873    DialogItemCheckButtonSetPtr(di, &tmp_roottip);
874
875    di = DialogAddItem(table, DITEM_TEXT);
876    DialogItemSetAlign(di, 0, 512);
877    DialogItemSetText(di, _("Tooltip Delay:\n"));
878
879    di = DialogAddItem(table, DITEM_SLIDER);
880    DialogItemSliderSetBounds(di, 0, 300);
881    DialogItemSliderSetUnits(di, 10);
882    DialogItemSliderSetJump(di, 25);
883    DialogItemSliderSetValPtr(di, &tmp_tooltiptime);
884 }
885
886 const DialogDef     DlgTooltips = {
887    "CONFIGURE_TOOLTIPS",
888    N_("Tooltips"),
889    N_("Tooltip Settings"),
890    SOUND_SETTINGS_TOOLTIPS,
891    "pix/tips.png",
892    N_("Enlightenment Tooltip\n" "Settings Dialog\n"),
893    _DlgFillTooltips,
894    DLG_OAC, CB_ConfigureTooltips,
895 };
896 #endif /* ENABLE_DIALOGS */
897
898 static const CfgItem TooltipsCfgItems[] = {
899    CFG_ITEM_BOOL(Conf_tooltips, enable, 1),
900    CFG_ITEM_BOOL(Conf_tooltips, showroottooltip, 1),
901    CFG_ITEM_INT(Conf_tooltips, delay, 1500),
902 };
903 #define N_CFG_ITEMS (sizeof(TooltipsCfgItems)/sizeof(CfgItem))
904
905 /*
906  * Module descriptor
907  */
908 extern const EModule ModTooltips;
909 const EModule       ModTooltips = {
910    "tooltips", "tt",
911    TooltipsSighan,
912    {0, NULL},
913    {N_CFG_ITEMS, TooltipsCfgItems}
914 };