2 /* Copyright (C) 2004 Olivier Chapuis */
3 /* This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 /* ---------------------------- included header files ---------------------- */
24 #include "libs/ftime.h"
27 #include <X11/Xatom.h>
32 #include "PictureBase.h"
36 #include "libs/FScreen.h"
39 /* ---------------------------- local definitions -------------------------- */
41 #define FVWM_TIPS_NOTHING 0
42 #define FVWM_TIPS_WAITING 1
43 #define FVWM_TIPS_MAPPED 2
45 /* ---------------------------- local macros ------------------------------- */
47 /* ---------------------------- imports ------------------------------------ */
49 /* ---------------------------- included code files ------------------------ */
51 /* ---------------------------- local types -------------------------------- */
53 /* ---------------------------- forward declarations ----------------------- */
55 /* ---------------------------- local variables ---------------------------- */
57 static Window win
= None
;
59 static Window win_for
;
61 static ftips_config
*current_config
, *default_config
;
64 static int state
= FVWM_TIPS_NOTHING
;
65 static void *boxID
= NULL
;
67 static FlocaleWinString fwin_string
;
70 static unsigned long timeOut
;
71 static unsigned long onTime
;
73 static Atom _net_um_for
= None
;
75 /* ---------------------------- exported variables (globals) --------------- */
77 /* ---------------------------- local functions ---------------------------- */
80 unsigned long __get_time(void)
84 gettimeofday(&t
, NULL
);
85 return (1000*t
.tv_sec
+ t
.tv_usec
/1000);
89 void __initialize_window(Display
*dpy
)
92 unsigned long valuemask
;
93 XSetWindowAttributes attributes
;
94 Atom _net_um_window_type
;
95 long _net_um_window_type_tooltips
;
97 valuemask
= CWOverrideRedirect
| CWEventMask
| CWColormap
;
98 attributes
.override_redirect
= True
;
99 attributes
.event_mask
= ExposureMask
;
100 attributes
.colormap
= Pcmap
;
102 dpy
, DefaultRootWindow(dpy
), 0, 0, 1, 1,
103 current_config
->border_width
, Pdepth
, InputOutput
, Pvisual
,
104 valuemask
, &attributes
);
106 _net_um_window_type
= XInternAtom(
107 dpy
, "_NET_UM_WINDOW_TYPE", False
);
108 _net_um_window_type_tooltips
= XInternAtom(
109 dpy
, "_NET_UM_WINDOW_TYPE_TOOLTIPS", False
);
112 dpy
, win
, _net_um_window_type
, XA_ATOM
, 32, PropModeReplace
,
113 (unsigned char *) &_net_um_window_type_tooltips
, 1);
115 _net_um_for
= XInternAtom(dpy
, "_NET_UM_FOR", False
);
117 gc
= fvwmlib_XCreateGC(dpy
, win
, 0, &xgcv
);
122 void __setup_cs(Display
*dpy
)
124 XSetWindowAttributes xswa
;
125 unsigned long valuemask
= 0;
128 if (current_config
->colorset
> -1)
130 xswa
.border_pixel
= Colorset
[current_config
->colorset
].fg
;
131 xswa
.background_pixel
= Colorset
[current_config
->colorset
].bg
;
132 if (Colorset
[current_config
->colorset
].pixmap
)
135 xswa
.background_pixmap
= None
;
136 valuemask
= CWBackPixmap
| CWBorderPixel
;;
140 valuemask
= CWBackPixel
| CWBorderPixel
;
145 xswa
.border_pixel
= current_config
->border_pixel
;
146 xswa
.background_pixel
= current_config
->bg
;
147 valuemask
= CWBackPixel
| CWBorderPixel
;
149 XChangeWindowAttributes(dpy
, win
, valuemask
, &xswa
);
153 void __setup_gc(Display
*dpy
)
156 unsigned long valuemask
;
158 valuemask
= GCForeground
;
159 if (current_config
->colorset
> -1)
161 xgcv
.foreground
= Colorset
[current_config
->colorset
].fg
;
165 xgcv
.foreground
= current_config
->fg
;
167 if (current_config
->Ffont
&& current_config
->Ffont
->font
!= NULL
)
169 xgcv
.font
= current_config
->Ffont
->font
->fid
;
172 XChangeGC(dpy
, gc
, valuemask
, &xgcv
);
178 void __draw(Display
*dpy
)
180 if (!current_config
->Ffont
)
185 fwin_string
.str
= label
;
186 fwin_string
.win
= win
;
188 if (current_config
->colorset
> -1)
190 fwin_string
.colorset
= &Colorset
[current_config
->colorset
];
191 fwin_string
.flags
.has_colorset
= True
;
195 fwin_string
.flags
.has_colorset
= False
;
198 fwin_string
.y
= current_config
->Ffont
->ascent
;
199 FlocaleDrawString(dpy
, current_config
->Ffont
, &fwin_string
, 0);
205 void __map_window(Display
*dpy
)
210 fscreen_scr_arg
*fsarg
= NULL
; /* for now no xinerama support */
211 ftips_placement_t placement
;
213 static int border_width
= 1;
214 static Window win_f
= None
;
216 if (border_width
!= current_config
->border_width
)
218 XSetWindowBorderWidth(dpy
, win
, current_config
->border_width
);
219 border_width
= current_config
->border_width
;
223 fsarg
, FSCREEN_GLOBAL
, &screen_g
.x
, &screen_g
.y
,
224 &screen_g
.width
, &screen_g
.height
);
226 new_g
.height
= ((current_config
->Ffont
)? current_config
->Ffont
->height
:0)
230 if (label
&& current_config
->Ffont
)
232 new_g
.width
+= FlocaleTextWidth(
233 current_config
->Ffont
, label
, strlen(label
));
236 if (current_config
->placement
!= FTIPS_PLACEMENT_AUTO_UPDOWN
&&
237 current_config
->placement
!= FTIPS_PLACEMENT_AUTO_LEFTRIGHT
)
239 placement
= current_config
->placement
;
243 XTranslateCoordinates(
244 dpy
, win_for
, DefaultRootWindow(dpy
), box
.x
, box
.y
,
246 if (current_config
->placement
== FTIPS_PLACEMENT_AUTO_UPDOWN
)
248 if (y
+ box
.height
/2 >= screen_g
.height
/2)
250 placement
= FTIPS_PLACEMENT_UP
;
254 placement
= FTIPS_PLACEMENT_DOWN
;
259 if (x
+ box
.width
/2 >= screen_g
.width
/2)
261 placement
= FTIPS_PLACEMENT_LEFT
;
265 placement
= FTIPS_PLACEMENT_RIGHT
;
270 if (placement
== FTIPS_PLACEMENT_RIGHT
||
271 placement
== FTIPS_PLACEMENT_LEFT
)
273 if (current_config
->justification
== FTIPS_JUSTIFICATION_CENTER
)
275 y
= box
.y
+ (box
.height
/ 2) - (new_g
.height
/ 2) -
276 current_config
->border_width
;
278 else if (current_config
->justification
==
279 FTIPS_JUSTIFICATION_RIGHT_DOWN
)
281 y
= box
.y
+ box
.height
- new_g
.height
-
282 (2 * current_config
->border_width
) -
283 current_config
->justification_offset
;
287 y
= box
.y
+ current_config
->justification_offset
;
291 else /* placement == FTIPS_PLACEMENT_DOWN ||
292 placement == FTIPS_PLACEMENT_UP */
294 if (current_config
->justification
== FTIPS_JUSTIFICATION_CENTER
)
296 x
= box
.x
+ (box
.width
/ 2) - (new_g
.width
/ 2) -
297 current_config
->border_width
;
299 else if (current_config
->justification
==
300 FTIPS_JUSTIFICATION_RIGHT_DOWN
)
302 x
= box
.x
+ box
.width
- new_g
.width
-
303 (2 * current_config
->border_width
) -
304 current_config
->justification_offset
;
308 x
= box
.x
+ current_config
->justification_offset
;
312 if (placement
== FTIPS_PLACEMENT_RIGHT
)
314 x
= box
.x
+ box
.width
+ current_config
->placement_offset
+ 1;
316 else if (placement
== FTIPS_PLACEMENT_LEFT
)
318 x
= box
.x
- current_config
->placement_offset
- new_g
.width
319 - (2 * current_config
->border_width
) - 1;
321 else if (placement
== FTIPS_PLACEMENT_DOWN
)
323 y
= box
.y
+ box
.height
+ current_config
->placement_offset
- 0;
327 y
= box
.y
- current_config
->placement_offset
- new_g
.height
328 + 0 - (2 * current_config
->border_width
);
331 XTranslateCoordinates(
332 dpy
, win_for
, DefaultRootWindow(dpy
), x
, y
,
333 &new_g
.x
, &new_g
.y
, &dummy
);
335 if (placement
== FTIPS_PLACEMENT_RIGHT
||
336 placement
== FTIPS_PLACEMENT_LEFT
)
342 x
= box
.x
+ box
.width
+ current_config
->placement_offset
344 XTranslateCoordinates(
345 dpy
, win_for
, DefaultRootWindow(dpy
), x
, y
,
348 l1
= new_g
.width
+ new_g
.x
- 2;
349 l2
= screen_g
.width
- (x1
+ new_g
.width
) -
350 current_config
->border_width
- 2;
356 else if (new_g
.x
+ new_g
.width
>
357 screen_g
.width
- (2 * current_config
->border_width
) - 2)
359 x
= box
.x
- current_config
->placement_offset
- new_g
.width
360 - (2 * current_config
->border_width
) - 1;
361 XTranslateCoordinates(
362 dpy
, win_for
, DefaultRootWindow(dpy
), x
, y
,
365 l1
= new_g
.width
+ x1
- 2;
366 l2
= screen_g
.width
- (new_g
.x
+ new_g
.width
) -
367 (2 * current_config
->border_width
) - 2;
377 else if (new_g
.y
+ new_g
.height
>
378 screen_g
.height
- (2 * current_config
->border_width
) - 2)
380 new_g
.y
= screen_g
.height
- new_g
.height
-
381 (2 * current_config
->border_width
) - 2;
384 else /* placement == FTIPS_PLACEMENT_DOWN ||
385 placement == FTIPS_PLACEMENT_UP */
389 y
= box
.y
+ box
.height
+
390 current_config
->placement_offset
- 0;
391 XTranslateCoordinates(
392 dpy
, win_for
, DefaultRootWindow(dpy
),
393 x
, y
, &new_g
.x
, &new_g
.y
, &dummy
);
395 else if (new_g
.y
+ new_g
.height
>
396 screen_g
.height
- (2 * current_config
->border_width
) - 2)
398 y
= box
.y
- current_config
->placement_offset
-
400 - (2 * current_config
->border_width
);
401 XTranslateCoordinates(
402 dpy
, win_for
, DefaultRootWindow(dpy
),
403 x
, y
, &new_g
.x
, &new_g
.y
, &dummy
);
409 else if (new_g
.x
+ new_g
.width
>
410 screen_g
.width
- (2 * current_config
->border_width
) - 2)
412 new_g
.x
= screen_g
.width
- new_g
.width
-
413 (2 * current_config
->border_width
) - 2;
417 /* make changes to window */
419 dpy
, win
, new_g
.x
, new_g
.y
, new_g
.width
, new_g
.height
);
421 if (current_config
->colorset
> -1)
424 dpy
, win
, new_g
.width
, new_g
.height
,
425 &Colorset
[current_config
->colorset
], Pdepth
, gc
, True
);
429 XSetWindowBackground (dpy
, win
, current_config
->bg
);
431 if (current_config
->border_width
> 0)
434 dpy
, win
, Colorset
[current_config
->colorset
].fg
);
437 if (state
!= FVWM_TIPS_MAPPED
&& win_f
!= win_for
)
443 dpy
, win
, _net_um_for
, XA_WINDOW
, 32, PropModeReplace
,
444 (unsigned char *) &l_win_for
, 1);
447 XMapRaised(dpy
, win
);
448 state
= FVWM_TIPS_MAPPED
;
453 /* ---------------------------- interface functions ------------------------ */
455 Bool
FTipsInit(Display
*dpy
)
458 current_config
= default_config
= FTipsNewConfig();
459 __initialize_window(dpy
);
461 if (gc
== None
|| win
== None
)
469 memset(&fwin_string
, 0, sizeof(fwin_string
));
474 ftips_config
*FTipsNewConfig(void)
478 fc
= (ftips_config
*)safemalloc(sizeof(ftips_config
));
480 memset(fc
, 0, sizeof(ftips_config
));
482 /* use colorset 0 as default */
483 fc
->border_width
= FTIPS_DEFAULT_BORDER_WIDTH
;
484 fc
->placement
= FTIPS_DEFAULT_PLACEMENT
;
485 fc
->justification
= FTIPS_DEFAULT_JUSTIFICATION
;
486 fc
->placement_offset
= FTIPS_DEFAULT_PLACEMENT_OFFSET
;
487 fc
->justification_offset
= FTIPS_DEFAULT_JUSTIFICATION_OFFSET
;
489 fc
->mapped_delay
= 300;
495 Display
*dpy
, Window win_f
, ftips_config
*fc
, void *id
, char *str
,
496 int x
, int y
, int w
, int h
)
515 CopyString(&label
, str
);
520 if (id
&& state
== FVWM_TIPS_WAITING
)
526 onTime
= __get_time();
527 if (state
== FVWM_TIPS_MAPPED
)
530 delay
= fc
->mapped_delay
;
537 timeOut
= onTime
+ delay
;
538 state
= FVWM_TIPS_WAITING
;
547 void FTipsCancel(Display
*dpy
)
549 if (state
== FVWM_TIPS_MAPPED
&& win
!= None
)
551 XUnmapWindow(dpy
, win
);
554 state
= FVWM_TIPS_NOTHING
;
557 unsigned long FTipsCheck(Display
*dpy
)
561 if (state
!= FVWM_TIPS_WAITING
|| win
== None
)
572 state
= FVWM_TIPS_MAPPED
;
582 Bool
FTipsExpose(Display
*dpy
, XEvent
*ev
)
586 if (win
== None
|| ev
->xany
.window
!= win
)
592 ex2
= ev
->xexpose
.x
+ ev
->xexpose
.width
;
593 ey2
= ev
->xexpose
.y
+ ev
->xexpose
.height
;
595 while (FCheckTypedWindowEvent(dpy
, ev
->xany
.window
, Expose
, ev
))
597 ex
= min(ex
, ev
->xexpose
.x
);
598 ey
= min(ey
, ev
->xexpose
.y
);
599 ex2
= max(ex2
, ev
->xexpose
.x
+ ev
->xexpose
.width
);
600 ey2
= max(ey2
, ev
->xexpose
.y
+ ev
->xexpose
.height
);
604 stderr
, "\tExpose: %i,%i,%i,%i %i\n",
605 ex
, ey
, ex2
-ex
, ey2
-ey
, ev
->xexpose
.count
);
612 Bool
FTipsHandleEvents(Display
*dpy
, XEvent
*ev
)
614 if (ev
->xany
.window
!= win
)
622 FTipsExpose(dpy
, ev
);
630 void FTipsUpdateLabel(Display
*dpy
, char *str
)
632 if (state
!= FVWM_TIPS_MAPPED
&& state
!= FVWM_TIPS_WAITING
)
641 CopyString(&label
, str
);
642 if (state
== FVWM_TIPS_MAPPED
)
649 void FTipsColorsetChanged(Display
*dpy
, int cs
)
651 if (state
!= FVWM_TIPS_MAPPED
|| cs
!= current_config
->colorset
)