diff --git a/client.c b/client.c
index 1f21a7c..f28253e 100644
--- a/client.c
+++ b/client.c
@@ -64,6 +64,8 @@ static struct Command c[] = {
{ "window_monocle" , IPCWindowMonocle , 0 , NULL } ,
{ "window_close" , IPCWindowClose , 0 , NULL } ,
{ "window_put_in_grid" , IPCWindowPutInGrid , 6 , fn_hack } ,
+ { "window_move_in_grid" , IPCWindowMoveInGrid , 2 , fn_offset } ,
+ { "window_resize_in_grid" , IPCWindowResizeInGrid , 2 , fn_offset } ,
{ "window_snap" , IPCWindowSnap , 1 , fn_position } ,
{ "window_cycle" , IPCWindowCycle , 0 , NULL } ,
{ "window_rev_cycle" , IPCWindowRevCycle , 0 , NULL } ,
diff --git a/ipc.h b/ipc.h
index 4aa3d83..5fb307e 100644
--- a/ipc.h
+++ b/ipc.h
@@ -21,6 +21,8 @@ enum IPCCommand {
IPCWindowMonocle,
IPCWindowClose,
IPCWindowPutInGrid,
+ IPCWindowMoveInGrid,
+ IPCWindowResizeInGrid,
IPCWindowSnap,
IPCWindowCycle,
IPCWindowRevCycle,
diff --git a/man/waitron.1 b/man/waitron.1
index 4e0ea74..7db2016 100644
--- a/man/waitron.1
+++ b/man/waitron.1
@@ -101,6 +101,14 @@ Closes the focused window\.
Moves and resizes the focused windows accordingly to fit in a cell defined by the \fIcell_x\fR and \fIcell_y\fR coordinates, measuring \fIcell_width\fR in width and \fIcell_height\fR in height, in a virtual grid with width \fIgrid_width\fR and height \fIgrid_height\fR on the current monitor\. \fIcell_width\fR and \fIcell_height\fR are expressed in grid cells\. Gaps around the windows in the grid can be added along with monitor gaps\.
.
.TP
+\fBwindow_move_in_grid\fR \fIx\fR \fIy\fR
+Move a gridded window by \fIx\fR and \fIy\fR grid spaces.
+.
+.TP
+\fBwindow_resize_in_grid\fR \fIx\fR \fIy\fR
+Resize a gridded window by \fIx\fR and \fIy\fR grid spaces.
+.
+.TP
\fBwindow_snap\fR \fIPOSITION\fR
Snap the window on the screen in a position defined by \fIPOSITION\fR\.
.
diff --git a/man/waitron.1.html b/man/waitron.1.html
index 17c2d0e..4517aba 100644
--- a/man/waitron.1.html
+++ b/man/waitron.1.html
@@ -137,6 +137,8 @@
COMMANDS
grid_width and height grid_height on the current monitor.
cell_width and cell_height are expressed in grid cells.
Gaps around the windows in the grid can be added along with monitor gaps.
+window_move_in_grid
x y Move a gridded window by x and y grid spaces.
+window_resize_in_grid
x y Resize a gridded window by x and y grid spaces.
window_snap
POSITION Snap the window on the screen in a position defined by POSITION.
window_cycle
Cycle through mapped windows.
window_rev_cycle
Reverse cycle through mapped windows.
diff --git a/man/waitron.1.md b/man/waitron.1.md
index 27b7bf4..1514430 100644
--- a/man/waitron.1.md
+++ b/man/waitron.1.md
@@ -90,6 +90,12 @@ anything on `stdout`.
and are expressed in grid cells.
Gaps around the windows in the grid can be added along with monitor gaps.
+* `window_move_in_grid` :
+ Move a gridded window by and grid spaces.
+
+* `window_resize_in_grid` :
+ Resize a gridded window by and grid spaces.
+
* `window_snap` :
Snap the window on the screen in a position defined by .
diff --git a/types.h b/types.h
index 9576568..ffc7984 100644
--- a/types.h
+++ b/types.h
@@ -63,11 +63,18 @@ struct window_geom {
bool set_by_user;
};
+struct grid {
+ int16_t gx, gy;
+ int16_t px, py;
+ int16_t sx, sy;
+};
+
struct client {
xcb_window_t window;
struct window_geom geom;
struct window_geom orig_geom;
- bool maxed, hmaxed, vmaxed, monocled;
+ struct grid grid;
+ bool maxed, hmaxed, vmaxed, monocled, gridded;
struct list_item *item;
struct list_item *focus_item;
struct monitor *monitor;
diff --git a/wm.c b/wm.c
index 7033c70..d8c9268 100644
--- a/wm.c
+++ b/wm.c
@@ -104,8 +104,8 @@ static void maximize_window(struct client *, int16_t, int16_t, uint16_t, uint16_
static void hmaximize_window(struct client *, int16_t, uint16_t);
static void vmaximize_window(struct client *, int16_t, uint16_t);
static void monocle_window(struct client *, int16_t, int16_t, uint16_t, uint16_t);
-static void unmaximize_window(struct client *);
-static bool is_maxed(struct client *);
+static void reset_window(struct client *);
+static bool is_special(struct client *);
static void cycle_window(struct client *);
static void rcycle_window(struct client *);
static void cycle_window_in_group(struct client *);
@@ -149,6 +149,8 @@ static void handle_wm_state(struct client *, xcb_atom_t, unsigned int);
static void snap_window(struct client *, enum position);
static void grid_window(struct client *, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t);
+static void move_grid_window(struct client *, uint16_t, uint16_t);
+static void resize_grid_window(struct client *, uint16_t, uint16_t);
static void register_event_handlers(void);
static void event_configure_request(xcb_generic_event_t *);
@@ -176,6 +178,8 @@ static void ipc_window_ver_maximize(uint32_t *);
static void ipc_window_monocle(uint32_t *);
static void ipc_window_close(uint32_t *);
static void ipc_window_put_in_grid(uint32_t *);
+static void ipc_window_move_in_grid(uint32_t *);
+static void ipc_window_resize_in_grid(uint32_t *);
static void ipc_window_snap(uint32_t *);
static void ipc_window_cycle(uint32_t *);
static void ipc_window_rev_cycle(uint32_t *);
@@ -699,9 +703,11 @@ setup_window(xcb_window_t win)
client->geom.x = client->geom.y = client->geom.width
= client->geom.height
= client->min_width = client->min_height = 0;
+ client->grid.gx = client->grid.gy = client->grid.px
+ = client->grid.py = client->grid.sx = client->grid.sy = 0;
client->width_inc = client->height_inc = 1;
client->maxed = client->hmaxed = client->vmaxed
- = client->monocled = client->geom.set_by_user = false;
+ = client->monocled = client->gridded = client->geom.set_by_user = false;
client->monitor = NULL;
client->mapped = false;
client->group = NULL_GROUP;
@@ -1068,8 +1074,8 @@ maximize_window(struct client *client, int16_t mon_x, int16_t mon_y, uint16_t mo
if (client == NULL)
return;
- if (is_maxed(client))
- unmaximize_window(client);
+ if (is_special(client))
+ reset_window(client);
client->maxed = true;
@@ -1099,8 +1105,8 @@ hmaximize_window(struct client *client, int16_t mon_x, uint16_t mon_width)
if (client == NULL)
return;
- if (is_maxed(client))
- unmaximize_window(client);
+ if (is_special(client))
+ reset_window(client);
if (client->geom.width != mon_width)
client->orig_geom = client->geom;
@@ -1121,8 +1127,8 @@ vmaximize_window(struct client *client, int16_t mon_y, uint16_t mon_height)
if (client == NULL)
return;
- if (is_maxed(client))
- unmaximize_window(client);
+ if (is_special(client))
+ reset_window(client);
if (client->geom.height != mon_height)
client->orig_geom = client->geom;
@@ -1144,8 +1150,8 @@ monocle_window(struct client *client, int16_t mon_x, int16_t mon_y, uint16_t mon
if (client == NULL)
return;
- if (is_maxed(client))
- unmaximize_window(client);
+ if (is_special(client))
+ reset_window(client);
client->orig_geom = client->geom;
@@ -1165,7 +1171,7 @@ monocle_window(struct client *client, int16_t mon_x, int16_t mon_y, uint16_t mon
}
static void
-unmaximize_window(struct client *client)
+reset_window(struct client *client)
{
xcb_atom_t state[] = {
XCB_ICCCM_WM_STATE_NORMAL,
@@ -1176,7 +1182,7 @@ unmaximize_window(struct client *client)
client->geom.width = client->orig_geom.width;
client->geom.height = client->orig_geom.height;
client->maxed = client->hmaxed
- = client->vmaxed = client->monocled = false;
+ = client->vmaxed = client->monocled = client->gridded = false;
teleport_window(client->window, client->geom.x, client->geom.y);
resize_window_absolute(client->window, client->geom.width, client->geom.height);
@@ -1188,7 +1194,7 @@ unmaximize_window(struct client *client)
}
static bool
-is_maxed(struct client *client)
+is_special(struct client *client)
{
if (client == NULL)
return false;
@@ -1196,7 +1202,8 @@ is_maxed(struct client *client)
return client->maxed
|| client->vmaxed
|| client->hmaxed
- || client->monocled;
+ || client->monocled
+ || client->gridded;
}
static void
@@ -1913,6 +1920,7 @@ static void update_window_status(struct client *client)
else if (client->hmaxed) state = "hmaxed";
else if (client->vmaxed) state = "vmaxed";
else if (client->monocled) state = "monocled";
+ else if (client->gridded) state = "gridded";
else state = "normal";
/* this is going to be fun */
#define _BOOL_VALUE(value) ((value) ? "true" : "false")
@@ -2182,11 +2190,11 @@ handle_wm_state(struct client *client, xcb_atom_t state, unsigned int action)
if (action == XCB_EWMH_WM_STATE_ADD) {
maximize_window(client, mon_x, mon_y, mon_w, mon_h);
} else if (action == XCB_EWMH_WM_STATE_REMOVE && client->maxed) {
- unmaximize_window(client);
+ reset_window(client);
set_focused(client);
} else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
if (client->maxed) {
- unmaximize_window(client);
+ reset_window(client);
set_focused(client);
} else {
maximize_window(client, mon_x, mon_y, mon_w, mon_h);
@@ -2197,10 +2205,10 @@ handle_wm_state(struct client *client, xcb_atom_t state, unsigned int action)
vmaximize_window(client, mon_y, mon_h);
} else if (action == XCB_EWMH_WM_STATE_REMOVE) {
if (client->vmaxed)
- unmaximize_window(client);
+ reset_window(client);
} else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
if (client->vmaxed)
- unmaximize_window(client);
+ reset_window(client);
else
vmaximize_window(client, mon_y, mon_h);
}
@@ -2209,10 +2217,10 @@ handle_wm_state(struct client *client, xcb_atom_t state, unsigned int action)
hmaximize_window(client, mon_y, mon_h);
} else if (action == XCB_EWMH_WM_STATE_REMOVE) {
if (client->hmaxed)
- unmaximize_window(client);
+ reset_window(client);
} else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
if (client->hmaxed)
- unmaximize_window(client);
+ reset_window(client);
else
hmaximize_window(client, mon_x, mon_w);
}
@@ -2232,8 +2240,8 @@ snap_window(struct client *client, enum position pos)
if (client == NULL)
return;
- if (is_maxed(client)) {
- unmaximize_window(client);
+ if (is_special(client)) {
+ reset_window(client);
set_focused(client);
}
@@ -2300,8 +2308,8 @@ grid_window(struct client *client, uint16_t grid_width, uint16_t grid_height, ui
return;
DMSG("Gridding window in grid of size (%d, %d) pos (%d, %d) window size (%d, %d)\n", grid_width, grid_height, grid_x, grid_y, occ_w, occ_h);
- if (is_maxed(client)) {
- unmaximize_window(client);
+ if (is_special(client)) {
+ reset_window(client);
set_focused(client);
}
@@ -2324,6 +2332,14 @@ grid_window(struct client *client, uint16_t grid_width, uint16_t grid_height, ui
client->geom.y = mon_y + conf.gap_up + grid_y
* (conf.border_width + base_h + conf.border_width + conf.grid_gap);
+ client->gridded = true;
+ client->grid.gx = grid_width;
+ client->grid.gy = grid_height;
+ client->grid.px = grid_x;
+ client->grid.py = grid_y;
+ client->grid.sx = occ_w;
+ client->grid.sy = occ_h;
+
DMSG("w: %d\th: %d\n", new_w, new_h);
teleport_window(client->window, client->geom.x, client->geom.y);
@@ -2332,6 +2348,44 @@ grid_window(struct client *client, uint16_t grid_width, uint16_t grid_height, ui
xcb_flush(conn);
}
+static void
+move_grid_window(struct client *client, uint16_t x, uint16_t y)
+{
+
+ int16_t new_px, new_py;
+
+ new_px = client->grid.px + x;
+ new_py = client->grid.py + y;
+
+ if (!client->gridded
+ || client->grid.gx < new_px + client->grid.sx
+ || client->grid.gy < new_py + client->grid.sy
+ || new_px < 0
+ || new_py < 0)
+ return;
+
+ grid_window(client, client->grid.gx, client->grid.gy, new_px, new_py, client->grid.sx, client->grid.sy);
+}
+
+static void
+resize_grid_window(struct client *client, uint16_t x, uint16_t y)
+{
+
+ int16_t new_sx, new_sy;
+
+ new_sx = client->grid.sx + x;
+ new_sy = client->grid.sy + y;
+
+ if (!client->gridded
+ || client->grid.gx < new_sx + client->grid.px
+ || client->grid.gy < new_sy + client->grid.py
+ || new_sx < 1
+ || new_sy < 1)
+ return;
+
+ grid_window(client, client->grid.gx, client->grid.gy, client->grid.px, client->grid.py, new_sx, new_sy);
+}
+
/*
* Adds X event handlers to the array.
*/
@@ -2747,6 +2801,8 @@ register_ipc_handlers(void)
ipc_handlers[IPCWindowMonocle] = ipc_window_monocle;
ipc_handlers[IPCWindowClose] = ipc_window_close;
ipc_handlers[IPCWindowPutInGrid] = ipc_window_put_in_grid;
+ ipc_handlers[IPCWindowMoveInGrid] = ipc_window_move_in_grid;
+ ipc_handlers[IPCWindowResizeInGrid] = ipc_window_resize_in_grid;
ipc_handlers[IPCWindowSnap] = ipc_window_snap;
ipc_handlers[IPCWindowCycle] = ipc_window_cycle;
ipc_handlers[IPCWindowRevCycle] = ipc_window_rev_cycle;
@@ -2774,14 +2830,14 @@ ipc_window_move(uint32_t *d)
if (focused_win == NULL)
return;
- if (is_maxed(focused_win)) {
- unmaximize_window(focused_win);
+ if (is_special(focused_win)) {
+ reset_window(focused_win);
set_focused(focused_win);
}
x = d[2];
y = d[3];
-if (d[0])
+ if (d[0])
x = -x;
if (d[1])
y = -y;
@@ -2801,8 +2857,8 @@ ipc_window_move_absolute(uint32_t *d)
if (focused_win == NULL)
return;
- if (is_maxed(focused_win)) {
- unmaximize_window(focused_win);
+ if (is_special(focused_win)) {
+ reset_window(focused_win);
set_focused(focused_win);
}
@@ -2829,8 +2885,8 @@ ipc_window_resize(uint32_t *d)
if (focused_win == NULL)
return;
- if (is_maxed(focused_win)) {
- unmaximize_window(focused_win);
+ if (is_special(focused_win)) {
+ reset_window(focused_win);
set_focused(focused_win);
}
@@ -2854,8 +2910,8 @@ ipc_window_resize_absolute(uint32_t *d)
if (focused_win == NULL)
return;
- if (is_maxed(focused_win)) {
- unmaximize_window(focused_win);
+ if (is_special(focused_win)) {
+ reset_window(focused_win);
set_focused(focused_win);
}
@@ -2886,7 +2942,7 @@ ipc_window_maximize(uint32_t *d)
return;
if (focused_win->maxed) {
- unmaximize_window(focused_win);
+ reset_window(focused_win);
} else {
get_monitor_size(focused_win, &mon_x, &mon_y, &mon_w, &mon_h);
maximize_window(focused_win, mon_x, mon_y, mon_w, mon_h);
@@ -2905,9 +2961,10 @@ ipc_window_unmaximize(uint32_t *d)
if (focused_win == NULL)
return;
- unmaximize_window(focused_win);
-
- set_focused(focused_win);
+ if (is_special(focused_win)) {
+ reset_window(focused_win);
+ set_focused(focused_win);
+ }
xcb_flush(conn);
}
@@ -2923,7 +2980,7 @@ ipc_window_hor_maximize(uint32_t *d)
return;
if (focused_win->hmaxed) {
- unmaximize_window(focused_win);
+ reset_window(focused_win);
} else {
get_monitor_size(focused_win, &mon_x, &mon_y, &mon_w, NULL);
hmaximize_window(focused_win, mon_x, mon_w);
@@ -2945,7 +3002,7 @@ ipc_window_ver_maximize(uint32_t *d)
return;
if (focused_win->vmaxed) {
- unmaximize_window(focused_win);
+ reset_window(focused_win);
} else {
get_monitor_size(focused_win, &mon_x, &mon_y, NULL, &mon_h);
vmaximize_window(focused_win, mon_y, mon_h);
@@ -2967,7 +3024,7 @@ ipc_window_monocle(uint32_t *d)
return;
if (focused_win->monocled) {
- unmaximize_window(focused_win);
+ reset_window(focused_win);
} else {
get_monitor_size(focused_win, &mon_x, &mon_y, &mon_w, &mon_h);
monocle_window(focused_win, mon_x, mon_y, mon_w, mon_h);
@@ -3007,6 +3064,44 @@ ipc_window_put_in_grid(uint32_t *d)
grid_window(focused_win, grid_width, grid_height, grid_x, grid_y, occ_w, occ_h);
}
+static void
+ipc_window_move_in_grid(uint32_t *d)
+{
+ uint16_t x, y;
+
+ if (focused_win == NULL)
+ return;
+
+ x = d[2];
+ y = d[3];
+
+ if (d[0] == IPC_MUL_MINUS)
+ x = -x;
+ if (d[1] == IPC_MUL_MINUS)
+ y = -y;
+
+ move_grid_window(focused_win, x, y);
+}
+
+static void
+ipc_window_resize_in_grid(uint32_t *d)
+{
+ uint16_t x, y;
+
+ if (focused_win == NULL)
+ return;
+
+ x = d[2];
+ y = d[3];
+
+ if (d[0] == IPC_MUL_MINUS)
+ x = -x;
+ if (d[1] == IPC_MUL_MINUS)
+ y = -y;
+
+ resize_grid_window(focused_win, x, y);
+}
+
static void
ipc_window_snap(uint32_t *d)
{
@@ -3352,7 +3447,7 @@ pointer_grab(enum pointer_action pac)
return false;
}
- if (is_maxed(client)) {
+ if (is_special(client)) {
return true;
}