Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache _NET_WM_STATE property and add rule target wm_state #549

Open
wants to merge 3 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions src/atom.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

#include <xcb/xcb.h>

#include "meta.h"
#include "cache.h"
#include "meta.h"

// clang-format off
// Splitted into 2 lists because of the limitation of our macros
Expand All @@ -23,9 +23,7 @@
WM_CLIENT_MACHINE, \
_NET_ACTIVE_WINDOW, \
_COMPTON_SHADOW, \
_NET_WM_WINDOW_TYPE

#define ATOM_LIST2 \
_NET_WM_WINDOW_TYPE, \
_NET_WM_WINDOW_TYPE_DESKTOP, \
_NET_WM_WINDOW_TYPE_DOCK, \
_NET_WM_WINDOW_TYPE_TOOLBAR, \
Expand All @@ -39,9 +37,23 @@
_NET_WM_WINDOW_TYPE_TOOLTIP, \
_NET_WM_WINDOW_TYPE_NOTIFICATION, \
_NET_WM_WINDOW_TYPE_COMBO, \
_NET_WM_WINDOW_TYPE_DND, \
_NET_WM_WINDOW_TYPE_DND

#define ATOM_LIST2 \
_NET_WM_STATE, \
_NET_WM_STATE_MODAL, \
_NET_WM_STATE_STICKY, \
_NET_WM_STATE_MAXIMIZED_VERT, \
_NET_WM_STATE_MAXIMIZED_HORZ, \
_NET_WM_STATE_SHADED, \
_NET_WM_STATE_SKIP_TASKBAR, \
_NET_WM_STATE_SKIP_PAGER, \
_NET_WM_STATE_HIDDEN, \
_NET_WM_STATE_FULLSCREEN, \
_NET_WM_STATE_ABOVE, \
_NET_WM_STATE_BELOW, \
_NET_WM_STATE_DEMANDS_ATTENTION, \
_NET_WM_STATE_FOCUSED, \
_NET_WM_BYPASS_COMPOSITOR, \
UTF8_STRING, \
C_STRING
Expand Down
12 changes: 7 additions & 5 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@
#include <X11/Xlib.h>
#include <ev.h>
#include <pixman.h>
#include <xcb/xproto.h>
#include <xcb/render.h>
#include <xcb/sync.h>
#include <xcb/xproto.h>

#include "uthash_extra.h"
#ifdef CONFIG_OPENGL
Expand All @@ -55,11 +55,11 @@
#include "backend/driver.h"
#include "compiler.h"
#include "config.h"
#include "list.h"
#include "region.h"
#include "render.h"
#include "types.h"
#include "utils.h"
#include "list.h"
#include "render.h"
#include "win_defs.h"
#include "x.h"

Expand Down Expand Up @@ -254,11 +254,11 @@ typedef struct session {
// Cached blur convolution kernels.
struct x_convolution_kernel **blur_kerns_cache;
/// If we should quit
bool quit:1;
bool quit : 1;
// TODO(yshui) use separate flags for dfferent kinds of updates so we don't
// waste our time.
/// Whether there are pending updates, like window creation, etc.
bool pending_updates:1;
bool pending_updates : 1;

// === Expose event related ===
/// Pointer to an array of <code>XRectangle</code>-s of exposed region.
Expand Down Expand Up @@ -369,6 +369,8 @@ typedef struct session {
struct atom *atoms;
/// Array of atoms of all possible window types.
xcb_atom_t atoms_wintypes[NUM_WINTYPES];
/// Array of atoms of all possible window wm_states.
xcb_atom_t atoms_wmstates[NUM_WMSTATES];
/// Linked list of additional atoms to track.
latom_t *track_atom_lst;

Expand Down
8 changes: 8 additions & 0 deletions src/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,14 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
}
}

// If _NET_WM_STATE changes
if (ev->atom == ps->atoms->a_NET_WM_STATE) {
struct managed_win *w = NULL;
if ((w = find_toplevel(ps, ev->window))) {
win_set_property_stale(w, ev->atom);
}
}

