/* Copyright (c) 2000-2004 Lars Bernhardsson, see README for license details */
#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
#include "dat.h"
#include "fns.h"
/*
* This file was added to David Hogan's 9wm source distribution.
* It is written by Lars Bernhardsson, with inspiration from
* such things as acme, wily, oberon and 100's of misplaced windows
* over the years. :)
*/
/* only tile visible top level windows on the current desktop. */
#define DO_TILE(x,s) (((x)->screen == (s)) && (((x)->desktop == (s)->desktop) || (x)->issticky) && ((x)->trans == None) && (!(x)->isnotile) && (!(x)->istool) && (normal(x)))
/* windows to raise when Raise Untiled is selected. */
#define DO_RAISE_NOTILE(x,s) (((x)->screen == (s)) && (((x)->desktop == (s)->desktop) || (x)->issticky) && ((x)->isnotile) && (normal(x)))
/* global variables for this module */
static int track_x[64][2];
static int track_width[64][2];
#define MAX_RC 1024
static Client *rc[MAX_RC];
static int nrc;
/* which tracks to reserve tool space in. */
static int res_track = 0;
void
getmouse (int *x, int *y, ScreenInfo * s)
{
Window dw1, dw2;
int t1, t2;
unsigned int t3;
XQueryPointer (dpy, s->root, &dw1, &dw2, x, y, &t1, &t2, &t3);
}
void
setmouse (int x, int y, ScreenInfo * s)
{
XWarpPointer (dpy, None, s->root, None, None, None, None, x, y);
}
void
rev_clients (void)
{
Client *c;
nrc = 0;
for (c = clients; c && (nrc < MAX_RC); c = c->next)
rc[nrc++] = c;
}
int
is_float (Client * c)
{
int i;
if (!c->class)
return 0;
for (i = 0; i < MAXFLOATCLASS; i++)
{
char *inst;
if (!prefs.floatclass[i])
continue;
if (strcmp (c->class, prefs.floatclass[i]) == 0)
return 1;
if (!c->instance)
return 0;
if (strcmp (c->instance, prefs.floatclass[i]) == 0)
return 1;
if ((inst = strchr (prefs.floatclass[i], '~')))
{
inst++;
if (strncmp (c->class, prefs.floatclass[i], strlen (c->class)) == 0)
if (strncmp (c->instance, inst, strlen (c->instance)) == 0)
return 1;
}
}
return 0;
}
int
is_sticky (Client * c)
{
int i;
if (!c->class)
return 0;
for (i = 0; i < MAXSTICKYCLASS; i++)
{
char *inst;
if (!prefs.stickyclass[i])
continue;
if (strcmp (c->class, prefs.stickyclass[i]) == 0)
return 1;
if (!c->instance)
return 0;
if (strcmp (c->instance, prefs.stickyclass[i]) == 0)
return 1;
if ((inst = strchr (prefs.stickyclass[i], '~')))
{
inst++;
if (strncmp (c->class, prefs.stickyclass[i], strlen (c->class)) ==
0)
if (strncmp (c->instance, inst, strlen (c->instance)) == 0)
return 1;
}
}
return 0;
}
int
is_tool (Client * c)
{
int i;
if (!c->class)
return 0;
for (i = 0; i < MAXTOOLCLASS; i++)
{
char *inst;
if (!prefs.toolclass[i])
continue;
if (strcmp (c->class, prefs.toolclass[i]) == 0)
return 1;
if (!c->instance)
return 0;
if (strcmp (c->instance, prefs.toolclass[i]) == 0)
return 1;
if ((inst = strchr (prefs.toolclass[i], '~')))
{
inst++;
if (strncmp (c->class, prefs.toolclass[i], strlen (c->class)) == 0)
if (strncmp (c->instance, inst, strlen (c->instance)) == 0)
return 1;
}
}
return 0;
}
int
is_notile (Client * c)
{
int i;
if (!c->class)
return 1;
for (i = 0; i < MAXNOTILECLASS; i++)
{
char *inst;
if (!prefs.notileclass[i])
continue;
if (strcmp (c->class, prefs.notileclass[i]) == 0)
return 0;
if (!c->instance)
return 1;
if (strcmp (c->instance, prefs.notileclass[i]) == 0)
return 0;
if ((inst = strchr (prefs.notileclass[i], '~')))
{
inst++;
if (strncmp (c->class, prefs.notileclass[i], strlen (c->class)) ==
0)
if (strncmp (c->instance, inst, strlen (c->instance)) == 0)
return 0;
}
}
return 1;
}
int
is_dt (Client * c)
{
int i;
if (!c->class)
return -1;
for (i = 0; i < MAXDTCLASS; i++)
{
char *inst;
if (!prefs.dtclass[i])
continue;
if (strcmp (c->class, prefs.dtclass[i]) == 0)
return prefs.dtnum[i];
if (!c->instance)
return -1;
if (strcmp (c->instance, prefs.dtclass[i]) == 0)
return prefs.dtnum[i];
if ((inst = strchr (prefs.dtclass[i], '~')))
{
inst++;
if (strncmp (c->class, prefs.dtclass[i], strlen (c->class)) == 0)
if (strncmp (c->instance, inst, strlen (c->instance)) == 0)
return prefs.dtnum[i];
}
}
return -1;
}
void
toggle_isfloat (Client * c)
{
if (c)
c->isfloat = !c->isfloat;
update_tbar ();
}
void
toggle_istool (Client * c)
{
if (c)
c->istool = !c->istool;
update_tbar ();
}
void
toggle_issticky (Client * c)
{
if (c)
c->issticky = !c->issticky;
update_tbar ();
}
void
toggle_inc (ScreenInfo * s)
{
if (s)
s->bigmr[s->desktop] = !s->bigmr[s->desktop];
update_tbar ();
}
void
toggle_clickthru (ScreenInfo * s)
{
if (s)
s->clickthru[s->desktop] = !s->clickthru[s->desktop];
update_tbar ();
}
void
toggle_tile_resize (ScreenInfo * s)
{
if (s)
s->tile_resize[s->desktop] = !s->tile_resize[s->desktop];
update_tbar ();
}
void
toggle_skip_focus (ScreenInfo * s)
{
if (s)
s->skip_focus[s->desktop] = !s->skip_focus[s->desktop];
update_tbar ();
}
int
count_clients (ScreenInfo * s)
{
Client *c;
int i = 0;
for (c = clients; c; c = c->next)
if (DO_TILE (c, s))
i++;
return i;
}
void
find_tools (ScreenInfo * s)
{
Client *c;
int min_y;
int min_x, max_x;
int t;
int found = 0;
if (!s)
abort ();
t = 0;
max_x = -1;
min_x = DisplayWidth (dpy, s->num) + 1;
min_y = DisplayHeight (dpy, s->num) + 1;
for (c = clients; c; c = c->next)
{
if (c->istool && (c->screen == s) && normal (c) &&
(c->issticky || (c->desktop == s->desktop)) &&
s->tile_resize[s->desktop])
{
int x1 = c->x - BORDER;
int y1 = c->y - BORDER;
int x2 = c->x + c->dx + BORDER;
found = 1;
if (x1 < min_x)
min_x = x1;
if (x2 > max_x)
max_x = x2;
if (y1 < min_y)
min_y = y1;
}
}
if (found)
{
s->res_height = min_y - TILE_PAD;
if (min_x < track_width[s->num][0])
t |= 1;
if (max_x >= track_x[s->num][1])
t |= 2;
res_track = t;
}
else
{
s->res_height = s->tile_height;
res_track = 0;
}
}
void
calc_track_sizes (ScreenInfo * s)
{
int screen_width;
if (!s)
abort ();
screen_width = DisplayWidth (dpy, s->num);
track_x[s->num][0] = 0;
track_width[s->num][0] =
(s->left_track_width[s->desktop] * screen_width) / 100;
track_x[s->num][1] = track_width[s->num][0];
track_width[s->num][1] = screen_width - track_width[s->num][0];
}
void
toggle_notile (ScreenInfo * s)
{
if (s->notile_raised[s->desktop])
raise_tile (s, 1);
else
raise_notile (s);
}
void
raise_notile (ScreenInfo * s)
{
int i;
rev_clients ();
for (i = nrc - 1; i >= 0; i--)
if (DO_RAISE_NOTILE (rc[i], s))
XMapRaised (dpy, rc[i]->parent);
s->notile_raised[s->desktop] = 1;
raise_tbar (s);
if (s->notilefocused[s->desktop]
&& DO_RAISE_NOTILE (s->notilefocused[s->desktop], s)
&& !s->notilefocused[s->desktop]->isaside)
{
active (s->notilefocused[s->desktop]);
}
else
{
revert_same (s);
}
if (current)
XMapRaised (dpy, current->parent);
update_tbar ();
}
void
raise_tile (ScreenInfo * s, int user)
{
Client *c;
for (c = clients; c; c = c->next)
if (DO_TILE (c, s))
XMapRaised (dpy, c->parent);
s->notile_raised[s->desktop] = 0;
raise_tbar (s);
if (s->focused[s->desktop] && DO_TILE (s->focused[s->desktop], s))
{
if (user || (!current && (mouse_on_screen () == s))
|| (current && (current->screen == s)))
{
active (s->focused[s->desktop]);
}
}
else
{
revert_same (s);
}
update_tbar ();
}
void
tile_all (ScreenInfo * s)
{
Client *c;
unsigned int screen_height_left, screen_height_right;
unsigned int track_width_left, track_width_right;
unsigned short clients_left, clients_right;
unsigned short current_client = 0;
unsigned short on_right = 0;
if (!s)
abort ();
calc_track_sizes (s);
find_tools (s);
track_width_left = track_width[s->num][0];
track_width_right = track_width[s->num][1];
screen_height_left = (res_track & 1 ? s->res_height : s->tile_height);
screen_height_right = (res_track & 2 ? s->res_height : s->tile_height);
clients_right = count_clients (s);
if (clients_right == 0)
return;
clients_left = 1;
--clients_right;
for (c = clients; c; c = c->next)
{
/*
* WARNING
* The variables "screen_height_left", "odx" and "ody"
* have more than one purpose.
*/
if (DO_TILE (c, s))
{
unsigned int x, y, width, height;
unsigned int odx, ody;
if (on_right)
{
x = track_width_left;
y = screen_height_right - screen_height_left;
height = screen_height_right / clients_right;
width = track_width_right;
if (++current_client < clients_right)
{
screen_height_left -= height;
height -= TILE_PAD;
}
else
height = screen_height_left;
}
else
{
x = y = 0;
height = screen_height_left;
width = track_width_left - TILE_PAD;
/*
* Here the purpose of
* screen_height_left changes
*/
screen_height_left = screen_height_right;
}
height -= 2 * BORDER;
width -= 2 * BORDER;
c->isleft = on_right ? 0 : 1;
odx = width;
ody = height;
/*
* resize in given increments if the program
* wishes this..
*/
if (c->size.flags & PResizeInc)
{
width = c->min_dx +
(((signed int) (width -
c->min_dx) / c->size.width_inc) *
c->size.width_inc);
height = c->min_dy +
(((signed int) (height -
c->min_dy) / c->size.height_inc) *
c->size.height_inc);
}
/* don't exceed this size */
if (c->size.flags & PMaxSize)
{
if (width > c->size.max_width)
width = c->size.max_width;
if (height > c->size.max_height)
height = c->size.max_height;
}
/*
* adjust track width if left window doesn't use
* all of it or height left if a right window
* doesn't use it all..
*/
if (on_right)
{
if (ody != height)
screen_height_left += ody - height;
}
else if (odx != width)
{
track_width_right += odx - width;
track_width_left -= odx - width;
}
/*
* The second meaning begins
*/
odx = c->dx;
ody = c->dy;
c->x = x;
c->y = y;
/*
* if resize is true OR we're at the upper left corner
* set size to maximum
*/
if (s->tile_resize[s->desktop] || !on_right)
{
c->dx = width;
c->dy = height;
}
XMoveResizeWindow (dpy, c->parent, c->x, c->y,
c->dx + (2 * BORDER), c->dy + (2 * BORDER));
XResizeWindow (dpy, c->window, c->dx, c->dy);
sendconfig (c);
/* give focus to window if appropriate */
if (c->isleft
&& (mouse_on_screen () == s) && !s->notile_raised[s->desktop])
{
if (!current
|| !s->skip_focus[s->desktop]
|| !s->tile_resize[s->desktop])
active (c);
}
on_right = 1;
}
}
if (current && !current->isnotile && !s->skip_focus[s->desktop])
{
top (current);
XMapRaised (dpy, current->parent);
}
if (!s->notile_raised[s->desktop])
{
raise_tile (s, 0);
}
}
void
goto_desktop (ScreenInfo * s, int n)
{
if (s)
{
s->desktop = n;
s->desktop %= prefs.desktops;
update_desktop (s);
}
}
void
next_desktop (ScreenInfo * s)
{
if (s)
{
s->desktop++;
s->desktop %= prefs.desktops;
update_desktop (s);
}
}
void
next_desktop_drag (ScreenInfo * s)
{
Client *t;
if (s)
{
if (current && (current->screen == s))
{
t = current;
t->desktop++;
t->desktop %= prefs.desktops;
next_desktop (s);
active (t);
if (t->isnotile)
raise_notile (s);
else
raise_tile (s, 0);
update_tbar ();
}
}
}
void
prev_desktop (ScreenInfo * s)
{
if (s)
{
s->desktop += (prefs.desktops - 1);
s->desktop %= prefs.desktops;
update_desktop (s);
}
}
void
prev_desktop_drag (ScreenInfo * s)
{
Client *t;
if (s)
{
if (current && (current->screen == s))
{
t = current;
t->desktop += (prefs.desktops - 1);
t->desktop %= prefs.desktops;
prev_desktop (s);
active (t);
if (t->isnotile)
raise_notile (s);
else
raise_tile (s, 0);
update_tbar ();
}
}
}
void
move_hide (Client * c)
{
if (c)
XMoveWindow (dpy, c->parent, DisplayWidth (dpy, c->screen->num), c->y);
}
void
move_show (Client * c)
{
if (c)
XMoveWindow (dpy, c->parent, c->x, c->y);
}
void
update_desktop (ScreenInfo * s)
{
Client *c;
for (c = clients; c; c = c->next)
{
if ((c->screen != s) || (c->parent == c->screen->root) || c->issticky
|| (c->state != NormalState))
continue;
if (c->desktop == s->desktop)
move_show (c);
else
move_hide (c);
}
if (!s->notile_raised[s->desktop] && s->focused[s->desktop])
active (s->focused[s->desktop]);
else if (s->notile_raised[s->desktop] && s->notilefocused[s->desktop])
active (s->notilefocused[s->desktop]);
else
{
revert_same (s);
if (!current)
revert_window (s);
}
tile_all (s);
update_tbar ();
}
void
revert_window (ScreenInfo * s)
{
Client *c;
if (mouse_on_screen () != s)
{
if (current && (current->screen == s))
nofocus ();
return;
}
if (prev_current)
{
c = prev_current;
if (!c->istool && !c->isaside
&& (DO_TILE (c, s) || DO_RAISE_NOTILE (c, s)))
{
if (c->isnotile)
raise_notile (s);
else
raise_tile (s, 0);
active (c);
return;
}
}
for (c = clients; c; c = c->next)
{
if (!c->istool && !c->isaside
&& (DO_TILE (c, s) || DO_RAISE_NOTILE (c, s)))
{
if (c->isnotile)
raise_notile (s);
else
raise_tile (s, 0);
active (c);
return;
}
}
nofocus ();
}
void
revert_same (ScreenInfo * s)
{
Client *c;
if (mouse_on_screen () != s)
{
if (current && (current->screen == s))
nofocus ();
return;
}
if (prev_current)
{
c = prev_current;
if (!c->istool && !c->isaside
&& (c->isnotile == s->notile_raised[s->desktop]) && (DO_TILE (c, s)
||
DO_RAISE_NOTILE
(c, s)))
{
active (c);
return;
}
}
for (c = clients; c; c = c->next)
{
if (!c->istool && !c->isaside
&& (c->isnotile == s->notile_raised[s->desktop]) && (DO_TILE (c, s)
||
DO_RAISE_NOTILE
(c, s)))
{
active (c);
return;
}
}
nofocus ();
}
void
prev_window (ScreenInfo * s)
{
Client *c;
if (!current || !prev_current || (prev_current == current)
|| (prev_current->desktop != current->desktop)
|| (prev_current->isnotile != current->isnotile)
|| (!s->notile_raised[s->desktop] && !s->skip_focus[s->desktop]))
{
for (c = clients; c; c = c->next)
{
if (!c->istool && !c->isaside &&
(c != current) &&
(c->isnotile == s->notile_raised[s->desktop]) &&
(DO_TILE (c, s) || DO_RAISE_NOTILE (c, s)))
{
active (c);
if (c->isnotile || (!c->isnotile && !s->skip_focus[s->desktop]))
{
raise_tbar (s);
top (c);
XMapRaised (dpy, c->parent);
tile_all (s);
}
return;
}
}
return;
}
c = prev_current;
if (!c->istool && !c->isaside &&
(c != current) &&
(c->isnotile == s->notile_raised[s->desktop]) &&
(DO_TILE (c, s) || DO_RAISE_NOTILE (c, s)))
{
active (c);
if (c->isnotile || (!c->isnotile && !s->skip_focus[s->desktop]))
{
raise_tbar (s);
top (c);
XMapRaised (dpy, c->parent);
tile_all (s);
}
}
}
void
next_window (ScreenInfo * s)
{
Client *c;
if (s->notile_raised[s->desktop] ||
(!s->notile_raised[s->desktop] && !s->skip_focus[s->desktop]))
{
Client *last = 0;
for (c = clients; c; c = c->next)
{
if (!c->istool && !c->isaside &&
(c != current) &&
(c->isnotile == s->notile_raised[s->desktop]) &&
(DO_TILE (c, s) || DO_RAISE_NOTILE (c, s)))
{
last = c;
}
}
if (last)
{
raise_tbar (s);
top (last);
XMapRaised (dpy, last->parent);
if (last->isnotile)
active (last);
else
tile_all (s);
}
return;
}
if (current &&
current->next &&
!s->notile_raised[s->desktop] && s->skip_focus[s->desktop])
{
for (c = current->next; c; c = c->next)
{
if (!c->istool && !c->isaside &&
(c != current) &&
(c->isnotile == s->notile_raised[s->desktop]) &&
(DO_TILE (c, s) || DO_RAISE_NOTILE (c, s)))
{
active (c);
if (c->isnotile || (!c->isnotile && !s->skip_focus[s->desktop]))
{
raise_tbar (s);
XMapRaised (dpy, c->parent);
tile_all (s);
}
return;
}
}
}
for (c = clients; c; c = c->next)
{
if (!c->istool && !c->isaside &&
(c != current) &&
(c->isnotile == s->notile_raised[s->desktop]) &&
(DO_TILE (c, s) || DO_RAISE_NOTILE (c, s)))
{
active (c);
if (c->isnotile || (!c->isnotile && !s->skip_focus[s->desktop]))
{
raise_tbar (s);
top (c);
XMapRaised (dpy, c->parent);
tile_all (s);
}
return;
}
}
}
void
prev_screen (ScreenInfo * s)
{
ScreenInfo *ns;
int cur;
if (!s)
abort ();
cur = s->num;
if (--cur < 0)
cur = num_screens - 1;
raise_tbar (s);
ns = &screens[cur];
setmouse (DisplayWidth (dpy, cur) / 2, DisplayHeight (dpy, cur) - 2, ns);
if (!ns->notile_raised[ns->desktop] && ns->focused[ns->desktop])
active (ns->focused[ns->desktop]);
else if (ns->notile_raised[ns->desktop] && ns->notilefocused[ns->desktop])
active (ns->notilefocused[ns->desktop]);
else
{
revert_same (ns);
if (!current)
revert_window (ns);
}
}
void
next_screen (ScreenInfo * s)
{
ScreenInfo *ns;
int cur;
if (!s)
abort ();
cur = s->num;
if (++cur >= num_screens)
cur = 0;
raise_tbar (s);
ns = &screens[cur];
setmouse (DisplayWidth (dpy, cur) / 2, DisplayHeight (dpy, cur) - 2, ns);
if (!ns->notile_raised[ns->desktop] && ns->focused[ns->desktop])
active (ns->focused[ns->desktop]);
else if (ns->notile_raised[ns->desktop] && ns->notilefocused[ns->desktop])
active (ns->notilefocused[ns->desktop]);
else
{
revert_same (ns);
if (!current)
revert_window (ns);
}
}
ScreenInfo *
mouse_on_screen (void)
{
int i;
if (num_screens == 1)
return &screens[0];
for (i = 0; i < num_screens; i++)
{
Window root, child;
int rx, ry, wx, wy;
unsigned int mask;
if (XQueryPointer
(dpy, screens[i].root, &root, &child, &rx, &ry, &wx, &wy,
&mask) == True)
return &screens[i];
}
return 0;
}
void
shrink_left (ScreenInfo * s)
{
if (s)
{
s->left_track_width[s->desktop] -= 5;
if (s->left_track_width[s->desktop] < 5)
s->left_track_width[s->desktop] = 5;
tile_all (s);
}
}
void
grow_left (ScreenInfo * s)
{
if (s)
{
s->left_track_width[s->desktop] += 5;
if (s->left_track_width[s->desktop] > 95)
s->left_track_width[s->desktop] = 95;
tile_all (s);
}
}
void
max_left (ScreenInfo * s)
{
if (s)
{
s->left_track_width[s->desktop] = 95;
tile_all (s);
}
}
void
restore_left (ScreenInfo * s)
{
if (s)
{
s->left_track_width[s->desktop] =
prefs.left_track_width[s->num][s->desktop];
tile_all (s);
}
}
void
move_northwest (Client * c)
{
if (c && c->isnotile)
{
c->x = 0;
c->y = 0;
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_north (Client * c)
{
if (c && c->isnotile)
{
c->x = (DisplayWidth (dpy, c->screen->num) / 2) - (c->dx / 2) - BORDER;
c->y = 0;
if (c->x < 0)
c->x = 0;
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_northeast (Client * c)
{
if (c && c->isnotile)
{
c->x = (DisplayWidth (dpy, c->screen->num)) - (c->dx) - (2 * BORDER);
c->y = 0;
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_west (Client * c)
{
if (c && c->isnotile)
{
c->x = 0;
c->y = (c->screen->tile_height / 2) - (c->dy / 2) - BORDER;
if (c->y < 0)
c->y = 0;
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_center (Client * c)
{
if (c && c->isnotile)
{
c->x = (DisplayWidth (dpy, c->screen->num) / 2) - (c->dx / 2) - BORDER;
c->y = (c->screen->tile_height / 2) - (c->dy / 2) - BORDER;
if (c->x < 0)
c->x = 0;
if (c->y < 0)
c->y = 0;
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_east (Client * c)
{
if (c && c->isnotile)
{
c->x = DisplayWidth (dpy, c->screen->num) - c->dx - (2 * BORDER);
c->y = (c->screen->tile_height / 2) - (c->dy / 2) - BORDER;
if (c->y < 0)
c->y = 0;
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_southwest (Client * c)
{
if (c && c->isnotile)
{
c->x = 0;
c->y = c->screen->tile_height - c->dy - (2 * BORDER);
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_south (Client * c)
{
if (c && c->isnotile)
{
c->x = (DisplayWidth (dpy, c->screen->num) / 2) - (c->dx / 2) - BORDER;
c->y = c->screen->tile_height - c->dy - (2 * BORDER);
if (c->x < 0)
c->x = 0;
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_southeast (Client * c)
{
if (c && c->isnotile)
{
c->x = DisplayWidth (dpy, c->screen->num) - c->dx - (2 * BORDER);
c->y = c->screen->tile_height - c->dy - (2 * BORDER);
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_up (Client * c)
{
if (c && c->isnotile)
{
if (c->screen->bigmr[c->screen->desktop])
c->y -= (c->screen->tile_height / 20);
else
c->y--;
if (c->y < 0)
c->y = 0;
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_down (Client * c)
{
if (c && c->isnotile)
{
int max_y = c->screen->tile_height - c->dy - (2 * BORDER);
if (c->screen->bigmr[c->screen->desktop])
c->y += (c->screen->tile_height / 20);
else
c->y++;
if (c->y > max_y)
c->y = max_y;
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_left (Client * c)
{
if (c && c->isnotile)
{
if (c->screen->bigmr[c->screen->desktop])
c->x -= (DisplayWidth (dpy, c->screen->num) / 20);
else
c->x--;
if (c->x < 0)
c->x = 0;
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
move_right (Client * c)
{
if (c && c->isnotile)
{
int max_x = DisplayWidth (dpy, c->screen->num) - c->dx - (2 * BORDER);
if (c->screen->bigmr[c->screen->desktop])
c->x += (DisplayWidth (dpy, c->screen->num) / 20);
else
c->x++;
if (c->x > max_x)
c->x = max_x;
XMoveWindow (dpy, c->parent, c->x, c->y);
sendconfig (c);
}
}
void
zoom (Client * c, int dimension)
{
if (c)
{
if (!c->isnotile)
{
if (c->screen->notile_raised[c->screen->desktop])
toggle_notile (c->screen);
if (c->isleft)
{
Client *p;
for (p = clients->next; p; p = p->next)
{
if (!p->istool &&
(p != current) &&
(p->isnotile ==
p->screen->notile_raised[p->screen->desktop])
&& (DO_TILE (p, c->screen)
|| DO_RAISE_NOTILE (p, c->screen)))
{
active (p);
break;
}
}
top (current);
tile_all (c->screen);
}
else
{
top (c);
tile_all (c->screen);
}
}
else if (c->iszoom == ZOOM_SELECT)
{
move_select (c, 0);
}
else if (c->iszoom == ZOOM_NORMAL)
{
c->x = c->zx;
c->y = c->zy;
c->dx = c->zdx;
c->dy = c->zdy;
XMoveResizeWindow (dpy, c->parent, c->x, c->y, c->dx + (2 * BORDER),
c->dy + (2 * BORDER));
XResizeWindow (dpy, c->window, c->dx, c->dy);
sendconfig (c);
c->iszoom = ZOOM_UNZOOMED;
}
else
{
int height;
int width;
if (dimension & DIM_OUTSIDE)
{
width = DisplayWidth (dpy, c->screen->num);
height = DisplayHeight (dpy, c->screen->num);
}
else
{
height = c->screen->tile_height - (2 * BORDER);
width = DisplayWidth (dpy, c->screen->num) - (2 * BORDER);
}
if (c->size.flags & PResizeInc)
{
width =
c->min_dx + (width -
c->min_dx) / c->size.width_inc *
c->size.width_inc;
height =
c->min_dy + (height -
c->min_dy) / c->size.height_inc *
c->size.height_inc;
}
if (c->size.flags & PMaxSize)
{
if (width > c->size.max_width)
width = c->size.max_width;
if (height > c->size.max_height)
height = c->size.max_height;
}
c->zx = c->x;
c->zy = c->y;
c->zdx = c->dx;
c->zdy = c->dy;
if (dimension & DIM_HORIZ)
{
c->dx = width;
if (dimension & DIM_OUTSIDE)
c->x = -BORDER;
else
c->x =
(DisplayWidth (dpy, c->screen->num) / 2) - (c->dx / 2) -
BORDER;
}
if (dimension & DIM_VERT)
{
c->dy = height;
if (dimension & DIM_OUTSIDE)
c->y = -BORDER;
else
c->y = (c->screen->tile_height / 2) - (c->dy / 2) - BORDER;
}
XMoveResizeWindow (dpy, c->parent, c->x, c->y, c->dx + (2 * BORDER),
c->dy + (2 * BORDER));
XResizeWindow (dpy, c->window, c->dx, c->dy);
sendconfig (c);
c->iszoom = ZOOM_NORMAL;
}
update_tbar ();
}
}
void
grow (Client * c, int dimension, int m)
{
int h, w, dh, dw, x, y;
int odx, ody, want_w, want_h;
int ddx, ddy;
if (!c || !dimension)
return;
if (!c->isnotile)
{
if ((dimension == DIM_HORIZ) || (dimension == (DIM_HORIZ | DIM_VERT)))
{
if (m > 0)
grow_left (c->screen);
else
shrink_left (c->screen);
}
else if (dimension == DIM_VERT)
{
if (m > 0)
max_left (c->screen);
else
restore_left (c->screen);
}
return;
}
x = c->x;
y = c->y;
w = odx = c->dx;
h = ody = c->dy;
dw = DisplayWidth (dpy, c->screen->num) - (2 * BORDER);
dh = c->screen->tile_height - (2 * BORDER);
if (c->screen->bigmr[c->screen->desktop])
{
ddx = (dw / 20);
ddy = (dh / 20);
}
else if (c->size.flags & PResizeInc)
{
ddx = c->size.width_inc;
ddy = c->size.height_inc;
}
else
{
ddx = 2;
ddy = 2;
}
if (dimension & DIM_HORIZ)
{
x -= (ddx / 2) * m;
w += ddx * m;
if ((x + w) > dw)
x = dw - w;
if (x < 0)
x = 0;
if ((x + w) > dw)
w = dw;
if (w < 1)
w = 1;
}
if (dimension & DIM_VERT)
{
y -= (ddy / 2) * m;
h += ddy * m;
if ((y + h) > dh)
y = dh - h;
if (y < 0)
y = 0;
if ((y + h) > dh)
h = dh;
if (h < 1)
h = 1;
}
want_w = w;
want_h = h;
if (c->size.flags & PResizeInc)
{
w = c->min_dx + (w - c->min_dx) / c->size.width_inc * c->size.width_inc;
h =
c->min_dy + (h - c->min_dy) / c->size.height_inc * c->size.height_inc;
}
if (c->size.flags & PMinSize)
{
if (w < c->size.min_width)
w = c->size.min_width;
if (h < c->size.min_height)
h = c->size.min_height;
}
if (c->size.flags & PMaxSize)
{
if (w > c->size.max_width)
w = c->size.max_width;
if (h > c->size.max_height)
h = c->size.max_height;
}
x += ((want_w - w) / 2);
y += ((want_h - h) / 2);
if ((w == odx) && (h == ody))
return;
if (w != odx)
{
c->x = x;
c->dx = w;
}
if (h != ody)
{
c->y = y;
c->dy = h;
}
XMoveResizeWindow (dpy, c->parent, c->x, c->y, c->dx + (2 * BORDER),
c->dy + (2 * BORDER));
XResizeWindow (dpy, c->window, c->dx, c->dy);
sendconfig (c);
}
void
move_select (Client * c, int untiled)
{
int h, w, dh, dw, x, y;
int odx, ody;
if (!c || !c->isnotile || c->isaside)
return;
odx = c->dx;
ody = c->dy;
if (c->iszoom == ZOOM_NORMAL)
{
zoom (c, DIM_HORIZ | DIM_VERT);
return;
}
else if (c->iszoom == ZOOM_SELECT)
{
c->x = c->zx;
c->y = c->zy;
c->dx = c->zdx;
c->dy = c->zdy;
XMoveResizeWindow (dpy, c->parent, c->x, c->y, c->dx + (2 * BORDER),
c->dy + (2 * BORDER));
XResizeWindow (dpy, c->window, c->dx, c->dy);
sendconfig (c);
XMapRaised (dpy, c->parent);
top (c);
active (c);
if (!c->screen->notile_raised[c->screen->desktop])
raise_notile (c->screen);
c->iszoom = ZOOM_UNZOOMED;
update_tbar ();
return;
}
x = c->x;
y = c->y;
w = odx;
h = ody;
dh = c->screen->tile_height - (2 * BORDER);
dw = DisplayWidth (dpy, c->screen->num) - (2 * BORDER);
if (untiled) /* window that just stopped being tiled, restore original size */
{
if ((c->size.flags & PSize)
&& ((c->size.height != ody) || (c->size.width != odx)))
{
h = c->size.height;
w = c->size.width;
}
else /* emacs changes size hints when you resize it... odd. */
{
h = dh / 2;
w = dw / 2;
}
}
else
{
h = dh;
w = (17 * h) / 22; /* US Letter ratio */
}
if (w > dw) /* for screens with non-standard ratios */
w = dw;
if (h > dh) /* for when hints says taller than screen */
h = dh;
if (c->size.flags & PResizeInc)
{
w = c->min_dx + (w - c->min_dx) / c->size.width_inc * c->size.width_inc;
h =
c->min_dy + (h - c->min_dy) / c->size.height_inc * c->size.height_inc;
}
if (c->size.flags & PMinSize)
{
if (w < c->size.min_width)
w = c->size.min_width;
if (h < c->size.min_height)
h = c->size.min_height;
}
if (c->size.flags & PMaxSize)
{
if (w > c->size.max_width)
w = c->size.max_width;
if (h > c->size.max_height)
h = c->size.max_height;
}
x = (DisplayWidth (dpy, c->screen->num) / 2) - (w / 2) - BORDER;
y = (c->screen->tile_height / 2) - (h / 2) - BORDER;
if (c->x < 0)
c->x = 0;
if (c->y < 0)
c->y = 0;
c->zx = c->x;
c->zy = c->y;
c->zdx = c->dx;
c->zdy = c->dy;
if (w != odx)
{
c->x = x;
c->dx = w;
}
if (h != ody)
{
c->y = y;
c->dy = h;
}
XMoveResizeWindow (dpy, c->parent, c->x, c->y, c->dx + (2 * BORDER),
c->dy + (2 * BORDER));
XResizeWindow (dpy, c->window, c->dx, c->dy);
sendconfig (c);
XMapRaised (dpy, c->parent);
top (c);
active (c);
if (!c->screen->notile_raised[c->screen->desktop])
raise_notile (c->screen);
if (untiled) /* if just stopped being tiled, do not count this as zoomed */
c->iszoom = ZOOM_UNZOOMED;
else
c->iszoom = ZOOM_SELECT;
update_tbar ();
}
int
count_aside (ScreenInfo * s)
{
int i = 0;
Client *c;
if (!s)
return 0;
for (c = clients; c; c = c->next)
{
if (c->isaside && DO_RAISE_NOTILE (c, s))
{
i++;
}
}
return i;
}
Client *
find_aside (ScreenInfo * s)
{
Client *c;
if (!s)
return (Client *) 0;
for (c = clients; c; c = c->next)
{
if (c->isaside && DO_RAISE_NOTILE (c, s))
{
return c;
}
}
return (Client *) 0;
}
void
arrange_aside (ScreenInfo * s)
{
int wnum = 0;
int wcount;
int ystep;
Client *c;
if (!s)
return;
wcount = count_aside (s);
if (wcount < 1)
{
return;
}
ystep = s->tile_height / wcount;
for (c = clients; c; c = c->next)
{
if (c->isaside && DO_RAISE_NOTILE (c, s))
{
c->y = ystep * wnum++;
XMapRaised (dpy, c->parent);
XMoveWindow (dpy, c->parent, c->x, c->y);
}
}
}
void
move_aside (ScreenInfo * s, Client * c)
{
if (!s)
return;
if (!c || !c->isnotile || c->istool)
{
Client *t = find_aside (s);
if (t)
{
raise_notile (s);
XMapRaised (dpy, s->barwin);
move_aside (s, t);
}
return;
}
if (c->isaside)
{
c->x = c->ax;
c->y = c->ay;
c->isaside = 0;
if (s->notile_raised[s->desktop] != c->isnotile)
toggle_notile (s);
arrange_aside (s);
active (c);
raise_tbar (s);
XMapRaised (dpy, c->parent);
XMoveWindow (dpy, c->parent, c->x, c->y);
}
else
{
c->ax = c->x;
c->ay = c->y;
c->x = (95 * DisplayWidth (dpy, s->num)) / 100;
c->isaside = 1;
arrange_aside (s);
revert_window (s);
XMapRaised (dpy, s->barwin);
if (current)
XMapRaised (dpy, current->parent);
}
}
void
move_aside_other (ScreenInfo * s)
{
Client *c;
if (!s || !current || !current->isnotile)
return;
for (c = clients; c; c = c->next)
{
if ((c != current) && !c->isaside && !c->istool
&& DO_RAISE_NOTILE (c, s))
{
c->ax = c->x;
c->ay = c->y;
c->x = (95 * DisplayWidth (dpy, s->num)) / 100;
c->isaside = 1;
}
}
arrange_aside (s);
XMapRaised (dpy, s->barwin);
XMapRaised (dpy, current->parent);
}
void
move_aside_clear (ScreenInfo * s, Client * c)
{
if (s && c && (c->screen == s) && c->isnotile && normal (c) && !c->isaside)
move_aside (s, c);
}
void
move_sd (Client * c)
{
if (!c)
return;
c->iszoom = ZOOM_UNZOOMED;
if (c->isnotile)
{
c->isnotile = 0;
raise_tile (c->screen, 0);
top (c);
active (c);
tile_all (c->screen);
}
else
{
c->isnotile = 1;
tile_all (c->screen);
raise_notile (c->screen);
move_select (c, 1);
}
}
syntax highlighted by Code2HTML, v. 0.9.1