]> git.sur5r.net Git - i3/i3/blobdiff - src/floating.c
Merge branch 'master' into next
[i3/i3] / src / floating.c
index b884a1820bbeb834853f2ea301b8e362c89adf88..643f204b64110a12aede45c4bf4b6ee9e4851f86 100644 (file)
@@ -28,6 +28,80 @@ static Rect total_outputs_dimensions(void) {
     return outputs_dimensions;
 }
 
+/**
+ * Called when a floating window is created or resized.
+ * This function resizes the window if its size is higher or lower than the
+ * configured maximum/minimum size, respectively.
+ *
+ */
+void floating_check_size(Con *floating_con) {
+    /* Define reasonable minimal and maximal sizes for floating windows */
+    const int floating_sane_min_height = 50;
+    const int floating_sane_min_width = 75;
+    Rect floating_sane_max_dimensions;
+    Con *focused_con = con_descend_focused(floating_con);
+
+    /* obey size increments */
+    if (focused_con->height_increment || focused_con->width_increment) {
+        Rect border_rect = con_border_style_rect(focused_con);
+
+        /* We have to do the opposite calculations that render_con() do
+         * to get the exact size we want. */
+        border_rect.width = -border_rect.width;
+        border_rect.width += 2 * focused_con->border_width;
+        border_rect.height = -border_rect.height;
+        border_rect.height += 2 * focused_con->border_width;
+        if (con_border_style(focused_con) == BS_NORMAL)
+            border_rect.height += render_deco_height();
+
+        if (focused_con->height_increment &&
+            floating_con->rect.height >= focused_con->base_height + border_rect.height) {
+            floating_con->rect.height -= focused_con->base_height + border_rect.height;
+            floating_con->rect.height -= floating_con->rect.height % focused_con->height_increment;
+            floating_con->rect.height += focused_con->base_height + border_rect.height;
+        }
+
+        if (focused_con->width_increment &&
+            floating_con->rect.width >= focused_con->base_width + border_rect.width) {
+            floating_con->rect.width -= focused_con->base_width + border_rect.width;
+            floating_con->rect.width -= floating_con->rect.width % focused_con->width_increment;
+            floating_con->rect.width += focused_con->base_width + border_rect.width;
+        }
+    }
+
+    /* Unless user requests otherwise (-1), ensure width/height do not exceed
+     * configured maxima or, if unconfigured, limit to combined width of all
+     * outputs */
+    if (config.floating_minimum_height != -1) {
+        if (config.floating_minimum_height == 0)
+            floating_con->rect.height = max(floating_con->rect.height, floating_sane_min_height);
+        else
+            floating_con->rect.height = max(floating_con->rect.height, config.floating_minimum_height);
+    }
+    if (config.floating_minimum_width != -1) {
+        if (config.floating_minimum_width == 0)
+            floating_con->rect.width = max(floating_con->rect.width, floating_sane_min_width);
+        else
+            floating_con->rect.width = max(floating_con->rect.width, config.floating_minimum_width);
+    }
+
+    /* Unless user requests otherwise (-1), raise the width/height to
+     * reasonable minimum dimensions */
+    floating_sane_max_dimensions = total_outputs_dimensions();
+    if (config.floating_maximum_height != -1) {
+        if (config.floating_maximum_height == 0)
+            floating_con->rect.height = min(floating_con->rect.height, floating_sane_max_dimensions.height);
+        else
+            floating_con->rect.height = min(floating_con->rect.height, config.floating_maximum_height);
+    }
+    if (config.floating_maximum_width != -1) {
+        if (config.floating_maximum_width == 0)
+            floating_con->rect.width = min(floating_con->rect.width, floating_sane_max_dimensions.width);
+        else
+            floating_con->rect.width = min(floating_con->rect.width, config.floating_maximum_width);
+    }
+}
+
 void floating_enable(Con *con, bool automatic) {
     bool set_focus = (con == focused);
 
@@ -120,7 +194,7 @@ void floating_enable(Con *con, bool automatic) {
     free(name);
 
     /* find the height for the decorations */
-    int deco_height = config.font.height + 5;
+    int deco_height = render_deco_height();
 
     DLOG("Original rect: (%d, %d) with %d x %d\n", con->rect.x, con->rect.y, con->rect.width, con->rect.height);
     DLOG("Geometry = (%d, %d) with %d x %d\n", con->geometry.x, con->geometry.y, con->geometry.width, con->geometry.height);
@@ -138,43 +212,7 @@ void floating_enable(Con *con, bool automatic) {
         }
     }
 
-    /* Define reasonable minimal and maximal sizes for floating windows */
-    const int floating_sane_min_height = 50;
-    const int floating_sane_min_width = 75;
-
-    Rect floating_sane_max_dimensions;
-    floating_sane_max_dimensions = total_outputs_dimensions();
-
-    /* Unless user requests otherwise (-1), ensure width/height do not exceed
-     * configured maxima or, if unconfigured, limit to combined width of all
-     * outputs */
-    if (config.floating_maximum_height != -1) {
-        if (config.floating_maximum_height == 0)
-            nc->rect.height = min(nc->rect.height, floating_sane_max_dimensions.height);
-        else
-            nc->rect.height = min(nc->rect.height, config.floating_maximum_height);
-    }
-    if (config.floating_maximum_width != -1) {
-        if (config.floating_maximum_width == 0)
-            nc->rect.width = min(nc->rect.width, floating_sane_max_dimensions.width);
-        else
-            nc->rect.width = min(nc->rect.width, config.floating_maximum_width);
-    }
-
-    /* Unless user requests otherwise (-1), raise the width/height to
-     * reasonable minimum dimensions */
-    if (config.floating_minimum_height != -1) {
-        if (config.floating_minimum_height == 0)
-            nc->rect.height = max(nc->rect.height, floating_sane_min_height);
-        else
-            nc->rect.height = max(nc->rect.height, config.floating_minimum_height);
-    }
-    if (config.floating_minimum_width != -1) {
-        if (config.floating_minimum_width == 0)
-            nc->rect.width = max(nc->rect.width, floating_sane_min_width);
-        else
-            nc->rect.width = max(nc->rect.width, config.floating_minimum_width);
-    }
+    floating_check_size(nc);
 
     /* 3: attach the child to the new parent container. We need to do this
      * because con_border_style_rect() needs to access con->parent. */
@@ -242,7 +280,7 @@ void floating_enable(Con *con, bool automatic) {
     /* 5: Subtract the deco_height in order to make the floating window appear
      * at precisely the position it specified in its original geometry (which
      * is what applications might remember). */
-    deco_height = (con->border_style == BS_NORMAL ? config.font.height + 5 : 0);
+    deco_height = (con->border_style == BS_NORMAL ? render_deco_height() : 0);
     nc->rect.y -= deco_height;
 
     DLOG("Corrected y = %d (deco_height = %d)\n", nc->rect.y, deco_height);
@@ -277,6 +315,8 @@ void floating_disable(Con *con, bool automatic) {
         return;
     }
 
+    const bool set_focus = (con == focused);
+
     Con *ws = con_get_workspace(con);
 
     /* 1: detach from parent container */
@@ -306,8 +346,9 @@ void floating_disable(Con *con, bool automatic) {
     con_attach(con, con->parent, false);
 
     con_fix_percent(con->parent);
-    // TODO: don’t influence focus handling when Con was not focused before.
-    con_focus(con);
+
+    if (set_focus)
+        con_focus(con);
 }
 
 /*
@@ -383,6 +424,8 @@ DRAGGING_CB(drag_window_callback) {
     /* Check if we cross workspace boundaries while moving */
     if (!floating_maybe_reassign_ws(con))
         return;
+    /* Ensure not to warp the pointer while dragging */
+    x_set_warp_to(NULL);
     tree_render();
 }
 
@@ -400,6 +443,11 @@ void floating_drag_window(Con *con, const xcb_button_press_event_t *event) {
 
     /* Drag the window */
     drag_pointer(con, event, XCB_NONE, BORDER_TOP /* irrelevant */, XCURSOR_CURSOR_MOVE, drag_window_callback, event);
+
+    /* If this is a scratchpad window, don't auto center it from now on. */
+    if (con->scratchpad_state == SCRATCHPAD_FRESH)
+        con->scratchpad_state = SCRATCHPAD_CHANGED;
+
     tree_render();
 }
 
@@ -438,26 +486,27 @@ DRAGGING_CB(resize_window_callback) {
         dest_height = old_rect->height - (new_y - event->root_y);
     else dest_height = old_rect->height + (new_y - event->root_y);
 
-    /* Obey minimum window size */
-    Rect minimum = con_minimum_size(con);
-    dest_width = max(dest_width, minimum.width);
-    dest_height = max(dest_height, minimum.height);
-
     /* User wants to keep proportions, so we may have to adjust our values */
     if (params->proportional) {
         dest_width = max(dest_width, (int) (dest_height * ratio));
         dest_height = max(dest_height, (int) (dest_width / ratio));
     }
 
+    con->rect = (Rect) { dest_x, dest_y, dest_width, dest_height };
+
+    /* Obey window size */
+    floating_check_size(con);
+
     /* If not the lower right corner is grabbed, we must also reposition
      * the client by exactly the amount we resized it */
     if (corner & BORDER_LEFT)
-        dest_x = old_rect->x + (old_rect->width - dest_width);
+        dest_x = old_rect->x + (old_rect->width - con->rect.width);
 
     if (corner & BORDER_TOP)
-        dest_y = old_rect->y + (old_rect->height - dest_height);
+        dest_y = old_rect->y + (old_rect->height - con->rect.height);
 
-    con->rect = (Rect) { dest_x, dest_y, dest_width, dest_height };
+    con->rect.x = dest_x;
+    con->rect.y = dest_y;
 
     /* TODO: don’t re-render the whole tree just because we change
      * coordinates of a floating window */
@@ -498,6 +547,10 @@ void floating_resize_window(Con *con, const bool proportional,
     struct resize_window_callback_params params = { corner, proportional, event };
 
     drag_pointer(con, event, XCB_NONE, BORDER_TOP /* irrelevant */, cursor, resize_window_callback, &params);
+
+    /* If this is a scratchpad window, don't auto center it from now on. */
+    if (con->scratchpad_state == SCRATCHPAD_FRESH)
+        con->scratchpad_state = SCRATCHPAD_CHANGED;
 }
 
 /*
@@ -609,11 +662,7 @@ void drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_window_t
 void floating_reposition(Con *con, Rect newrect) {
     /* Sanity check: Are the new coordinates on any output? If not, we
      * ignore that request. */
-    Output *output = get_output_containing(
-        newrect.x + (newrect.width / 2),
-        newrect.y + (newrect.height / 2));
-
-    if (!output) {
+    if (!contained_by_output(newrect)) {
         ELOG("No output found at destination coordinates. Not repositioning.\n");
         return;
     }
@@ -621,6 +670,11 @@ void floating_reposition(Con *con, Rect newrect) {
     con->rect = newrect;
 
     floating_maybe_reassign_ws(con);
+
+    /* If this is a scratchpad window, don't auto center it from now on. */
+    if (con->scratchpad_state == SCRATCHPAD_FRESH)
+        con->scratchpad_state = SCRATCHPAD_CHANGED;
+
     tree_render();
 }