mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-19 20:38:08 +01:00
No more ghost dock when switching sides: the real swap happens immediately, you can still adjust vertically afterwards. Removed two functions in superfluous that are no longer used
382 lines
9.0 KiB
C
382 lines
9.0 KiB
C
/*
|
|
* Window Maker window manager
|
|
*
|
|
* Copyright (c) 1997-2003 Alfredo K. Kojima
|
|
* Copyright (c) 1998-2003 Dan Pascu
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "wconfig.h"
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
|
|
#include <wraster.h>
|
|
|
|
#include "WindowMaker.h"
|
|
#include "screen.h"
|
|
#include "superfluous.h"
|
|
#include "framewin.h"
|
|
#include "window.h"
|
|
#include "actions.h"
|
|
#include "xinerama.h"
|
|
#include "stacking.h"
|
|
|
|
#define PIECES ((64/ICON_KABOOM_PIECE_SIZE)*(64/ICON_KABOOM_PIECE_SIZE))
|
|
#define KAB_PRECISION 4
|
|
#define BOUNCE_HZ 25
|
|
#define BOUNCE_DELAY (1000/BOUNCE_HZ)
|
|
#define BOUNCE_HEIGHT 24
|
|
#define BOUNCE_LENGTH 0.3
|
|
#define BOUNCE_DAMP 0.6
|
|
#define URGENT_BOUNCE_DELAY 3000
|
|
|
|
extern WPreferences wPreferences;
|
|
|
|
void DoKaboom(WScreen * scr, Window win, int x, int y)
|
|
{
|
|
#ifdef NORMAL_ICON_KABOOM
|
|
int i, j, k;
|
|
int sw = scr->scr_width, sh = scr->scr_height;
|
|
int px[PIECES];
|
|
short py[PIECES];
|
|
char pvx[PIECES], pvy[PIECES];
|
|
/* in MkLinux/PPC gcc seems to think that char is unsigned? */
|
|
signed char ax[PIECES], ay[PIECES];
|
|
Pixmap tmp;
|
|
|
|
XSetClipMask(dpy, scr->copy_gc, None);
|
|
tmp = XCreatePixmap(dpy, scr->root_win, wPreferences.icon_size, wPreferences.icon_size, scr->depth);
|
|
if (scr->w_visual == DefaultVisual(dpy, scr->screen))
|
|
XCopyArea(dpy, win, tmp, scr->copy_gc, 0, 0, wPreferences.icon_size, wPreferences.icon_size, 0, 0);
|
|
else {
|
|
XImage *image;
|
|
|
|
image = XGetImage(dpy, win, 0, 0, wPreferences.icon_size,
|
|
wPreferences.icon_size, AllPlanes, ZPixmap);
|
|
if (!image) {
|
|
XUnmapWindow(dpy, win);
|
|
return;
|
|
}
|
|
XPutImage(dpy, tmp, scr->copy_gc, image, 0, 0, 0, 0,
|
|
wPreferences.icon_size, wPreferences.icon_size);
|
|
XDestroyImage(image);
|
|
}
|
|
|
|
for (i = 0, k = 0; i < wPreferences.icon_size / ICON_KABOOM_PIECE_SIZE && k < PIECES; i++) {
|
|
for (j = 0; j < wPreferences.icon_size / ICON_KABOOM_PIECE_SIZE && k < PIECES; j++) {
|
|
if (rand() % 2) {
|
|
ax[k] = i;
|
|
ay[k] = j;
|
|
px[k] = (x + i * ICON_KABOOM_PIECE_SIZE) << KAB_PRECISION;
|
|
py[k] = y + j * ICON_KABOOM_PIECE_SIZE;
|
|
pvx[k] = rand() % (1 << (KAB_PRECISION + 3)) - (1 << (KAB_PRECISION + 3)) / 2;
|
|
pvy[k] = -15 - rand() % 7;
|
|
k++;
|
|
} else {
|
|
ax[k] = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
XUnmapWindow(dpy, win);
|
|
|
|
j = k;
|
|
while (k > 0) {
|
|
XEvent foo;
|
|
|
|
if (XCheckTypedEvent(dpy, ButtonPress, &foo)) {
|
|
XPutBackEvent(dpy, &foo);
|
|
XClearWindow(dpy, scr->root_win);
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < j; i++) {
|
|
if (ax[i] >= 0) {
|
|
int _px = px[i] >> KAB_PRECISION;
|
|
XClearArea(dpy, scr->root_win, _px, py[i],
|
|
ICON_KABOOM_PIECE_SIZE, ICON_KABOOM_PIECE_SIZE, False);
|
|
px[i] += pvx[i];
|
|
py[i] += pvy[i];
|
|
_px = px[i] >> KAB_PRECISION;
|
|
pvy[i]++;
|
|
if (_px < -wPreferences.icon_size || _px > sw || py[i] >= sh) {
|
|
ax[i] = -1;
|
|
k--;
|
|
} else {
|
|
XCopyArea(dpy, tmp, scr->root_win, scr->copy_gc,
|
|
ax[i] * ICON_KABOOM_PIECE_SIZE, ay[i] * ICON_KABOOM_PIECE_SIZE,
|
|
ICON_KABOOM_PIECE_SIZE, ICON_KABOOM_PIECE_SIZE, _px, py[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
XFlush(dpy);
|
|
wusleep(MINIATURIZE_ANIMATION_DELAY_Z * 2);
|
|
}
|
|
|
|
XFreePixmap(dpy, tmp);
|
|
#endif /* NORMAL_ICON_KABOOM */
|
|
}
|
|
|
|
Pixmap MakeGhostIcon(WScreen * scr, Drawable drawable)
|
|
{
|
|
RImage *back;
|
|
RColor color;
|
|
Pixmap pixmap;
|
|
|
|
if (!drawable)
|
|
return None;
|
|
|
|
back = RCreateImageFromDrawable(scr->rcontext, drawable, None);
|
|
if (!back)
|
|
return None;
|
|
|
|
color.red = 0xff;
|
|
color.green = 0xff;
|
|
color.blue = 0xff;
|
|
color.alpha = 200;
|
|
|
|
RClearImage(back, &color);
|
|
RConvertImage(scr->rcontext, back, &pixmap);
|
|
|
|
RReleaseImage(back);
|
|
|
|
return pixmap;
|
|
}
|
|
|
|
void DoWindowBirth(WWindow *wwin)
|
|
{
|
|
#ifdef WINDOW_BIRTH_ZOOM
|
|
int center_x, center_y;
|
|
int width = wwin->frame->core->width;
|
|
int height = wwin->frame->core->height;
|
|
int w = WMIN(width, 20);
|
|
int h = WMIN(height, 20);
|
|
WScreen *scr = wwin->screen_ptr;
|
|
|
|
center_x = wwin->frame_x + (width - w) / 2;
|
|
center_y = wwin->frame_y + (height - h) / 2;
|
|
|
|
animateResize(scr, center_x, center_y, 1, 1, wwin->frame_x, wwin->frame_y, width, height);
|
|
#endif
|
|
}
|
|
|
|
typedef struct AppBouncerData {
|
|
WApplication *wapp;
|
|
int count;
|
|
int pow;
|
|
int dir;
|
|
WMHandlerID *timer;
|
|
} AppBouncerData;
|
|
|
|
static void doAppBounce(void *arg)
|
|
{
|
|
AppBouncerData *data = (AppBouncerData*)arg;
|
|
WAppIcon *aicon = data->wapp->app_icon;
|
|
|
|
reinit:
|
|
if (aicon && data->wapp->refcount > 1) {
|
|
if (wPreferences.raise_appicons_when_bouncing)
|
|
XRaiseWindow(dpy, aicon->icon->core->window);
|
|
|
|
const double ticks = BOUNCE_HZ * BOUNCE_LENGTH;
|
|
const double s = sqrt(BOUNCE_HEIGHT)/(ticks/2);
|
|
double h = BOUNCE_HEIGHT*pow(BOUNCE_DAMP, data->pow);
|
|
double sqrt_h = sqrt(h);
|
|
if (h > 3) {
|
|
double offset, x = s * data->count - sqrt_h;
|
|
if (x > sqrt_h) {
|
|
++data->pow;
|
|
data->count = 0;
|
|
goto reinit;
|
|
} else ++data->count;
|
|
offset = h - x*x;
|
|
|
|
switch (data->dir) {
|
|
case 0: /* left, bounce to right */
|
|
XMoveWindow(dpy, aicon->icon->core->window,
|
|
aicon->x_pos + (int)offset, aicon->y_pos);
|
|
break;
|
|
case 1: /* right, bounce to left */
|
|
XMoveWindow(dpy, aicon->icon->core->window,
|
|
aicon->x_pos - (int)offset, aicon->y_pos);
|
|
break;
|
|
case 2: /* top, bounce down */
|
|
XMoveWindow(dpy, aicon->icon->core->window,
|
|
aicon->x_pos, aicon->y_pos + (int)offset);
|
|
break;
|
|
case 3: /* bottom, bounce up */
|
|
XMoveWindow(dpy, aicon->icon->core->window,
|
|
aicon->x_pos, aicon->y_pos - (int)offset);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
XMoveWindow(dpy, aicon->icon->core->window,
|
|
aicon->x_pos, aicon->y_pos);
|
|
CommitStackingForWindow(aicon->icon->core);
|
|
data->wapp->flags.bouncing = 0;
|
|
WMDeleteTimerHandler(data->timer);
|
|
wApplicationDestroy(data->wapp);
|
|
free(data);
|
|
}
|
|
|
|
static int bounceDirection(WAppIcon *aicon)
|
|
{
|
|
enum { left_e = 1, right_e = 2, top_e = 4, bottom_e = 8 };
|
|
|
|
WScreen *scr = aicon->icon->core->screen_ptr;
|
|
WMRect rr, sr;
|
|
int l, r, t, b, h, v;
|
|
int dir = 0;
|
|
|
|
rr.pos.x = aicon->x_pos;
|
|
rr.pos.y = aicon->y_pos;
|
|
rr.size.width = rr.size.height = 64;
|
|
|
|
sr = wGetRectForHead(scr, wGetHeadForRect(scr, rr));
|
|
|
|
l = rr.pos.x - sr.pos.x;
|
|
r = sr.pos.x + sr.size.width - rr.pos.x - rr.size.width;
|
|
t = rr.pos.y - sr.pos.y;
|
|
b = sr.pos.y + sr.size.height - rr.pos.y - rr.size.height;
|
|
|
|
if (l < r) {
|
|
dir |= left_e;
|
|
h = l;
|
|
} else {
|
|
dir |= right_e;
|
|
h = r;
|
|
}
|
|
|
|
if (t < b) {
|
|
dir |= top_e;
|
|
v = t;
|
|
} else {
|
|
dir |= bottom_e;
|
|
v = b;
|
|
}
|
|
|
|
if (aicon->dock && abs(aicon->xindex) != abs(aicon->yindex)) {
|
|
if (abs(aicon->xindex) < abs(aicon->yindex)) dir &= ~(top_e | bottom_e);
|
|
else dir &= ~(left_e | right_e);
|
|
} else {
|
|
if (h < v) dir &= ~(top_e | bottom_e);
|
|
else dir &= ~(left_e | right_e);
|
|
}
|
|
|
|
switch (dir) {
|
|
case left_e:
|
|
dir = 0;
|
|
break;
|
|
|
|
case right_e:
|
|
dir = 1;
|
|
break;
|
|
|
|
case top_e:
|
|
dir = 2;
|
|
break;
|
|
|
|
case bottom_e:
|
|
dir = 3;
|
|
break;
|
|
|
|
default:
|
|
wwarning(_("Impossible direction: %d"), dir);
|
|
dir = 3;
|
|
break;
|
|
}
|
|
|
|
return dir;
|
|
}
|
|
|
|
void wAppBounce(WApplication *wapp)
|
|
{
|
|
if (!wPreferences.no_animations && wapp->app_icon && !wapp->flags.bouncing
|
|
&& !wPreferences.do_not_make_appicons_bounce) {
|
|
++wapp->refcount;
|
|
wapp->flags.bouncing = 1;
|
|
|
|
AppBouncerData *data = (AppBouncerData *)malloc(sizeof(AppBouncerData));
|
|
data->wapp = wapp;
|
|
data->count = data->pow = 0;
|
|
data->dir = bounceDirection(wapp->app_icon);
|
|
data->timer = WMAddPersistentTimerHandler(BOUNCE_DELAY, doAppBounce, data);
|
|
}
|
|
}
|
|
|
|
static int appIsUrgent(WApplication *wapp)
|
|
{
|
|
WScreen *scr;
|
|
WWindow *wlist;
|
|
|
|
if (!wapp->main_window_desc) {
|
|
wwarning("group leader not found for window group");
|
|
return 0;
|
|
}
|
|
scr = wapp->main_window_desc->screen_ptr;
|
|
wlist = scr->focused_window;
|
|
if (!wlist)
|
|
return 0;
|
|
|
|
while (wlist) {
|
|
if (wlist->main_window == wapp->main_window) {
|
|
if (wlist->flags.urgent)
|
|
return 1;
|
|
}
|
|
wlist = wlist->prev;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void doAppUrgentBounce(void *arg)
|
|
{
|
|
WApplication *wapp = (WApplication *)arg;
|
|
|
|
if (appIsUrgent(wapp)) {
|
|
if(wPreferences.bounce_appicons_when_urgent) wAppBounce(wapp);
|
|
} else {
|
|
WMDeleteTimerHandler(wapp->urgent_bounce_timer);
|
|
wapp->urgent_bounce_timer = NULL;
|
|
}
|
|
}
|
|
|
|
void wAppBounceWhileUrgent(WApplication *wapp)
|
|
{
|
|
if (!wapp) return;
|
|
if (appIsUrgent(wapp)) {
|
|
if (!wapp->urgent_bounce_timer) {
|
|
wapp->urgent_bounce_timer = WMAddPersistentTimerHandler(URGENT_BOUNCE_DELAY, doAppUrgentBounce, wapp);
|
|
doAppUrgentBounce(wapp);
|
|
}
|
|
} else {
|
|
if (wapp->urgent_bounce_timer) {
|
|
WMDeleteTimerHandler(wapp->urgent_bounce_timer);
|
|
wapp->urgent_bounce_timer = NULL;
|
|
}
|
|
}
|
|
}
|