Skip to content

Commit

Permalink
Implement ICCCM's WM_TAKE_FOCUS behavior
Browse files Browse the repository at this point in the history
Additionally, the `apply_shadow_property` was renamed to
`apply_floating_atom`.
  • Loading branch information
baskerville committed Sep 5, 2013
1 parent 824ee42 commit 387ece3
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 50 deletions.
2 changes: 1 addition & 1 deletion bash_completion
@@ -1,7 +1,7 @@
_bspc() {
local commands='window desktop monitor query pointer rule restore control config quit'

local settings='focused_border_color active_border_color normal_border_color presel_border_color focused_locked_border_color active_locked_border_color normal_locked_border_color urgent_border_color border_width window_gap split_ratio borderless_monocle gapless_monocle focus_follows_pointer pointer_follows_monitor adaptative_raise apply_shadow_property auto_alternate auto_cancel history_aware_focus'
local settings='focused_border_color active_border_color normal_border_color presel_border_color focused_locked_border_color active_locked_border_color normal_locked_border_color urgent_border_color border_width window_gap split_ratio borderless_monocle gapless_monocle focus_follows_pointer pointer_follows_monitor adaptative_raise apply_floating_atom auto_alternate auto_cancel history_aware_focus'

COMPREPLY=()

Expand Down
12 changes: 6 additions & 6 deletions bspwm.c
Expand Up @@ -216,12 +216,12 @@ void setup(void)
xcb_ewmh_set_supported(ewmh, default_screen, LENGTH(net_atoms), net_atoms);
ewmh_set_supporting(motion_recorder);

xcb_intern_atom_reply_t *iar = xcb_intern_atom_reply(dpy, xcb_intern_atom(dpy, 0, strlen("_COMPTON_SHADOW"), "_COMPTON_SHADOW"), NULL);

if (iar != NULL) {
compton_shadow = iar->atom;
free(iar);
}
#define GETATOM(a) \
get_atom(#a, &a);
GETATOM(WM_DELETE_WINDOW)
GETATOM(WM_TAKE_FOCUS)
GETATOM(_BSPWM_FLOATING_WINDOW)
#undef GETATOM

const xcb_query_extension_reply_t *qep = xcb_get_extension_data(dpy, &xcb_randr_id);
if (qep->present && import_monitors()) {
Expand Down
5 changes: 3 additions & 2 deletions bspwm.h
Expand Up @@ -31,8 +31,9 @@ rule_t *rule_tail;

pointer_state_t *frozen_pointer;
xcb_window_t motion_recorder;
xcb_atom_t compton_shadow;

xcb_atom_t WM_TAKE_FOCUS;
xcb_atom_t WM_DELETE_WINDOW;
xcb_atom_t _BSPWM_FLOATING_WINDOW;
int exit_status;

bool visible;
Expand Down
18 changes: 9 additions & 9 deletions doc/bspwm.1
Expand Up @@ -898,6 +898,11 @@ Value of the gap that separates windows\&.
Default split ratio\&.
.RE
.PP
\fIhistory_aware_focus\fR
.RS 4
Give priority to the focus history when focusing nodes\&.
.RE
.PP
\fIborderless_monocle\fR
.RS 4
Remove borders for tiled windows in monocle mode\&.
Expand All @@ -923,13 +928,6 @@ When focusing a monitor, put the pointer at its center\&.
Prevent floating windows from being raised when they might cover other floating windows\&.
.RE
.PP
\fIapply_shadow_property\fR
.RS 4
Enable shadows for floating windows via the
\fI_COMPTON_SHADOW\fR
property\&.
.RE
.PP
\fIauto_alternate\fR
.RS 4
Interpret two consecutive identical
Expand All @@ -948,9 +946,11 @@ messages as a
message\&.
.RE
.PP
\fIhistory_aware_focus\fR
\fIapply_floating_atom\fR
.RS 4
Give priority to the focus history when focusing nodes\&.
Set the value of the
\fI_BSPWM_FLOATING_WINDOW\fR
atom of each window according to its floating state\&.
.RE
.SH "ENVIRONMENT VARIABLES"
.PP
Expand Down
11 changes: 6 additions & 5 deletions doc/bspwm.1.txt
Expand Up @@ -550,6 +550,9 @@ All the boolean settings are 'false' by default.
'split_ratio'::
Default split ratio.

'history_aware_focus'::
Give priority to the focus history when focusing nodes.

'borderless_monocle'::
Remove borders for tiled windows in monocle mode.

Expand All @@ -565,17 +568,15 @@ All the boolean settings are 'false' by default.
'adaptative_raise'::
Prevent floating windows from being raised when they might cover other floating windows.

'apply_shadow_property'::
Enable shadows for floating windows via the '_COMPTON_SHADOW' property.

'auto_alternate'::
Interpret two consecutive identical *use* messages as an *alternate* message.

'auto_cancel'::
Interpret two consecutive identical *presel* messages as a *cancel* message.

'history_aware_focus'::
Give priority to the focus history when focusing nodes.
'apply_floating_atom'::
Set the value of the '_BSPWM_FLOATING_WINDOW' atom of each window according to its floating state.


Environment Variables
---------------------
Expand Down
4 changes: 2 additions & 2 deletions messages.c
Expand Up @@ -729,7 +729,7 @@ bool set_setting(char *name, char *value)
SETBOOL(gapless_monocle)
SETBOOL(pointer_follows_monitor)
SETBOOL(adaptative_raise)
SETBOOL(apply_shadow_property)
SETBOOL(apply_floating_atom)
SETBOOL(auto_alternate)
SETBOOL(auto_cancel)
SETBOOL(history_aware_focus)
Expand Down Expand Up @@ -773,7 +773,7 @@ bool get_setting(char *name, char* rsp)
GETBOOL(focus_follows_pointer)
GETBOOL(pointer_follows_monitor)
GETBOOL(adaptative_raise)
GETBOOL(apply_shadow_property)
GETBOOL(apply_floating_atom)
GETBOOL(auto_alternate)
GETBOOL(auto_cancel)
GETBOOL(history_aware_focus)
Expand Down
2 changes: 1 addition & 1 deletion settings.c
Expand Up @@ -46,7 +46,7 @@ void load_settings(void)
focus_follows_pointer = FOCUS_FOLLOWS_POINTER;
pointer_follows_monitor = POINTER_FOLLOWS_MONITOR;
adaptative_raise = ADAPTATIVE_RAISE;
apply_shadow_property = APPLY_SHADOW_PROPERTY;
apply_floating_atom = APPLY_FLOATING_ATOM;
auto_alternate = AUTO_ALTERNATE;
auto_cancel = AUTO_CANCEL;
history_aware_focus = HISTORY_AWARE_FOCUS;
Expand Down
8 changes: 4 additions & 4 deletions settings.h
Expand Up @@ -20,15 +20,15 @@
#define WINDOW_GAP 6
#define SPLIT_RATIO 0.5

#define HISTORY_AWARE_FOCUS false
#define BORDERLESS_MONOCLE false
#define GAPLESS_MONOCLE false
#define FOCUS_FOLLOWS_POINTER false
#define POINTER_FOLLOWS_MONITOR false
#define ADAPTATIVE_RAISE false
#define APPLY_SHADOW_PROPERTY false
#define AUTO_ALTERNATE false
#define AUTO_CANCEL false
#define HISTORY_AWARE_FOCUS false
#define ADAPTATIVE_RAISE false
#define APPLY_FLOATING_ATOM false

char focused_border_color[MAXLEN];
char active_border_color[MAXLEN];
Expand All @@ -48,7 +48,7 @@ bool gapless_monocle;
bool focus_follows_pointer;
bool pointer_follows_monitor;
bool adaptative_raise;
bool apply_shadow_property;
bool apply_floating_atom;
bool auto_alternate;
bool auto_cancel;
bool history_aware_focus;
Expand Down
7 changes: 7 additions & 0 deletions types.c
Expand Up @@ -219,6 +219,13 @@ client_t *make_client(xcb_window_t win)
c->border_width = border_width;
c->window = win;
c->floating = c->transient = c->fullscreen = c->locked = c->urgent = false;
c->icccm_focus = false;
xcb_icccm_get_wm_protocols_reply_t protocols;
if (xcb_icccm_get_wm_protocols_reply(dpy, xcb_icccm_get_wm_protocols(dpy, win, ewmh->WM_PROTOCOLS), &protocols, NULL) == 1) {
if (has_proto(WM_TAKE_FOCUS, &protocols))
c->icccm_focus = true;
xcb_icccm_get_wm_protocols_reply_wipe(&protocols);
}
return c;
}

Expand Down
5 changes: 3 additions & 2 deletions types.h
Expand Up @@ -139,10 +139,11 @@ typedef struct {
char class_name[MAXLEN];
unsigned int border_width;
bool floating;
bool transient; /* transient window are always floating */
bool transient; /* transient window are always floating */
bool fullscreen;
bool locked; /* protects window from being closed */
bool locked; /* protects window from being closed */
bool urgent;
bool icccm_focus; /* send an event to request input focus */
xcb_rectangle_t floating_rectangle;
xcb_rectangle_t tiled_rectangle;
} client_t;
Expand Down
71 changes: 57 additions & 14 deletions window.c
Expand Up @@ -107,7 +107,7 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
handle_rules(win, &m, &d, &floating, &follow, &transient, &fullscreen, &takes_focus, &manage);

if (!manage) {
disable_shadow(win);
disable_floating_atom(win);
window_show(win);
return;
}
Expand All @@ -129,7 +129,7 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)

insert_node(m, d, n, d->focus);

disable_shadow(c->window);
disable_floating_atom(c->window);

if (floating)
set_floating(d, n, true);
Expand Down Expand Up @@ -351,10 +351,10 @@ void set_floating(desktop_t *d, node_t *n, bool value)
c->floating = n->vacant = value;
update_vacant_state(n->parent);
if (value) {
enable_shadow(c->window);
enable_floating_atom(c->window);
unrotate_brother(n);
} else {
disable_shadow(c->window);
disable_floating_atom(c->window);
rotate_brother(n);
}
stack(d, n);
Expand Down Expand Up @@ -382,21 +382,21 @@ void set_urgency(monitor_t *m, desktop_t *d, node_t *n, bool value)
put_status();
}

