Skip to content

Commit

Permalink
Merge pull request #1282 from yshui/ewmh-transient-for
Browse files Browse the repository at this point in the history
wm/win: implement EWMH WM_TRANSIENT_FOR extension
  • Loading branch information
yshui authored Jun 27, 2024
2 parents 5b5174b + df194f2 commit 69dd18d
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 8 deletions.
4 changes: 3 additions & 1 deletion src/inspect.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ setup_window(struct x_connection *c, struct atom *atoms, struct options *options

// Determine if the window is focused
xcb_window_t wid = XCB_NONE;
bool exists;
if (options->use_ewmh_active_win) {
wid_get_prop_window(c, c->screen_info->root, atoms->a_NET_ACTIVE_WINDOW);
wid_get_prop_window(c, c->screen_info->root, atoms->a_NET_ACTIVE_WINDOW,
&exists);
} else {
// Determine the currently focused window so we can apply appropriate
// opacity on it
Expand Down
4 changes: 3 additions & 1 deletion src/picom.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,10 @@ void add_damage(session_t *ps, const region_t *damage) {
*/
void update_ewmh_active_win(session_t *ps) {
// Search for the window
bool exists;
xcb_window_t wid = wid_get_prop_window(&ps->c, ps->c.screen_info->root,
ps->atoms->a_NET_ACTIVE_WINDOW);
ps->atoms->a_NET_ACTIVE_WINDOW, &exists);

auto cursor = wm_find_by_client(ps->wm, wid);
auto w = cursor ? wm_ref_deref(cursor) : NULL;

Expand Down
35 changes: 31 additions & 4 deletions src/wm/win.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,8 @@ static void win_update_properties(session_t *ps, struct win *w) {
}

if (win_fetch_and_unset_property_stale(w, ps->atoms->aWM_CLIENT_LEADER) ||
win_fetch_and_unset_property_stale(w, ps->atoms->aWM_TRANSIENT_FOR)) {
win_fetch_and_unset_property_stale(w, ps->atoms->aWM_TRANSIENT_FOR) ||
win_fetch_and_unset_property_stale(w, XCB_ATOM_WM_HINTS)) {
auto client_win = win_client_id(w, /*fallback_to_self=*/true);
auto new_leader = win_get_leader_property(&ps->c, ps->atoms, client_win,
ps->o.detect_transient,
Expand Down Expand Up @@ -1532,17 +1533,37 @@ static xcb_window_t
win_get_leader_property(struct x_connection *c, struct atom *atoms, xcb_window_t wid,
bool detect_transient, bool detect_client_leader) {
xcb_window_t leader = XCB_NONE;
bool exists = false;

// Read the leader properties
if (detect_transient) {
leader = wid_get_prop_window(c, wid, atoms->aWM_TRANSIENT_FOR);
leader = wid_get_prop_window(c, wid, atoms->aWM_TRANSIENT_FOR, &exists);
log_debug("Leader via WM_TRANSIENT_FOR of window %#010x: %#010x", wid, leader);
if (exists && (leader == c->screen_info->root || leader == XCB_NONE)) {
// If WM_TRANSIENT_FOR is set to NONE or the root window, use the
// window group leader.
//
// Ref:
// https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#idm44981516332096
auto prop = x_get_prop(c, wid, XCB_ATOM_WM_HINTS, INT_MAX,
XCB_ATOM_WM_HINTS, 32);
if (prop.nitems >= 9) { // 9-th member is window_group
leader = prop.c32[8];
log_debug("Leader via WM_HINTS of window %#010x: %#010x",
wid, leader);
} else {
leader = XCB_NONE;
}
free_winprop(&prop);
}
}

if (detect_client_leader && leader == XCB_NONE) {
leader = wid_get_prop_window(c, wid, atoms->aWM_CLIENT_LEADER);
leader = wid_get_prop_window(c, wid, atoms->aWM_CLIENT_LEADER, &exists);
log_debug("Leader via WM_CLIENT_LEADER of window %#010x: %#010x", wid, leader);
}

log_trace("window %#010x: leader %#010x", wid, leader);
log_debug("window %#010x: leader %#010x", wid, leader);
return leader;
}

Expand All @@ -1556,6 +1577,12 @@ static struct wm_ref *win_get_leader_raw(session_t *ps, struct win *w, int recur
// Leader defaults to client window, or to the window itself if
// it doesn't have a client window
w->cache_leader = wm_find(ps->wm, w->leader);
if (w->cache_leader == wm_root_ref(ps->wm)) {
log_warn("Window manager set the leader of window %#010x to "
"root, a broken window manager.",
win_id(w));
w->cache_leader = NULL;
}
if (!w->cache_leader) {
w->cache_leader = client_win ?: w->tree_ref;
}
Expand Down
6 changes: 5 additions & 1 deletion src/x.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,14 +284,18 @@ winprop_info_t x_get_prop_info(const struct x_connection *c, xcb_window_t w, xcb
*
* @return the value if successful, 0 otherwise
*/
xcb_window_t wid_get_prop_window(struct x_connection *c, xcb_window_t wid, xcb_atom_t aprop) {
xcb_window_t wid_get_prop_window(struct x_connection *c, xcb_window_t wid,
xcb_atom_t aprop, bool *exists) {
// Get the attribute
xcb_window_t p = XCB_NONE;
winprop_t prop = x_get_prop(c, wid, aprop, 1L, XCB_ATOM_WINDOW, 32);

// Return it
if (prop.nitems) {
*exists = true;
p = (xcb_window_t)*prop.p32;
} else {
*exists = false;
}

free_winprop(&prop);
Expand Down
3 changes: 2 additions & 1 deletion src/x.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ static inline void x_discard_events(struct x_connection *c) {
*
* @return the value if successful, 0 otherwise
*/
xcb_window_t wid_get_prop_window(struct x_connection *c, xcb_window_t wid, xcb_atom_t aprop);
xcb_window_t wid_get_prop_window(struct x_connection *c, xcb_window_t wid,
xcb_atom_t aprop, bool *exists);

/**
* Get the value of a text property of a window.
Expand Down

0 comments on commit 69dd18d

Please sign in to comment.