Added option to 'configure' to control debug information for compilation
[wmaker-crm.git] / src / superfluous.c
blob135ce429bb494ae9c8fa66d308a9776699913c0c
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
52 extern WPreferences wPreferences;
54 void DoKaboom(WScreen * scr, Window win, int x, int y)
56 #ifdef NORMAL_ICON_KABOOM
57 int i, j, k;
58 int sw = scr->scr_width, sh = scr->scr_height;
59 int px[PIECES];
60 short py[PIECES];
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];
64 Pixmap tmp;
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);
70 else {
71 XImage *image;
73 image = XGetImage(dpy, win, 0, 0, wPreferences.icon_size,
74 wPreferences.icon_size, AllPlanes, ZPixmap);
75 if (!image) {
76 XUnmapWindow(dpy, win);
77 return;
79 XPutImage(dpy, tmp, scr->copy_gc, image, 0, 0, 0, 0,
80 wPreferences.icon_size, wPreferences.icon_size);
81 XDestroyImage(image);
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++) {
86 if (rand() % 2) {
87 ax[k] = i;
88 ay[k] = 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;
93 k++;
94 } else {
95 ax[k] = -1;
100 XUnmapWindow(dpy, win);
102 j = k;
103 while (k > 0) {
104 XEvent foo;
106 if (XCheckTypedEvent(dpy, ButtonPress, &foo)) {
107 XPutBackEvent(dpy, &foo);
108 XClearWindow(dpy, scr->root_win);
109 break;
112 for (i = 0; i < j; i++) {
113 if (ax[i] >= 0) {
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);
117 px[i] += pvx[i];
118 py[i] += pvy[i];
119 _px = px[i] >> KAB_PRECISION;
120 pvy[i]++;
121 if (_px < -wPreferences.icon_size || _px > sw || py[i] >= sh) {
122 ax[i] = -1;
123 k--;
124 } else {
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]);
132 XFlush(dpy);
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;
143 XImage *img;
144 RImage *back, *dock_image;
145 Pixmap pixmap;
146 int i, virtual_tiles, h, j, n;
147 unsigned long red_mask, green_mask, blue_mask;
149 virtual_tiles = 0;
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;
154 virtual_tiles++;
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);
162 if (!img)
163 return None;
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);
170 XDestroyImage(img);
171 if (!back) {
172 return None;
175 for (i = 0; i < dock->max_icons; i++) {
176 if (dock->icon_array[i] != NULL && dock->icon_array[i]->yindex < virtual_tiles) {
177 Pixmap which;
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;
182 else
183 which = dock->icon_array[i]->icon->core->window;
185 img = XGetImage(dpy, which, 0, 0, wPreferences.icon_size, n, AllPlanes, ZPixmap);
187 if (!img) {
188 RReleaseImage(back);
189 return None;
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);
196 XDestroyImage(img);
197 if (!dock_image) {
198 RReleaseImage(back);
199 return None;
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);
209 RReleaseImage(back);
211 return pixmap;
214 Pixmap MakeGhostIcon(WScreen * scr, Drawable drawable)
216 RImage *back;
217 RColor color;
218 Pixmap pixmap;
220 if (!drawable)
221 return None;
223 back = RCreateImageFromDrawable(scr->rcontext, drawable, None);
224 if (!back)
225 return None;
227 color.red = 0xff;
228 color.green = 0xff;
229 color.blue = 0xff;
230 color.alpha = 200;
232 RClearImage(back, &color);
233 RConvertImage(scr->rcontext, back, &pixmap);
235 RReleaseImage(back);
237 return 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);
254 #endif
257 typedef struct AppBouncerData {
258 WApplication *wapp;
259 int count;
260 int pow;
261 int dir;
262 WMHandlerID *timer;
263 } AppBouncerData;
265 static void doAppBounce(void *arg)
267 AppBouncerData *data = (AppBouncerData*)arg;
268 WAppIcon *aicon = data->wapp->app_icon;
270 reinit:
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);
279 if (h > 3) {
280 double offset, x = s * data->count - sqrt_h;
281 if (x > sqrt_h) {
282 ++data->pow;
283 data->count = 0;
284 goto reinit;
285 } else ++data->count;
286 offset = h - x*x;
288 switch (data->dir) {
289 case 0: /* left, bounce to right */
290 XMoveWindow(dpy, aicon->icon->core->window,
291 aicon->x_pos + (int)offset, aicon->y_pos);
292 break;
293 case 1: /* right, bounce to left */
294 XMoveWindow(dpy, aicon->icon->core->window,
295 aicon->x_pos - (int)offset, aicon->y_pos);
296 break;
297 case 2: /* top, bounce down */
298 XMoveWindow(dpy, aicon->icon->core->window,
299 aicon->x_pos, aicon->y_pos + (int)offset);
300 break;
301 case 3: /* bottom, bounce up */
302 XMoveWindow(dpy, aicon->icon->core->window,
303 aicon->x_pos, aicon->y_pos - (int)offset);
304 break;
306 return;
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);
316 free(data);
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;
324 WMRect rr, sr;
325 int l, r, t, b, h, v;
326 int dir = 0;
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;
339 if (l < r) {
340 dir |= left_e;
341 h = l;
342 } else {
343 dir |= right_e;
344 h = r;
347 if (t < b) {
348 dir |= top_e;
349 v = t;
350 } else {
351 dir |= bottom_e;
352 v = b;
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);
358 } else {
359 if (h < v) dir &= ~(top_e | bottom_e);
360 else dir &= ~(left_e | right_e);
363 switch (dir) {
364 case left_e:
365 dir = 0;
366 break;
368 case right_e:
369 dir = 1;
370 break;
372 case top_e:
373 dir = 2;
374 break;
376 case bottom_e:
377 dir = 3;
378 break;
380 default:
381 wwarning(_("Impossible direction: %d"), dir);
382 dir = 3;
383 break;
386 return dir;
389 void wAppBounce(WApplication *wapp)
391 if (!wPreferences.no_animations && wapp->app_icon && !wapp->flags.bouncing
392 && !wPreferences.do_not_make_appicons_bounce) {
393 ++wapp->refcount;
394 wapp->flags.bouncing = 1;
396 AppBouncerData *data = (AppBouncerData *)malloc(sizeof(AppBouncerData));
397 data->wapp = wapp;
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)
406 WScreen *scr;
407 WWindow *wlist;
409 if (!wapp->main_window_desc) {
410 wwarning("group leader not found for window group");
411 return 0;
413 scr = wapp->main_window_desc->screen_ptr;
414 wlist = scr->focused_window;
415 if (!wlist)
416 return 0;
418 while (wlist) {
419 if (wlist->main_window == wapp->main_window) {
420 if (wlist->flags.urgent)
421 return 1;
423 wlist = wlist->prev;
426 return 0;
429 static void doAppUrgentBounce(void *arg)
431 WApplication *wapp = (WApplication *)arg;
433 if (appIsUrgent(wapp)) {
434 if(wPreferences.bounce_appicons_when_urgent) wAppBounce(wapp);
435 } else {
436 WMDeleteTimerHandler(wapp->urgent_bounce_timer);
437 wapp->urgent_bounce_timer = NULL;
441 void wAppBounceWhileUrgent(WApplication *wapp)
443 if (!wapp) return;
444 if (appIsUrgent(wapp)) {
445 if (!wapp->urgent_bounce_timer) {
446 wapp->urgent_bounce_timer = WMAddPersistentTimerHandler(URGENT_BOUNCE_DELAY, doAppUrgentBounce, wapp);
447 doAppUrgentBounce(wapp);
449 } else {
450 if (wapp->urgent_bounce_timer) {
451 WMDeleteTimerHandler(wapp->urgent_bounce_timer);
452 wapp->urgent_bounce_timer = NULL;