From 71cf2c073b0c48c06b79e422e2f0f5ff395cb165 Mon Sep 17 00:00:00 2001 From: seanpringle Date: Fri, 31 Aug 2012 18:32:14 +1000 Subject: [PATCH] support fullscreen toggle --- README.md | 2 +- cerberus.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++--- cerberus.h | 7 +++++- config.h | 3 +++ proto.h | 4 ++++ 5 files changed, 78 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ca6d2f8..69dc1e4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ cerberus ======== -* Designed for wide screens. +* Designed for wide screens, including multi-head support. * Static tiling; you get just three fixed asymmetric tiles and windows never move automatically. * Bare minimum EWMH to support panels and [simpleswitcher](https://github.com/seanpringle/simpleswitcher) * A few keyboard controls for moving, focusing, cycling, closing, and finding windows. diff --git a/cerberus.c b/cerberus.c index bb3c6a7..dd426a1 100644 --- a/cerberus.c +++ b/cerberus.c @@ -182,6 +182,8 @@ client* window_client(Window win) ? (c->attr.y > m->y + m->h/2 ? SPOT3: SPOT2) : SPOT1; + window_get_atom_prop(c->window, atoms[_NET_WM_STATE], c->states, MAX_NET_WM_STATES); + if (c->visible) { XWMHints *hints = XGetWMHints(display, c->window); @@ -202,6 +204,55 @@ client* window_client(Window win) return NULL; } +// check _NET_WM_STATE +int client_state(client *c, Atom state) +{ + int i; + for (i = 0; i < MAX_NET_WM_STATES && c->states[i]; i++) + if (c->states[i] == state) + return 1; + return 0; +} + +int client_add_state(client *c, Atom state) +{ + int i; + for (i = 0; i < MAX_NET_WM_STATES; i++) + { + if (c->states[i]) continue; + + c->states[i] = state; + window_set_atom_prop(c->window, atoms[_NET_WM_STATE], c->states, i+1); + return 1; + } + return 0; +} + +int client_drop_state(client *c, Atom state) +{ + int i, j; + for (i = 0, j = 0; i < MAX_NET_WM_STATES && c->states[i]; i++) + { + if (c->states[i] == state) continue; + c->states[i] = c->states[j++]; + } + window_set_atom_prop(c->window, atoms[_NET_WM_STATE], c->states, j); + int rc = i != j ? 1:0; + + for (; j < MAX_NET_WM_STATES; j++) + c->states[j] = None; + + return rc; +} + +void client_toggle_state(client *c, Atom state) +{ + if (client_state(c, state)) + client_drop_state(c, state); + else + client_add_state(c, state); +} + // build a list of visible windows void windows_visible(stack *s) { @@ -278,6 +329,13 @@ void client_close(client *c) void client_position(client *c, int x, int y, int w, int h) { if (!c) return; + monitor *m = &monitors[c->monitor]; + + if (client_state(c, atoms[_NET_WM_STATE_FULLSCREEN])) + { + XMoveResizeWindow(display, c->window, m->x, m->y, m->w, m->h); + return; + } w -= BORDER*2; h -= BORDER*2; @@ -319,8 +377,6 @@ void client_position(client *c, int x, int y, int w, int h) if (w < sw) x += (sw-w)/2; if (h < sh) y += (sh-h)/2; - monitor *m = &monitors[c->monitor]; - // bump onto screen x = MAX(0, MIN(x, m->x + m->w - w - BORDER*2)); y = MAX(0, MIN(y, m->y + m->h - h - BORDER*2)); @@ -556,7 +612,7 @@ void window_listen(Window win) void client_review(client *c) { XSetWindowBorder(display, c->window, color_get(c->window == current ? BORDER_FOCUS: BORDER_BLUR)); - XSetWindowBorderWidth(display, c->window, BORDER); + XSetWindowBorderWidth(display, c->window, client_state(c, atoms[_NET_WM_STATE_FULLSCREEN]) ? 0: BORDER); } // ------- event handlers -------- @@ -734,6 +790,11 @@ void key_press(XKeyEvent *e) client_spot(c, c->spot, 1); } break; + case ACTION_FULLSCREEN_TOGGLE: + client_toggle_state(c, atoms[_NET_WM_STATE_FULLSCREEN]); + client_review(c); + client_spot(c, c->spot, 1); + break; } } switch (act) diff --git a/cerberus.h b/cerberus.h index 7a09678..7549af1 100644 --- a/cerberus.h +++ b/cerberus.h @@ -63,13 +63,15 @@ typedef struct { monitor monitors[MAX_MONITORS]; int nmonitors; +#define MAX_NET_WM_STATES 5 + typedef struct { Window window; XWindowAttributes attr; XWMHints hints; XSizeHints size; Window transient_for; - Atom type; + Atom type, states[MAX_NET_WM_STATES]; short monitor, spot, visible, trans, manage, input, urgent; } client; @@ -109,6 +111,8 @@ int struts[4] = { 0, 0, 0, 0 }; X(_NET_WM_WINDOW_TYPE_DIALOG),\ X(_NET_CLIENT_LIST_STACKING),\ X(_NET_WM_STATE),\ + X(_NET_WM_STATE_FULLSCREEN),\ + X(_NET_WM_STATE_DEMANDS_ATTENTION),\ X(WM_PROTOCOLS) enum { GENERAL_ATOMS(ATOM_ENUM), ATOMS }; @@ -134,6 +138,7 @@ enum { ACTION_MOVE_MONITOR_DEC, ACTION_FOCUS_MONITOR_INC, ACTION_FOCUS_MONITOR_DEC, + ACTION_FULLSCREEN_TOGGLE, ACTIONS }; diff --git a/config.h b/config.h index dad907b..c49b036 100644 --- a/config.h +++ b/config.h @@ -63,6 +63,9 @@ binding keys[] = { // Gracefully close the current window. { .mod = Mod4Mask, .key = XK_Escape, .act = ACTION_CLOSE }, + // Toggle current window full screen. + { .mod = Mod4Mask, .key = XK_f, .act = ACTION_FULLSCREEN_TOGGLE }, + // Switch focus between monitors. { .mod = Mod4Mask, .key = XK_Right, .act = ACTION_FOCUS_MONITOR_INC }, { .mod = Mod4Mask, .key = XK_Left, .act = ACTION_FOCUS_MONITOR_DEC }, diff --git a/proto.h b/proto.h index 50e1b24..c78f18e 100644 --- a/proto.h +++ b/proto.h @@ -10,6 +10,10 @@ void window_set_cardinal_prop(Window w, Atom prop, unsigned long *values, int co void ewmh_client_list(); void ewmh_active_window(Window w); client* window_client(Window win); +int client_state(client *c, Atom state); +int client_add_state(client *c, Atom state); +int client_drop_state(client *c, Atom state); +void client_toggle_state(client *c, Atom state); void windows_visible(stack *s); int window_message(Window target, Window subject, Atom atom, unsigned long protocol, unsigned long mask); void client_free(client *c);