]> git.sur5r.net Git - i3/i3/commitdiff
Implement new criterion 'window_type = normal|dialog|utility|toolbar|splash|menu...
authorIngo Bürk <ingo.buerk@tngtech.com>
Sat, 18 Apr 2015 19:09:03 +0000 (21:09 +0200)
committerIngo Bürk <ingo.buerk@tngtech.com>
Mon, 20 Apr 2015 17:27:39 +0000 (19:27 +0200)
fixes #1658

13 files changed:
docs/userguide
include/atoms.xmacro
include/data.h
include/xcb.h
parser-specs/commands.spec
parser-specs/config.spec
src/commands.c
src/config_directives.c
src/ewmh.c
src/main.c
src/manage.c
src/match.c
src/xcb.c

index 687dff10e5221c48ebfd3f3f1207eff76c4199c8..965f839ea3e0ce94482a493d0b49560877c686d8 100644 (file)
@@ -1508,6 +1508,10 @@ instance::
        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::
index 59dab6eddd1c1eeeff16b3b5b26d5992b137ad85..b9ee4eb7ec9b277f54c9c27dc3003489b1418c31 100644 (file)
@@ -7,11 +7,16 @@ xmacro(_NET_WM_STATE_DEMANDS_ATTENTION)
 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)
index 50e1f1807bfc4cf2b16459a3d154f0883024f27f..5fb9a07458e28a60d1e6ee1974d9b31a510653cd 100644 (file)
@@ -378,6 +378,9 @@ struct Window {
      * 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,
@@ -408,6 +411,7 @@ struct Match {
     struct regex *instance;
     struct regex *mark;
     struct regex *window_role;
+    xcb_atom_t window_type;
     enum {
         U_DONTCHECK = -1,
         U_LATEST = 0,
index 9f4ea91fd8f29733ff4549ad2d8fcaa9af386ece..69d5af2ce5eef440d7d3ec72e4063820b6a7eacd 100644 (file)
@@ -108,6 +108,16 @@ void xcb_raise_window(xcb_connection_t *conn, xcb_window_t window);
  */
 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);
 
 /**
index 87db6cf082cebfeb04e430cc5a31ba1fe19370e4..e6217b1981ddf11a8b2cae5e8df1d82f69f7b4e4 100644 (file)
@@ -49,6 +49,7 @@ state CRITERIA:
   ctype = 'con_mark' -> CRITERION
   ctype = 'title' -> CRITERION
   ctype = 'urgent' -> CRITERION
+  ctype = 'window_type' -> CRITERION
   ']' -> call cmd_criteria_match_windows(); INITIAL
 
 state CRITERION:
index d27e0792127a6f78b863995941994cf66523439b..c5c8ad2535db5dfe8689162c3d6334f5185e9642 100644 (file)
@@ -167,6 +167,7 @@ state CRITERIA:
   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
index 79071d6bb5f451dbae214fcb6fd2a53dbde7813f..6b72025139ad30d10dc3615028eed7bc61859b71 100644 (file)
@@ -363,6 +363,31 @@ void cmd_criteria_add(I3_CMD, char *ctype, char *cvalue) {
         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;
index 398e53bb7c8cb9c7186f2050ba80b6686708e76b..49e8d91d8faaeb98b8ae684b90f438ac39bed461 100644 (file)
@@ -89,6 +89,31 @@ CFGFUN(criteria_add, const char *ctype, const char *cvalue) {
         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;
index 844a0db921ada15d78cea84818ef82b282da19ac..883b929e8e31f2dea6de2291500658411f1b1371 100644 (file)
@@ -234,6 +234,6 @@ void ewmh_setup_hints(void) {
     /* 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);
 }
index ac40e7a389bc2eb41c303a2dd28637e4fea8007c..3c534431291cbc5e2b090ab332fe82aadbaaa9c0 100644 (file)
@@ -474,6 +474,12 @@ int main(int argc, char *argv[]) {
     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
@@ -491,6 +497,20 @@ int main(int argc, char *argv[]) {
     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) {
@@ -512,12 +532,6 @@ int main(int argc, char *argv[]) {
     }
     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
@@ -547,20 +561,6 @@ int main(int argc, char *argv[]) {
 
     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();
index 3499963b97647d4b6fa7796cd0978fc8feb5f3fa..bc9c9bff08043f60b2261eaf71458e3d2bf4b4f2 100644 (file)
@@ -210,6 +210,9 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
     /* 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;
 
index dc4d422f27550d9754ea791977d00c899148c0c6..21778ed13dd541e1e56e1ac8e7070fe006b15859 100644 (file)
  */
 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;
 }
 
 /*
@@ -48,6 +50,7 @@ bool match_is_empty(Match *match) {
             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);
@@ -129,6 +132,14 @@ bool match_matches_window(Match *match, i3Window *window) {
         }
     }
 
+    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 */
@@ -161,7 +172,7 @@ bool match_matches_window(Match *match, i3Window *window) {
         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) &&
index 5dda5ccee1bc6d940842af8100fb04209923ff03..d081d54d10a29a510dc69b1818cc2d540979cdf2 100644 (file)
--- a/src/xcb.c
+++ b/src/xcb.c
@@ -154,6 +154,35 @@ void xcb_set_window_rect(xcb_connection_t *conn, xcb_window_t window, Rect r) {
     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.
  *