diff --git a/include/view.h b/include/view.h index 411cbb0b..ce6a6ce9 100644 --- a/include/view.h +++ b/include/view.h @@ -37,6 +37,17 @@ enum view_edge { }; struct view; + +/* Basic size hints (subset of XSizeHints from X11) */ +struct view_size_hints { + int min_width; + int min_height; + int width_inc; + int height_inc; + int base_width; + int base_height; +}; + struct view_impl { void (*configure)(struct view *view, struct wlr_box geo); void (*close)(struct view *view); @@ -57,7 +68,7 @@ struct view_impl { void (*move_to_back)(struct view *view); struct view *(*get_root)(struct view *self); void (*append_children)(struct view *self, struct wl_array *children); - void (*fill_size_hints)(struct view *self, struct wlr_box *box); + struct view_size_hints (*get_size_hints)(struct view *self); }; struct view { @@ -306,6 +317,7 @@ void view_update_title(struct view *view); void view_update_app_id(struct view *view); void view_reload_ssd(struct view *view); +struct view_size_hints view_get_size_hints(struct view *view); void view_adjust_size(struct view *view, int *w, int *h); void view_evacuate_region(struct view *view); diff --git a/include/xwayland.h b/include/xwayland.h index b586cd6b..29c7da0c 100644 --- a/include/xwayland.h +++ b/include/xwayland.h @@ -48,8 +48,6 @@ void xwayland_view_create(struct server *server, struct wlr_xwayland_surface *xwayland_surface_from_view(struct view *view); -bool xwayland_apply_size_hints(struct view *view, int *w, int *h); - void xwayland_server_init(struct server *server, struct wlr_compositor *compositor); void xwayland_server_finish(struct server *server); diff --git a/src/ssd/resize_indicator.c b/src/ssd/resize_indicator.c index 3a41323d..d972d470 100644 --- a/src/ssd/resize_indicator.c +++ b/src/ssd/resize_indicator.c @@ -49,18 +49,6 @@ resize_indicator_init(struct view *view) resize_indicator_reconfigure_view(indicator); } -static struct wlr_box -get_size_hints(struct view *view) -{ - assert(view); - - struct wlr_box hints = { 0 }; - if (view->impl->fill_size_hints) { - view->impl->fill_size_hints(view, &hints); - } - return hints; -} - static bool wants_indicator(struct view *view) { @@ -70,8 +58,8 @@ wants_indicator(struct view *view) if (view->server->input_mode != LAB_INPUT_STATE_RESIZE) { return false; } - struct wlr_box size_hints = get_size_hints(view); - if (size_hints.width && size_hints.height) { + struct view_size_hints hints = view_get_size_hints(view); + if (hints.width_inc && hints.height_inc) { return true; } } @@ -173,10 +161,12 @@ resize_indicator_update(struct view *view) switch (view->server->input_mode) { case LAB_INPUT_STATE_RESIZE: ; /* works around "a label can only be part of a statement" */ - struct wlr_box size_hints = get_size_hints(view); + struct view_size_hints hints = view_get_size_hints(view); snprintf(text, sizeof(text), "%d x %d", - view->current.width / MAX(1, size_hints.width), - view->current.height / MAX(1, size_hints.height)); + MAX(0, view->current.width - hints.base_width) + / MAX(1, hints.width_inc), + MAX(0, view->current.height - hints.base_height) + / MAX(1, hints.height_inc)); break; case LAB_INPUT_STATE_MOVE: ; /* works around "a label can only be part of a statement" */ diff --git a/src/view.c b/src/view.c index 51798e94..d43aeafe 100644 --- a/src/view.c +++ b/src/view.c @@ -296,20 +296,68 @@ view_move_relative(struct view *view, int x, int y) view_move(view, view->pending.x + x, view->pending.y + y); } +struct view_size_hints +view_get_size_hints(struct view *view) +{ + if (view->impl->get_size_hints) { + return view->impl->get_size_hints(view); + } + return (struct view_size_hints){0}; +} + +static void +substitute_nonzero(int *a, int *b) +{ + if (!(*a)) { + *a = *b; + } else if (!(*b)) { + *b = *a; + } +} + +static int +round_to_increment(int val, int base, int inc) +{ + if (base < 0 || inc <= 0) { + return val; + } + return base + (val - base + inc / 2) / inc * inc; +} + void view_adjust_size(struct view *view, int *w, int *h) { assert(view); + struct view_size_hints hints = view_get_size_hints(view); -#if HAVE_XWAYLAND - if (xwayland_apply_size_hints(view, w, h)) { - /* We don't want to cap the size to keep the aspect ratio */ - return; + /* + * "If a base size is not provided, the minimum size is to be + * used in its place and vice versa." (ICCCM 4.1.2.3) + */ + substitute_nonzero(&hints.min_width, &hints.base_width); + substitute_nonzero(&hints.min_height, &hints.base_height); + + /* + * Snap width/height to requested size increments (if any). + * Typically, terminal emulators use these to make sure that the + * terminal is resized to a width/height evenly divisible by the + * cell (character) size. + */ + *w = round_to_increment(*w, hints.base_width, hints.width_inc); + *h = round_to_increment(*h, hints.base_height, hints.height_inc); + + /* + * If a minimum width/height was not set, then use default. + * This is currently always the case for xdg-shell views. + */ + if (hints.min_width < 1) { + hints.min_width = LAB_MIN_VIEW_WIDTH; } -#endif - - *w = MAX(*w, LAB_MIN_VIEW_WIDTH); - *h = MAX(*h, LAB_MIN_VIEW_HEIGHT); + if (hints.min_height < 1) { + hints.min_height = LAB_MIN_VIEW_HEIGHT; + } + *w = MAX(*w, hints.min_width); + *h = MAX(*h, hints.min_height); } static void diff --git a/src/xwayland.c b/src/xwayland.c index ae405311..604edfad 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -13,56 +13,21 @@ #include "workspaces.h" #include "xwayland.h" -static int -round_to_increment(int val, int base, int inc) +static struct view_size_hints +xwayland_view_get_size_hints(struct view *view) { - if (base < 0 || inc <= 0) { - return val; + xcb_size_hints_t *hints = xwayland_surface_from_view(view)->size_hints; + if (!hints) { + return (struct view_size_hints){0}; } - return base + (val - base + inc / 2) / inc * inc; -} - -bool -xwayland_apply_size_hints(struct view *view, int *w, int *h) -{ - assert(view); - if (view->type == LAB_XWAYLAND_VIEW) { - xcb_size_hints_t *hints = - xwayland_surface_from_view(view)->size_hints; - - /* - * Honor size increments from WM_SIZE_HINTS. Typically, X11 - * terminal emulators will use WM_SIZE_HINTS to make sure that - * the terminal is resized to a width/height evenly divisible by - * the cell (character) size. - */ - if (hints) { - *w = round_to_increment(*w, hints->base_width, - hints->width_inc); - *h = round_to_increment(*h, hints->base_height, - hints->height_inc); - - *w = MAX(*w, MAX(1, hints->min_width)); - *h = MAX(*h, MAX(1, hints->min_height)); - return true; - } - } - return false; -} - -static void -xwayland_view_fill_size_hints(struct view *view, struct wlr_box *box) -{ - if (view->type == LAB_XWAYLAND_VIEW) { - xcb_size_hints_t *hints = xwayland_surface_from_view(view)->size_hints; - if (hints) { - box->width = hints->width_inc; - box->height = hints->height_inc; - return; - } - } - box->width = 0; - box->height = 0; + return (struct view_size_hints){ + .min_width = hints->min_width, + .min_height = hints->min_height, + .width_inc = hints->width_inc, + .height_inc = hints->height_inc, + .base_width = hints->base_width, + .base_height = hints->base_height, + }; } static struct wlr_xwayland_surface * @@ -669,7 +634,7 @@ static const struct view_impl xwayland_view_impl = { .move_to_back = xwayland_view_move_to_back, .get_root = xwayland_view_get_root, .append_children = xwayland_view_append_children, - .fill_size_hints = xwayland_view_fill_size_hints, + .get_size_hints = xwayland_view_get_size_hints, }; void