]> git.sur5r.net Git - i3/i3/blobdiff - src/manage.c
Bugfix: Floating: open windows at their requested position
[i3/i3] / src / manage.c
index 9a26f21424695c4817e1a2d725997fa69875cfde..bfdd9b4fa8fbfe96261aa2d4ecf8ccd718f8249f 100644 (file)
@@ -113,6 +113,7 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn, xcb_
         xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_CLASS);
         xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME);
         xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NORMAL_HINTS);
+        xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_TRANSIENT_FOR);
         xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[_NET_WM_NAME]);
 
         free(geom);
@@ -136,6 +137,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                                   utf8_title_cookie, title_cookie, class_cookie;
         uint32_t mask = 0;
         uint32_t values[3];
+        uint16_t original_height = height;
 
         /* We are interested in property changes */
         mask = XCB_CW_EVENT_MASK;
@@ -169,6 +171,10 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         new->container = CUR_CELL;
         new->workspace = new->container->workspace;
 
+        /* Minimum useful size for managed windows is 75x50 (primarily affects floating) */
+        width = max(width, 75);
+        height = max(height, 50);
+
         new->frame = xcb_generate_id(conn);
         new->child = child;
         new->rect.width = width;
@@ -235,20 +241,37 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                         1 /* left mouse button */,
                         XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
 
+        xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS,
+                        XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
+                        1 /* left mouse button */, XCB_MOD_MASK_1);
+
         /* Get _NET_WM_WINDOW_TYPE (to see if it’s a dock) */
         xcb_atom_t *atom;
         xcb_get_property_reply_t *preply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
         if (preply != NULL && preply->value_len > 0 && (atom = xcb_get_property_value(preply))) {
-                for (int i = 0; i < xcb_get_property_value_length(preply); i++) {
-                        if (atom[i] != atoms[_NET_WM_WINDOW_TYPE_DOCK])
-                                continue;
-                        LOG("Window is a dock.\n");
-                        new->dock = true;
-                        new->titlebar_position = TITLEBAR_OFF;
-                        new->force_reconfigure = true;
-                        new->container = NULL;
-                        SLIST_INSERT_HEAD(&(c_ws->screen->dock_clients), new, dock_clients);
-                }
+                for (int i = 0; i < xcb_get_property_value_length(preply); i++)
+                        if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DOCK]) {
+                                LOG("Window is a dock.\n");
+                                new->dock = true;
+                                new->titlebar_position = TITLEBAR_OFF;
+                                new->force_reconfigure = true;
+                                new->container = NULL;
+                                SLIST_INSERT_HEAD(&(c_ws->screen->dock_clients), new, dock_clients);
+                                /* If it’s a dock we can’t make it float, so we break */
+                                break;
+                        } else if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DIALOG] ||
+                                   atom[i] == atoms[_NET_WM_WINDOW_TYPE_UTILITY] ||
+                                   atom[i] == atoms[_NET_WM_WINDOW_TYPE_TOOLBAR] ||
+                                   atom[i] == atoms[_NET_WM_WINDOW_TYPE_SPLASH]) {
+                                /* Set the dialog window to automatically floating, will be used below */
+                                new->floating = FLOATING_AUTO_ON;
+                                LOG("dialog/utility/toolbar/splash window, automatically floating\n");
+                        }
+        }
+
+        if (new->workspace->auto_float) {
+                new->floating = FLOATING_AUTO_ON;
+                LOG("workspace is in autofloat mode, setting floating\n");
         }
 
         if (new->dock) {
@@ -262,13 +285,13 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                            TODO: bars at the top */
                         new->desired_height = strut[3];
                         if (new->desired_height == 0) {
-                                LOG("Client wanted to be 0 pixels high, using the window's height (%d)\n", height);
-                                new->desired_height = height;
+                                LOG("Client wanted to be 0 pixels high, using the window's height (%d)\n", original_height);
+                                new->desired_height = original_height;
                         }
                         LOG("the client wants to be %d pixels high\n", new->desired_height);
                 } else {
-                        LOG("The client didn't specify space to reserve at the screen edge, using its height (%d)\n", height);
-                        new->desired_height = height;
+                        LOG("The client didn't specify space to reserve at the screen edge, using its height (%d)\n", original_height);
+                        new->desired_height = original_height;
                 }
         } else {
                 /* If it’s not a dock, we can check on which workspace we should put it. */
@@ -292,6 +315,12 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                         if (get_matching_client(conn, assign->windowclass_title, new) == NULL)
                                 continue;
 
+                        if (assign->floating) {
+                                new->floating = FLOATING_AUTO_ON;
+                                LOG("Assignment matches, putting client into floating mode\n");
+                                break;
+                        }
+
                         LOG("Assignment \"%s\" matches, so putting it on workspace %d\n",
                             assign->windowclass_title, assign->workspace);
 
@@ -311,6 +340,8 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
                         new->container = t_ws->table[t_ws->current_col][t_ws->current_row];
                         new->workspace = t_ws;
+                        old_focused = new->container->currently_focused;
+
                         xcb_unmap_window(conn, new->frame);
                         break;
                 }
@@ -325,14 +356,15 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         } else if (!new->dock) {
                 /* Focus the new window if we’re not in fullscreen mode and if it is not a dock window */
                 if (new->container->workspace->fullscreen_client == NULL) {
-                        new->container->currently_focused = new;
+                        if (new->floating <= FLOATING_USER_OFF)
+                                new->container->currently_focused = new;
                         if (new->container == CUR_CELL)
                                 xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
                 }
         }
 
         /* Insert into the currently active container, if it’s not a dock window */
-        if (!new->dock) {
+        if (!new->dock && new->floating <= FLOATING_USER_OFF) {
                 /* Insert after the old active client, if existing. If it does not exist, the
                    container is empty and it does not matter, where we insert it */
                 if (old_focused != NULL && !old_focused->dock)
@@ -341,17 +373,29 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
                 SLIST_INSERT_HEAD(&(new->container->workspace->focus_stack), new, focus_clients);
 
-                /* Ensure that it is below all floating clients */
-                Client *first_floating;
-                SLIST_FOREACH(first_floating, &(new->container->workspace->focus_stack), focus_clients)
-                        if (first_floating->floating >= FLOATING_AUTO_ON)
-                                break;
+                client_set_below_floating(conn, new);
+        }
 
-                if (first_floating != SLIST_END(&(new->container->workspace->focus_stack))) {
-                        LOG("Setting below floating\n");
-                        uint32_t values[] = { first_floating->frame, XCB_STACK_MODE_BELOW };
-                        xcb_configure_window(conn, new->frame, XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, values);
-                }
+        if (new->floating >= FLOATING_AUTO_ON) {
+                SLIST_INSERT_HEAD(&(new->workspace->focus_stack), new, focus_clients);
+
+                /* Add the client to the list of floating clients for its workspace */
+                TAILQ_INSERT_TAIL(&(new->workspace->floating_clients), new, floating_clients);
+
+                new->container = NULL;
+
+                new->floating_rect.x = new->rect.x = x;
+                new->floating_rect.y = new->rect.y = y;
+                LOG("copying size from tiling (%d, %d) size (%d, %d)\n",
+                                new->floating_rect.x, new->floating_rect.y,
+                                new->floating_rect.width, new->floating_rect.height);
+
+                /* Make sure it is on top of the other windows */
+                xcb_raise_window(conn, new->frame);
+                reposition_client(conn, new);
+                resize_client(conn, new);
+                /* redecorate_window flushes */
+                redecorate_window(conn, new);
         }
 
         new->initialized = true;