Code refactoring: replaced macro 'HAVE_XRANDR' by 'USE_XRANDR' for consistency
[wmaker-crm.git] / src / superfluous.c
blob0883cc111576ed6eec016ea1072d8a441ac89006
1 /*
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.
22 #include "wconfig.h"
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <math.h>
30 #include <time.h>
32 #include <wraster.h>
34 #include "WindowMaker.h"
35 #include "screen.h"
36 #include "superfluous.h"
37 #include "framewin.h"
38 #include "window.h"
39 #include "actions.h"
40 #include "xinerama.h"
41 #include "stacking.h"
43 #define PIECES ((64/ICON_KABOOM_PIECE_SIZE)*(64/ICON_KABOOM_PIECE_SIZE))
44 #define KAB_PRECISION 4
45 #define BOUNCE_HZ 25
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
53 void DoKaboom(WScreen * scr, Window win, int x, int y)
55 #ifdef NORMAL_ICON_KABOOM
56 int i, j, k;
57 int sw = scr->scr_width, sh = scr->scr_height;
58 int px[PIECES];
59 short py[PIECES];
60 char pvx[PIECES], pvy[PIECES];
61 /* in MkLinux/PPC gcc seems to think that char is unsigned? */
62 signed char ax[PIECES], ay[PIECES];
63 Pixmap tmp;
65 XSetClipMask(dpy, scr->copy_gc, None);
66 tmp = XCreatePixmap(dpy, scr->root_win, wPreferences.icon_size, wPreferences.icon_size, scr->depth);
67 if (scr->w_visual == DefaultVisual(dpy, scr->screen))
68 XCopyArea(dpy, win, tmp, scr->copy_gc, 0, 0, wPreferences.icon_size, wPreferences.icon_size, 0, 0);
69 else {
70 XImage *image;
72 image = XGetImage(dpy, win, 0, 0, wPreferences.icon_size,
73 wPreferences.icon_size, AllPlanes, ZPixmap);
74 if (!image) {
75 XUnmapWindow(dpy, win);
76 return;
78 XPutImage(dpy, tmp, scr->copy_gc, image, 0, 0, 0, 0,
79 wPreferences.icon_size, wPreferences.icon_size);
80 XDestroyImage(image);
83 for (i = 0, k = 0; i < wPreferences.icon_size / ICON_KABOOM_PIECE_SIZE && k < PIECES; i++) {
84 for (j = 0; j < wPreferences.icon_size / ICON_KABOOM_PIECE_SIZE && k < PIECES; j++) {
85 if (rand() % 2) {
86 ax[k] = i;
87 ay[k] = j;
88 px[k] = (x + i * ICON_KABOOM_PIECE_SIZE) << KAB_PRECISION;
89 py[k] = y + j * ICON_KABOOM_PIECE_SIZE;
90 pvx[k] = rand() % (1 << (KAB_PRECISION + 3)) - (1 << (KAB_PRECISION + 3)) / 2;
91 pvy[k] = -15 - rand() % 7;
92 k++;
93 } else {
94 ax[k] = -1;
99 XUnmapWindow(dpy, win);
101 j = k;
102 while (k > 0) {
103 XEvent foo;
105 if (XCheckTypedEvent(dpy, ButtonPress, &foo)) {
106 XPutBackEvent(dpy, &foo);
107 XClearWindow(dpy, scr->root_win);
108 break;
111 for (i = 0; i < j; i++) {
112 if (ax[i] >= 0) {
113 int _px = px[i] >> KAB_PRECISION;
114 XClearArea(dpy, scr->root_win, _px, py[i],
115 ICON_KABOOM_PIECE_SIZE, ICON_KABOOM_PIECE_SIZE, False);
116 px[i] += pvx[i];
117 py[i] += pvy[i];
118 _px = px[i] >> KAB_PRECISION;
119 pvy[i]++;
120 if (_px < -wPreferences.icon_size || _px > sw || py[i] >= sh) {
121 ax[i] = -1;
122 k--;
123 } else {
124 XCopyArea(dpy, tmp, scr->root_win, scr->copy_gc,
125 ax[i] * ICON_KABOOM_PIECE_SIZE, ay[i] * ICON_KABOOM_PIECE_SIZE,
126 ICON_KABOOM_PIECE_SIZE, ICON_KABOOM_PIECE_SIZE, _px, py[i]);
131 XFlush(dpy);
132 wusleep(MINIATURIZE_ANIMATION_DELAY_Z * 2);
135 XFreePixmap(dpy, tmp);
136 #endif /* NORMAL_ICON_KABOOM */
139 Pixmap MakeGhostIcon(WScreen * scr, Drawable drawable)
141 RImage *back;
142 RColor color;
143 Pixmap pixmap;
145 if (!drawable)
146 return None;
148 back = RCreateImageFromDrawable(scr->rcontext, drawable, None);
149 if (!back)
150 return None;
152 color.red = 0xff;
153 color.green = 0xff;
154 color.blue = 0xff;
155 color.alpha = 200;
157 RClearImage(back, &color);
158 RConvertImage(scr->rcontext, back, &pixmap);
160 RReleaseImage(back);
162 return pixmap;
165 void DoWindowBirth(WWindow *wwin)
167 #ifdef WINDOW_BIRTH_ZOOM
168 int center_x, center_y;
169 int width = wwin->frame->core->width;
170 int height = wwin->frame->core->height;
171 int w = WMIN(width, 20);
172 int h = WMIN(height, 20);
173 WScreen *scr = wwin->screen_ptr;
175 center_x = wwin->frame_x + (width - w) / 2;
176 center_y = wwin->frame_y + (height - h) / 2;
178 animateResize(scr, center_x, center_y, 1, 1, wwin->frame_x, wwin->frame_y, width, height);
179 #else
180 /* Parameter not used, but tell the compiler that it is ok */
181 (void) wwin;
182 #endif
185 typedef struct AppBouncerData {
186 WApplication *wapp;
187 int count;
188 int pow;
189 int dir;
190 WMHandlerID *timer;
191 } AppBouncerData;
193 static void doAppBounce(void *arg)
195 AppBouncerData *data = (AppBouncerData*)arg;
196 WAppIcon *aicon = data->wapp->app_icon;
198 reinit:
199 if (aicon && data->wapp->refcount > 1) {
200 if (wPreferences.raise_appicons_when_bouncing)
201 XRaiseWindow(dpy, aicon->icon->core->window);
203 const double ticks = BOUNCE_HZ * BOUNCE_LENGTH;
204 const double s = sqrt(BOUNCE_HEIGHT)/(ticks/2);
205 double h = BOUNCE_HEIGHT*pow(BOUNCE_DAMP, data->pow);
206 double sqrt_h = sqrt(h);
207 if (h > 3) {
208 double offset, x = s * data->count - sqrt_h;
209 if (x > sqrt_h) {
210 ++data->pow;
211 data->count = 0;
212 goto reinit;
213 } else ++data->count;
214 offset = h - x*x;
216 switch (data->dir) {
217 case 0: /* left, bounce to right */
218 XMoveWindow(dpy, aicon->icon->core->window,
219 aicon->x_pos + (int)offset, aicon->y_pos);
220 break;
221 case 1: /* right, bounce to left */
222 XMoveWindow(dpy, aicon->icon->core->window,
223 aicon->x_pos - (int)offset, aicon->y_pos);
224 break;
225 case 2: /* top, bounce down */
226 XMoveWindow(dpy, aicon->icon->core->window,
227 aicon->x_pos, aicon->y_pos + (int)offset);
228 break;
229 case 3: /* bottom, bounce up */
230 XMoveWindow(dpy, aicon->icon->core->window,
231 aicon->x_pos, aicon->y_pos - (int)offset);
232 break;
234 return;
238 XMoveWindow(dpy, aicon->icon->core->window,
239 aicon->x_pos, aicon->y_pos);
240 CommitStackingForWindow(aicon->icon->core);
241 data->wapp->flags.bouncing = 0;
242 WMDeleteTimerHandler(data->timer);
243 wApplicationDestroy(data->wapp);
244 free(data);
247 static int bounceDirection(WAppIcon *aicon)
249 enum { left_e = 1, right_e = 2, top_e = 4, bottom_e = 8 };
251 WScreen *scr = aicon->icon->core->screen_ptr;
252 WMRect rr, sr;
253 int l, r, t, b, h, v;
254 int dir = 0;
256 rr.pos.x = aicon->x_pos;
257 rr.pos.y = aicon->y_pos;
258 rr.size.width = rr.size.height = 64;
260 sr = wGetRectForHead(scr, wGetHeadForRect(scr, rr));
262 l = rr.pos.x - sr.pos.x;
263 r = sr.pos.x + sr.size.width - rr.pos.x - rr.size.width;
264 t = rr.pos.y - sr.pos.y;
265 b = sr.pos.y + sr.size.height - rr.pos.y - rr.size.height;
267 if (l < r) {
268 dir |= left_e;
269 h = l;
270 } else {
271 dir |= right_e;
272 h = r;
275 if (t < b) {
276 dir |= top_e;
277 v = t;
278 } else {
279 dir |= bottom_e;
280 v = b;
283 if (aicon->dock && abs(aicon->xindex) != abs(aicon->yindex)) {
284 if (abs(aicon->xindex) < abs(aicon->yindex)) dir &= ~(top_e | bottom_e);
285 else dir &= ~(left_e | right_e);
286 } else {
287 if (h < v) dir &= ~(top_e | bottom_e);
288 else dir &= ~(left_e | right_e);
291 switch (dir) {
292 case left_e:
293 dir = 0;
294 break;
296 case right_e:
297 dir = 1;
298 break;
300 case top_e:
301 dir = 2;
302 break;
304 case bottom_e:
305 dir = 3;
306 break;
308 default:
309 wwarning(_("Impossible direction: %d"), dir);
310 dir = 3;
311 break;
314 return dir;
317 void wAppBounce(WApplication *wapp)
319 if (!wPreferences.no_animations && wapp->app_icon && !wapp->flags.bouncing
320 && !wPreferences.do_not_make_appicons_bounce) {
321 ++wapp->refcount;
322 wapp->flags.bouncing = 1;
324 AppBouncerData *data = (AppBouncerData *)malloc(sizeof(AppBouncerData));
325 data->wapp = wapp;
326 data->count = data->pow = 0;
327 data->dir = bounceDirection(wapp->app_icon);
328 data->timer = WMAddPersistentTimerHandler(BOUNCE_DELAY, doAppBounce, data);
332 static int appIsUrgent(WApplication *wapp)
334 WScreen *scr;
335 WWindow *wlist;
337 if (!wapp->main_window_desc) {
338 wwarning("group leader not found for window group");
339 return 0;
341 scr = wapp->main_window_desc->screen_ptr;
342 wlist = scr->focused_window;
343 if (!wlist)
344 return 0;
346 while (wlist) {
347 if (wlist->main_window == wapp->main_window) {
348 if (wlist->flags.urgent)
349 return 1;
351 wlist = wlist->prev;
354 return 0;
357 static void doAppUrgentBounce(void *arg)
359 WApplication *wapp = (WApplication *)arg;
361 if (appIsUrgent(wapp)) {
362 if(wPreferences.bounce_appicons_when_urgent) wAppBounce(wapp);
363 } else {
364 WMDeleteTimerHandler(wapp->urgent_bounce_timer);
365 wapp->urgent_bounce_timer = NULL;
369 void wAppBounceWhileUrgent(WApplication *wapp)
371 if (!wapp) return;
372 if (appIsUrgent(wapp)) {
373 if (!wapp->urgent_bounce_timer) {
374 wapp->urgent_bounce_timer = WMAddPersistentTimerHandler(URGENT_BOUNCE_DELAY, doAppUrgentBounce, wapp);
375 doAppUrgentBounce(wapp);
377 } else {
378 if (wapp->urgent_bounce_timer) {
379 WMDeleteTimerHandler(wapp->urgent_bounce_timer);
380 wapp->urgent_bounce_timer = NULL;