if (ev->atom == ps->atoms->a_NET_WM_BYPASS_COMPOSITOR) {
// Unnecessay until we remove the queue_redraw in ev_handle
queue_redraw(ps);
Expand Down
18 changes: 18 additions & 0 deletions src/picom.c
Original file line number Diff line number Diff line change
Expand Up @@ -1687,6 +1687,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
.xrfilter_convolution_exists = false,

.atoms_wintypes = {0},
.atoms_wmstates = {0},
.track_atom_lst = NULL,

#ifdef CONFIG_DBUS
Expand Down Expand Up @@ -1877,6 +1878,23 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
SET_WM_TYPE_ATOM(COMBO);
SET_WM_TYPE_ATOM(DND);
#undef SET_WM_TYPE_ATOM
ps->atoms_wmstates[WMSTATE_UNKNOWN] = 0;
#define SET_WM_STATE_ATOM(x) \
ps->atoms_wmstates[WMSTATE_##x] = ps->atoms->a_NET_WM_STATE_##x
SET_WM_STATE_ATOM(MODAL);
SET_WM_STATE_ATOM(STICKY);
SET_WM_STATE_ATOM(MAXIMIZED_VERT);
SET_WM_STATE_ATOM(MAXIMIZED_HORZ);
SET_WM_STATE_ATOM(SHADED);
SET_WM_STATE_ATOM(SKIP_TASKBAR);
SET_WM_STATE_ATOM(SKIP_PAGER);
SET_WM_STATE_ATOM(HIDDEN);
SET_WM_STATE_ATOM(FULLSCREEN);
SET_WM_STATE_ATOM(ABOVE);
SET_WM_STATE_ATOM(BELOW);
SET_WM_STATE_ATOM(DEMANDS_ATTENTION);
SET_WM_STATE_ATOM(FOCUSED);
#undef SET_WM_STATE_ATOM

// Get needed atoms for c2 condition lists
if (!(c2_list_postprocess(ps, ps->o.unredir_if_possible_blacklist) &&
Expand Down
76 changes: 46 additions & 30 deletions src/win.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ static const double ROUNDED_PERCENT = 0.05;
static bool win_update_class(session_t *ps, struct managed_win *w);
static int win_update_role(session_t *ps, struct managed_win *w);
static void win_update_wintype(session_t *ps, struct managed_win *w);
static void win_update_wm_state(session_t *ps, struct managed_win *w);
static int win_update_name(session_t *ps, struct managed_win *w);
/**
* Reread opacity property of a window.
Expand Down Expand Up @@ -362,6 +363,10 @@ static void win_update_properties(session_t *ps, struct managed_win *w) {
win_update_wintype(ps, w);
}

if (win_fetch_and_unset_property_stale(w, ps->atoms->a_NET_WM_STATE)) {
win_update_wm_state(ps, w);
}

if (win_fetch_and_unset_property_stale(w, ps->atoms->a_NET_WM_WINDOW_OPACITY)) {
win_update_opacity_prop(ps, w);
// we cannot receive OPACITY change when window has been destroyed
Expand Down Expand Up @@ -643,6 +648,23 @@ static wintype_t wid_get_prop_wintype(session_t *ps, xcb_window_t wid) {
return WINTYPE_UNKNOWN;
}

static win_wmstate_t wid_get_prop_wm_state(session_t *ps, xcb_window_t wid) {
winprop_t prop =
x_get_prop(ps, wid, ps->atoms->a_NET_WM_STATE, 32L, XCB_ATOM_ATOM, 32);

win_wmstate_t wm_state = WMSTATE_UNKNOWN;
for (unsigned i = 0; i < prop.nitems; ++i) {
for (enum wm_state j = 1; j < NUM_WMSTATES; ++j) {
if (ps->atoms_wmstates[j] == (xcb_atom_t)prop.p32[i]) {
wm_state |= (1 << (j - 1));
}
}
}

free_winprop(&prop);
return wm_state;
}

static bool
wid_get_opacity_prop(session_t *ps, xcb_window_t wid, opacity_t def, opacity_t *out) {
bool ret = false;
Expand Down Expand Up @@ -1117,6 +1139,27 @@ void win_update_wintype(session_t *ps, struct managed_win *w) {
}
}

/**
* Update window wm_state.
*/
void win_update_wm_state(session_t *ps, struct managed_win *w) {
const win_wmstate_t wmstate_old = w->wm_state;

// Detect window wm_state here
w->wm_state = wid_get_prop_wm_state(ps, w->client_win);

if (w->wm_state != wmstate_old) {
win_on_factor_change(ps, w);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should set the FACTOR_CHANGE flag instead.

Copy link
Collaborator Author

@tryone144 tryone144 Nov 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, missed that one. Same would apply in win_update_wintype() above.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we're at it: I think win_update_opacity_target can be replaced as well.

}
}

bool win_check_wm_state(const struct managed_win *w, enum wm_state state) {
if (state == WMSTATE_UNKNOWN) {
return false;
}
return (w->wm_state & (1 << (state - 1))) != 0;
}

/**
* Mark a window as the client window of another.
*
Expand All @@ -1143,6 +1186,7 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client)
}

win_update_wintype(ps, w);
win_update_wm_state(ps, w);

// Get frame widths. The window is in damaged area already.
win_update_frame_extents(ps, w, client);
Expand Down Expand Up @@ -1388,6 +1432,7 @@ struct win *fill_win(session_t *ps, struct win *w) {
.leader = XCB_NONE,
.cache_leader = XCB_NONE,
.window_type = WINTYPE_UNKNOWN,
.wm_state = WMSTATE_UNKNOWN,
.wmwin = false,
.focused = false,
.opacity = 0,
Expand Down Expand Up @@ -2478,34 +2523,6 @@ static inline bool rect_is_fullscreen(const session_t *ps, int x, int y, int wid
return (x <= 0 && y <= 0 && (x + wid) >= ps->root_width && (y + hei) >= ps->root_height);
}

/**
* Check if a window is fulscreen using EWMH
*
* TODO(yshui) cache this property
*/
static inline bool
win_is_fullscreen_xcb(xcb_connection_t *c, const struct atom *a, const xcb_window_t w) {
xcb_get_property_cookie_t prop =
xcb_get_property(c, 0, w, a->a_NET_WM_STATE, XCB_ATOM_ATOM, 0, 12);
xcb_get_property_reply_t *reply = xcb_get_property_reply(c, prop, NULL);
if (!reply) {
return false;
}

if (reply->length) {
xcb_atom_t *val = xcb_get_property_value(reply);
for (uint32_t i = 0; i < reply->length; i++) {
if (val[i] != a->a_NET_WM_STATE_FULLSCREEN) {
continue;
}
free(reply);
return true;
}
}
free(reply);
return false;
}

/// Set flags on a window. Some sanity checks are performed
void win_set_flags(struct managed_win *w, uint64_t flags) {
log_debug("Set flags %" PRIu64 " to window %#010x (%s)", flags, w->base.id, w->name);
Expand Down Expand Up @@ -2591,8 +2608,7 @@ bool win_check_flags_all(struct managed_win *w, uint64_t flags) {
* It's not using w->border_size for performance measures.
*/
bool win_is_fullscreen(const session_t *ps, const struct managed_win *w) {
if (!ps->o.no_ewmh_fullscreen &&
win_is_fullscreen_xcb(ps->c, ps->atoms, w->client_win)) {
if (!ps->o.no_ewmh_fullscreen && win_check_wm_state(w, WMSTATE_FULLSCREEN)) {
tryone144 marked this conversation as resolved.
Show resolved Hide resolved
return true;
}
return rect_is_fullscreen(ps, w->g.x, w->g.y, w->widthb, w->heightb) &&
Expand Down
2 changes: 2 additions & 0 deletions src/win.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ struct managed_win {
xcb_window_t client_win;
/// Type of the window.
wintype_t window_type;
/// State of the window as described by the window manager in _NET_WM_STATE.
win_wmstate_t wm_state;
/// Whether it looks like a WM window. We consider a window WM window if
/// it does not have a decedent with WM_STATE and it is not override-
/// redirected itself.
Expand Down
24 changes: 21 additions & 3 deletions src/win_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <stdint.h>

typedef enum {
WINTYPE_UNKNOWN,
WINTYPE_UNKNOWN = 0,
WINTYPE_DESKTOP,
WINTYPE_DOCK,
WINTYPE_TOOLBAR,
Expand All @@ -20,6 +20,25 @@ typedef enum {
NUM_WINTYPES
} wintype_t;

enum wm_state {
WMSTATE_UNKNOWN = 0,
WMSTATE_MODAL,
WMSTATE_STICKY,
WMSTATE_MAXIMIZED_VERT,
WMSTATE_MAXIMIZED_HORZ,
WMSTATE_SHADED,
WMSTATE_SKIP_TASKBAR,
WMSTATE_SKIP_PAGER,
WMSTATE_HIDDEN,
WMSTATE_FULLSCREEN,
WMSTATE_ABOVE,
WMSTATE_BELOW,
WMSTATE_DEMANDS_ATTENTION,
WMSTATE_FOCUSED,
NUM_WMSTATES,
};
typedef uint64_t win_wmstate_t;

/// Enumeration type of window painting mode.
typedef enum {
WMODE_TRANS, // The window body is (potentially) transparent
Expand Down Expand Up @@ -96,7 +115,6 @@ enum win_flags {
WIN_FLAGS_FACTOR_CHANGED = 1024,
};

static const uint64_t WIN_FLAGS_IMAGES_STALE =
WIN_FLAGS_PIXMAP_STALE | WIN_FLAGS_SHADOW_STALE;
static const uint64_t WIN_FLAGS_IMAGES_STALE = WIN_FLAGS_PIXMAP_STALE | WIN_FLAGS_SHADOW_STALE;

#define WIN_FLAGS_IMAGES_NONE (WIN_FLAGS_PIXMAP_NONE | WIN_FLAGS_SHADOW_NONE)