]> git.sur5r.net Git - i3/i3/commitdiff
Merge pull request #1591 from Airblader/feature-child-cleanup
authorMichael Stapelberg <stapelberg@users.noreply.github.com>
Fri, 27 Mar 2015 08:51:00 +0000 (09:51 +0100)
committerMichael Stapelberg <stapelberg@users.noreply.github.com>
Fri, 27 Mar 2015 08:51:00 +0000 (09:51 +0100)
Return in child parsing as soon as the match was made.

docs/userguide
i3bar/src/xcb.c
parser-specs/commands.spec
src/commands_parser.c
src/handlers.c
testcases/t/102-dock.t
testcases/t/187-commands-parser.t

index d60eefb2103e1ed9d222608797ced5343be27ae4..3d935e40aac7c2fbf8f5d5f6c2b45e47db4dec8b 100644 (file)
@@ -2029,6 +2029,27 @@ bindsym $mod+minus scratchpad show
 bindsym mod4+s [title="^Sup ::"] scratchpad show
 ------------------------------------------------
 
+=== Nop
+
+There is a no operation command +nop+ which allows you to override default
+behavior. This can be useful for, e.g., disabling a focus change on clicks with
+the middle mouse button.
+
+The optional +comment+ argument is ignored, but will be printed to the log file
+for debugging purposes.
+
+*Syntax*:
+---------------
+nop [<comment>]
+---------------
+
+*Example*:
+----------------------------------------------
+# Disable focus change for clicks on titlebars
+# with the middle mouse button
+bindsym button2 nop
+----------------------------------------------
+
 === i3bar control
 
 There are two options in the configuration of each i3bar instance that can be
