support fullscreen toggle
This commit is contained in:
@@ -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.
|
||||
|
||||
67
cerberus.c
67
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)
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
3
config.h
3
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 },
|
||||
|
||||
4
proto.h
4
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);
|
||||
|
||||
Reference in New Issue
Block a user