]> git.sur5r.net Git - i3/i3/commitdiff
xinerama: correctly put windows which are assigned to a specific screen on that scree...
authorMichael Stapelberg <michael@stapelberg.de>
Mon, 21 Dec 2009 21:30:08 +0000 (22:30 +0100)
committerMichael Stapelberg <michael@stapelberg.de>
Mon, 21 Dec 2009 21:30:08 +0000 (22:30 +0100)
include/workspace.h
src/commands.c
src/manage.c
src/workspace.c
src/xinerama.c

index f3bdd565ad0502064282ff4f4dfc3a50c50e2201..01e1b6fae97975087682e943660aca7327d5bf16 100644 (file)
@@ -44,6 +44,17 @@ bool workspace_is_visible(Workspace *ws);
 /** Switches to the given workspace */
 void workspace_show(xcb_connection_t *conn, int workspace);
 
+/**
+ * Assigns the given workspace to the given screen by correctly updating its
+ * state and reconfiguring all the clients on this workspace.
+ *
+ * This is called when initializing a screen and when re-assigning it to a
+ * different screen which just got available (if you configured it to be on
+ * screen 1 and you just plugged in screen 1).
+ *
+ */
+void workspace_assign_to(Workspace *ws, i3Screen *screen);
+
 /**
  * Initializes the given workspace if it is not already initialized. The given
  * screen is to be understood as a fallback, if the workspace itself either
@@ -51,7 +62,7 @@ void workspace_show(xcb_connection_t *conn, int workspace);
  * the screen is not attached at the moment.
  *
  */
-void workspace_initialize(Workspace *ws, i3Screen *screen);
+void workspace_initialize(Workspace *ws, i3Screen *screen, bool recheck);
 
 /**
  * Gets the first unused workspace for the given screen, taking into account
index 7cb0bdca3f328b43f0ed50536c79e962fb62caad..32b7a398b9af84608408c76eee6a1c72023b1eb7 100644 (file)
@@ -531,7 +531,7 @@ static void move_floating_window_to_workspace(xcb_connection_t *conn, Client *cl
 
         LOG("moving floating\n");
 
-        workspace_initialize(t_ws, c_ws->screen);
+        workspace_initialize(t_ws, c_ws->screen, false);
 
         /* Check if there is already a fullscreen client on the destination workspace and
          * stop moving if so. */