index 205e277a5b97d9db37218de31f1c2e48de5ecdd8..d0bc3d6ca09d79b74d473ffef86b290e6e5c6ffe 100644 (file)
@@ -516,7 +516,7 @@ void handle_button(xcb_button_press_event_t *event) {
     size_t namelen = 0;
     const char *utf8_name = cur_ws->canonical_name;
     for (const char *walk = utf8_name; *walk != '\0'; walk++) {
-        if (*walk == '"')
+        if (*walk == '"' || *walk == '\\')
             num_quotes++;
         /* While we’re looping through the name anyway, we can save one
          * strlen(). */
@@ -530,7 +530,7 @@ void handle_button(xcb_button_press_event_t *event) {
     for (inpos = 0, outpos = strlen("workspace \"");
          inpos < namelen;
          inpos++, outpos++) {
-        if (utf8_name[inpos] == '"') {
+        if (utf8_name[inpos] == '"' || utf8_name[inpos] == '\\') {
             buffer[outpos] = '\\';
             outpos++;
         }
@@ -1525,6 +1525,50 @@ void realloc_sl_buffer(void) {
     }
 }
 
+/* Strut partial tells i3 where to reserve space for i3bar. This is determined
+ * by the `position` bar config directive. */
+xcb_void_cookie_t config_strut_partial(i3_output *output) {
+    /* A local struct to save the strut_partial property */
+    struct {
+        uint32_t left;
+        uint32_t right;
+        uint32_t top;
+        uint32_t bottom;
+        uint32_t left_start_y;
+        uint32_t left_end_y;
+        uint32_t right_start_y;
+        uint32_t right_end_y;
+        uint32_t top_start_x;
+        uint32_t top_end_x;
+        uint32_t bottom_start_x;
+        uint32_t bottom_end_x;
+    } __attribute__((__packed__)) strut_partial;
+    memset(&strut_partial, 0, sizeof(strut_partial));
+
+    switch (config.position) {
+        case POS_NONE:
+            break;
+        case POS_TOP:
+            strut_partial.top = bar_height;
+            strut_partial.top_start_x = output->rect.x;
+            strut_partial.top_end_x = output->rect.x + output->rect.w;
+            break;
+        case POS_BOT:
+            strut_partial.bottom = bar_height;
+            strut_partial.bottom_start_x = output->rect.x;
+            strut_partial.bottom_end_x = output->rect.x + output->rect.w;
+            break;
+    }
+    return xcb_change_property(xcb_connection,
+                               XCB_PROP_MODE_REPLACE,
+                               output->bar,
+                               atoms[_NET_WM_STRUT_PARTIAL],
+                               XCB_ATOM_CARDINAL,
+                               32,
+                               12,
+                               &strut_partial);
+}
+
 /*
  * Reconfigure all bars and create new bars for recently activated outputs
  *
@@ -1624,49 +1668,7 @@ void reconfig_windows(bool redraw_bars) {
                                                                 1,
                                                                 (unsigned char *)&atoms[_NET_WM_WINDOW_TYPE_DOCK]);
 
-            /* We need to tell i3, where to reserve space for i3bar */
-            /* left, right, top, bottom, left_start_y, left_end_y,
-             * right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x,
-             * bottom_end_x */
-            /* A local struct to save the strut_partial property */
-            struct {
-                uint32_t left;
-                uint32_t right;
-                uint32_t top;
-                uint32_t bottom;
-                uint32_t left_start_y;
-                uint32_t left_end_y;
-                uint32_t right_start_y;
-                uint32_t right_end_y;
-                uint32_t top_start_x;
-                uint32_t top_end_x;
-                uint32_t bottom_start_x;
-                uint32_t bottom_end_x;
-            } __attribute__((__packed__)) strut_partial;
-            memset(&strut_partial, 0, sizeof(strut_partial));
-
-            switch (config.position) {
-                case POS_NONE:
-                    break;
-                case POS_TOP:
-                    strut_partial.top = bar_height;
-                    strut_partial.top_start_x = walk->rect.x;
-                    strut_partial.top_end_x = walk->rect.x + walk->rect.w;
-                    break;
-                case POS_BOT:
-                    strut_partial.bottom = bar_height;
-                    strut_partial.bottom_start_x = walk->rect.x;
-                    strut_partial.bottom_end_x = walk->rect.x + walk->rect.w;
-                    break;
-            }
-            xcb_void_cookie_t strut_cookie = xcb_change_property(xcb_connection,
-                                                                 XCB_PROP_MODE_REPLACE,
-                                                                 walk->bar,
-                                                                 atoms[_NET_WM_STRUT_PARTIAL],
-                                                                 XCB_ATOM_CARDINAL,
-                                                                 32,
-                                                                 12,
-                                                                 &strut_partial);
+            xcb_void_cookie_t strut_cookie = config_strut_partial(walk);
 
             /* We also want a graphics context for the bars (it defines the properties
              * with which we draw to them) */
@@ -1726,6 +1728,9 @@ void reconfig_windows(bool redraw_bars) {
             values[3] = bar_height;
             values[4] = XCB_STACK_MODE_ABOVE;
 
+            DLOG("Reconfiguring strut partial property for output %s\n", walk->name);
+            xcb_void_cookie_t strut_cookie = config_strut_partial(walk);
+
             DLOG("Destroying buffer for output %s\n", walk->name);
             xcb_free_pixmap(xcb_connection, walk->buffer);
 
@@ -1774,6 +1779,7 @@ void reconfig_windows(bool redraw_bars) {
             if (xcb_request_failed(cfg_cookie, "Could not reconfigure window") ||
                 xcb_request_failed(chg_cookie, "Could not change window") ||
                 xcb_request_failed(pm_cookie, "Could not create pixmap") ||
+                xcb_request_failed(strut_cookie, "Could not set strut") ||
                 (redraw_bars && (xcb_request_failed(umap_cookie, "Could not unmap window") ||
                                  (config.hide_on_modifier == M_DOCK && xcb_request_failed(map_cookie, "Could not map window"))))) {
                 exit(EXIT_FAILURE);
index 82348df79c9c47d6b5dc9f352eceaaabb4b5100f..315a9218dd5930695e540506ce11e0cd30cabbf4 100644 (file)
@@ -353,6 +353,8 @@ state MODE:
 state NOP:
   comment = string
       -> call cmd_nop($comment)
+  end
+      -> call cmd_nop(NULL)
 
 state SCRATCHPAD:
   'show'
index f325a048afc6ebf6859ee81347fafd7c8dc4de28..fa4c2360101513e4796490c9720ff9b63533915f 100644 (file)
@@ -216,8 +216,9 @@ char *parse_string(const char **walk, bool as_word) {
     if (**walk == '"') {
         beginning++;
         (*walk)++;
-        while (**walk != '\0' && (**walk != '"' || *(*walk - 1) == '\\'))
-            (*walk)++;
+        for (; **walk != '\0' && **walk != '"'; (*walk)++)
+            if (**walk == '\\' && *(*walk + 1) != '\0')
+                (*walk)++;
     } else {
         if (!as_word) {
             /* For a string (starting with 's'), the delimiters are
@@ -248,10 +249,10 @@ char *parse_string(const char **walk, bool as_word) {
     for (inpos = 0, outpos = 0;
          inpos < (*walk - beginning);
          inpos++, outpos++) {
-        /* We only handle escaped double quotes to not break
-         * backwards compatibility with people using \w in
-         * regular expressions etc. */
-        if (beginning[inpos] == '\\' && beginning[inpos + 1] == '"')
+        /* We only handle escaped double quotes and backslashes to not break
+         * backwards compatibility with people using \w in regular expressions
+         * etc. */
+        if (beginning[inpos] == '\\' && (beginning[inpos + 1] == '"' || beginning[inpos + 1] == '\\'))
             inpos++;
         str[outpos] = beginning[inpos];
     }
index 0cd397fd0669e6f855dc80e6a4957498f3c8c1b6..4b5c87d4fd0651db363b8bea27e1c9507cd1fb0c 100644 (file)
@@ -1159,6 +1159,87 @@ static bool handle_class_change(void *data, xcb_connection_t *conn, uint8_t stat
     return true;
 }
 
+/*
+ * Handles the _NET_WM_STRUT_PARTIAL property for allocating space for dock clients.
+ *
+ */
+static bool handle_strut_partial_change(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
+                                        xcb_atom_t name, xcb_get_property_reply_t *prop) {
+    DLOG("strut partial change for window 0x%08x\n", window);
+
+    Con *con;
+    if ((con = con_by_window_id(window)) == NULL || con->window == NULL) {
+        return false;
+    }
+
+    if (prop == NULL) {
+        xcb_generic_error_t *err = NULL;
+        xcb_get_property_cookie_t strut_cookie = xcb_get_property(conn, false, window, A__NET_WM_STRUT_PARTIAL,
+                                                                  XCB_GET_PROPERTY_TYPE_ANY, 0, UINT32_MAX);
+        prop = xcb_get_property_reply(conn, strut_cookie, &err);
+
+        if (err != NULL) {
+            DLOG("got error when getting strut partial property: %d\n", err->error_code);
+            free(err);
+            return false;
+        }
+
+        if (prop == NULL) {
+            return false;
+        }
+    }
+
+    DLOG("That is con %p / %s\n", con, con->name);
+
+    window_update_strut_partial(con->window, prop);
+
+    /* we only handle this change for dock clients */
+    if (con->parent == NULL || con->parent->type != CT_DOCKAREA) {
+        return true;
+    }
+
+    Con *search_at = croot;
+    Con *output = con_get_output(con);
+    if (output != NULL) {
+        DLOG("Starting search at output %s\n", output->name);
+        search_at = output;
+    }
+
+    /* find out the desired position of this dock window */
+    if (con->window->reserved.top > 0 && con->window->reserved.bottom == 0) {
+        DLOG("Top dock client\n");
+        con->window->dock = W_DOCK_TOP;
+    } else if (con->window->reserved.top == 0 && con->window->reserved.bottom > 0) {
+        DLOG("Bottom dock client\n");
+        con->window->dock = W_DOCK_BOTTOM;
+    } else {
+        DLOG("Ignoring invalid reserved edges (_NET_WM_STRUT_PARTIAL), using position as fallback:\n");
+        if (con->geometry.y < (int16_t)(search_at->rect.height / 2)) {
+            DLOG("geom->y = %d < rect.height / 2 = %d, it is a top dock client\n",
+                 con->geometry.y, (search_at->rect.height / 2));
+            con->window->dock = W_DOCK_TOP;
+        } else {
+            DLOG("geom->y = %d >= rect.height / 2 = %d, it is a bottom dock client\n",
+                 con->geometry.y, (search_at->rect.height / 2));
+            con->window->dock = W_DOCK_BOTTOM;
+        }
+    }
+
+    /* find the dockarea */
+    Con *dockarea = con_for_window(search_at, con->window, NULL);
+    assert(dockarea != NULL);
+
+    /* attach the dock to the dock area */
+    con_detach(con);
+    con->parent = dockarea;
+    TAILQ_INSERT_HEAD(&(dockarea->focus_head), con, focused);
+    TAILQ_INSERT_HEAD(&(dockarea->nodes_head), con, nodes);
+
+    tree_render();
+
+    return true;
+}
+
 /* Returns false if the event could not be processed (e.g. the window could not
  * be found), true otherwise */
 typedef bool (*cb_property_handler_t)(void *data, xcb_connection_t *c, uint8_t state, xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *property);
@@ -1177,7 +1258,8 @@ static struct property_handler_t property_handlers[] = {
     {0, UINT_MAX, handle_clientleader_change},
     {0, UINT_MAX, handle_transient_for},
     {0, 128, handle_windowrole_change},
-    {0, 128, handle_class_change}};
+    {0, 128, handle_class_change},
+    {0, UINT_MAX, handle_strut_partial_change}};
 #define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
 
 /*
@@ -1196,6 +1278,7 @@ void property_handlers_init(void) {
     property_handlers[5].atom = XCB_ATOM_WM_TRANSIENT_FOR;
     property_handlers[6].atom = A_WM_WINDOW_ROLE;
     property_handlers[7].atom = XCB_ATOM_WM_CLASS;
+    property_handlers[8].atom = A__NET_WM_STRUT_PARTIAL;
 }
 
 static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {
index 1bac40f053e43318b242c0b61b2d1b6175e83b4b..bb9c71c9283826b1b6e2cae025b109e8d7cddecd 100644 (file)
@@ -143,6 +143,22 @@ wait_for_map $window;
 @docked = get_dock_clients('top');
 is(@docked, 1, 'dock client on top');
 
+# now change strut_partial to reserve space on the bottom and the dock should
+# be moved to the bottom dock area
+$x->change_property(
+    PROP_MODE_REPLACE,
+    $window->id,
+    $atomname->id,
+    $atomtype->id,
+    32,         # 32 bit integer
+    12,
+    pack('L12', 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 1280, 0)
+);
+
+sync_with_i3;
+@docked = get_dock_clients('bottom');
+is(@docked, 1, 'dock client on bottom');
+
 $window->destroy;
 
 wait_for_unmap $window;
index 5ee94f876f141b5c8133b47c506582ef9259a10a..6d67731a1e71a9914485962ebc3fc73215d1b042 100644 (file)
@@ -156,7 +156,7 @@ is(parser_calls('move something to somewhere'),
    'error for unknown literal ok');
 
 ################################################################################
-# 3: Verify that escaping of double quotes works correctly
+# 3: Verify that escaping works correctly
 ################################################################################
 
 is(parser_calls('workspace "foo"'),
@@ -171,6 +171,18 @@ is(parser_calls('workspace "foo \"bar"'),
    'cmd_workspace_name(foo "bar)',
    'Command with escaped double quotes ok');
 
+is(parser_calls('workspace "foo \\'),
+   'cmd_workspace_name(foo \\)',
+   'Command with single backslash in the end ok');
+
+is(parser_calls('workspace "foo\\\\bar"'),
+   'cmd_workspace_name(foo\\bar)',
+   'Command with escaped backslashes ok');
+
+is(parser_calls('workspace "foo\\\\\\"bar"'),
+   'cmd_workspace_name(foo\\"bar)',
+   'Command with escaped double quotes after escaped backslashes ok');
+
 ################################################################################
 # 4: Verify that resize commands with a "px or ppt"-construction are parsed
 # correctly