]> git.sur5r.net Git - i3/i3/commitdiff
Merge pull request #3178 from orestisf1993/pr-2314
authorIngo Bürk <admin@airblader.de>
Fri, 23 Mar 2018 13:50:46 +0000 (14:50 +0100)
committerGitHub <noreply@github.com>
Fri, 23 Mar 2018 13:50:46 +0000 (14:50 +0100)
Support _NET_WM_STATE_FOCUSED

15 files changed:
docs/userguide
i3-msg/main.c
i3-sensible-terminal
include/commands.h
include/data.h
include/floating.h
man/i3-sensible-terminal.man
parser-specs/commands.spec
src/assignments.c
src/commands.c
src/config.c
src/floating.c
src/move.c
testcases/t/113-urgent.t
testcases/t/294-focus-order.t

index ccedc577924ff53997aa18560c4d488164b31ba1..5fc36585d02b3fb7a67bfe7adc43e6aca6bf2a62 100644 (file)
@@ -2030,10 +2030,13 @@ Use the +move+ command to move a container.
 # defaults to 10 pixels.
 move <left|right|down|up> [<px> px]
 
-# Moves the container either to a specific location
-# or to the center of the screen. If 'absolute' is
-# used, it is moved to the center of all outputs.
-move [absolute] position <pos_x> [px] <pos_y> [px]
+# Moves the container to the specified pos_x and pos_y
+# coordinates on the screen.
+move position <pos_x> [px] <pos_y> [px]
+
+# Moves the container to the center of the screen.
+# If 'absolute' is used, it is moved to the center of
+# all outputs.
 move [absolute] position center
 
 # Moves the container to the current position of the
@@ -2258,8 +2261,7 @@ See <<move_to_outputs>> for how to move a container/workspace to a different
 RandR output.
 
 [[move_to_outputs]]