@@ -592,7 +592,7 @@ static void move_current_window_to_workspace(xcb_connection_t *conn, int workspa
         if (to_focus == NULL)
                 to_focus = CIRCLEQ_PREV_OR_NULL(&(container->clients), current_client, clients);
 
-        workspace_initialize(t_ws, container->workspace->screen);
+        workspace_initialize(t_ws, container->workspace->screen, false);
         /* Check if there is already a fullscreen client on the destination workspace and
          * stop moving if so. */
         if (current_client->fullscreen && (t_ws->fullscreen_client != NULL)) {
index 54e02fe40dc8bff2054ec3bb1bffe017d318ada9..40a6f64a735670afd12baa58b0045532b7848cf1 100644 (file)
@@ -340,7 +340,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
                         DLOG("Changing container/workspace and unmapping the client\n");
                         Workspace *t_ws = workspace_get(assign->workspace-1);
-                        workspace_initialize(t_ws, c_ws->screen);
+                        workspace_initialize(t_ws, c_ws->screen, false);
 
                         new->container = t_ws->table[t_ws->current_col][t_ws->current_row];
                         new->workspace = t_ws;
index bca0544c5621eafde78ce6605cc94a6b9f36b191..f8bfcd76f06a60af7b72c2d90d7c19d24fb01d2c 100644 (file)
@@ -117,7 +117,7 @@ void workspace_show(xcb_connection_t *conn, int workspace) {
         c_ws->current_col = current_col;
 
         /* Check if the workspace has not been used yet */
-        workspace_initialize(t_ws, c_ws->screen);
+        workspace_initialize(t_ws, c_ws->screen, false);
 
         if (c_ws->screen != t_ws->screen) {
                 /* We need to switch to the other screen first */
@@ -244,6 +244,49 @@ static i3Screen *get_screen_from_preference(struct screens_head *slist, char *pr
         return NULL;
 }
 
+/*
+ * Assigns the given workspace to the given screen by correctly updating its
+ * state and reconfiguring all the clients on this workspace.
+ *
+ * This is called when initializing a screen and when re-assigning it to a
+ * different screen which just got available (if you configured it to be on
+ * screen 1 and you just plugged in screen 1).
+ *
+ */
+void workspace_assign_to(Workspace *ws, i3Screen *screen) {
+        Client *client;
+        bool empty = true;
+
+        ws->screen = screen;
+
+        /* Copy the dimensions from the virtual screen */
+        memcpy(&(ws->rect), &(ws->screen->rect), sizeof(Rect));
+
+        /* Force reconfiguration for each client on that workspace */
+        FOR_TABLE(ws)
+                CIRCLEQ_FOREACH(client, &(ws->table[cols][rows]->clients), clients) {
+                        client->force_reconfigure = true;
+                        empty = false;
+                }
+
+        if (empty)
+                return;
+
+        /* Render the workspace to reconfigure the clients. However, they will be visible now, so… */
+        render_workspace(global_conn, screen, ws);
+
+        /* …unless we want to see them at the moment, we should hide that workspace */
+        if (workspace_is_visible(ws))
+                return;
+
+        workspace_unmap_clients(global_conn, ws);
+
+        if (c_ws == ws) {
+                DLOG("Need to adjust c_ws...\n");
+                c_ws = screen->current_workspace;
+        }
+}
+
 /*
  * Initializes the given workspace if it is not already initialized. The given
  * screen is to be understood as a fallback, if the workspace itself either
@@ -251,12 +294,16 @@ static i3Screen *get_screen_from_preference(struct screens_head *slist, char *pr
  * the screen is not attached at the moment.
  *
  */
-void workspace_initialize(Workspace *ws, i3Screen *screen) {
-        if (ws->screen != NULL) {
+void workspace_initialize(Workspace *ws, i3Screen *screen, bool recheck) {
+        i3Screen *old_screen;
+
+        if (ws->screen != NULL && !recheck) {
                 DLOG("Workspace already initialized\n");
                 return;
         }
 
+        old_screen = ws->screen;
+
         /* If this workspace has no preferred screen or if the screen it wants
          * to be on is not available at the moment, we initialize it with
          * the screen which was given */
@@ -264,8 +311,12 @@ void workspace_initialize(Workspace *ws, i3Screen *screen) {
             (ws->screen = get_screen_from_preference(virtual_screens, ws->preferred_screen)) == NULL)
                 ws->screen = screen;
 
-        /* Copy the dimensions from the virtual screen */
-        memcpy(&(ws->rect), &(ws->screen->rect), sizeof(Rect));
+        DLOG("old_screen = %p, ws->screen = %p\n", old_screen, ws->screen);
+        /* If the assignment did not change, we do not need to update anything */
+        if (old_screen != NULL && ws->screen == old_screen)
+                return;
+
+        workspace_assign_to(ws, ws->screen);
 }
 
 /*
@@ -308,7 +359,7 @@ Workspace *get_first_workspace_for_screen(struct screens_head *slist, i3Screen *
                 result = workspace_get(last_ws + 1);
         }
 
-        workspace_initialize(result, screen);
+        workspace_initialize(result, screen, false);
         return result;
 }
 
index 68c90ac43bd3ee4a90dcdb413802735b7d529b30..81359ec2ba76881421bebd89effc0d42a4040498 100644 (file)
@@ -203,12 +203,14 @@ static void query_screens(xcb_connection_t *conn, struct screens_head *screenlis
                 for (int screen = 0; screen < screens; screen++) {
                         i3Screen *s = get_screen_at(screen_info[screen].x_org, screen_info[screen].y_org, screenlist);
                         if (s != NULL) {
+                                DLOG("Re-used old Xinerama screen %p\n", s);
                                 /* This screen already exists. We use the littlest screen so that the user
                                    can always see the complete workspace */
                                 s->rect.width = min(s->rect.width, screen_info[screen].width);
                                 s->rect.height = min(s->rect.height, screen_info[screen].height);
                         } else {
                                 s = calloc(sizeof(i3Screen), 1);
+                                DLOG("Created new Xinerama screen %p\n", s);
                                 s->rect.x = screen_info[screen].x_org;
                                 s->rect.y = screen_info[screen].y_org;
                                 s->rect.width = screen_info[screen].width;
@@ -331,7 +333,7 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
 
                         Rect bar_rect = {screen->rect.x,
                                          screen->rect.y + screen->rect.height - (font->height + 6),
-                                         screen->rect.x + screen->rect.width,
+                                         screen->rect.width,
                                          font->height + 6};
 
                         DLOG("configuring bar to be at %d x %d with %d x %d\n",
@@ -401,34 +403,13 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
                 if (ws->reassigned)
                         continue;
 
-                Client *client;
-
                 DLOG("Closing bar window (%p)\n", ws->screen->bar);
                 xcb_destroy_window(conn, ws->screen->bar);
 
                 DLOG("Workspace %d's screen out of bounds, assigning to first screen\n", ws->num + 1);
-                ws->screen = first;
-                memcpy(&(ws->rect), &(first->rect), sizeof(Rect));
-
-                /* Force reconfiguration for each client on that workspace */
-                FOR_TABLE(ws)
-                        CIRCLEQ_FOREACH(client, &(ws->table[cols][rows]->clients), clients)
-                                client->force_reconfigure = true;
-
-                /* Render the workspace to reconfigure the clients. However, they will be visible now, so… */
-                render_workspace(conn, first, ws);
-
-                /* …unless we want to see them at the moment, we should hide that workspace */
-                if (workspace_is_visible(ws))
-                        continue;
-
-                workspace_unmap_clients(conn, ws);
-
-                if (c_ws == ws) {
-                        DLOG("Need to adjust c_ws...\n");
-                        c_ws = first->current_workspace;
-                }
+                workspace_assign_to(ws, first);
         }
+
         xcb_flush(conn);
 
         /* Free the old list */
@@ -441,6 +422,15 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
 
         virtual_screens = new_screens;
 
+        /* Check for workspaces which need to be assigned to specific screens
+         * which may now be available */
+        TAILQ_FOREACH(ws, workspaces, workspaces) {
+                if (ws->preferred_screen == NULL)
+                        continue;
+
+                workspace_initialize(ws, ws->screen, true);
+        }
+
         DLOG("Current workspace is now: %d\n", first->current_workspace);
 
         render_layout(conn);