1 /* dockapp.c - support functions for a WindowMaker docked application
2 *
3 * From WMAppl (http://www.pobox.com/~charkins/wmappl.html)
4 *
5 * Copyright (C) 2002 Casey Harkins (charkins@pobox.com)
6 *
7 * Authors:
8 * Casey Harkins (charkins@pobox.com)
9 * Jarek (talen@charybda.icm.edu.pl)
10 *
11 * This is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This software is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public
22 * License along with this software; if not, write to the Free
23 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 #include "dockapp.h"
27 #ifdef USE_TOOLTIPS
28 # ifdef HAVE_GETTIMEOFDAY
29 # include <sys/time.h>
30 # else
31 # include <time.h>
32 # endif
33 #endif
34 #include "options.h"
35 #include "pixmap.h"
36
37 /* some globals */
38 Display *display;
39 Window draw_window = 0;
40 Window normal_window = 0;
41 Window root_window = 0;
42 GC gc;
43 int paint_requested;
44
45 extern wmappl_opt *options;
46
47 /* callback function pointers */
48 void (*paint_ptr) (Display * dsp, Drawable drw, GC g);
49 void (*mouse_ptr) (int x, int y, int b, int s);
50
51
52 /* tooltip specific info */
53 #ifdef USE_TOOLTIPS
54 # ifdef HAVE_GETTIMEOFDAY
55
56 typedef struct timeval wmappl_time_t;
57 # define DEFAULT_TOOLTIP_DELAY 200 // 200 ms
58 # define wmappl_currenttime(x) gettimeofday((x),NULL)
59 # define wmappl_timerclear(x) timerclear(x)
60 # define wmappl_timerisset(x) timerisset(x)
61 # define wmappl_timerdiff(x,y) ((((y)->tv_sec - (x)->tv_sec) * 1000000 + ((y)->tv_usec - (x)->tv_usec)) / 1000)
62
63 # else
64
65 typedef time_t wmappl_time_t;
66 # define DEFAULT_TOOLTIP_DELAY 1
67 # define wmappl_currenttime(x) (time(x))
68 # define wmappl_timerclear(x) ((*x)=(time_t)0)
69 # define wmappl_timerisset(x) ((*x)!=(time_t)0)
70 # define wmappl_timerdiff(x,y) ((*y)-(*x))
71 # endif
72
73 #define TOOLTIP_MAX_WIDTH 45
74 #define TOOLTIP_GUTTER 5
75 #define CURSOR_WIDTH 8
76 #define CURSOR_HEIGHT 16
77
78 char * (*tooltip_ptr) (int x, int y);
79
80 Tooltip tooltip;
81 int tooltip_x = 0;
82 int tooltip_y = 0;
83 unsigned long tooltip_fg;
84 unsigned long tooltip_bg;
85
86 int tooltipDelay = DEFAULT_TOOLTIP_DELAY;
87 wmappl_time_t still_time;
88 #endif
89
90
91 /* dockapp_create
92 * PARAMETERS:
93 * char * appname : name of application to be registered with X
94 * char * geometry : X geometry string to use when creating the window
95 * char **interface : the XPM to use for the background and shape mask
96 * int withdrawn : if withdrawn is > 0 then the app is drawn in
97 * withdrawn state (WindowMaker DockApps)
98 * if withdrawn is zero then it is drawn as a
99 * normal window
100 * int argc : number of command line parameters
101 * char **argv : array of command line parameters
102 * RETURN:
103 * int : returns non-zero on success
104 */
dockapp_create(char * appname,char * geometry,char ** interface,int withdrawn,int argc,char ** argv)105 int dockapp_create(char *appname, char *geometry, char **interface,
106 int withdrawn, int argc, char **argv) {
107 /* some X structs */
108 XSizeHints xsh;
109 XWMHints *xwmh;
110 XClassHint xch;
111 XGCValues xgcv;
112 XTextProperty xtp;
113 Window win = 0, iconwin = 0;
114 Pixmap pixmap, pixmask;
115 XpmAttributes pixattr;
116 int screen, win_x, win_y, win_w, win_h, garbage;
117 unsigned long blackpixel, whitepixel;
118
119 paint_requested = 0;
120
121 /* set callbacks to NULL */
122 mouse_ptr = NULL;
123 paint_ptr = NULL;
124
125 #ifdef USE_TOOLTIPS
126 tooltip_ptr = NULL;
127 tooltip.win = 0;
128 if (options->tooltipDelay > 0) {
129 # ifdef HAVE_GETTIMEOFDAY
130 tooltipDelay = options->tooltipDelay;
131 if ( tooltipDelay < 10 ) {
132 tooltipDelay = 10;
133 }
134 # else
135 tooltipDelay = options->tooltipDelay / 1000;
136 if ( options->tooltipDelay % 1000 >= 500 ) {
137 tooltipDelay++;
138 }
139 if ( tooltipDelay == 0 ) {
140 tooltipDelay++;
141 }
142 # endif
143 }
144 #endif
145
146
147 /* get screen and root window */
148 screen = DefaultScreen(display);
149 root_window = RootWindow(display, screen);
150
151 /* get black and white pixel values */
152 blackpixel = BlackPixel(display, screen);
153 whitepixel = WhitePixel(display, screen);
154
155 /* set Window Manager size hints */
156 xsh.flags = USSize;
157 xsh.width = 64;
158 xsh.height = 64;
159
160 XWMGeometry(display, screen, geometry, "64x64+0+0", 0, &xsh, &win_x, &win_y, &win_w, &win_h, &garbage);
161
162 /* create the normal window */
163 win = XCreateSimpleWindow(display, root_window, win_x, win_y, win_w, win_h, 0, blackpixel, whitepixel);
164 if(!win) {
165 fprintf(stderr, "dockapp:dockapp_create() - Couldn't create normal window.\n");
166 return (0);
167 }
168
169 /* set the draw window to the normal window */
170 draw_window = win;
171
172 /* store the normal window */
173 normal_window = win;
174
175 /* if we're using withdrawn state, create the icon window */
176 if(withdrawn) {
177 /* create the icon window */
178 iconwin = XCreateSimpleWindow(display, root_window, win_x, win_y, win_w, win_h, 0, blackpixel, whitepixel);
179 if(!iconwin) {
180 fprintf(stderr, "dockapp:dockapp_create() - Couldn't create icon window.\n");
181 return (0);
182 }
183
184 /* set the draw window to the icon window */
185 draw_window = iconwin;
186 }
187
188 /* set the valuemask on the XpmAttributes structure */
189 pixattr.valuemask = 0;
190
191 /* load interface pixmap */
192 if(XpmCreatePixmapFromData(display, root_window, interface, &pixmap, &pixmask, &pixattr) != XpmSuccess) {
193 fprintf(stderr, "dockapp:dockapp_create() - Couldn't create interface pixmap.\n");
194 return (0);
195 }
196
197 /* set background pixmap for the draw window */
198 dockapp_set_background_pixmap(pixmap);
199
200 /* shape the draw window if supported */
201 if(XShapeQueryExtension(display, &garbage, &garbage)) {
202 XShapeCombineMask(display, draw_window, ShapeBounding, 0, 0, pixmask, ShapeSet);
203 }
204 else {
205 fprintf(stderr, "dockapp:dockapp_create() - Shaped window extension not supported.\n");
206 }
207
208 /* setup Window Manager hints */
209 xwmh = XAllocWMHints();
210 xwmh->flags = InputHint | WindowGroupHint;
211 xwmh->input = True;
212 xwmh->window_group = win;
213
214 /* add withdrawn state and icon window hints if we're using withdrawn */
215 if(withdrawn) {
216 xwmh->flags = xwmh->flags | IconWindowHint | StateHint;
217 xwmh->icon_window = iconwin;
218 xwmh->initial_state = WithdrawnState;
219 }
220 XSetWMHints(display, win, xwmh);
221
222 /* set class hints */
223 xch.res_name = appname;
224 xch.res_class = appname;
225 XSetClassHint(display, win, &xch);
226
227 /* set size hints */
228 XSetWMNormalHints(display, win, &xsh);
229
230 /* tell window manager app name */
231 if(!XStringListToTextProperty(&appname, 1, &xtp)) {
232 fprintf(stderr, "dockapp:dockapp_create() - Couldn't create text property.\n");
233 return (0);
234 }
235 XSetWMName(display, win, &xtp);
236
237 /* create a graphics context */
238 gc = XCreateGC(display, draw_window, GCForeground | GCBackground, &xgcv);
239 if(!gc) {
240 fprintf(stderr, "dockapp:dockapp_create() - Couldn't create graphics context.\n");
241 return (0);
242 }
243
244 /* select events to catch */
245 XSelectInput(display, draw_window, ExposureMask | ButtonPressMask | ButtonReleaseMask |
246 #ifdef USE_TOOLTIPS
247 PointerMotionMask | EnterWindowMask | LeaveWindowMask |
248 #endif
249 StructureNotifyMask);
250
251 /* set default tooltip foreground and background colors */
252 #ifdef USE_TOOLTIPS
253 tooltip_fg = dockapp_black_pixel();
254 tooltip_bg = dockapp_white_pixel();
255 #endif
256
257 /* set the command line for restarting */
258 XSetCommand(display, win, argv, argc);
259
260 /* map the main window */
261 XMapWindow(display, win);
262
263 return 1;
264 } /* end dockapp_create */
265
266 /* dockapp_run
267 * PARAMETERS:
268 * none
269 * RETURN:
270 * int : returns non-zero on success
271 */
dockapp_run()272 int dockapp_run() {
273 int close = 0;
274 XEvent e;
275
276 #ifdef USE_TOOLTIPS
277 wmappl_time_t now;
278 #endif
279
280 while(!close) {
281
282 /* sleep while there are no events pending */
283 while(XPending(display) == 0) {
284
285 #ifdef USE_TOOLTIPS
286 if(tooltip_ptr!=NULL) {
287 wmappl_currenttime(&now);
288
289 #if 0
290 printf ( "Delay = %d, Still = %d, Now = %d\n", tooltipDelay, still_time, now );
291
292 printf ( "TimerIsSet = %d, TimerDiff = %d\n",
293 wmappl_timerisset(&still_time),
294 wmappl_timerdiff(&still_time,&now) );
295 #endif
296
297 if(wmappl_timerisset(&still_time) && wmappl_timerdiff(&still_time,&now) > tooltipDelay ) {
298 // printf ( "*Debug* OK to show tooltip\n" );
299 wmappl_timerclear(&still_time);
300 dockapp_show_tooltip(tooltip_x, tooltip_y, tooltip_ptr(tooltip_x, tooltip_y));
301 }
302 }
303 #endif
304
305 usleep(_DELAY_TIME);
306 }
307
308 /* process all pending events */
309 while(XPending(display)) {
310
311 /* get next event ifrom queue */
312 XNextEvent(display, &e);
313
314 /* handle events */
315 switch (e.type) {
316 case ClientMessage:
317 paint_requested = 1;
318 break;
319 case ButtonPress:
320 if(mouse_ptr)
321 mouse_ptr(e.xbutton.x, e.xbutton.y, e.xbutton.button, MOUSE_PRESSED);
322
323 #ifdef USE_TOOLTIPS
324 /* if visible, hide tooltip */
325 if(tooltip.win) {
326 dockapp_hide_tooltip();
327 }
328 #endif
329 break;
330 case ButtonRelease:
331 if(mouse_ptr)
332 mouse_ptr(e.xbutton.x, e.xbutton.y, e.xbutton.button, MOUSE_RELEASED);
333
334 #ifdef USE_TOOLTIPS
335 /* if visible, hide tooltip */
336 if(tooltip.win) {
337 dockapp_hide_tooltip();
338 }
339 #endif
340 break;
341 #ifdef USE_TOOLTIPS
342 case EnterNotify:
343 break;
344 case MotionNotify:
345 if(tooltip_ptr==NULL) {
346 break;
347 }
348
349 wmappl_timerclear(&still_time);
350
351 if(wmappl_currenttime(&still_time)<0) {
352 fprintf(stderr, "dockapp:dockapp_run() - Could not get time since epoch.\n");
353 break;
354 }
355
356 tooltip_x=e.xbutton.x;
357 tooltip_y=e.xbutton.y;
358
359 /* if visible, hide tooltip */
360 if(tooltip.win) {
361 dockapp_hide_tooltip();
362 }
363
364 break;
365
366 case LeaveNotify:
367 if(tooltip_ptr==NULL) {
368 break;
369 }
370
371 wmappl_timerclear(&still_time);
372
373 /* if visible, hide tooltip */
374 if(tooltip.win) {
375 dockapp_hide_tooltip();
376 }
377
378 break;
379 #endif
380 case Expose:
381 if(e.xexpose.count != 0)
382 break;
383 paint_requested = 1;
384 break;
385 case ConfigureNotify:
386 paint_requested = 1;
387 break;
388 case DestroyNotify:
389 close = 1;
390 break;
391 } /* switch */
392 /* call paint function if it has been requested */
393 if(paint_requested) {
394 paint_requested = 0;
395 if(paint_ptr)
396 paint_ptr(display, draw_window, gc);
397 #ifdef USE_TOOLTIPS
398 if(tooltip.win)
399 dockapp_update_tooltip();
400 #endif
401 }
402 } /* while XPending */
403 } /* while not close */
404
405 return 1;
406 } /* end dockapp_run */
407
408 /* dockapp_redraw - requests that the paint function be called
409 * PARAMETERS:
410 * none
411 * RETURN:
412 * none
413 */
dockapp_redraw()414 void dockapp_redraw() {
415 paint_requested = 1;
416 }
417
418 /* dockapp_clear - clears the draw window
419 * PARAMETERS:
420 * none
421 * RETURN:
422 * none
423 */
dockapp_clear()424 void dockapp_clear() {
425 XClearWindow(display, draw_window);
426 }
427
428 /* dockapp_set_paint
429 * PARAMETERS:
430 * void (*func)(Display dsp, Drawable drw, GC g) : pointer to paint
431 * function
432 * RETURN:
433 * int : returns non-zero on success
434 */
dockapp_set_paint(void (* func)(Display * dsp,Drawable drw,GC g))435 int dockapp_set_paint(void (*func) (Display * dsp, Drawable drw, GC g)) {
436 if(func) {
437 paint_ptr = func;
438 return 1;
439 }
440 return 0;
441 }
442
443 /* dockapp_set_mouse
444 * PARAMETERS:
445 * void (*func)(int x, int y, int b, int s) : pointer to mouse function
446 * RETURN:
447 * int : returns non-zero on success
448 */
dockapp_set_mouse(void (* func)(int x,int y,int b,int s))449 int dockapp_set_mouse(void (*func) (int x, int y, int b, int s)) {
450 if(func) {
451 mouse_ptr = func;
452 return 1;
453 }
454 return 0;
455 }
456
457 /* dockapp_init_display
458 *
459 * RETURN: status. <0 on error, 0 when OK
460 */
dockapp_init_display(void)461 int dockapp_init_display(void) {
462 /* connect to default display */
463 display = XOpenDisplay((char *) getenv("DISPLAY"));
464 if(!display) {
465 fprintf(stderr, "dockapp:dockapp_init_display() - Couldn't connect to display.\n");
466 return -1;
467 }
468 return 0;
469 }
470
471 /* dockapp_get_display()
472 * RETURN:
473 * Display * : returns display
474 */
dockapp_get_display()475 Display *dockapp_get_display() {
476 return display;
477 }
478
479 /* dockapp_get_screen()
480 * RETURN:
481 * int : returns screen
482 */
dockapp_get_screen()483 int dockapp_get_screen() {
484 return DefaultScreen(display);
485 }
486
487 /* dockapp_black_pixel()
488 * RETURN:
489 * unsigned long : black pixel value
490 */
dockapp_black_pixel()491 unsigned long dockapp_black_pixel() {
492 return BlackPixel(display, dockapp_get_screen());
493
494 }
495
496 /* dockapp_white_pixel()
497 * RETURN:
498 * unsigned long : white pixel value
499 */
dockapp_white_pixel()500 unsigned long dockapp_white_pixel() {
501 return WhitePixel(display, dockapp_get_screen());
502
503 }
504
505 /* dockapp_to_screen_coords
506 * PARAMETERS:
507 * int x : x coordinate relative to origin of draw_window
508 * int y : y coordinate relative to origin of draw_window
509 * int *x_return : returned x coordinate relative to root window
510 * int *y_return : returned y coordinate relative to root window
511 * RETURN:
512 * int : returns non-zero on success
513 */
dockapp_to_screen_coords(int x,int y,int * x_return,int * y_return)514 int dockapp_to_screen_coords(int x, int y, int *x_return, int *y_return) {
515 Window c;
516
517 if(XTranslateCoordinates(display, draw_window, root_window, x, y, x_return, y_return, &c) == 0) {
518 fprintf(stderr, "dockapp:get_screen_coordinates() - Translate error!\n");
519 }
520 return 1;
521 }
522
523 /* dockapp_set_background_color
524 * PARAMETERS:
525 * char *: background color name
526 *
527 */
dockapp_set_background_color(char * color)528 void dockapp_set_background_color(char *color) {
529 XColor xcolor;
530 Colormap colormap = XDefaultColormap(display, dockapp_get_screen());
531
532 if(XParseColor(display, colormap, color, &xcolor)==0) {
533 fprintf(stderr, "Could not parse color: %s\n", color);
534 return;
535 }
536 if(XAllocColor(display, colormap, &xcolor)==0) {
537 fprintf(stderr, "Could not allocate color: %s\n", color);
538 return;
539 }
540 dockapp_set_background_pixel(xcolor.pixel);
541 }
542
543 /* dockapp_set_background_pixel
544 * PARAMETERS:
545 * unsigned long pixel : background color
546 *
547 */
dockapp_set_background_pixel(unsigned long pixel)548 void dockapp_set_background_pixel(unsigned long pixel) {
549 XSetWindowBackground(display, draw_window, pixel);
550 dockapp_clear();
551 }
552
553 /* dockapp_set_background_pixmap_data
554 * PARAMETERS:
555 * char **data : background pixmap
556 *
557 */
dockapp_set_background_pixmap_data(char ** data)558 void dockapp_set_background_pixmap_data(char **data) {
559 XpmAttributes pixattr;
560 Pixmap pixmap, pixmask;
561
562 /* set the valuemask on the XpmAttributes structure */
563 pixattr.valuemask = 0;
564
565 /* load pixmap */
566 if(XpmCreatePixmapFromData(display, root_window, data, &pixmap, &pixmask, &pixattr) != XpmSuccess) {
567 return;
568 }
569
570 dockapp_set_background_pixmap(pixmap);
571 }
572
573 /* dockapp_set_background_pixmap_file
574 * PARAMETERS:
575 * char *data : absolute path to background pixmap
576 *
577 */
dockapp_set_background_pixmap_file(char * file)578 void dockapp_set_background_pixmap_file(char *file) {
579 XpmAttributes pixattr;
580 Pixmap pixmap, pixmask;
581
582 /* set the valuemask on the XpmAttributes structure */
583 pixattr.valuemask = 0;
584
585 /* load pixmap */
586 create_button_pixmap(display, file, &pixmap, &pixmask, &pixattr);
587
588 dockapp_set_background_pixmap(pixmap);
589 }
590
591 /* dockapp_set_background_pixmap
592 * PARAMETERS:
593 * Pixmap pixmap : background pixmap
594 *
595 */
dockapp_set_background_pixmap(Pixmap pixmap)596 void dockapp_set_background_pixmap(Pixmap pixmap) {
597 XSetWindowBackgroundPixmap(display, draw_window, pixmap);
598 dockapp_clear();
599 }
600
601 #ifdef USE_TOOLTIPS
602
603 /* dockapp_set_tooltip_foreground
604 * PARAMETERS:
605 * char *: tooltip foreground color name
606 *
607 */
dockapp_set_tooltip_foreground(char * color)608 void dockapp_set_tooltip_foreground(char *color) {
609 XColor xcolor;
610 Colormap colormap = XDefaultColormap(display, dockapp_get_screen());
611
612 if(XParseColor(display, colormap, color, &xcolor)==0) {
613 fprintf(stderr, "Could not parse color: %s\n", color);
614 return;
615 }
616 if(XAllocColor(display, colormap, &xcolor)==0) {
617 fprintf(stderr, "Could not allocate color: %s\n", color);
618 return;
619 }
620 tooltip_fg=xcolor.pixel;
621 }
622
623 /* dockapp_set_tooltip_background
624 * PARAMETERS:
625 * char *: tooltip background color name
626 *
627 */
dockapp_set_tooltip_background(char * color)628 void dockapp_set_tooltip_background(char *color) {
629 XColor xcolor;
630 Colormap colormap = XDefaultColormap(display, dockapp_get_screen());
631
632 if(XParseColor(display, colormap, color, &xcolor)==0) {
633 fprintf(stderr, "Could not parse color: %s\n", color);
634 return;
635 }
636 if(XAllocColor(display, colormap, &xcolor)==0) {
637 fprintf(stderr, "Could not allocate color: %s\n", color);
638 return;
639 }
640 tooltip_bg=xcolor.pixel;
641 }
642
643 /* dockapp_set_tooltip
644 * PARAMETERS:
645 * char * (*func)(int x, int y) : pointer to tooltip function
646 *
647 * RETURN:
648 * int : returns non-zero on success
649 */
dockapp_set_tooltip(char * (* func)(int x,int y))650 int dockapp_set_tooltip(char * (*func) (int x, int y)) {
651 if(func) {
652 tooltip_ptr = func;
653 return 1;
654 }
655 return 0;
656 } /* end tooltip_func */
657
658 /* dockapp_show_tooltip(int x, int y, char *string)
659 * PARAMETERS:
660 * int x : x coordinate of "tip" of the tooltip
661 * int y : y coordinate of "tip" of the tooltip
662 * char *string : the string to be displayed in the tooltip
663 *
664 * RETURN:
665 * int : non-zero on success
666 */
dockapp_show_tooltip(int x,int y,char * string)667 int dockapp_show_tooltip(int x, int y, char *string) {
668 XGCValues gcvals;
669 XSizeHints sizehints;
670 XSetWindowAttributes winattribs;
671
672 if(tooltip.win) {
673 dockapp_hide_tooltip();
674 }
675
676
677 /* return if string is NULL */
678 if(string==NULL) {
679 return 0;
680 }
681
682 /* query the font if it hasn't been already */
683 if(!tooltip.font) {
684 if(options->tooltipfont) {
685 tooltip.font = XLoadQueryFont(display, options->tooltipfont);
686 }
687 if(tooltip.font == NULL) {
688 tooltip.font = XLoadQueryFont(display, "fixed");
689 }
690 if(tooltip.font == NULL) {
691 fprintf(stderr, "dockapp:dockapp_show_tooltip() - Couldn't load fixed font!\n");
692 return (0);
693 }
694 }
695
696 /* process string into lines of appropriate width */
697 dockapp_process_tooltip(string);
698
699 /* map the tooltip window */
700 /* set the size hints structure */
701 sizehints.flags = USSize | USPosition;
702
703 dockapp_to_screen_coords(x, y, &sizehints.x, &sizehints.y);
704
705 /* sizehints.x = x;
706 sizehints.y = y; */
707
708 if(tooltip.lines == 1) {
709 sizehints.width = XTextWidth(tooltip.font, tooltip.text[0], strlen(tooltip.text[0])) + 2;
710 }
711 else if(tooltip.lines > 1) {
712 sizehints.width = XTextWidth(tooltip.font, tooltip.text[0], strlen(tooltip.text[0])) + 4;
713 }
714 else {
715 sizehints.width = 0;
716 }
717 sizehints.height = ((tooltip.font->ascent + tooltip.font->descent + 4) * tooltip.lines);
718
719 /* ensure tooltip is entirely on screen */
720 dockapp_tooltip_location(&sizehints);
721
722 /* create the window */
723 tooltip.win = XCreateSimpleWindow(display, DefaultRootWindow(display),
724 sizehints.x, sizehints.y, sizehints.width, sizehints.height,
725 0, dockapp_black_pixel(), dockapp_white_pixel());
726 if(!tooltip.win) {
727 fprintf(stderr, "dockapp:dockapp_show_tooltip() - Couldn't create tooltip window!\n");
728 return (0);
729 }
730
731 /* set the size hints */
732 XSetWMNormalHints(display, tooltip.win, &sizehints);
733
734 /* set the window attributes */
735 winattribs.save_under = True;
736 winattribs.override_redirect = True;
737 XChangeWindowAttributes(display, tooltip.win, CWSaveUnder | CWOverrideRedirect, &winattribs);
738
739 /* set the window name */
740 XStoreName(display, tooltip.win, "tooltip");
741
742 /* select to receive exposure events */
743 XSelectInput(display, tooltip.win, ExposureMask);
744
745 /* create the graphics context if it hasn't been created */
746 if(!tooltip.gc) {
747 gcvals.foreground = tooltip_fg;
748 gcvals.background = tooltip_bg;
749 gcvals.graphics_exposures = 0;
750 tooltip.gc = XCreateGC(display, tooltip.win, GCForeground | GCBackground | GCGraphicsExposures, &gcvals);
751 if(tooltip.gc == NULL) {
752 fprintf(stderr, "dockapp:dockapp_show_tooltip() - Couldn't create graphics context!\n");
753 return (0);
754 }
755
756 XSetFont(display, tooltip.gc, tooltip.font->fid);
757 }
758
759 XSetWindowBackground(display, tooltip.win, tooltip_bg);
760
761 XMapRaised(display, tooltip.win);
762
763 return 1;
764 }
765
dockapp_hide_tooltip()766 int dockapp_hide_tooltip() {
767 int i = 0;
768
769 if(!tooltip.win)
770 return -1;
771 XUnmapWindow(display, tooltip.win);
772 for(i = 0; i < tooltip.lines; i++) {
773 free(tooltip.text[i]);
774 }
775 free(tooltip.text);
776 tooltip.lines = 0;
777 tooltip.win = 0;
778 XFlush(display);
779 return 1;
780 }
781
dockapp_update_tooltip()782 void dockapp_update_tooltip() {
783 int i=0;
784
785 if(!tooltip.win || !tooltip.gc || !tooltip.text) {
786 return;
787 }
788
789 for(i = 0; i < tooltip.lines; i++) {
790 XDrawString(display, tooltip.win, tooltip.gc, 1,
791 (i + 1) * (tooltip.font->ascent + tooltip.font->descent + 4) - 4,
792 tooltip.text[i], strlen(tooltip.text[i]));
793 }
794
795
796 XFlush(display);
797 }
798
799
dockapp_process_tooltip(char * string)800 void dockapp_process_tooltip(char *string)
801 {
802 int length = 0;
803 int size = 0;
804 int i = 0;
805 char *pointer = NULL;
806
807 length = strlen(string);
808
809 /* calculate number of lines */
810 tooltip.lines = length / TOOLTIP_MAX_WIDTH;
811 if(length % TOOLTIP_MAX_WIDTH != 0)
812 tooltip.lines++;
813
814 /* allocate pointers to the lines */
815 tooltip.text = (char **) malloc(sizeof(char *) * tooltip.lines);
816
817 pointer = string;
818
819 for(i = 0; i < tooltip.lines; i++) {
820 /* allocate the line */
821 if(length < TOOLTIP_MAX_WIDTH) {
822 tooltip.text[i] = (char *) malloc(sizeof(char) * (length + 1));
823 size = length;
824 }
825 else {
826 tooltip.text[i] = (char *) malloc(sizeof(char) * (TOOLTIP_MAX_WIDTH + 1));
827 size = TOOLTIP_MAX_WIDTH;
828 }
829
830 strncpy(tooltip.text[i], pointer, size);
831 tooltip.text[i][size] = '\0';
832
833 length = length - size;
834 pointer = &pointer[size];
835
836 }
837 }
838
839
dockapp_tooltip_location(XSizeHints * sizehints)840 void dockapp_tooltip_location(XSizeHints *sizehints) {
841
842 XWindowAttributes rootattr;
843
844 if(XGetWindowAttributes(display, root_window, &rootattr) == 0) {
845 fprintf(stderr, "dockapp:set_tooltip_location() - Couldn't determine screen size, tooltips may run off of the screen.\n");
846 return;
847 }
848
849 /* check if tooltip should go to the right or left of the mouse cursor */
850 if(sizehints->x < rootattr.width/2) {
851 /* tooltip goes to the right, need to account for mouse cursor width */
852 sizehints->x=sizehints->x+TOOLTIP_GUTTER+CURSOR_WIDTH;
853 }
854 else {
855 /* tooltip goes to the left, need to account for the tooltip width */
856 sizehints->x=sizehints->x-TOOLTIP_GUTTER-sizehints->width;
857 }
858
859 /* check if tooltip should go above or below the mouse cursor */
860 if(sizehints->y < rootattr.height/2) {
861 /* tooltip goes below, need to account for mouse cursor height */
862 sizehints->y=sizehints->y+TOOLTIP_GUTTER+CURSOR_HEIGHT;
863 }
864 else {
865 /* tooltip goes above, need to account for tooltip height */
866 sizehints->y=sizehints->y-TOOLTIP_GUTTER-sizehints->height;
867 }
868
869 }
870
871
872
873 #endif
874