2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
5 * Copyright (c) 1998-2003 Dan Pascu
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include <X11/Xutil.h>
34 #include "WindowMaker.h"
36 #include "superfluous.h"
43 #define PIECES ((64/ICON_KABOOM_PIECE_SIZE)*(64/ICON_KABOOM_PIECE_SIZE))
44 #define KAB_PRECISION 4
46 #define BOUNCE_DELAY (1000/BOUNCE_HZ)
47 #define BOUNCE_HEIGHT 24
48 #define BOUNCE_LENGTH 0.3
49 #define BOUNCE_DAMP 0.6
50 #define URGENT_BOUNCE_DELAY 3000
52 extern WPreferences wPreferences
;
54 void DoKaboom(WScreen
* scr
, Window win
, int x
, int y
)
56 #ifdef NORMAL_ICON_KABOOM
58 int sw
= scr
->scr_width
, sh
= scr
->scr_height
;
61 char pvx
[PIECES
], pvy
[PIECES
];
62 /* in MkLinux/PPC gcc seems to think that char is unsigned? */
63 signed char ax
[PIECES
], ay
[PIECES
];
66 XSetClipMask(dpy
, scr
->copy_gc
, None
);
67 tmp
= XCreatePixmap(dpy
, scr
->root_win
, wPreferences
.icon_size
, wPreferences
.icon_size
, scr
->depth
);
68 if (scr
->w_visual
== DefaultVisual(dpy
, scr
->screen
))
69 XCopyArea(dpy
, win
, tmp
, scr
->copy_gc
, 0, 0, wPreferences
.icon_size
, wPreferences
.icon_size
, 0, 0);
73 image
= XGetImage(dpy
, win
, 0, 0, wPreferences
.icon_size
,
74 wPreferences
.icon_size
, AllPlanes
, ZPixmap
);
76 XUnmapWindow(dpy
, win
);
79 XPutImage(dpy
, tmp
, scr
->copy_gc
, image
, 0, 0, 0, 0,
80 wPreferences
.icon_size
, wPreferences
.icon_size
);
84 for (i
= 0, k
= 0; i
< wPreferences
.icon_size
/ ICON_KABOOM_PIECE_SIZE
&& k
< PIECES
; i
++) {
85 for (j
= 0; j
< wPreferences
.icon_size
/ ICON_KABOOM_PIECE_SIZE
&& k
< PIECES
; j
++) {
89 px
[k
] = (x
+ i
* ICON_KABOOM_PIECE_SIZE
) << KAB_PRECISION
;
90 py
[k
] = y
+ j
* ICON_KABOOM_PIECE_SIZE
;
91 pvx
[k
] = rand() % (1 << (KAB_PRECISION
+ 3)) - (1 << (KAB_PRECISION
+ 3)) / 2;
92 pvy
[k
] = -15 - rand() % 7;
100 XUnmapWindow(dpy
, win
);
106 if (XCheckTypedEvent(dpy
, ButtonPress
, &foo
)) {
107 XPutBackEvent(dpy
, &foo
);
108 XClearWindow(dpy
, scr
->root_win
);
112 for (i
= 0; i
< j
; i
++) {
114 int _px
= px
[i
] >> KAB_PRECISION
;
115 XClearArea(dpy
, scr
->root_win
, _px
, py
[i
],
116 ICON_KABOOM_PIECE_SIZE
, ICON_KABOOM_PIECE_SIZE
, False
);
119 _px
= px
[i
] >> KAB_PRECISION
;
121 if (_px
< -wPreferences
.icon_size
|| _px
> sw
|| py
[i
] >= sh
) {
125 XCopyArea(dpy
, tmp
, scr
->root_win
, scr
->copy_gc
,
126 ax
[i
] * ICON_KABOOM_PIECE_SIZE
, ay
[i
] * ICON_KABOOM_PIECE_SIZE
,
127 ICON_KABOOM_PIECE_SIZE
, ICON_KABOOM_PIECE_SIZE
, _px
, py
[i
]);
133 wusleep(MINIATURIZE_ANIMATION_DELAY_Z
* 2);
136 XFreePixmap(dpy
, tmp
);
137 #endif /* NORMAL_ICON_KABOOM */
140 Pixmap
MakeGhostDock(WDock
* dock
, int sx
, int dx
, int y
)
142 WScreen
*scr
= dock
->screen_ptr
;
144 RImage
*back
, *dock_image
;
146 int i
, virtual_tiles
, h
, j
, n
;
147 unsigned long red_mask
, green_mask
, blue_mask
;
150 for (i
= 0; i
< dock
->max_icons
; i
++) {
151 if (dock
->icon_array
[i
] != NULL
&& dock
->icon_array
[i
]->yindex
> virtual_tiles
)
152 virtual_tiles
= dock
->icon_array
[i
]->yindex
;
155 h
= virtual_tiles
* wPreferences
.icon_size
;
156 h
= (y
+ h
> scr
->scr_height
) ? scr
->scr_height
- y
: h
;
157 virtual_tiles
= h
/ wPreferences
.icon_size
; /* The visible ones */
158 if (h
% wPreferences
.icon_size
)
159 virtual_tiles
++; /* There is one partially visible tile at end */
161 img
= XGetImage(dpy
, scr
->root_win
, dx
, y
, wPreferences
.icon_size
, h
, AllPlanes
, ZPixmap
);
165 red_mask
= img
->red_mask
;
166 green_mask
= img
->green_mask
;
167 blue_mask
= img
->blue_mask
;
169 back
= RCreateImageFromXImage(scr
->rcontext
, img
, NULL
);
175 for (i
= 0; i
< dock
->max_icons
; i
++) {
176 if (dock
->icon_array
[i
] != NULL
&& dock
->icon_array
[i
]->yindex
< virtual_tiles
) {
178 j
= dock
->icon_array
[i
]->yindex
* wPreferences
.icon_size
;
179 n
= (h
- j
< wPreferences
.icon_size
) ? h
- j
: wPreferences
.icon_size
;
180 if (dock
->icon_array
[i
]->icon
->pixmap
)
181 which
= dock
->icon_array
[i
]->icon
->pixmap
;
183 which
= dock
->icon_array
[i
]->icon
->core
->window
;
185 img
= XGetImage(dpy
, which
, 0, 0, wPreferences
.icon_size
, n
, AllPlanes
, ZPixmap
);
191 img
->red_mask
= red_mask
;
192 img
->green_mask
= green_mask
;
193 img
->blue_mask
= blue_mask
;
195 dock_image
= RCreateImageFromXImage(scr
->rcontext
, img
, NULL
);
201 RCombineAreaWithOpaqueness(back
, dock_image
, 0, 0,
202 wPreferences
.icon_size
, n
, 0, j
, 30 * 256 / 100);
203 RReleaseImage(dock_image
);
207 RConvertImage(scr
->rcontext
, back
, &pixmap
);
214 Pixmap
MakeGhostIcon(WScreen
* scr
, Drawable drawable
)
223 back
= RCreateImageFromDrawable(scr
->rcontext
, drawable
, None
);
232 RClearImage(back
, &color
);
233 RConvertImage(scr
->rcontext
, back
, &pixmap
);
240 void DoWindowBirth(WWindow
*wwin
)
242 #ifdef WINDOW_BIRTH_ZOOM
243 int center_x
, center_y
;
244 int width
= wwin
->frame
->core
->width
;
245 int height
= wwin
->frame
->core
->height
;
246 int w
= WMIN(width
, 20);
247 int h
= WMIN(height
, 20);
248 WScreen
*scr
= wwin
->screen_ptr
;
250 center_x
= wwin
->frame_x
+ (width
- w
) / 2;
251 center_y
= wwin
->frame_y
+ (height
- h
) / 2;
253 animateResize(scr
, center_x
, center_y
, 1, 1, wwin
->frame_x
, wwin
->frame_y
, width
, height
);
257 typedef struct AppBouncerData
{
265 static void doAppBounce(void *arg
)
267 AppBouncerData
*data
= (AppBouncerData
*)arg
;
268 WAppIcon
*aicon
= data
->wapp
->app_icon
;
271 if (aicon
&& data
->wapp
->refcount
> 1) {
272 if (wPreferences
.raise_appicons_when_bouncing
)
273 XRaiseWindow(dpy
, aicon
->icon
->core
->window
);
275 const double ticks
= BOUNCE_HZ
* BOUNCE_LENGTH
;
276 const double s
= sqrt(BOUNCE_HEIGHT
)/(ticks
/2);
277 double h
= BOUNCE_HEIGHT
*pow(BOUNCE_DAMP
, data
->pow
);
278 double sqrt_h
= sqrt(h
);
280 double offset
, x
= s
* data
->count
- sqrt_h
;
285 } else ++data
->count
;
289 case 0: /* left, bounce to right */
290 XMoveWindow(dpy
, aicon
->icon
->core
->window
,
291 aicon
->x_pos
+ (int)offset
, aicon
->y_pos
);
293 case 1: /* right, bounce to left */
294 XMoveWindow(dpy
, aicon
->icon
->core
->window
,
295 aicon
->x_pos
- (int)offset
, aicon
->y_pos
);
297 case 2: /* top, bounce down */
298 XMoveWindow(dpy
, aicon
->icon
->core
->window
,
299 aicon
->x_pos
, aicon
->y_pos
+ (int)offset
);
301 case 3: /* bottom, bounce up */
302 XMoveWindow(dpy
, aicon
->icon
->core
->window
,
303 aicon
->x_pos
, aicon
->y_pos
- (int)offset
);
310 XMoveWindow(dpy
, aicon
->icon
->core
->window
,
311 aicon
->x_pos
, aicon
->y_pos
);
312 CommitStackingForWindow(aicon
->icon
->core
);
313 data
->wapp
->flags
.bouncing
= 0;
314 WMDeleteTimerHandler(data
->timer
);
315 wApplicationDestroy(data
->wapp
);
319 static int bounceDirection(WAppIcon
*aicon
)
321 enum { left_e
= 1, right_e
= 2, top_e
= 4, bottom_e
= 8 };
323 WScreen
*scr
= aicon
->icon
->core
->screen_ptr
;
325 int l
, r
, t
, b
, h
, v
;
328 rr
.pos
.x
= aicon
->x_pos
;
329 rr
.pos
.y
= aicon
->y_pos
;
330 rr
.size
.width
= rr
.size
.height
= 64;
332 sr
= wGetRectForHead(scr
, wGetHeadForRect(scr
, rr
));
334 l
= rr
.pos
.x
- sr
.pos
.x
;
335 r
= sr
.pos
.x
+ sr
.size
.width
- rr
.pos
.x
- rr
.size
.width
;
336 t
= rr
.pos
.y
- sr
.pos
.y
;
337 b
= sr
.pos
.y
+ sr
.size
.height
- rr
.pos
.y
- rr
.size
.height
;
355 if (aicon
->dock
&& abs(aicon
->xindex
) != abs(aicon
->yindex
)) {
356 if (abs(aicon
->xindex
) < abs(aicon
->yindex
)) dir
&= ~(top_e
| bottom_e
);
357 else dir
&= ~(left_e
| right_e
);
359 if (h
< v
) dir
&= ~(top_e
| bottom_e
);
360 else dir
&= ~(left_e
| right_e
);
381 wwarning(_("Impossible direction: %d"), dir
);
389 void wAppBounce(WApplication
*wapp
)
391 if (!wPreferences
.no_animations
&& wapp
->app_icon
&& !wapp
->flags
.bouncing
392 && !wPreferences
.do_not_make_appicons_bounce
) {
394 wapp
->flags
.bouncing
= 1;
396 AppBouncerData
*data
= (AppBouncerData
*)malloc(sizeof(AppBouncerData
));
398 data
->count
= data
->pow
= 0;
399 data
->dir
= bounceDirection(wapp
->app_icon
);
400 data
->timer
= WMAddPersistentTimerHandler(BOUNCE_DELAY
, doAppBounce
, data
);
404 static int appIsUrgent(WApplication
*wapp
)
409 if (!wapp
->main_window_desc
) {
410 wwarning("group leader not found for window group");
413 scr
= wapp
->main_window_desc
->screen_ptr
;
414 wlist
= scr
->focused_window
;
419 if (wlist
->main_window
== wapp
->main_window
) {
420 if (wlist
->flags
.urgent
)
429 static void doAppUrgentBounce(void *arg
)
431 WApplication
*wapp
= (WApplication
*)arg
;
433 if (appIsUrgent(wapp
)) {
434 if(wPreferences
.bounce_appicons_when_urgent
) wAppBounce(wapp
);
436 WMDeleteTimerHandler(wapp
->urgent_bounce_timer
);
437 wapp
->urgent_bounce_timer
= NULL
;
441 void wAppBounceWhileUrgent(WApplication
*wapp
)
444 if (appIsUrgent(wapp
)) {
445 if (!wapp
->urgent_bounce_timer
) {
446 wapp
->urgent_bounce_timer
= WMAddPersistentTimerHandler(URGENT_BOUNCE_DELAY
, doAppUrgentBounce
, wapp
);
447 doAppUrgentBounce(wapp
);
450 if (wapp
->urgent_bounce_timer
) {
451 WMDeleteTimerHandler(wapp
->urgent_bounce_timer
);
452 wapp
->urgent_bounce_timer
= NULL
;