X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Ffloating.c;h=bfb130fbdf2b168ee9fb036e90eb75df06834429;hb=d2d6d6e0;hp=7ba7c9fb09d1353390ef924a52f43e2b58ef708d;hpb=5d89bd344fb325c2a74cf962f3f931ac274c128e;p=i3%2Fi3 diff --git a/src/floating.c b/src/floating.c index 7ba7c9fb..bfb130fb 100644 --- a/src/floating.c +++ b/src/floating.c @@ -59,13 +59,18 @@ static void floating_set_hint_atom(Con *con, bool floating) { xcb_flush(conn); } -/** - * 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. +/* + * 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 or when adjustments are needed to conform to the + * configured size increments or aspect ratio limits. + * + * When prefer_height is true and the window needs to be resized because of the + * configured aspect ratio, the width is adjusted first, preserving the previous + * height. * */ -void floating_check_size(Con *floating_con) { +void floating_check_size(Con *floating_con, bool prefer_height) { /* Define reasonable minimal and maximal sizes for floating windows */ const int floating_sane_min_height = 50; const int floating_sane_min_width = 75; @@ -83,31 +88,89 @@ void floating_check_size(Con *floating_con) { border_rect.height += render_deco_height(); } - if (focused_con->window != NULL) { - if (focused_con->window->min_width) { + i3Window *window = focused_con->window; + if (window != NULL) { + /* ICCCM says: If a base size is not provided, the minimum size is to be used in its place + * and vice versa. */ + int min_width = (window->min_width ? window->min_width : window->base_width); + int min_height = (window->min_height ? window->min_height : window->base_height); + int base_width = (window->base_width ? window->base_width : window->min_width); + int base_height = (window->base_height ? window->base_height : window->min_height); + + if (min_width) { floating_con->rect.width -= border_rect.width; - floating_con->rect.width = max(floating_con->rect.width, focused_con->window->min_width); + floating_con->rect.width = max(floating_con->rect.width, min_width); floating_con->rect.width += border_rect.width; } - if (focused_con->window->min_height) { + if (min_height) { floating_con->rect.height -= border_rect.height; - floating_con->rect.height = max(floating_con->rect.height, focused_con->window->min_height); + floating_con->rect.height = max(floating_con->rect.height, min_height); floating_con->rect.height += border_rect.height; } - if (focused_con->window->height_increment && - floating_con->rect.height >= focused_con->window->base_height + border_rect.height) { - floating_con->rect.height -= focused_con->window->base_height + border_rect.height; - floating_con->rect.height -= floating_con->rect.height % focused_con->window->height_increment; - floating_con->rect.height += focused_con->window->base_height + border_rect.height; + if (window->max_width) { + floating_con->rect.width -= border_rect.width; + floating_con->rect.width = min(floating_con->rect.width, window->max_width); + floating_con->rect.width += border_rect.width; + } + + if (window->max_height) { + floating_con->rect.height -= border_rect.height; + floating_con->rect.height = min(floating_con->rect.height, window->max_height); + floating_con->rect.height += border_rect.height; } - if (focused_con->window->width_increment && - floating_con->rect.width >= focused_con->window->base_width + border_rect.width) { - floating_con->rect.width -= focused_con->window->base_width + border_rect.width; - floating_con->rect.width -= floating_con->rect.width % focused_con->window->width_increment; - floating_con->rect.width += focused_con->window->base_width + border_rect.width; + /* Obey the aspect ratio, if any, unless we are in fullscreen mode. + * + * The spec isn’t explicit on whether the aspect ratio hints should be + * respected during fullscreen mode. Other WMs such as Openbox don’t do + * that, and this post suggests that this is the correct way to do it: + * https://mail.gnome.org/archives/wm-spec-list/2003-May/msg00007.html + * + * Ignoring aspect ratio during fullscreen was necessary to fix MPlayer + * subtitle rendering, see https://bugs.i3wm.org/594 */ + const double min_ar = window->min_aspect_ratio; + const double max_ar = window->max_aspect_ratio; + if (floating_con->fullscreen_mode == CF_NONE && (min_ar > 0 || max_ar > 0)) { + /* The ICCCM says to subtract the base size from the window size for + * aspect ratio calculations. However, unlike determining the base + * size itself we must not fall back to using the minimum size in + * this case according to the ICCCM. */ + double width = floating_con->rect.width - window->base_width - border_rect.width; + double height = floating_con->rect.height - window->base_height - border_rect.height; + const double ar = (double)width / (double)height; + double new_ar = -1; + if (min_ar > 0 && ar < min_ar) { + new_ar = min_ar; + } else if (max_ar > 0 && ar > max_ar) { + new_ar = max_ar; + } + if (new_ar > 0) { + if (prefer_height) { + width = round(height * new_ar); + height = round(width / new_ar); + } else { + height = round(width / new_ar); + width = round(height * new_ar); + } + floating_con->rect.width = width + window->base_width + border_rect.width; + floating_con->rect.height = height + window->base_height + border_rect.height; + } + } + + if (window->height_increment && + floating_con->rect.height >= base_height + border_rect.height) { + floating_con->rect.height -= base_height + border_rect.height; + floating_con->rect.height -= floating_con->rect.height % window->height_increment; + floating_con->rect.height += base_height + border_rect.height; + } + + if (window->width_increment && + floating_con->rect.width >= base_width + border_rect.width) { + floating_con->rect.width -= base_width + border_rect.width; + floating_con->rect.width -= floating_con->rect.width % window->width_increment; + floating_con->rect.width += base_width + border_rect.width; } } @@ -246,7 +309,7 @@ void floating_enable(Con *con, bool automatic) { Con *parent = con->parent; /* clear the pointer before calling tree_close_internal in which the memory is freed */ con->parent = NULL; - tree_close_internal(parent, DONT_KILL_WINDOW, false, false); + tree_close_internal(parent, DONT_KILL_WINDOW, false); } char *name; @@ -301,7 +364,7 @@ void floating_enable(Con *con, bool automatic) { nc->rect.height += con->border_width * 2; nc->rect.width += con->border_width * 2; - floating_check_size(nc); + floating_check_size(nc, false); /* Some clients (like GIMP’s color picker window) get mapped * to (0, 0), so we push them to a reasonable position @@ -349,8 +412,7 @@ void floating_enable(Con *con, bool automatic) { DLOG("Corrected y = %d (deco_height = %d)\n", nc->rect.y, deco_height); /* render the cons to get initial window_rect correct */ - render_con(nc, false); - render_con(con, false); + render_con(nc); if (set_focus) con_activate(con); @@ -366,13 +428,17 @@ void floating_disable(Con *con, bool automatic) { } Con *ws = con_get_workspace(con); + if (con_is_internal(ws)) { + LOG("Can't disable floating for container in internal workspace.\n"); + return; + } Con *tiling_focused = con_descend_tiling_focused(ws); if (tiling_focused->type == CT_WORKSPACE) { Con *parent = con->parent; con_detach(con); con->parent = NULL; - tree_close_internal(parent, DONT_KILL_WINDOW, true, false); + tree_close_internal(parent, DONT_KILL_WINDOW, true); con_attach(con, tiling_focused, false); con->percent = 0.0; con_fix_percent(con->parent); @@ -501,7 +567,7 @@ DRAGGING_CB(drag_window_callback) { con->rect.x = old_rect->x + (new_x - event->root_x); con->rect.y = old_rect->y + (new_y - event->root_y); - render_con(con, false); + render_con(con); x_push_node(con); xcb_flush(conn); @@ -595,7 +661,7 @@ DRAGGING_CB(resize_window_callback) { con->rect = (Rect){dest_x, dest_y, dest_width, dest_height}; /* Obey window size */ - floating_check_size(con); + floating_check_size(con, false); /* If not the lower right corner is grabbed, we must also reposition * the client by exactly the amount we resized it */ @@ -608,9 +674,7 @@ DRAGGING_CB(resize_window_callback) { 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 */ - tree_render(); + render_con(con); x_push_changes(croot); } @@ -744,9 +808,14 @@ static bool drain_drag_events(EV_P, struct drag_x11_cb *dragloop) { free(event); if (dragloop->result != DRAGGING) { - free(last_motion_notify); ev_break(EV_A_ EVBREAK_ONE); - return true; + if (dragloop->result == DRAG_SUCCESS) { + /* Ensure motion notify events are handled. */ + break; + } else { + free(last_motion_notify); + return true; + } } } @@ -768,7 +837,7 @@ static bool drain_drag_events(EV_P, struct drag_x11_cb *dragloop) { FREE(last_motion_notify); xcb_flush(conn); - return false; + return dragloop->result != DRAGGING; } static void xcb_drag_prepare_cb(EV_P_ ev_prepare *w, int revents) { @@ -786,8 +855,7 @@ static void xcb_drag_prepare_cb(EV_P_ ev_prepare *w, int revents) { * rect of the client, the event and the new coordinates (x, y). * */ -drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_window_t - confine_to, +drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_window_t confine_to, border_t border, int cursor, callback_t callback, const void *extra) { xcb_cursor_t xcursor = (cursor && xcursor_supported) ? xcursor_get_cursor(cursor) : XCB_NONE; @@ -879,13 +947,17 @@ bool floating_reposition(Con *con, Rect newrect) { con->rect = newrect; - floating_maybe_reassign_ws(con); + bool reassigned = 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(); + /* Workspace change will already result in a tree_render. */ + if (!reassigned) { + render_con(con); + x_push_node(con); + } return true; } @@ -896,7 +968,7 @@ bool floating_reposition(Con *con, Rect newrect) { * window's size hints. * */ -void floating_resize(Con *floating_con, int x, int y) { +void floating_resize(Con *floating_con, uint32_t x, uint32_t y) { DLOG("floating resize to %dx%d px\n", x, y); Rect *rect = &floating_con->rect; Con *focused_con = con_descend_focused(floating_con); @@ -906,6 +978,7 @@ void floating_resize(Con *floating_con, int x, int y) { } int wi = focused_con->window->width_increment; int hi = focused_con->window->height_increment; + bool prefer_height = (rect->width == x); rect->width = x; rect->height = y; if (wi) @@ -913,7 +986,7 @@ void floating_resize(Con *floating_con, int x, int y) { if (hi) rect->height += (hi - 1 - rect->height) % hi; - floating_check_size(floating_con); + floating_check_size(floating_con, prefer_height); /* If this is a scratchpad window, don't auto center it from now on. */ if (floating_con->scratchpad_state == SCRATCHPAD_FRESH)