2 * Window Maker window manager
4 * Copyright (c) 1998-2002 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 <WINGs/WINGsP.h>
39 #include "WindowMaker.h"
47 #include "workspace.h"
52 extern WPreferences wPreferences
;
54 typedef struct _WBalloon
{
80 #define TLEFT (TOP|LEFT)
81 #define TRIGHT (TOP|RIGHT)
82 #define BLEFT (BOTTOM|LEFT)
83 #define BRIGHT (BOTTOM|RIGHT)
92 drawBalloon(WScreen
*scr
, Pixmap bitmap
, Pixmap pix
, int x
, int y
, int w
,
95 GC bgc
= scr
->balloon
->monoGC
;
102 XSetForeground(dpy
, bgc
, 1);
104 XFillArc(dpy
, bitmap
, bgc
, x
, y
, rad
, rad
, 90*64, 90*64);
105 XFillArc(dpy
, bitmap
, bgc
, x
, y
+h
-1-rad
, rad
, rad
, 180*64, 90*64);
107 XFillArc(dpy
, bitmap
, bgc
, x
+w
-1-rad
, y
, rad
, rad
, 0*64, 90*64);
108 XFillArc(dpy
, bitmap
, bgc
, x
+w
-1-rad
, y
+h
-1-rad
, rad
, rad
, 270*64, 90*64);
110 XFillRectangle(dpy
, bitmap
, bgc
, x
, y
+rad
/2, w
, h
-rad
);
111 XFillRectangle(dpy
, bitmap
, bgc
, x
+rad
/2, y
, w
-rad
, h
);
114 XSetForeground(dpy
, gc
, scr
->white_pixel
);
116 XFillArc(dpy
, pix
, gc
, x
+1, y
+1, rad
, rad
, 90*64, 90*64);
117 XFillArc(dpy
, pix
, gc
, x
+1, y
+h
-2-rad
, rad
, rad
, 180*64, 90*64);
119 XFillArc(dpy
, pix
, gc
, x
+w
-2-rad
, y
+1, rad
, rad
, 0*64, 90*64);
120 XFillArc(dpy
, pix
, gc
, x
+w
-2-rad
, y
+h
-2-rad
, rad
, rad
, 270*64, 90*64);
122 XFillRectangle(dpy
, pix
, gc
, x
+1, y
+1+rad
/2, w
-2, h
-2-rad
);
123 XFillRectangle(dpy
, pix
, gc
, x
+1+rad
/2, y
+1, w
-2-rad
, h
-2);
127 pt
[1].y
= y
+h
-1+SPACE
;
129 ipt
[0].y
= pt
[0].y
-1;
130 ipt
[1].y
= pt
[1].y
-1;
131 ipt
[2].y
= pt
[2].y
-1;
136 ipt
[0].y
= pt
[0].y
+1;
137 ipt
[1].y
= pt
[1].y
+1;
138 ipt
[2].y
= pt
[2].y
+1;
141 /*w1 = WMAX(h, 24);*/
145 pt
[0].x
= x
+w
-w1
+2*w1
/16;
146 pt
[1].x
= x
+w
-w1
+11*w1
/16;
147 pt
[2].x
= x
+w
-w1
+7*w1
/16;
148 ipt
[0].x
= x
+1+w
-w1
+2*(w1
-1)/16;
149 ipt
[1].x
= x
+1+w
-w1
+11*(w1
-1)/16;
150 ipt
[2].x
= x
+1+w
-w1
+7*(w1
-1)/16;
151 /*ipt[0].x = pt[0].x+1;
153 ipt[2].x = pt[2].x;*/
155 pt
[0].x
= x
+w1
-2*w1
/16;
156 pt
[1].x
= x
+w1
-11*w1
/16;
157 pt
[2].x
= x
+w1
-7*w1
/16;
158 ipt
[0].x
= x
-1+w1
-2*(w1
-1)/16;
159 ipt
[1].x
= x
-1+w1
-11*(w1
-1)/16;
160 ipt
[2].x
= x
-1+w1
-7*(w1
-1)/16;
161 /*ipt[0].x = pt[0].x-1;
163 ipt[2].x = pt[2].x;*/
166 XFillPolygon(dpy
, bitmap
, bgc
, pt
, 3, Convex
, CoordModeOrigin
);
167 XFillPolygon(dpy
, pix
, gc
, ipt
, 3, Convex
, CoordModeOrigin
);
170 XSetForeground(dpy
, gc
, scr
->black_pixel
);
172 XDrawLines(dpy
, pix
, gc
, pt
, 3, CoordModeOrigin
);
180 XDrawLines(dpy
, pix
, gc
, pt
, 3, CoordModeOrigin
);
185 makePixmap(WScreen
*scr
, int width
, int height
, int side
, Pixmap
*mask
)
187 WBalloon
*bal
= scr
->balloon
;
192 bitmap
= XCreatePixmap(dpy
, scr
->root_win
, width
+SPACE
, height
+SPACE
, 1);
195 bal
->monoGC
= XCreateGC(dpy
, bitmap
, 0, NULL
);
197 XSetForeground(dpy
, bal
->monoGC
, 0);
198 XFillRectangle(dpy
, bitmap
, bal
->monoGC
, 0, 0, width
+SPACE
, height
+SPACE
);
200 pixmap
= XCreatePixmap(dpy
, scr
->root_win
, width
+SPACE
, height
+SPACE
,
202 XSetForeground(dpy
, scr
->draw_gc
, scr
->black_pixel
);
203 XFillRectangle(dpy
, pixmap
, scr
->draw_gc
, 0, 0, width
+SPACE
, height
+SPACE
);
212 drawBalloon(scr
, bitmap
, pixmap
, x
, y
, width
, height
, side
);
221 showText(WScreen
*scr
, int x
, int y
, int h
, int w
, char *text
)
227 WMFont
*font
= scr
->info_text_font
;
232 if (scr
->balloon
->contents
)
233 XFreePixmap(dpy
, scr
->balloon
->contents
);
235 width
= WMWidthOfString(font
, text
, strlen(text
))+16;
236 height
= WMFontHeight(font
) + 4;
244 if (x
+ width
> scr
->scr_width
) {
246 bx
= x
- width
+ w
/2;
253 if (bx
+ width
> scr
->scr_width
)
254 bx
= scr
->scr_width
- width
;
256 if (y
- (height
+ SPACE
) < 0) {
262 by
= y
- (height
+ SPACE
);
265 pixmap
= makePixmap(scr
, width
, height
, side
, &mask
);
267 WMDrawString(scr
->wmscreen
, pixmap
, scr
->black
, font
, 8,
268 ty
+ (height
- WMFontHeight(font
))/2,
271 XSetWindowBackgroundPixmap(dpy
, scr
->balloon
->window
, pixmap
);
272 scr
->balloon
->contents
= pixmap
;
274 XResizeWindow(dpy
, scr
->balloon
->window
, width
, height
+SPACE
);
275 XShapeCombineMask(dpy
, scr
->balloon
->window
, ShapeBounding
, 0, 0, mask
,
277 XFreePixmap(dpy
, mask
);
278 XMoveWindow(dpy
, scr
->balloon
->window
, bx
, by
);
279 XMapRaised(dpy
, scr
->balloon
->window
);
282 scr
->balloon
->mapped
= 1;
284 #else /* !SHAPED_BALLOON */
286 showText(WScreen
*scr
, int x
, int y
, int h
, int w
, char *text
)
291 WMFont
*font
= scr
->info_text_font
;
293 if (scr
->balloon
->contents
)
294 XFreePixmap(dpy
, scr
->balloon
->contents
);
296 width
= WMWidthOfString(font
, text
, strlen(text
))+8;
297 height
= WMFontHeight(font
) + 4;
301 else if (x
+ width
> scr
->scr_width
-1)
302 x
= scr
->scr_width
- width
;
304 if (y
- height
- 2 < 0) {
312 if (scr
->window_title_texture
[0])
313 XSetForeground(dpy
, scr
->draw_gc
,
314 scr
->window_title_texture
[0]->any
.color
.pixel
);
316 XSetForeground(dpy
, scr
->draw_gc
, scr
->light_pixel
);
318 pixmap
= XCreatePixmap(dpy
, scr
->root_win
, width
, height
, scr
->w_depth
);
319 XFillRectangle(dpy
, pixmap
, scr
->draw_gc
, 0, 0, width
, height
);
321 WMDrawString(scr
->wmscreen
, pixmap
, scr
->window_title_color
[0], font
, 4, 2,
324 XResizeWindow(dpy
, scr
->balloon
->window
, width
, height
);
325 XMoveWindow(dpy
, scr
->balloon
->window
, x
, y
);
327 XSetWindowBackgroundPixmap(dpy
, scr
->balloon
->window
, pixmap
);
328 XClearWindow(dpy
, scr
->balloon
->window
);
329 XMapRaised(dpy
, scr
->balloon
->window
);
331 scr
->balloon
->contents
= pixmap
;
333 scr
->balloon
->mapped
= 1;
335 #endif /* !SHAPED_BALLOON */
339 showBalloon(WScreen
*scr
)
346 scr
->balloon
->timer
= NULL
;
347 scr
->balloon
->ignoreTimer
= 1;
350 if (!XGetGeometry(dpy
, scr
->balloon
->objectWindow
, &foow
, &x
, &y
,
351 &w
, &foo
, &foo
, &foo
)) {
352 scr
->balloon
->prevType
= 0;
355 showText(scr
, x
, y
, scr
->balloon
->h
, w
, scr
->balloon
->text
);
361 frameBalloon(WObjDescriptor
*object
)
363 WFrameWindow
*fwin
= (WFrameWindow
*)object
->parent
;
364 WScreen
*scr
= fwin
->core
->screen_ptr
;
366 if (fwin
->titlebar
!= object
->self
367 || !fwin
->flags
.is_client_window_frame
) {
371 if (fwin
->title
&& fwin
->flags
.incomplete_title
) {
372 scr
->balloon
->h
= (fwin
->titlebar
? fwin
->titlebar
->height
: 0);
373 scr
->balloon
->text
= wstrdup(fwin
->title
);
374 scr
->balloon
->objectWindow
= fwin
->core
->window
;
375 scr
->balloon
->timer
= WMAddTimerHandler(BALLOON_DELAY
,
376 (WMCallback
*)showBalloon
, scr
);
382 miniwindowBalloon(WObjDescriptor
*object
)
384 WIcon
*icon
= (WIcon
*)object
->parent
;
385 WScreen
*scr
= icon
->core
->screen_ptr
;
387 if (!icon
->icon_name
) {
391 scr
->balloon
->h
= icon
->core
->height
;
392 scr
->balloon
->text
= wstrdup(icon
->icon_name
);
393 scr
->balloon
->objectWindow
= icon
->core
->window
;
394 if ((scr
->balloon
->prevType
== object
->parent_type
395 || scr
->balloon
->prevType
== WCLASS_APPICON
)
396 && scr
->balloon
->ignoreTimer
) {
397 XUnmapWindow(dpy
, scr
->balloon
->window
);
400 scr
->balloon
->timer
= WMAddTimerHandler(BALLOON_DELAY
,
401 (WMCallback
*)showBalloon
, scr
);
408 appiconBalloon(WObjDescriptor
*object
)
410 WAppIcon
*aicon
= (WAppIcon
*)object
->parent
;
411 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
414 if (aicon
->command
&& aicon
->wm_class
) {
415 int len
= strlen(aicon
->command
)+strlen(aicon
->wm_class
)+8;
417 snprintf(tmp
, len
, "%s (%s)", aicon
->wm_class
, aicon
->command
);
418 scr
->balloon
->text
= tmp
;
419 } else if (aicon
->command
) {
420 scr
->balloon
->text
= wstrdup(aicon
->command
);
421 } else if (aicon
->wm_class
) {
422 scr
->balloon
->text
= wstrdup(aicon
->wm_class
);
427 scr
->balloon
->h
= aicon
->icon
->core
->height
-2;
429 scr
->balloon
->objectWindow
= aicon
->icon
->core
->window
;
430 if ((scr
->balloon
->prevType
== object
->parent_type
431 || scr
->balloon
->prevType
== WCLASS_MINIWINDOW
)
432 && scr
->balloon
->ignoreTimer
) {
433 XUnmapWindow(dpy
, scr
->balloon
->window
);
436 scr
->balloon
->timer
= WMAddTimerHandler(BALLOON_DELAY
,
437 (WMCallback
*)showBalloon
, scr
);
444 wBalloonInitialize(WScreen
*scr
)
447 XSetWindowAttributes attribs
;
450 bal
= wmalloc(sizeof(WBalloon
));
451 memset(bal
, 0, sizeof(WBalloon
));
455 vmask
= CWSaveUnder
|CWOverrideRedirect
|CWColormap
|CWBackPixel
457 attribs
.save_under
= True
;
458 attribs
.override_redirect
= True
;
459 attribs
.colormap
= scr
->w_colormap
;
460 attribs
.background_pixel
= scr
->icon_back_texture
->normal
.pixel
;
461 attribs
.border_pixel
= 0; /* do not care */
463 bal
->window
= XCreateWindow(dpy
, scr
->root_win
, 1, 1, 10, 10, 1,
464 scr
->w_depth
, CopyFromParent
,
465 scr
->w_visual
, vmask
, &attribs
);
467 /* select EnterNotify to so that the balloon will be unmapped
468 * when the pointer is moved over it */
469 XSelectInput(dpy
, bal
->window
, EnterWindowMask
);
476 wBalloonEnteredObject(WScreen
*scr
, WObjDescriptor
*object
)
478 WBalloon
*balloon
= scr
->balloon
;
480 if (balloon
->timer
) {
481 WMDeleteTimerHandler(balloon
->timer
);
482 balloon
->timer
= NULL
;
483 balloon
->ignoreTimer
= 0;
486 if (scr
->balloon
->text
)
487 wfree(scr
->balloon
->text
);
488 scr
->balloon
->text
= NULL
;
492 balloon
->ignoreTimer
= 0;
495 switch (object
->parent_type
) {
497 if (wPreferences
.window_balloon
) {
498 frameBalloon(object
);
502 case WCLASS_DOCK_ICON
:
503 if (object
->parent
!= scr
->clip_icon
&& wPreferences
.appicon_balloon
)
504 appiconBalloon(object
);
509 case WCLASS_MINIWINDOW
:
510 if (wPreferences
.miniwin_balloon
) {
511 miniwindowBalloon(object
);
515 if (wPreferences
.appicon_balloon
)
516 appiconBalloon(object
);
522 scr
->balloon
->prevType
= object
->parent_type
;
528 wBalloonHide(WScreen
*scr
)
531 if (scr
->balloon
->mapped
) {
532 XUnmapWindow(dpy
, scr
->balloon
->window
);
533 scr
->balloon
->mapped
= 0;
534 } else if (scr
->balloon
->timer
) {
535 WMDeleteTimerHandler(scr
->balloon
->timer
);
536 scr
->balloon
->timer
= NULL
;
538 scr
->balloon
->prevType
= 0;