]> git.sur5r.net Git - i3/i3/blobdiff - src/con.c
Merge branch 'master' into next
[i3/i3] / src / con.c
index ccdd5682ae947354572f284b4fc99db6296637c4..1d86d73a9825f44d7cdb8ca7e98efcd4ad857e8d 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -1,3 +1,5 @@
+#undef I3__FILE__
+#define I3__FILE__ "con.c"
 /*
  * vim:ts=4:sw=4:expandtab
  *
@@ -676,7 +678,9 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
      * con focused. Otherwise, we leave the focus on the current workspace as we
      * don’t want to focus invisible workspaces */
     if (source_output != dest_output &&
-        workspace_is_visible(workspace)) {
+        workspace_is_visible(workspace) &&
+        workspace->name[0] != '_' &&
+        workspace->name[1] != '_') {
         DLOG("Moved to a different output, focusing target\n");
     } else {
         /* Descend focus stack in case focus_next is a workspace which can
@@ -934,12 +938,46 @@ Con *con_descend_direction(Con *con, direction_t direction) {
  *
  */
 Rect con_border_style_rect(Con *con) {
-    switch (con_border_style(con)) {
+    adjacent_t borders_to_hide = ADJ_NONE;
+    Rect result;
+    /* Shortcut to avoid calling con_adjacent_borders() on dock containers. */
+    int border_style = con_border_style(con);
+    if (border_style == BS_NONE)
+        return (Rect){ 0, 0, 0, 0 };
+    borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders;
+    switch (border_style) {
     case BS_NORMAL:
-        return (Rect){2, 0, -(2 * 2), -2};
+        result = (Rect){2, 0, -(2 * 2), -2};
+        if (borders_to_hide & ADJ_LEFT_SCREEN_EDGE) {
+            result.x -= 2;
+            result.width += 2;
+        }
+        if (borders_to_hide & ADJ_RIGHT_SCREEN_EDGE) {
+            result.width += 2;
+        }
+        /* With normal borders we never hide the upper border */
+        if (borders_to_hide & ADJ_LOWER_SCREEN_EDGE) {
+            result.height += 2;
+        }
+        return result;
 
     case BS_1PIXEL:
-        return (Rect){1, 1, -2, -2};
+        result = (Rect){1, 1, -2, -2};
+        if (borders_to_hide & ADJ_LEFT_SCREEN_EDGE) {
+            result.x -= 1;
+            result.width += 1;
+        }
+        if (borders_to_hide & ADJ_RIGHT_SCREEN_EDGE) {
+            result.width += 1;
+        }
+        if (borders_to_hide & ADJ_UPPER_SCREEN_EDGE) {
+            result.y -= 1;
+            result.height += 1;
+        }
+        if (borders_to_hide & ADJ_LOWER_SCREEN_EDGE) {
+            result.height += 1;
+        }
+        return result;
 
     case BS_NONE:
         return (Rect){0, 0, 0, 0};
@@ -949,6 +987,24 @@ Rect con_border_style_rect(Con *con) {
     }
 }
 
+/*
+ * Returns adjacent borders of the window. We need this if hide_edge_borders is
+ * enabled.
+ */
+adjacent_t con_adjacent_borders(Con *con) {
+    adjacent_t result = ADJ_NONE;
+    Con *workspace = con_get_workspace(con);
+    if (con->rect.x == workspace->rect.x)
+        result |= ADJ_LEFT_SCREEN_EDGE;
+    if (con->rect.x + con->rect.width == workspace->rect.x + workspace->rect.width)
+        result |= ADJ_RIGHT_SCREEN_EDGE;
+    if (con->rect.y == workspace->rect.y)
+        result |= ADJ_UPPER_SCREEN_EDGE;
+    if (con->rect.y + con->rect.height == workspace->rect.y + workspace->rect.height)
+        result |= ADJ_LOWER_SCREEN_EDGE;
+    return result;
+}
+
 /*
  * Use this function to get a container’s border style. This is important
  * because when inside a stack, the border style is always BS_NORMAL.
@@ -1028,11 +1084,27 @@ void con_set_border_style(Con *con, int border_style) {
  *
  */
 void con_set_layout(Con *con, int layout) {
+    DLOG("con_set_layout(%p, %d), con->type = %d\n",
+         con, layout, con->type);
+
+    /* Users can focus workspaces, but not any higher in the hierarchy.
+     * Focus on the workspace is a special case, since in every other case, the
+     * user means "change the layout of the parent split container". */
+    if (con->type != CT_WORKSPACE)
+        con = con->parent;
+
+    /* We fill in last_split_layout when switching to a different layout
+     * since there are many places in the code that don’t use
+     * con_set_layout(). */
+    if (con->layout == L_SPLITH || con->layout == L_SPLITV)
+        con->last_split_layout = con->layout;
+
     /* When the container type is CT_WORKSPACE, the user wants to change the
      * whole workspace into stacked/tabbed mode. To do this and still allow
      * intuitive operations (like level-up and then opening a new window), we
      * need to create a new split container. */
-    if (con->type == CT_WORKSPACE) {
+    if (con->type == CT_WORKSPACE &&
+        (layout == L_STACKED || layout == L_TABBED)) {
         DLOG("Creating new split container\n");
         /* 1: create a new split container */
         Con *new = con_new(NULL, NULL);
@@ -1041,6 +1113,7 @@ void con_set_layout(Con *con, int layout) {
         /* 2: Set the requested layout on the split container and mark it as
          * split. */
         new->layout = layout;
+        new->last_split_layout = con->last_split_layout;
         new->split = true;
 
         Con *old_focused = TAILQ_FIRST(&(con->focus_head));
@@ -1079,12 +1152,10 @@ void con_set_layout(Con *con, int layout) {
          * default", and in v4.9 we will remove it entirely (with an
          * appropriate i3-migrate-config mechanism). */
         con->layout = con->last_split_layout;
+        /* In case last_split_layout was not initialized… */
+        if (con->layout == L_DEFAULT)
+            con->layout = L_SPLITH;
     } else {
-        /* We fill in last_split_layout when switching to a different layout
-         * since there are many places in the code that don’t use
-         * con_set_layout(). */
-        if (con->layout == L_SPLITH || con->layout == L_SPLITV)
-            con->last_split_layout = con->layout;
         con->layout = layout;
     }
 }
@@ -1097,30 +1168,38 @@ void con_set_layout(Con *con, int layout) {
  *
  */
 void con_toggle_layout(Con *con, const char *toggle_mode) {
+    Con *parent = con;
+    /* Users can focus workspaces, but not any higher in the hierarchy.
+     * Focus on the workspace is a special case, since in every other case, the
+     * user means "change the layout of the parent split container". */
+    if (con->type != CT_WORKSPACE)
+        parent = con->parent;
+    DLOG("con_toggle_layout(%p, %s), parent = %p\n", con, toggle_mode, parent);
+
     if (strcmp(toggle_mode, "split") == 0) {
         /* Toggle between splits. When the current layout is not a split
          * layout, we just switch back to last_split_layout. Otherwise, we
          * change to the opposite split layout. */
-        if (con->layout != L_SPLITH && con->layout != L_SPLITV)
-            con_set_layout(con, con->last_split_layout);
+        if (parent->layout != L_SPLITH && parent->layout != L_SPLITV)
+            con_set_layout(con, parent->last_split_layout);
         else {
-            if (con->layout == L_SPLITH)
+            if (parent->layout == L_SPLITH)
                 con_set_layout(con, L_SPLITV);
             else con_set_layout(con, L_SPLITH);
         }
     } else {
-        if (con->layout == L_STACKED)
+        if (parent->layout == L_STACKED)
             con_set_layout(con, L_TABBED);
-        else if (con->layout == L_TABBED) {
+        else if (parent->layout == L_TABBED) {
             if (strcmp(toggle_mode, "all") == 0)
                 con_set_layout(con, L_SPLITH);
-            else con_set_layout(con, con->last_split_layout);
-        } else if (con->layout == L_SPLITH || con->layout == L_SPLITV) {
+            else con_set_layout(con, parent->last_split_layout);
+        } else if (parent->layout == L_SPLITH || parent->layout == L_SPLITV) {
             if (strcmp(toggle_mode, "all") == 0) {
                 /* When toggling through all modes, we toggle between
                  * splith/splitv, whereas normally we just directly jump to
                  * stacked. */
-                if (con->layout == L_SPLITH)
+                if (parent->layout == L_SPLITH)
                     con_set_layout(con, L_SPLITV);
                 else con_set_layout(con, L_STACKED);
             } else {
@@ -1257,6 +1336,9 @@ bool con_fullscreen_permits_focusing(Con *con) {
     while (fs && fs->fullscreen_mode == CF_NONE)
         fs = fs->parent;
 
+    /* fs must be non-NULL since the workspace con doesn’t have CF_NONE and
+     * there always has to be a workspace con in the hierarchy. */
+    assert(fs != NULL);
     /* The most common case is we hit the workspace level. In this
      * situation, changing focus is also harmless. */
     assert(fs->fullscreen_mode != CF_NONE);