/*
* BadWM - minimalistic window manager for the X Window System
* Copyright (C) Robert Annessi <robert@annessi.at>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "include/BadWM.h"
#include "include/config.h"
#include <assert.h>
void draw_outline(Client *c) {
XDrawRectangle(dpy, c->screen->root, c->screen->invert_gc,
c->x - c->border, c->y - c->border,
c->width + opt_bw, c->height + opt_bw);
}
void get_mouse_position(int *x, int *y, Window root) {
Window dw1, dw2;
int t1, t2;
unsigned int t3;
XQueryPointer(dpy, root, &dw1, &dw2, x, y, &t1, &t2, &t3);
}
void recalculate_sweep(Client *c, int x1, int y1, int x2, int y2,
int westwards, int northwards ) {
int basex, basey;
int xsnap=0, ysnap=0;
c->width = abs(x1 - x2);
c->height = abs(y1 - y2);
if (c->size->flags & PResizeInc) {
basex = (c->size->flags & PBaseSize) ? c->size->base_width :
(c->size->flags & PMinSize) ? c->size->min_width : 0;
basey = (c->size->flags & PBaseSize) ? c->size->base_height :
(c->size->flags & PMinSize) ? c->size->min_height : 0;
xsnap = (c->width - basex) % c->size->width_inc;
ysnap = (c->height - basey) % c->size->height_inc;
c->width -= xsnap;
c->height -= ysnap;
}
if (c->size->flags & PMinSize) {
if (c->width < c->size->min_width) c->width = c->size->min_width;
if (c->height < c->size->min_height) c->height = c->size->min_height;
}
if (c->size->flags & PMaxSize) {
if (c->width > c->size->max_width) c->width = c->size->max_width;
if (c->height > c->size->max_height) c->height = c->size->max_height;
}
c->x = (x1 <= x2) ? x1 : x1 - c->width;
c->y = (y1 <= y2) ? y1 : y1 - c->height;
if (x1>x2)
xsnap = -xsnap;
if (y1>y2)
ysnap = -ysnap;
if (westwards)
c->x += xsnap;
if (northwards)
c->y += ysnap;
}
void sweep(Client *c) {
XEvent ev;
int win_px,win_py;
double win_px_n,win_py_n;
int root_px,root_py;
Window dumw;
int dumi;
ResizeDir dir;
int x1 = c->x;
int y1 = c->y;
int x2 = c->x+c->width;
int y2 = c->y+c->height;
XQueryPointer(dpy,c->window,&dumw,&dumw,&root_px,&root_py,&win_px,&win_py,&dumi);
win_px_n = (double)win_px/(double)c->width;
win_py_n = (double)win_py/(double)c->height;
if (win_py_n<0.3)
{
if (win_px_n<0.3)
dir = NorthWest;
else if (win_px_n>0.7)
dir = NorthEast;
else
dir = North;
}
else if (win_py_n>0.7)
{
if (win_px_n<0.3)
dir = SouthWest;
else if (win_px_n>0.7)
dir = SouthEast;
else
dir = South;
}
else
{
if (win_px_n<=0.5)
dir = West;
else
dir = East;
}
if (!grab_pointer(c->screen->root, MouseMask, resize_cursors[dir])) return;
if ( config.global->solidwindows == 0 ) {
XGrabServer(dpy);
draw_outline(c);
}
for (;;)
{
int dx;
int dy;
XMaskEvent(dpy, MouseMask, &ev);
switch (ev.type) {
case MotionNotify:
draw_outline(c); /* clear */
XUngrabServer(dpy);
dx = ev.xmotion.x-root_px;
dy = ev.xmotion.y-root_py;
switch (dir)
{
case NorthWest:
recalculate_sweep(c,x1+dx,y1+dy,x2,y2,1,1);
break;
case North:
recalculate_sweep(c,x1,y1+dy,x2,y2,0,1);
break;
case NorthEast:
recalculate_sweep(c,x1,y1+dy,x2+dx,y2,0,1);
break;
case East:
recalculate_sweep(c,x1,y1,x2+dx,y2,0,0);
break;
case SouthEast:
recalculate_sweep(c,x1,y1,x2+dx,y2+dy,0,0);
break;
case South:
recalculate_sweep(c,x1,y1,x2,y2+dy,0,0);
break;
case SouthWest:
recalculate_sweep(c,x1+dx,y1,x2,y2+dy,1,0);
break;
case West:
recalculate_sweep(c,x1+dx,y1,x2,y2,1,0);
break;
}
if (config.global->solidwindows == 0) {
XSync(dpy, False);
XGrabServer(dpy);
draw_outline(c);
} else {
XMoveResizeWindow(dpy, c->parent, c->x - c->border,
c->y - c->border, c->width + (c->border*2),
c->height + (c->border*2));
XMoveResizeWindow(dpy, c->window, c->border, c->border,
c->width, c->height);
send_config(c);
}
break;
case ButtonRelease:
if (config.global->solidwindows == 0) {
draw_outline(c); /* clear */
XUngrabServer(dpy);
}
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
static int absmin(int a, int b) {
if (abs(a) < abs(b))
return a;
return b;
}
static void snap_client(Client *c) {
int dx, dy;
Client *ci;
/* snap to screen border */
if (abs(c->x - c->border) < config.global->snap_distance) c->x = c->border;
if (abs(c->y - c->border) < config.global->snap_distance) c->y = c->border;
if (abs(c->x + c->width + c->border - DisplayWidth(dpy, c->screen->screen)) < config.global->snap_distance)
c->x = DisplayWidth(dpy, c->screen->screen) - c->width - c->border;
if (abs(c->y + c->height + c->border - DisplayHeight(dpy, c->screen->screen)) < config.global->snap_distance)
c->y = DisplayHeight(dpy, c->screen->screen) - c->height - c->border;
/* snap to other windows */
dx = dy = config.global->snap_distance;
for (ci = head_client; ci; ci = ci->next) {
if (ci != c && (ci->vdesk == vdesk || ci->vdesk == STICKY)) {
if (ci->y - ci->border - c->border - c->height - c->y <= config.global->snap_distance && c->y - c->border - ci->border - ci->height - ci->y <= config.global->snap_distance) {
dx = absmin(dx, ci->x + ci->width - c->x + c->border + ci->border);
dx = absmin(dx, ci->x + ci->width - c->x - c->width);
dx = absmin(dx, ci->x - c->x - c->width - c->border - ci->border);
dx = absmin(dx, ci->x - c->x);
}
if (ci->x - ci->border - c->border - c->width - c->x <= config.global->snap_distance && c->x - c->border - ci->border - ci->width - ci->x <= config.global->snap_distance) {
dy = absmin(dy, ci->y + ci->height - c->y + c->border + ci->border);
dy = absmin(dy, ci->y + ci->height - c->y - c->height);
dy = absmin(dy, ci->y - c->y - c->height - c->border - ci->border);
dy = absmin(dy, ci->y - c->y);
}
}
}
if (abs(dx) < config.global->snap_distance)
c->x += dx;
if (abs(dy) < config.global->snap_distance)
c->y += dy;
}
void drag(Client *c) {
int x1, y1;
int old_cx = c->x;
int old_cy = c->y;
XEvent ev;
if (!grab_pointer(c->screen->root, MouseMask, move_curs)) return;
get_mouse_position(&x1, &y1, c->screen->root);
if ( config.global->solidwindows == 0 ) {
XGrabServer(dpy);
draw_outline(c);
}
for (;;) {
XMaskEvent(dpy, MouseMask, &ev);
switch (ev.type) {
case MotionNotify:
if ( config.global->solidwindows == 0 ) {
draw_outline(c);
XUngrabServer(dpy);
}
/* changing vdesk when pointer is at the edge of screen */
if ( ev.xmotion.x == 0) {
ev.xmotion.x = DisplayWidth(dpy, c->screen->screen) - 2;
setmouse(c->screen->root, ev.xmotion.x, ev.xmotion.y);
switch_vdesk_down();
if ( config.global->solidwindows == 1 ) { /* we have to move the window to if solid */
c->vdesk = vdesk;
unhide(c, RAISE);
}
}
else
if ( ev.xmotion.x == DisplayWidth(dpy, c->screen->screen) - 1) {
ev.xmotion.x = 2;
setmouse(c->screen->root, ev.xmotion.x, ev.xmotion.y);
switch_vdesk_up();
if ( config.global->solidwindows == 1 ) { /* we have to move the window to if solid */
c->vdesk = vdesk;
unhide(c, RAISE);
}
}
c->x = old_cx + (ev.xmotion.x - x1);
c->y = old_cy + (ev.xmotion.y - y1);
snap_client(c);
if ( config.global->solidwindows == 0 ) {
XSync(dpy, False);
XGrabServer(dpy);
draw_outline(c);
} else {
XMoveWindow(dpy, c->parent, c->x - c->border, c->y - c->border);
send_config(c);
}
break;
case ButtonRelease:
/* redrawing (unhiding) the window if vdesk changed */
if ( c->vdesk != vdesk && c->vdesk != STICKY ) {
c->vdesk = vdesk;
client_update_current(current, NULL);
unhide(c, RAISE);
}
else
if ( config.global->solidwindows == 0 ) draw_outline(c);
XUngrabServer(dpy);
XUngrabPointer(dpy, CurrentTime);
return;
default:
break;
}
}
}
void move(Client *c, int set) {
if (c) {
XRaiseWindow(dpy, c->parent);
if (!set)
drag(c);
XMoveWindow(dpy, c->parent, c->x - c->border, c->y - c->border);
send_config(c);
}
}
void resize(Client *c, int set) {
if (c) {
XRaiseWindow(dpy, c->parent);
if (!set)
sweep(c);
XMoveResizeWindow(dpy, c->parent, c->x - c->border,
c->y - c->border, c->width + (c->border*2),
c->height + (c->border*2));
XMoveResizeWindow(dpy, c->window, c->border, c->border,
c->width, c->height);
send_config(c);
}
}
void maximise_horiz(Client *c) {
#ifdef DEBUG
bad_debug(1,"SCREEN: maximise_horiz()\n");
#endif
if (c->oldw) {
c->x = c->oldx;
c->width = c->oldw;
c->oldw = 0;
} else {
c->oldx = c->x;
c->oldw = c->width;
recalculate_sweep(c, 0, c->y, DisplayWidth(dpy, c->screen->screen),
c->y + c->height,0,0);
}
}
void maximise_vert(Client *c) {
#ifdef DEBUG
bad_debug(1,"SCREEN: maximise_vert()\n");
#endif
if (c->oldh) {
c->y = c->oldy;
c->height = c->oldh;
c->oldh = 0;
} else {
c->oldy = c->y;
c->oldh = c->height;
recalculate_sweep(c, c->x, 0, c->x + c->width,
DisplayHeight(dpy, c->screen->screen),0,0);
}
}
void hide(Client *c) {
if (c) {
c->ignore_unmap += 2;
#ifdef DEBUG
bad_debug(1,"screen:XUnmapWindow(parent)\n");
#endif
XUnmapWindow(dpy, c->parent);
#ifdef DEBUG
bad_debug(1,"screen:XUnmapWindow(window)\n");
#endif
XUnmapWindow(dpy, c->window);
set_wm_state(c, IconicState);
}
}
void unhide(Client *c, int raise) {
XMapWindow(dpy, c->window);
raise ? XMapRaised(dpy, c->parent) : XMapWindow(dpy, c->parent);
set_wm_state(c, NormalState);
}
void next(void) {
Client *newc = current;
Client *stop;
#ifdef DEBUG
bad_debug(1,"\n");
#endif
if (current) {
stop = current;
newc = current->fix_next;
} else {
stop = newc = head_client;
}
/* selecting window */
assert(newc != NULL);
for (;;) {
if ( newc->vdesk == vdesk ) break;
assert(newc->fix_next != NULL);
newc = newc->fix_next;
if ( newc == stop ) {
newc = NULL;
break;
}
}
if ( newc ) {
/* focusing new window */
unhide(newc,RAISE);
focus_client(newc);
#ifdef DEBUG
} else {
bad_debug(1,"NEXT: hmm, no next window\n");
#endif
}
}
void switch_vdesk(int v) {
Client *c;
int wdesk;
if (v == vdesk) return;
if (current && current->vdesk != STICKY) {
client_update_current(current, NULL);
}
#ifdef DEBUG
bad_debug(1,"Switching to desk %d\n", v);
#endif
for (c = head_client; c; c = c->next) {
wdesk = c->vdesk;
if (wdesk == vdesk) {
hide(c);
} else if (wdesk == v) {
unhide(c, NO_RAISE);
}
}
vdesk = v;
}
ScreenInfo *find_screen(Window root) {
int i;
for (i = 0; i < num_screens; i++) {
if (screens[i].root == root)
return &screens[i];
}
return NULL;
}
void switch_vdesk_up(void)
{
if (config.global->max_vdesks == 10 && vdesk == 9) switch_vdesk(0);
else if (vdesk < config.global->max_vdesks) switch_vdesk(vdesk+1);
else switch_vdesk(1);
}
void switch_vdesk_down(void)
{
if (vdesk > config.global->min_vdesk) switch_vdesk(vdesk-1);
else if (config.global->max_vdesks == 10 && vdesk == 0) switch_vdesk(9);
else switch_vdesk(config.global->max_vdesks);
}
syntax highlighted by Code2HTML, v. 0.9.1