]> git.sur5r.net Git - i3/i3/blobdiff - src/manage.c
ipc: also send workspace event when initializing a workspace for an output
[i3/i3] / src / manage.c
index 40a6f64a735670afd12baa58b0045532b7848cf1..10cf74c7eb612279a738dd46d68633a30c85edcf 100644 (file)
@@ -3,7 +3,7 @@
  *
  * i3 - an improved dynamic tiling window manager
  *
- * © 2009 Michael Stapelberg and contributors
+ * © 2009-2010 Michael Stapelberg and contributors
  *
  * See file LICENSE for license information.
  *
@@ -31,6 +31,7 @@
 #include "client.h"
 #include "workspace.h"
 #include "log.h"
+#include "ewmh.h"
 
 /*
  * Go through all existing windows (if the window manager is restarted) and manage them
@@ -62,6 +63,28 @@ void manage_existing_windows(xcb_connection_t *conn, xcb_property_handlers_t *pr
         free(cookies);
 }
 
+/*
+ * Restores the geometry of each window by reparenting it to the root window
+ * at the position of its frame.
+ *
+ * This is to be called *only* before exiting/restarting i3 because of evil
+ * side-effects which are to be expected when continuing to run i3.
+ *
+ */
+void restore_geometry(xcb_connection_t *conn) {
+        Workspace *ws;
+        Client *client;
+        DLOG("Restoring geometry\n");
+
+        TAILQ_FOREACH(ws, workspaces, workspaces)
+                SLIST_FOREACH(client, &(ws->focus_stack), focus_clients)
+                        xcb_reparent_window(conn, client->child, root,
+                                            client->rect.x, client->rect.y);
+
+        /* Make sure our changes reach the X server, we restart/exit now */
+        xcb_flush(conn);
+}
+
 /*
  * Do some sanity checks and then reparent the window.
  *
@@ -159,7 +182,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
         LOG("Managing window 0x%08x\n", child);
         DLOG("x = %d, y = %d, width = %d, height = %d\n", x, y, width, height);
-        new = calloc(sizeof(Client), 1);
+        new = scalloc(sizeof(Client));
         new->force_reconfigure = true;
 
         /* Update the data structures */
@@ -249,12 +272,18 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                 for (int i = 0; i < xcb_get_property_value_length(preply); i++)
                         if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DOCK]) {
                                 DLOG("Window is a dock.\n");
+                                Output *t_out = get_output_containing(x, y);
+                                if (t_out != c_ws->output) {
+                                        DLOG("Dock client requested to be on output %s by geometry (%d, %d)\n",
+                                                        t_out->name, x, y);
+                                        new->workspace = t_out->current_workspace;
+                                }
                                 new->dock = true;
                                 new->borderless = true;
                                 new->titlebar_position = TITLEBAR_OFF;
                                 new->force_reconfigure = true;
                                 new->container = NULL;
-                                SLIST_INSERT_HEAD(&(c_ws->screen->dock_clients), new, dock_clients);
+                                SLIST_INSERT_HEAD(&(t_out->dock_clients), new, dock_clients);
                                 /* If it’s a dock we can’t make it float, so we break */
                                 new->floating = FLOATING_AUTO_OFF;
                                 break;
@@ -317,6 +346,29 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                 preply = xcb_get_property_reply(conn, leader_cookie, NULL);
                 handle_clientleader_change(NULL, conn, 0, new->child, atoms[WM_CLIENT_LEADER], preply);
 
+                /* if WM_CLIENT_LEADER is set, we put the new window on the
+                 * same window as its leader. This might be overwritten by
+                 * assignments afterwards. */
+                if (new->leader != XCB_NONE) {
+                        DLOG("client->leader is set (to 0x%08x)\n", new->leader);
+                        Client *parent = table_get(&by_child, new->leader);
+                        if (parent != NULL && parent->container != NULL) {
+                                Workspace *t_ws = parent->workspace;
+                                new->container = t_ws->table[parent->container->col][parent->container->row];
+                                new->workspace = t_ws;
+                                old_focused = new->container->currently_focused;
+                                map_frame = workspace_is_visible(t_ws);
+                                new->urgent = true;
+                                /* This is a little tricky: we cannot use
+                                 * workspace_update_urgent_flag() because the
+                                 * new window was not yet inserted into the
+                                 * focus stack on t_ws. */
+                                t_ws->urgent = true;
+                        } else {
+                                DLOG("parent is not usable\n");
+                        }
+                }
+
                 struct Assignment *assign;
                 TAILQ_FOREACH(assign, &assignments, assignments) {
                         if (get_matching_client(conn, assign->windowclass_title, new) == NULL)
@@ -333,14 +385,14 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                         LOG("Assignment \"%s\" matches, so putting it on workspace %d\n",
                             assign->windowclass_title, assign->workspace);
 
-                        if (c_ws->screen->current_workspace->num == (assign->workspace-1)) {
+                        if (c_ws->output->current_workspace->num == (assign->workspace-1)) {
                                 DLOG("We are already there, no need to do anything\n");
                                 break;
                         }
 
                         DLOG("Changing container/workspace and unmapping the client\n");
                         Workspace *t_ws = workspace_get(assign->workspace-1);
-                        workspace_initialize(t_ws, c_ws->screen, false);
+                        workspace_initialize(t_ws, c_ws->output, false);
 
                         new->container = t_ws->table[t_ws->current_col][t_ws->current_row];
                         new->workspace = t_ws;
@@ -354,9 +406,15 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         if (new->workspace->fullscreen_client != NULL) {
                 DLOG("Setting below fullscreen window\n");
 
-                /* If we are in fullscreen, we should lower the window to not be annoying */
-                uint32_t values[] = { XCB_STACK_MODE_BELOW };
-                xcb_configure_window(conn, new->frame, XCB_CONFIG_WINDOW_STACK_MODE, values);
+                /* If we are in fullscreen, we should place the window below
+                 * the fullscreen window to not be annoying */
+                uint32_t values[] = {
+                        new->workspace->fullscreen_client->frame,
+                        XCB_STACK_MODE_BELOW
+                };
+                xcb_configure_window(conn, new->frame,
+                                     XCB_CONFIG_WINDOW_SIBLING |
+                                     XCB_CONFIG_WINDOW_STACK_MODE, values);
         }
 
         /* Insert into the currently active container, if it’s not a dock window */
@@ -450,8 +508,10 @@ map:
                                 if (map_frame)
                                         render_container(conn, new->container);
                         }
-                        if (new->container == CUR_CELL || client_is_floating(new))
+                        if (new->container == CUR_CELL || client_is_floating(new)) {
                                 xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
+                                ewmh_update_active_window(new->child);
+                        }
                 }
         }