void set_shadow(xcb_window_t win, uint32_t value)
void set_floating_atom(xcb_window_t win, uint32_t value)
{
if (!apply_shadow_property)
if (!apply_floating_atom)
return;
xcb_change_property(dpy, XCB_PROP_MODE_REPLACE, win, compton_shadow, XCB_ATOM_CARDINAL, 32, 1, &value);
set_atom(win, _BSPWM_FLOATING_WINDOW, value);
}

void enable_shadow(xcb_window_t win)
void enable_floating_atom(xcb_window_t win)
{
set_shadow(win, 1);
set_floating_atom(win, 1);
}

void disable_shadow(xcb_window_t win)
void disable_floating_atom(xcb_window_t win)
{
set_shadow(win, 0);
set_floating_atom(win, 0);
}

uint32_t get_border_color(client_t *c, bool focused_window, bool focused_monitor)
Expand Down Expand Up @@ -600,10 +600,14 @@ void update_input_focus(void)

void set_input_focus(node_t *n)
{
if (n == NULL)
if (n == NULL) {
clear_input_focus();
else
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, n->client->window, XCB_CURRENT_TIME);
} else {
if (n->client->icccm_focus)
icccm_focus(n->client->window);
else
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, n->client->window, XCB_CURRENT_TIME);
}
}

