/* Copyright (c) 2000-2004 Lars Bernhardsson, see README for license details */ #include #include #include #include #include #include #include #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); } }