-[[_moving_containers_workspaces_to_randr_outputs]]
-=== Moving containers/workspaces to RandR outputs
+=== [[_moving_containers_workspaces_to_randr_outputs]]Moving containers/workspaces to RandR outputs
 
 To move a container to another RandR output (addressed by names like +LVDS1+ or
 +VGA1+) or to a RandR output identified by a specific direction (like +left+,
index 91a714e56637b5df408885509f680ad14e6c4b48..96edb2c3a6e0a668dfe0fb36bd19d95124e70a38 100644 (file)
@@ -95,8 +95,10 @@ static int reply_start_map_cb(void *params) {
 
 static int reply_end_map_cb(void *params) {
     if (!last_reply.success) {
-        fprintf(stderr, "ERROR: Your command: %s\n", last_reply.input);
-        fprintf(stderr, "ERROR:               %s\n", last_reply.errorposition);
+        if (last_reply.input) {
+            fprintf(stderr, "ERROR: Your command: %s\n", last_reply.input);
+            fprintf(stderr, "ERROR:               %s\n", last_reply.errorposition);
+        }
         fprintf(stderr, "ERROR: %s\n", last_reply.error);
     }
     return 1;
index f1eb256ecdf4c0a6cf9543cd9c47222d3a31412f..6638098c560dbdf96c1b4b3fe2961b3cd67ae3e3 100755 (executable)
@@ -8,7 +8,7 @@
 # We welcome patches that add distribution-specific mechanisms to find the
 # preferred terminal emulator. On Debian, there is the x-terminal-emulator
 # symlink for example.
-for terminal in "$TERMINAL" x-terminal-emulator urxvt rxvt termit terminator Eterm aterm uxterm xterm gnome-terminal roxterm xfce4-terminal termite lxterminal mate-terminal terminology st qterminal lilyterm tilix terminix konsole kitty guake tilda; do
+for terminal in "$TERMINAL" x-terminal-emulator urxvt rxvt termit terminator Eterm aterm uxterm xterm gnome-terminal roxterm xfce4-terminal termite lxterminal mate-terminal terminology st qterminal lilyterm tilix terminix konsole kitty guake tilda alacritty; do
     if command -v "$terminal" > /dev/null 2>&1; then
         exec "$terminal" "$@"
     fi
index 1057f021db5a3d2aa45034b3557f51071cf03c07..aaa0875fbf399380b503545bcadd816d148ac198 100644 (file)
@@ -264,7 +264,7 @@ void cmd_focus_output(I3_CMD, const char *name);
  * Implementation of 'move [window|container] [to] [absolute] position <px> [px] <px> [px]
  *
  */
-void cmd_move_window_to_position(I3_CMD, const char *method, long x, long y);
+void cmd_move_window_to_position(I3_CMD, long x, long y);
 
 /**
  * Implementation of 'move [window|container] [to] [absolute] position center
index 69a46e464331172172873a70940af6d348cb09bd..32fb098f970bb1bed29e036b9bb46550882e851e 100644 (file)
@@ -573,7 +573,7 @@ struct Assignment {
     /** the criteria to check if a window matches */
     Match match;
 
-    /** destination workspace/command, depending on the type */
+    /** destination workspace/command/output, depending on the type */
     union {
         char *command;
         char *workspace;
index babfafc9a583f3321dbe32c4394b9d4ca8e22070..4382437bbbb8f01ef262ca99b4db0fb76ddc2dce 100644 (file)
@@ -143,7 +143,7 @@ drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event,
  * outputs.
  *
  */
-void floating_reposition(Con *con, Rect newrect);
+bool floating_reposition(Con *con, Rect newrect);
 
 /**
  * Sets size of the CT_FLOATING_CON to specified dimensions. Might limit the
index 894af9120ed404da00610a8a8d797b5c92aa7e8c..fc956eef6d2c064420ef1edf5790bf7ec1bf583a 100644 (file)
@@ -47,6 +47,7 @@ It tries to start one of the following (in that order):
 * kitty
 * guake
 * tilda
+* alacritty
 
 Please don’t complain about the order: If the user has any preference, they will
 have $TERMINAL set or modified their i3 configuration file.
index 0289fa1ab6018a404cb2445f5fa57b61eaf283eb..4048768e5cee375b1ef31e55ca0ceef50e0c0fcd 100644 (file)
@@ -396,7 +396,7 @@ state MOVE_TO_POSITION_X:
 
 state MOVE_TO_POSITION_Y:
   'px', end
-      -> call cmd_move_window_to_position($method, &coord_x, &coord_y)
+      -> call cmd_move_window_to_position(&coord_x, &coord_y)
 
 # mode <string>
 state MODE:
index a0f5d5a747b79f02c23d1dfe478b5ef59c9e03ae..abacc0a3658990b0e752749e6ff8146afdf24039 100644 (file)
@@ -22,7 +22,7 @@ void run_assignments(i3Window *window) {
     /* Check if any assignments match */
     Assignment *current;
     TAILQ_FOREACH(current, &assignments, assignments) {
-        if (!match_matches_window(&(current->match), window))
+        if (current->type != A_COMMAND || !match_matches_window(&(current->match), window))
             continue;
 
         bool skip = false;
@@ -45,19 +45,16 @@ void run_assignments(i3Window *window) {
         window->ran_assignments = srealloc(window->ran_assignments, sizeof(Assignment *) * window->nr_assignments);
         window->ran_assignments[window->nr_assignments - 1] = current;
 
-        DLOG("matching assignment, would do:\n");
-        if (current->type == A_COMMAND) {
-            DLOG("execute command %s\n", current->dest.command);
-            char *full_command;
-            sasprintf(&full_command, "[id=\"%d\"] %s", window->id, current->dest.command);
-            CommandResult *result = parse_command(full_command, NULL);
-            free(full_command);
+        DLOG("matching assignment, execute command %s\n", current->dest.command);
+        char *full_command;
+        sasprintf(&full_command, "[id=\"%d\"] %s", window->id, current->dest.command);
+        CommandResult *result = parse_command(full_command, NULL);
+        free(full_command);
 
-            if (result->needs_tree_render)
-                needs_tree_render = true;
+        if (result->needs_tree_render)
+            needs_tree_render = true;
 
-            command_result_free(result);
-        }
+        command_result_free(result);
     }
 
     /* If any of the commands required re-rendering, we will do that now. */
index 899bbb90c8f0854254b4d36b52e0e2a21619e034..98625a911bd5b121a3b8574aef5e558ab0beef73 100644 (file)
@@ -1694,7 +1694,7 @@ void cmd_focus_output(I3_CMD, const char *name) {
  * Implementation of 'move [window|container] [to] [absolute] position <px> [px] <px> [px]
  *
  */
-void cmd_move_window_to_position(I3_CMD, const char *method, long x, long y) {
+void cmd_move_window_to_position(I3_CMD, long x, long y) {
     bool has_error = false;
 
     owindow *current;
@@ -1712,27 +1712,18 @@ void cmd_move_window_to_position(I3_CMD, const char *method, long x, long y) {
             continue;
         }
 
-        if (strcmp(method, "absolute") == 0) {
-            current->con->parent->rect.x = x;
-            current->con->parent->rect.y = y;
+        Rect newrect = current->con->parent->rect;
 
-            DLOG("moving to absolute position %ld %ld\n", x, y);
-            floating_maybe_reassign_ws(current->con->parent);
-            cmd_output->needs_tree_render = true;
-        }
+        DLOG("moving to position %ld %ld\n", x, y);
+        newrect.x = x;
+        newrect.y = y;
 
-        if (strcmp(method, "position") == 0) {
-            Rect newrect = current->con->parent->rect;
-
-            DLOG("moving to position %ld %ld\n", x, y);
-            newrect.x = x;
-            newrect.y = y;
-
-            floating_reposition(current->con->parent, newrect);
+        if (!floating_reposition(current->con->parent, newrect)) {
+            yerror("Cannot move window/container out of bounds.");
+            has_error = true;
         }
     }
 
-    // XXX: default reply for now, make this a better reply
     if (!has_error)
         ysuccess(true);
 }
index 24c7b541e447e4f80ab2b676c4d3f0b140bdff6c..fd379fdea475d234a47932b5f234b9116d144c9a 100644 (file)
@@ -103,6 +103,8 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
                 FREE(assign->dest.workspace);
             else if (assign->type == A_COMMAND)
                 FREE(assign->dest.command);
+            else if (assign->type == A_TO_OUTPUT)
+                FREE(assign->dest.output);
             match_free(&(assign->match));
             TAILQ_REMOVE(&assignments, assign, assignments);
             FREE(assign);
@@ -160,10 +162,16 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
             FREE(barconfig);
         }
 
-        /* Invalidate pixmap caches in case font or colors changed */
         Con *con;
-        TAILQ_FOREACH(con, &all_cons, all_cons)
-        FREE(con->deco_render_params);
+        TAILQ_FOREACH(con, &all_cons, all_cons) {
+            /* Assignments changed, previously ran assignments are invalid. */
+            if (con->window) {
+                con->window->nr_assignments = 0;
+                FREE(con->window->ran_assignments);
+            }
+            /* Invalidate pixmap caches in case font or colors changed. */
+            FREE(con->deco_render_params);
+        }
 
         /* Get rid of the current font */
         free_font();
index e958153d6a647ab5242188d932f28e1b3ae19e98..2130d6732278fbea5e8570a465d101939ed65b14 100644 (file)
@@ -864,12 +864,12 @@ drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_
  * outputs.
  *
  */
-void floating_reposition(Con *con, Rect newrect) {
+bool floating_reposition(Con *con, Rect newrect) {
     /* Sanity check: Are the new coordinates on any output? If not, we
      * ignore that request. */
     if (!contained_by_output(newrect)) {
         ELOG("No output found at destination coordinates. Not repositioning.\n");
-        return;
+        return false;
     }
 
     con->rect = newrect;
@@ -881,6 +881,7 @@ void floating_reposition(Con *con, Rect newrect) {
         con->scratchpad_state = SCRATCHPAD_CHANGED;
 
     tree_render();
+    return true;
 }
 
 /*
index 97ca6d40b42423a07582d44f3ade0f9001d7ef7f..a60a27caae947e9c97a92b6135e686aaf807752b 100644 (file)
 typedef enum { BEFORE,
                AFTER } position_t;
 
+/*
+ * Returns the lowest container in the tree that has both a and b as descendants.
+ *
+ */
+static Con *lowest_common_ancestor(Con *a, Con *b) {
+    Con *parent_a = a;
+    while (parent_a) {
+        Con *parent_b = b;
+        while (parent_b) {
+            if (parent_a == parent_b) {
+                return parent_a;
+            }
+            parent_b = parent_b->parent;
+        }
+        parent_a = parent_a->parent;
+    }
+    assert(false);
+}
+
+/*
+ * Returns the direct child of ancestor that contains con.
+ *
+ */
+static Con *child_containing_con_recursively(Con *ancestor, Con *con) {
+    Con *child = con;
+    while (child && child->parent != ancestor) {
+        child = child->parent;
+        assert(child->parent);
+    }
+    return child;
+}
+
+/*
+ * Returns true if the given container is the focused descendant of ancestor, recursively.
+ *
+ */
+static bool is_focused_descendant(Con *con, Con *ancestor) {
+    Con *current = con;
+    while (current != ancestor) {
+        if (TAILQ_FIRST(&(current->parent->focus_head)) != current) {
+            return false;
+        }
+        current = current->parent;
+        assert(current->parent);
+    }
+    return true;
+}
+
 /*
  * This function detaches 'con' from its parent and inserts it either before or
  * after 'target'.
@@ -24,6 +72,52 @@ static void insert_con_into(Con *con, Con *target, position_t position) {
      * afterwards which might then close the con if it is empty. */
     Con *old_parent = con->parent;
 
+    /* We compare the focus order of the children of the lowest common ancestor. If con or
+     * its ancestor is before target's ancestor then con should be placed before the target
+     * in the focus stack. */
+    Con *lca = lowest_common_ancestor(con, parent);
+    if (lca == con) {
+        ELOG("Container is being inserted into one of its descendants.\n");
+        return;
+    }
+
+    Con *con_ancestor = child_containing_con_recursively(lca, con);
+    Con *target_ancestor = child_containing_con_recursively(lca, target);
+    bool moves_focus_from_ancestor = is_focused_descendant(con, con_ancestor);
+    bool focus_before;
+
+    /* Determine if con is going to be placed before or after target in the parent's focus stack. */
+    if (con_ancestor == target_ancestor) {
+        /* Happens when the target is con's old parent. Eg with layout V [ A H [ B C ] ],
+         * if we move C up. Target will be H. */
+        focus_before = moves_focus_from_ancestor;
+    } else {
+        /* Look at the focus stack order of the children of the lowest common ancestor. */
+        Con *current;
+        TAILQ_FOREACH(current, &(lca->focus_head), focused) {
+            if (current == con_ancestor || current == target_ancestor) {
+                break;
+            }
+        }
+        focus_before = (current == con_ancestor);
+    }
+
+    /* If con is the focused container in our old ancestor we place the new ancestor
+     * before the old ancestor in the focus stack. Example:
+     * Consider the layout [ H [ V1 [ A* B ] V2 [ C ] ] ] where A is focused. We move to
+     * a second workspace and from there we move A to the right and switch back to the
+     * original workspace. Without the change focus would move to B instead of staying
+     * with A. */
+    if (moves_focus_from_ancestor && focus_before) {
+        Con *place = TAILQ_PREV(con_ancestor, focus_head, focused);
+        TAILQ_REMOVE(&(lca->focus_head), target_ancestor, focused);
+        if (place) {
+            TAILQ_INSERT_AFTER(&(lca->focus_head), place, target_ancestor, focused);
+        } else {
+            TAILQ_INSERT_HEAD(&(lca->focus_head), target_ancestor, focused);
+        }
+    }
+
     con_detach(con);
     con_fix_percent(con->parent);
 
@@ -46,12 +140,28 @@ static void insert_con_into(Con *con, Con *target, position_t position) {
 
     con->parent = parent;
 
+    if (parent == lca) {
+        if (focus_before) {
+            /* Example layout: H [ A B* ], we move A up/down. 'target' will be H. */
+            TAILQ_INSERT_BEFORE(target, con, focused);
+        } else {
+            /* Example layout: H [ A B* ], we move A up/down. 'target' will be H. */
+            TAILQ_INSERT_AFTER(&(parent->focus_head), target, con, focused);
+        }
+    } else {
+        if (focus_before) {
+            /* Example layout: V [ H [ A B ] C* ], we move C up. 'target' will be A. */
+            TAILQ_INSERT_HEAD(&(parent->focus_head), con, focused);
+        } else {
+            /* Example layout: V [ H [ A* B ] C ], we move C up. 'target' will be A. */
+            TAILQ_INSERT_TAIL(&(parent->focus_head), con, focused);
+        }
+    }
+
     if (position == BEFORE) {
         TAILQ_INSERT_BEFORE(target, con, nodes);
-        TAILQ_INSERT_HEAD(&(parent->focus_head), con, focused);
     } else if (position == AFTER) {
         TAILQ_INSERT_AFTER(&(parent->nodes_head), target, con, nodes);
-        TAILQ_INSERT_HEAD(&(parent->focus_head), con, focused);
     }
 
     /* Pretend the con was just opened with regards to size percent values.
@@ -264,11 +374,6 @@ void tree_move(Con *con, int direction) {
     }
 
 end:
-    /* We need to call con_focus() to fix the focus stack "above" the container
-     * we just inserted the focused container into (otherwise, the parent
-     * container(s) would still point to the old container(s)). */
-    con_focus(con);
-
     /* force re-painting the indicators */
     FREE(con->deco_render_params);
 
index 1e2644ad96ed334437042825293b50df54660753..0de90193c60cb0ae1935a342e940b88bc172d456 100644 (file)
@@ -332,6 +332,34 @@ for ($type = 1; $type <= 2; $type++) {
     ok(!$source_ws->{urgent}, 'Source workspace is no longer marked urgent');
     is($target_ws->{urgent}, 1, 'Target workspace is now marked urgent');
 
+##############################################################################
+# Test that moving an unfocused container doesn't reset its urgency hint.
+##############################################################################
+    $tmp = fresh_workspace;
+    $win1 = open_window;
+    $win2 = open_window;
+    cmd 'split v';
+    $win3 = open_window;
+    set_urgency($win1, 1, $type);
+    sync_with_i3;
+
+    my $win1_info;
+
+    @content = @{get_ws_content($tmp)};
+    $win1_info = first { $_->{window} == $win1->id } @content;
+    ok($win1_info->{urgent}, 'win1 window is marked urgent');
+
+    cmd '[id="' . $win1->id . '"] move right';
+    cmd '[id="' . $win1->id . '"] move right';
+    @content = @{get_ws_content($tmp)};
+    $win1_info = first { $_->{window} == $win1->id } @content;
+    ok($win1_info->{urgent}, 'win1 window is still marked urgent after moving');
+
+    cmd '[id="' . $win1->id . '"] focus';
+    @content = @{get_ws_content($tmp)};
+    $win1_info = first { $_->{window} == $win1->id } @content;
+    ok(!$win1_info->{urgent}, 'win1 window is not marked urgent after focusing');
+
 ##############################################################################
 
     exit_gracefully($pid);
index 41c0bf07009f43ed073a9b466b28526503110e0c..0f11624134eda4f77aca53e729e6b2211885f5ab 100644 (file)
@@ -106,4 +106,20 @@ $windows[0] = open_window;
 cmd 'move left';
 confirm_focus('split-v + move');
 
+######################################################################
+# Test that moving an unfocused container maintains the correct focus
+# order.
+# Layout: H [ A V1 [ B C D ] ]
+######################################################################
+
+fresh_workspace;
+$windows[3] = open_window;
+$windows[2] = open_window;
+cmd 'split v';
+$windows[1] = open_window;
+$windows[0] = open_window;
+
+cmd '[id=' . $windows[3]->id . '] move right';
+confirm_focus('split-v + unfocused move');
+
 done_testing;