void clear_input_focus(void)
Expand All @@ -619,3 +623,42 @@ void center_pointer(monitor_t *m)
xcb_warp_pointer(dpy, XCB_NONE, root, 0, 0, 0, 0, cx, cy);
window_raise(motion_recorder);
}

void get_atom(char *name, xcb_atom_t *atom)
{
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(dpy, xcb_intern_atom(dpy, 0, strlen(name), name), NULL);
if (reply != NULL)
*atom = reply->atom;
else
*atom = XCB_NONE;
free(reply);
}

void set_atom(xcb_window_t win, xcb_atom_t atom, uint32_t value)
{
xcb_change_property(dpy, XCB_PROP_MODE_REPLACE, win, atom, XCB_ATOM_CARDINAL, 32, 1, &value);
}

bool has_proto(xcb_atom_t atom, xcb_icccm_get_wm_protocols_reply_t *protocols)
{
for (uint32_t i = 0; i < protocols->atoms_len; i++)
if (protocols->atoms[i] == atom)
return true;
return false;
}

void icccm_focus(xcb_window_t win)
{
PRINTF("focus via ICCCM %X\n", win);
xcb_client_message_event_t e;

e.response_type = XCB_CLIENT_MESSAGE;
e.window = win;
e.format = 32;
e.sequence = 0;
e.type = ewmh->WM_PROTOCOLS;
e.data.data32[0] = WM_TAKE_FOCUS;
e.data.data32[1] = XCB_CURRENT_TIME;

xcb_send_event(dpy, false, win, XCB_EVENT_MASK_NO_EVENT, (char *) &e);
}
11 changes: 8 additions & 3 deletions window.h
Expand Up @@ -3,6 +3,7 @@

