2 * Window Maker window manager
4 * Copyright (c) 1998 Alfredo K. Kojima
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
27 #include <X11/Xutil.h>
29 #include <X11/extensions/shape.h>
37 #include "WindowMaker.h"
45 #include "workspace.h"
50 extern WPreferences wPreferences
;
52 typedef struct _WBalloon
{
78 #define TLEFT (TOP|LEFT)
79 #define TRIGHT (TOP|RIGHT)
80 #define BLEFT (BOTTOM|LEFT)
81 #define BRIGHT (BOTTOM|RIGHT)
87 #define MIN(a,b) ((a)<(b)?(a):(b))
88 #define MAX(a,b) ((a)>(b)?(a):(b))
91 drawBalloon(Pixmap pix
, GC gc
, int x
, int y
, int w
, int h
, int side
)
96 XFillArc(dpy
, pix
, gc
, x
, y
, rad
, rad
, 90*64, 90*64);
97 XFillArc(dpy
, pix
, gc
, x
, y
+h
-1-rad
, rad
, rad
, 180*64, 90*64);
99 XFillArc(dpy
, pix
, gc
, x
+w
-1-rad
, y
, rad
, rad
, 0*64, 90*64);
100 XFillArc(dpy
, pix
, gc
, x
+w
-1-rad
, y
+h
-1-rad
, rad
, rad
, 270*64, 90*64);
102 XFillRectangle(dpy
, pix
, gc
, x
, y
+rad
/2, w
, h
-rad
);
103 XFillRectangle(dpy
, pix
, gc
, x
+rad
/2, y
, w
-rad
, h
);
107 pt
[1].y
= y
+h
-1+SPACE
;
115 pt
[0].x
= x
+w
-h
+2*h
/16;
116 pt
[1].x
= x
+w
-h
+11*h
/16;
117 pt
[2].x
= x
+w
-h
+7*h
/16;
119 pt
[0].x
= x
+h
-2*h
/16;
120 pt
[1].x
= x
+h
-11*h
/16;
121 pt
[2].x
= x
+h
-7*h
/16;
123 XFillPolygon(dpy
, pix
, gc
, pt
, 3, Convex
, CoordModeOrigin
);
128 makePixmap(WScreen
*scr
, int width
, int height
, int side
, Pixmap
*mask
)
130 WBalloon
*bal
= scr
->balloon
;
135 bitmap
= XCreatePixmap(dpy
, scr
->root_win
, width
+SPACE
, height
+SPACE
, 1);
138 bal
->monoGC
= XCreateGC(dpy
, bitmap
, 0, NULL
);
140 XSetForeground(dpy
, bal
->monoGC
,
141 BlackPixelOfScreen(ScreenOfDisplay(dpy
, scr
->screen
)));
142 XFillRectangle(dpy
, bitmap
, bal
->monoGC
, 0, 0, width
+SPACE
, height
+SPACE
);
144 pixmap
= XCreatePixmap(dpy
, scr
->root_win
, width
+SPACE
, height
+SPACE
,
146 XSetForeground(dpy
, scr
->draw_gc
, scr
->black_pixel
);
147 XFillRectangle(dpy
, pixmap
, scr
->draw_gc
, 0, 0, width
+SPACE
, height
+SPACE
);
156 XSetForeground(dpy
, bal
->monoGC
,
157 WhitePixelOfScreen(ScreenOfDisplay(dpy
, scr
->screen
)));
158 drawBalloon(bitmap
, bal
->monoGC
, x
, y
, width
, height
, side
);
159 XSetForeground(dpy
, scr
->draw_gc
, scr
->white_pixel
);
160 drawBalloon(pixmap
, scr
->draw_gc
, x
+1, y
+1, width
-2, height
-2, side
);
169 showText(WScreen
*scr
, int x
, int y
, int h
, int w
, char *text
)
175 WFont
*font
= scr
->info_text_font
;
180 if (scr
->balloon
->contents
)
181 XFreePixmap(dpy
, scr
->balloon
->contents
);
183 width
= wTextWidth(font
->font
, text
, strlen(text
))+16;
184 height
= font
->height
+ 4;
192 if (x
+ width
> scr
->scr_width
) {
194 bx
= x
- width
+ w
/2;
201 if (bx
+ width
> scr
->scr_width
)
202 bx
= scr
->scr_width
- width
;
204 if (y
- (height
+ SPACE
) < 0) {
210 by
= y
- (height
+ SPACE
);
213 pixmap
= makePixmap(scr
, width
, height
, side
, &mask
);
215 XSetForeground(dpy
, scr
->info_text_gc
, scr
->black_pixel
);
217 wDrawString(pixmap
, font
, scr
->info_text_gc
, 8,
218 ty
+ font
->y
+ (height
- font
->height
)/2,
221 XSetWindowBackgroundPixmap(dpy
, scr
->balloon
->window
, pixmap
);
222 scr
->balloon
->contents
= pixmap
;
224 XResizeWindow(dpy
, scr
->balloon
->window
, width
, height
+SPACE
);
225 XShapeCombineMask(dpy
, scr
->balloon
->window
, ShapeBounding
, 0, 0, mask
,
227 XFreePixmap(dpy
, mask
);
228 XMoveWindow(dpy
, scr
->balloon
->window
, bx
, by
);
229 XMapRaised(dpy
, scr
->balloon
->window
);
231 scr
->balloon
->mapped
= 1;
233 #else /* !SHAPED_BALLOON */
235 showText(WScreen
*scr
, int x
, int y
, int h
, int w
, char *text
)
240 WFont
*font
= scr
->info_text_font
;
242 if (scr
->balloon
->contents
)
243 XFreePixmap(dpy
, scr
->balloon
->contents
);
245 width
= wTextWidth(font
->font
, text
, strlen(text
))+8;
246 height
= font
->height
+ 4;
250 else if (x
+ width
> scr
->scr_width
-1)
251 x
= scr
->scr_width
- width
;
253 if (y
- height
- 2 < 0) {
261 if (scr
->window_title_texture
[0])
262 XSetForeground(dpy
, scr
->draw_gc
,
263 scr
->window_title_texture
[0]->any
.color
.pixel
);
265 XSetForeground(dpy
, scr
->draw_gc
, scr
->light_pixel
);
267 pixmap
= XCreatePixmap(dpy
, scr
->root_win
, width
, height
, scr
->w_depth
);
268 XFillRectangle(dpy
, pixmap
, scr
->draw_gc
, 0, 0, width
, height
);
270 XSetForeground(dpy
, scr
->info_text_gc
, scr
->window_title_pixel
[0]);
272 wDrawString(pixmap
, font
->font
, scr
->info_text_gc
, 4, font
->y
+2, text
,
275 XResizeWindow(dpy
, scr
->balloon
->window
, width
, height
);
276 XMoveWindow(dpy
, scr
->balloon
->window
, x
, y
);
278 XSetWindowBackgroundPixmap(dpy
, scr
->balloon
->window
, pixmap
);
279 XClearWindow(dpy
, scr
->balloon
->window
);
280 XMapRaised(dpy
, scr
->balloon
->window
);
282 scr
->balloon
->contents
= pixmap
;
284 scr
->balloon
->mapped
= 1;
286 #endif /* !SHAPED_BALLOON */
290 showBalloon(WScreen
*scr
)
297 scr
->balloon
->timer
= NULL
;
298 scr
->balloon
->ignoreTimer
= 1;
301 if (!XGetGeometry(dpy
, scr
->balloon
->objectWindow
, &foow
, &x
, &y
,
302 &w
, &foo
, &foo
, &foo
)) {
303 scr
->balloon
->prevType
= 0;
306 showText(scr
, x
, y
, scr
->balloon
->h
, w
, scr
->balloon
->text
);
312 frameBalloon(WObjDescriptor
*object
)
314 WFrameWindow
*fwin
= (WFrameWindow
*)object
->parent
;
315 WScreen
*scr
= fwin
->core
->screen_ptr
;
317 if (fwin
->titlebar
!= object
->self
318 || !fwin
->flags
.is_client_window_frame
) {
322 if (fwin
->title
&& fwin
->flags
.incomplete_title
) {
323 scr
->balloon
->h
= (fwin
->titlebar
? fwin
->titlebar
->height
: 0);
324 scr
->balloon
->text
= wstrdup(fwin
->title
);
325 scr
->balloon
->objectWindow
= fwin
->core
->window
;
326 scr
->balloon
->timer
= WMAddTimerHandler(BALLOON_DELAY
,
327 (WMCallback
*)showBalloon
, scr
);
333 miniwindowBalloon(WObjDescriptor
*object
)
335 WIcon
*icon
= (WIcon
*)object
->parent
;
336 WScreen
*scr
= icon
->core
->screen_ptr
;
338 if (!icon
->icon_name
) {
342 scr
->balloon
->h
= icon
->core
->height
;
343 scr
->balloon
->text
= wstrdup(icon
->icon_name
);
344 scr
->balloon
->objectWindow
= icon
->core
->window
;
345 if (scr
->balloon
->prevType
== object
->parent_type
346 && scr
->balloon
->ignoreTimer
) {
347 XUnmapWindow(dpy
, scr
->balloon
->window
);
350 scr
->balloon
->timer
= WMAddTimerHandler(BALLOON_DELAY
,
351 (WMCallback
*)showBalloon
, scr
);
358 appiconBalloon(WObjDescriptor
*object
)
360 WAppIcon
*aicon
= (WAppIcon
*)object
->parent
;
361 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
364 if (aicon
->command
&& aicon
->wm_class
) {
365 tmp
= wmalloc(strlen(aicon
->command
)+strlen(aicon
->wm_class
)+8);
366 sprintf(tmp
, "%s (%s)", aicon
->wm_class
, aicon
->command
);
367 scr
->balloon
->text
= tmp
;
368 } else if (aicon
->command
) {
369 scr
->balloon
->text
= wstrdup(aicon
->command
);
370 } else if (aicon
->wm_class
) {
371 scr
->balloon
->text
= wstrdup(aicon
->wm_class
);
376 scr
->balloon
->h
= aicon
->icon
->core
->height
-2;
378 scr
->balloon
->objectWindow
= aicon
->icon
->core
->window
;
379 if (scr
->balloon
->prevType
== object
->parent_type
380 && scr
->balloon
->ignoreTimer
) {
381 XUnmapWindow(dpy
, scr
->balloon
->window
);
384 scr
->balloon
->timer
= WMAddTimerHandler(BALLOON_DELAY
,
385 (WMCallback
*)showBalloon
, scr
);
392 wBalloonInitialize(WScreen
*scr
)
395 XSetWindowAttributes attribs
;
398 bal
= wmalloc(sizeof(WBalloon
));
399 memset(bal
, 0, sizeof(WBalloon
));
403 vmask
= CWSaveUnder
|CWOverrideRedirect
|CWColormap
;
404 attribs
.save_under
= True
;
405 attribs
.override_redirect
= True
;
406 attribs
.colormap
= scr
->w_colormap
;
408 bal
->window
= XCreateWindow(dpy
, scr
->root_win
, 1, 1, 10, 10, 1,
409 scr
->w_depth
, CopyFromParent
,
410 scr
->w_visual
, vmask
, &attribs
);
412 /* select EnterNotify to so that the balloon will be unmapped
413 * when the pointer is moved over it */
414 XSelectInput(dpy
, bal
->window
, EnterWindowMask
);
421 wBalloonEnteredObject(WScreen
*scr
, WObjDescriptor
*object
)
423 WBalloon
*balloon
= scr
->balloon
;
425 if (balloon
->timer
) {
426 WMDeleteTimerHandler(balloon
->timer
);
427 balloon
->timer
= NULL
;
428 balloon
->ignoreTimer
= 0;
431 if (scr
->balloon
->text
)
432 free(scr
->balloon
->text
);
433 scr
->balloon
->text
= NULL
;
437 balloon
->ignoreTimer
= 0;
440 switch (object
->parent_type
) {
442 if (wPreferences
.window_balloon
) {
443 frameBalloon(object
);
447 case WCLASS_DOCK_ICON
:
448 if (object
->parent
!= scr
->clip_icon
&& wPreferences
.appicon_balloon
)
449 appiconBalloon(object
);
452 case WCLASS_MINIWINDOW
:
453 if (wPreferences
.miniwin_balloon
) {
454 miniwindowBalloon(object
);
458 if (wPreferences
.appicon_balloon
)
459 appiconBalloon(object
);
465 scr
->balloon
->prevType
= object
->parent_type
;
471 wBalloonHide(WScreen
*scr
)
474 if (scr
->balloon
->mapped
) {
475 XUnmapWindow(dpy
, scr
->balloon
->window
);
476 scr
->balloon
->mapped
= 0;
477 } else if (scr
->balloon
->timer
) {
478 WMDeleteTimerHandler(scr
->balloon
->timer
);
479 scr
->balloon
->timer
= NULL
;
481 scr
->balloon
->prevType
= 0;