Compares the window instance (the first part of WM_CLASS)
window_role::
Compares the window role (WM_WINDOW_ROLE).
+window_type::
+ Compare the window type (_NET_WM_WINDOW_TYPE). Possible values are
+ +normal+, +dialog+, +utility+, +toolbar+, +splash+, +menu+, +dropdown_menu+,
+ +popup_menu+ and +toolti+.
id::
Compares the X11 window ID, which you can get via +xwininfo+ for example.
title::
xmacro(_NET_WM_STATE_MODAL)
xmacro(_NET_WM_STATE)
xmacro(_NET_WM_WINDOW_TYPE)
+xmacro(_NET_WM_WINDOW_TYPE_NORMAL)
xmacro(_NET_WM_WINDOW_TYPE_DOCK)
xmacro(_NET_WM_WINDOW_TYPE_DIALOG)
xmacro(_NET_WM_WINDOW_TYPE_UTILITY)
xmacro(_NET_WM_WINDOW_TYPE_TOOLBAR)
xmacro(_NET_WM_WINDOW_TYPE_SPLASH)
+xmacro(_NET_WM_WINDOW_TYPE_MENU)
+xmacro(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU)
+xmacro(_NET_WM_WINDOW_TYPE_POPUP_MENU)
+xmacro(_NET_WM_WINDOW_TYPE_TOOLTIP)
xmacro(_NET_WM_DESKTOP)
xmacro(_NET_WM_STRUT_PARTIAL)
xmacro(_NET_CLIENT_LIST)
* default will be 'accepts focus'. */
bool doesnt_accept_focus;
+ /** The _NET_WM_WINDOW_TYPE for this window. */
+ xcb_atom_t window_type;
+
/** Whether the window says it is a dock window */
enum { W_NODOCK = 0,
W_DOCK_TOP = 1,
struct regex *instance;
struct regex *mark;
struct regex *window_role;
+ xcb_atom_t window_type;
enum {
U_DONTCHECK = -1,
U_LATEST = 0,
*/
void xcb_set_window_rect(xcb_connection_t *conn, xcb_window_t window, Rect r);
+/**
+ * Returns the first supported _NET_WM_WINDOW_TYPE atom.
+ *
+ */
+xcb_atom_t xcb_get_preferred_window_type(xcb_get_property_reply_t *reply);
+
+/**
+ * Returns true if the given reply contains the given data.
+ *
+ */
bool xcb_reply_contains_atom(xcb_get_property_reply_t *prop, xcb_atom_t atom);
/**
ctype = 'con_mark' -> CRITERION
ctype = 'title' -> CRITERION
ctype = 'urgent' -> CRITERION
+ ctype = 'window_type' -> CRITERION
']' -> call cmd_criteria_match_windows(); INITIAL
state CRITERION:
ctype = 'window_role' -> CRITERION
ctype = 'con_id' -> CRITERION
ctype = 'id' -> CRITERION
+ ctype = 'window_type' -> CRITERION
ctype = 'con_mark' -> CRITERION
ctype = 'title' -> CRITERION
ctype = 'urgent' -> CRITERION
return;
}
+ if (strcmp(ctype, "window_type") == 0) {
+ if (strcasecmp(cvalue, "normal") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_NORMAL;
+ else if (strcasecmp(cvalue, "dialog") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_DIALOG;
+ else if (strcasecmp(cvalue, "utility") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_UTILITY;
+ else if (strcasecmp(cvalue, "toolbar") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLBAR;
+ else if (strcasecmp(cvalue, "splash") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_SPLASH;
+ else if (strcasecmp(cvalue, "menu") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_MENU;
+ else if (strcasecmp(cvalue, "dropdown_menu") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
+ else if (strcasecmp(cvalue, "popup_menu") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_POPUP_MENU;
+ else if (strcasecmp(cvalue, "tooltip") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLTIP;
+ else
+ ELOG("unknown window_type value \"%s\"\n", cvalue);
+
+ return;
+ }
+
if (strcmp(ctype, "con_mark") == 0) {
current_match->mark = regex_new(cvalue);
return;
return;
}
+ if (strcmp(ctype, "window_type") == 0) {
+ if (strcasecmp(cvalue, "normal") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_NORMAL;
+ else if (strcasecmp(cvalue, "dialog") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_DIALOG;
+ else if (strcasecmp(cvalue, "utility") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_UTILITY;
+ else if (strcasecmp(cvalue, "toolbar") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLBAR;
+ else if (strcasecmp(cvalue, "splash") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_SPLASH;
+ else if (strcasecmp(cvalue, "menu") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_MENU;
+ else if (strcasecmp(cvalue, "dropdown_menu") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
+ else if (strcasecmp(cvalue, "popup_menu") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_POPUP_MENU;
+ else if (strcasecmp(cvalue, "tooltip") == 0)
+ current_match->window_type = A__NET_WM_WINDOW_TYPE_TOOLTIP;
+ else
+ ELOG("unknown window_type value \"%s\"\n", cvalue);
+
+ return;
+ }
+
if (strcmp(ctype, "con_mark") == 0) {
current_match->mark = regex_new(cvalue);
return;
/* I’m not entirely sure if we need to keep _NET_WM_NAME on root. */
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3");
- /* only send the first 24 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */
- xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 24, supported_atoms);
+ /* only send the first 29 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 29, supported_atoms);
}
root_screen = xcb_aux_get_screen(conn, conn_screen);
root = root_screen->root;
+/* Place requests for the atoms we need as soon as possible */
+#define xmacro(atom) \
+ xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
+#include "atoms.xmacro"
+#undef xmacro
+
/* By default, we use the same depth and visual as the root window, which
* usually is TrueColor (24 bit depth) and the corresponding visual.
* However, we also check if a 32 bit depth and visual are available (for
xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(conn, root);
xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(conn, root);
+/* Setup NetWM atoms */
+#define xmacro(name) \
+ do { \
+ xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name##_cookie, NULL); \
+ if (!reply) { \
+ ELOG("Could not get atom " #name "\n"); \
+ exit(-1); \
+ } \
+ A_##name = reply->atom; \
+ free(reply); \
+ } while (0);
+#include "atoms.xmacro"
+#undef xmacro
+
load_configuration(conn, override_configpath, false);
if (config.ipc_socket_path == NULL) {
}
DLOG("root geometry reply: (%d, %d) %d x %d\n", greply->x, greply->y, greply->width, greply->height);
-/* Place requests for the atoms we need as soon as possible */
-#define xmacro(atom) \
- xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
-#include "atoms.xmacro"
-#undef xmacro
-
xcursor_load_cursors();
/* Set a cursor for the root window (otherwise the root window will show no
restore_connect();
-/* Setup NetWM atoms */
-#define xmacro(name) \
- do { \
- xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name##_cookie, NULL); \
- if (!reply) { \
- ELOG("Could not get atom " #name "\n"); \
- exit(-1); \
- } \
- A_##name = reply->atom; \
- free(reply); \
- } while (0);
-#include "atoms.xmacro"
-#undef xmacro
-
property_handlers_init();
ewmh_setup_hints();
/* check if the window needs WM_TAKE_FOCUS */
cwindow->needs_take_focus = window_supports_protocol(cwindow->id, A_WM_TAKE_FOCUS);
+ /* read the preferred _NET_WM_WINDOW_TYPE atom */
+ cwindow->window_type = xcb_get_preferred_window_type(type_reply);
+
/* Where to start searching for a container that swallows the new one? */
Con *search_at = croot;
*/
void match_init(Match *match) {
memset(match, 0, sizeof(Match));
- match->dock = -1;
+ match->dock = M_DONTCHECK;
match->urgent = U_DONTCHECK;
+ /* we use this as the placeholder value for "not set". */
+ match->window_type = UINT32_MAX;
}
/*
match->window_role == NULL &&
match->urgent == U_DONTCHECK &&
match->id == XCB_NONE &&
+ match->window_type == UINT32_MAX &&
match->con_id == NULL &&
match->dock == -1 &&
match->floating == M_ANY);
}
}
+ if (match->window_type != UINT32_MAX) {
+ if (window->window_type == match->window_type) {
+ LOG("window_type matches (%i)\n", match->window_type);
+ } else {
+ return false;
+ }
+ }
+
Con *con = NULL;
if (match->urgent == U_LATEST) {
/* if the window isn't urgent, no sense in searching */
LOG("urgent matches oldest\n");
}
- if (match->dock != -1) {
+ if (match->dock != M_DONTCHECK) {
if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
(window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
add_ignore_event(cookie.sequence, -1);
}
+/*
+ * Returns the first supported _NET_WM_WINDOW_TYPE atom.
+ *
+ */
+xcb_atom_t xcb_get_preferred_window_type(xcb_get_property_reply_t *reply) {
+ if (reply == NULL || xcb_get_property_value_length(reply) == 0)
+ return XCB_NONE;
+
+ xcb_atom_t *atoms;
+ if ((atoms = xcb_get_property_value(reply)) == NULL)
+ return XCB_NONE;
+
+ for (int i = 0; i < xcb_get_property_value_length(reply) / (reply->format / 8); i++) {
+ if (atoms[i] == A__NET_WM_WINDOW_TYPE_NORMAL ||
+ atoms[i] == A__NET_WM_WINDOW_TYPE_DIALOG ||
+ atoms[i] == A__NET_WM_WINDOW_TYPE_UTILITY ||
+ atoms[i] == A__NET_WM_WINDOW_TYPE_TOOLBAR ||
+ atoms[i] == A__NET_WM_WINDOW_TYPE_SPLASH ||
+ atoms[i] == A__NET_WM_WINDOW_TYPE_MENU ||
+ atoms[i] == A__NET_WM_WINDOW_TYPE_DROPDOWN_MENU ||
+ atoms[i] == A__NET_WM_WINDOW_TYPE_POPUP_MENU ||
+ atoms[i] == A__NET_WM_WINDOW_TYPE_TOOLTIP) {
+ return atoms[i];
+ }
+ }
+
+ return XCB_NONE;
+}
+
/*
* Returns true if the given reply contains the given atom.
*