#include <stdarg.h>
#include <xcb/xcb.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xcb_event.h>
#include "types.h"

Expand All @@ -26,9 +27,9 @@ void set_fullscreen(desktop_t *, node_t *, bool);
void set_floating(desktop_t *, node_t *, bool);
void set_locked(monitor_t *, desktop_t *, node_t *, bool);
void set_urgency(monitor_t *, desktop_t *, node_t *, bool);
void set_shadow(xcb_window_t, uint32_t);
void enable_shadow(xcb_window_t);
void disable_shadow(xcb_window_t);
void set_floating_atom(xcb_window_t, uint32_t);
void enable_floating_atom(xcb_window_t);
void disable_floating_atom(xcb_window_t);
void window_border_width(xcb_window_t, uint32_t);
void window_move(xcb_window_t, int16_t, int16_t);
void window_resize(xcb_window_t, uint16_t, uint16_t);
Expand All @@ -51,5 +52,9 @@ void update_input_focus(void);
void set_input_focus(node_t *);
void clear_input_focus(void);
void center_pointer(monitor_t *);
void get_atom(char *, xcb_atom_t *);
void set_atom(xcb_window_t, xcb_atom_t, uint32_t);
bool has_proto(xcb_atom_t, xcb_icccm_get_wm_protocols_reply_t *);
void icccm_focus(xcb_window_t);

#endif
2 changes: 1 addition & 1 deletion zsh_completion
Expand Up @@ -3,7 +3,7 @@
_bspc() {
local -a commands settings
commands=('window' 'desktop' 'monitor' 'query' 'pointer' 'rule' 'restore' 'control' 'config' 'quit')
settings=('focused_border_color' 'active_border_color' 'normal_border_color' 'presel_border_color' 'focused_locked_border_color' 'active_locked_border_color' 'normal_locked_border_color' 'urgent_border_color' 'border_width' 'window_gap' 'split_ratio' 'borderless_monocle' 'gapless_monocle' 'focus_follows_pointer' 'pointer_follows_monitor' 'adaptative_raise' 'apply_shadow_property' 'auto_alternate' 'auto_cancel' 'history_aware_focus')
settings=('focused_border_color' 'active_border_color' 'normal_border_color' 'presel_border_color' 'focused_locked_border_color' 'active_locked_border_color' 'normal_locked_border_color' 'urgent_border_color' 'border_width' 'window_gap' 'split_ratio' 'borderless_monocle' 'gapless_monocle' 'focus_follows_pointer' 'pointer_follows_monitor' 'adaptative_raise' 'apply_floating_atom' 'auto_alternate' 'auto_cancel' 'history_aware_focus')
if (( CURRENT == 2 )) ; then
_values 'command' "$commands[@]"
elif (( CURRENT == 3 )) ; then
Expand Down

0 comments on commit 387ece3

Please sign in to comment.