};
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);
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 {
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);
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);
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)
{
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;
}
}
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" */
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;
- }
-#endif
+ /*
+ * "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);
- *w = MAX(*w, LAB_MIN_VIEW_WIDTH);
- *h = MAX(*h, LAB_MIN_VIEW_HEIGHT);
+ /*
+ * 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;
+ }
+ 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
#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 *
.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