]> git.sur5r.net Git - i3/i3/blobdiff - src/con.c
Merge pull request #1589 from Deiz/fix-center
[i3/i3] / src / con.c
index 78fe5fef55268494957e529e23a54a284440cddf..41dd0196ba8931e9793a7ba7c103e99a2ec0cbf8 100644 (file)
--- a/src/con.c
+++ b/src/con.c
  *
  */
 #include "all.h"
-
-char *colors[] = {
-    "#ff0000",
-    "#00FF00",
-    "#0000FF",
-    "#ff00ff",
-    "#00ffff",
-    "#ffff00",
-    "#aa0000",
-    "#00aa00",
-    "#0000aa",
-    "#aa00aa"};
+#include "yajl_utils.h"
 
 static void con_on_remove_child(Con *con);
 
@@ -31,7 +20,7 @@ static void con_on_remove_child(Con *con);
  * force parent split containers to be redrawn
  *
  */
-static void con_force_split_parents_redraw(Con *con) {
+void con_force_split_parents_redraw(Con *con) {
     Con *parent = con;
 
     while (parent && parent->type != CT_WORKSPACE && parent->type != CT_DOCKAREA) {
@@ -59,16 +48,7 @@ Con *con_new_skeleton(Con *parent, i3Window *window) {
         new->depth = window->depth;
     else
         new->depth = XCB_COPY_FROM_PARENT;
-    static int cnt = 0;
-    DLOG("opening window %d\n", cnt);
-
-    /* TODO: remove window coloring after test-phase */
-    DLOG("color %s\n", colors[cnt]);
-    new->name = strdup(colors[cnt]);
-    //uint32_t cp = get_colorpixel(colors[cnt]);
-    cnt++;
-    if ((cnt % (sizeof(colors) / sizeof(char *))) == 0)
-        cnt = 0;
+    DLOG("opening window\n");
 
     TAILQ_INIT(&(new->floating_head));
     TAILQ_INIT(&(new->nodes_head));
@@ -586,37 +566,27 @@ void con_fix_percent(Con *con) {
  *
  */
 void con_toggle_fullscreen(Con *con, int fullscreen_mode) {
-    Con *workspace, *fullscreen;
-
     if (con->type == CT_WORKSPACE) {
         DLOG("You cannot make a workspace fullscreen.\n");
         return;
     }
 
     DLOG("toggling fullscreen for %p / %s\n", con, con->name);
-    if (con->fullscreen_mode == CF_NONE) {
-        /* 1: check if there already is a fullscreen con */
-        if (fullscreen_mode == CF_GLOBAL)
-            fullscreen = con_get_fullscreen_con(croot, CF_GLOBAL);
-        else {
-            workspace = con_get_workspace(con);
-            fullscreen = con_get_fullscreen_con(workspace, CF_OUTPUT);
-        }
-        if (fullscreen != NULL) {
-            /* Disable fullscreen for the currently fullscreened
-             * container and enable it for the one the user wants
-             * to have in fullscreen mode. */
-            LOG("Disabling fullscreen for (%p/%s) upon user request\n",
-                fullscreen, fullscreen->name);
-            fullscreen->fullscreen_mode = CF_NONE;
-        }
 
-        /* 2: enable fullscreen */
-        con->fullscreen_mode = fullscreen_mode;
-    } else {
-        /* 1: disable fullscreen */
-        con->fullscreen_mode = CF_NONE;
-    }
+    if (con->fullscreen_mode == CF_NONE)
+        con_enable_fullscreen(con, fullscreen_mode);
+    else
+        con_disable_fullscreen(con);
+}
+
+/*
+ * Sets the specified fullscreen mode for the given container, sends the
+ * “fullscreen_mode” event and changes the XCB fullscreen property of the
+ * container’s window, if any.
+ *
+ */
+static void con_set_fullscreen_mode(Con *con, fullscreen_mode_t fullscreen_mode) {
+    con->fullscreen_mode = fullscreen_mode;
 
     DLOG("mode now: %d\n", con->fullscreen_mode);
 
@@ -639,6 +609,79 @@ void con_toggle_fullscreen(Con *con, int fullscreen_mode) {
                         A__NET_WM_STATE, XCB_ATOM_ATOM, 32, num, values);
 }
 
+/*
+ * Enables fullscreen mode for the given container, if necessary.
+ *
+ * If the container’s mode is already CF_OUTPUT or CF_GLOBAL, the container is
+ * kept fullscreen but its mode is set to CF_GLOBAL and CF_OUTPUT,
+ * respectively.
+ *
+ * Other fullscreen containers will be disabled first, if they hide the new
+ * one.
+ *
+ */
+void con_enable_fullscreen(Con *con, fullscreen_mode_t fullscreen_mode) {
+    if (con->type == CT_WORKSPACE) {
+        DLOG("You cannot make a workspace fullscreen.\n");
+        return;
+    }
+
+    assert(fullscreen_mode == CF_GLOBAL || fullscreen_mode == CF_OUTPUT);
+
+    if (fullscreen_mode == CF_GLOBAL)
+        DLOG("enabling global fullscreen for %p / %s\n", con, con->name);
+    else
+        DLOG("enabling fullscreen for %p / %s\n", con, con->name);
+
+    if (con->fullscreen_mode == fullscreen_mode) {
+        DLOG("fullscreen already enabled for %p / %s\n", con, con->name);
+        return;
+    }
+
+    Con *con_ws = con_get_workspace(con);
+
+    /* Disable any fullscreen container that would conflict the new one. */
+    Con *fullscreen = con_get_fullscreen_con(croot, CF_GLOBAL);
+    if (fullscreen == NULL)
+        fullscreen = con_get_fullscreen_con(con_ws, CF_OUTPUT);
+    if (fullscreen != NULL)
+        con_disable_fullscreen(fullscreen);
+
+    /* Set focus to new fullscreen container. Unless in global fullscreen mode
+     * and on another workspace restore focus afterwards.
+     * Switch to the container’s workspace if mode is global. */
+    Con *cur_ws = con_get_workspace(focused);
+    Con *old_focused = focused;
+    if (fullscreen_mode == CF_GLOBAL && cur_ws != con_ws)
+        workspace_show(con_ws);
+    con_focus(con);
+    if (fullscreen_mode != CF_GLOBAL && cur_ws != con_ws)
+        con_focus(old_focused);
+
+    con_set_fullscreen_mode(con, fullscreen_mode);
+}
+
+/*
+ * Disables fullscreen mode for the given container regardless of the mode, if
+ * necessary.
+ *
+ */
+void con_disable_fullscreen(Con *con) {
+    if (con->type == CT_WORKSPACE) {
+        DLOG("You cannot make a workspace fullscreen.\n");
+        return;
+    }
+
+    DLOG("disabling fullscreen for %p / %s\n", con, con->name);
+
+    if (con->fullscreen_mode == CF_NONE) {
+        DLOG("fullscreen already disabled for %p / %s\n", con, con->name);
+        return;
+    }
+
+    con_set_fullscreen_mode(con, CF_NONE);
+}
+
 /*
  * Moves the given container to the currently focused container on the given
  * workspace.
@@ -693,6 +736,9 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
         }
     }
 
+    /* Save the urgency state so that we can restore it. */
+    bool urgent = con->urgent;
+
     /* Save the current workspace. So we can call workspace_show() by the end
      * of this function. */
     Con *current_ws = con_get_workspace(focused);
@@ -800,7 +846,7 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
     if (source_ws == current_ws)
         con_focus(con_descend_focused(focus_next));
 
-    /* If anything within the container is associated with a startup sequence,
+    /* 9. If anything within the container is associated with a startup sequence,
      * delete it so child windows won't be created on the old workspace. */
     struct Startup_Sequence *sequence;
     xcb_get_property_cookie_t cookie;
@@ -834,6 +880,12 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
 
     CALL(parent, on_remove_child);
 
+    /* 10. If the container was marked urgent, move the urgency hint. */
+    if (urgent) {
+        workspace_update_urgent_flag(source_ws);
+        con_set_urgency(con, true);
+    }
+
     ipc_send_window_event("move", con);
 }
 
@@ -1106,12 +1158,12 @@ Rect con_border_style_rect(Con *con) {
     /* 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};
+        return (Rect){0, 0, 0, 0};
     borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders;
     if (border_style == BS_NORMAL) {
-        result = (Rect) {border_width, 0, -(2 * border_width), -(border_width)};
+        result = (Rect){border_width, 0, -(2 * border_width), -(border_width)};
     } else {
-        result = (Rect) {border_width, border_width, -(2 * border_width), -(2 * border_width)};
+        result = (Rect){border_width, border_width, -(2 * border_width), -(2 * border_width)};
     }
 
     /* Floating windows are never adjacent to any other window, so
@@ -1266,9 +1318,15 @@ void con_set_layout(Con *con, layout_t layout) {
             new->layout = layout;
             new->last_split_layout = con->last_split_layout;
 
+            /* Save the container that was focused before we move containers
+             * around, but only if the container is visible (otherwise focus
+             * will be restored properly automatically when switching). */
             Con *old_focused = TAILQ_FIRST(&(con->focus_head));
             if (old_focused == TAILQ_END(&(con->focus_head)))
                 old_focused = NULL;
+            if (old_focused != NULL &&
+                !workspace_is_visible(con_get_workspace(old_focused)))
+                old_focused = NULL;
 
             /* 3: move the existing cons of this workspace below the new con */
             DLOG("Moving cons\n");
@@ -1387,8 +1445,15 @@ static void con_on_remove_child(Con *con) {
     if (con->type == CT_WORKSPACE) {
         if (TAILQ_EMPTY(&(con->focus_head)) && !workspace_is_visible(con)) {
             LOG("Closing old workspace (%p / %s), it is empty\n", con, con->name);
+            yajl_gen gen = ipc_marshal_workspace_event("empty", con, NULL);
             tree_close(con, DONT_KILL_WINDOW, false, false);
-            ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"empty\"}");
+
+            const unsigned char *payload;
+            ylength length;
+            y(get_buf, &payload, &length);
+            ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload);
+
+            y(free);
         }
         return;
     }
@@ -1417,7 +1482,7 @@ Rect con_minimum_size(Con *con) {
 
     if (con_is_leaf(con)) {
         DLOG("leaf node, returning 75x50\n");
-        return (Rect) {0, 0, 75, 50};
+        return (Rect){0, 0, 75, 50};
     }
 
     if (con->type == CT_FLOATING_CON) {
@@ -1437,7 +1502,7 @@ Rect con_minimum_size(Con *con) {
         }
         DLOG("stacked/tabbed now, returning %d x %d + deco_rect = %d\n",
              max_width, max_height, deco_height);
-        return (Rect) {0, 0, max_width, max_height + deco_height};
+        return (Rect){0, 0, max_width, max_height + deco_height};
     }
 
     /* For horizontal/vertical split containers we sum up the width (h-split)
@@ -1457,7 +1522,7 @@ Rect con_minimum_size(Con *con) {
             }
         }
         DLOG("split container, returning width = %d x height = %d\n", width, height);
-        return (Rect) {0, 0, width, height};
+        return (Rect){0, 0, width, height};
     }
 
     ELOG("Unhandled case, type = %d, layout = %d, split = %d\n",