diff options
author | Jon TURNEY <jon.turney@dronecode.org.uk> | 2012-10-30 22:39:00 +0000 |
---|---|---|
committer | Jon TURNEY <jon.turney@dronecode.org.uk> | 2012-11-21 14:02:36 +0000 |
commit | d20bbf60b5e0bbc6486d74b4648b3bcd578159a5 (patch) | |
tree | 04290f41fd06336ae62a1d79eccb9f44c389861d | |
parent | 81a3951f9062b684b0a36071207b60be691f72cb (diff) |
Add xcwm_window_constrain_sizing()
XtoQ appears to rely on the native windowing system to constrain the window size.
For Windows, the application has to do this itself. Rather than marhsalling all
WM_NORMAL_HINTS data through xcwm, just add a helper function to perform the size
constraints for WM_NORMAL_HINTS
This supports the aspect ratio constraint, which we seem to be ignoring before.
Future work: libxcwm appears to assume that WM_NORMAL_HINTS doesn't change after
the window is mapped, which doesn't seem to be guaranteed.
-rw-r--r-- | include/xcwm/context.h | 1 | ||||
-rw-r--r-- | include/xcwm/window.h | 11 | ||||
-rw-r--r-- | src/libxcwm/atoms.c | 10 | ||||
-rw-r--r-- | src/libxcwm/window.c | 147 |
4 files changed, 159 insertions, 10 deletions
diff --git a/include/xcwm/context.h b/include/xcwm/context.h index cb02d3b..ce0fbad 100644 --- a/include/xcwm/context.h +++ b/include/xcwm/context.h @@ -32,6 +32,7 @@ #include <xcb/xcb.h> #include <xcb/damage.h> +#include <xcb/xcb_icccm.h> /* Abstract types for context data types * FIXME: Move this to window.h once accessor API functions in place */ diff --git a/include/xcwm/window.h b/include/xcwm/window.h index 4890ca4..b510571 100644 --- a/include/xcwm/window.h +++ b/include/xcwm/window.h @@ -97,6 +97,7 @@ struct xcwm_window_t { xcb_damage_damage_t damage; xcwm_rect_t *bounds; xcwm_rect_t *dmg_bounds; + xcb_size_hints_t size_hints; /* WM_NORMAL_HINTS */ xcwm_window_sizing_t *sizing; /* Sizing information for the window */ char *name; /* The name of the window */ int wm_delete_set; /* Flag for WM_DELETE_WINDOW, 1 if set */ @@ -242,6 +243,16 @@ xcwm_window_sizing_t const * xcwm_window_get_sizing(xcwm_window_t const *window); /** + * Constrain height and width values according to sizing + * hints for window + * @param window The window + * @param widthp The height + * @param heightp The width + */ +void +xcwm_window_constrain_sizing(xcwm_window_t const *window, int *widthp, int *heightp); + +/** * Set the window to an iconic state. Usually this means the window * has been minimized. * @param window The window to iconify diff --git a/src/libxcwm/atoms.c b/src/libxcwm/atoms.c index a498dc7..dac552a 100644 --- a/src/libxcwm/atoms.c +++ b/src/libxcwm/atoms.c @@ -342,21 +342,13 @@ void set_window_size_hints(xcwm_window_t *window) { xcb_get_property_cookie_t cookie; - xcb_size_hints_t hints; - cookie = xcb_icccm_get_wm_normal_hints(window->context->conn, window->window_id); if (!xcb_icccm_get_wm_normal_hints_reply(window->context->conn, - cookie, &hints, NULL)) { + cookie, &(window->size_hints), NULL)) { /* Use 0 for all values (as set in calloc), or previous values */ return; } - window->sizing->min_width = hints.min_width; - window->sizing->min_height = hints.min_height;; - window->sizing->max_width = hints.max_width; - window->sizing->max_height = hints.max_height; - window->sizing->width_inc = hints.width_inc; - window->sizing->height_inc = hints.height_inc; } void diff --git a/src/libxcwm/window.c b/src/libxcwm/window.c index 40f877d..7a2aaeb 100644 --- a/src/libxcwm/window.c +++ b/src/libxcwm/window.c @@ -371,11 +371,156 @@ xcwm_window_copy_name(xcwm_window_t const *window) xcwm_window_sizing_t const * xcwm_window_get_sizing(xcwm_window_t const *window) { - + window->sizing->min_width = window->size_hints.min_width; + window->sizing->min_height = window->size_hints.min_height;; + window->sizing->max_width = window->size_hints.max_width; + window->sizing->max_height = window->size_hints.max_height; + window->sizing->width_inc = window->size_hints.width_inc; + window->sizing->height_inc = window->size_hints.height_inc; return window->sizing; } void +xcwm_window_constrain_sizing(xcwm_window_t const *window, int *widthp, int *heightp) +{ + /*/ + * (based on something taken from TWM sources) + * Respect WM_NORMAL_HINTS constraints for sizing + */ + const xcb_size_hints_t *hints = &(window->size_hints); + +#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) ) + int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta; + int baseWidth, baseHeight; + + /* Accept input values */ + int dwidth = *widthp, dheight = *heightp; + + /* Interpret hints */ + if (hints->flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) + { + minWidth = hints->min_width; + minHeight = hints->min_height; + } + else if (hints->flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) + { + minWidth = hints->base_width; + minHeight = hints->base_height; + } + else + minWidth = minHeight = 1; + + if (hints->flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) + { + baseWidth = hints->base_width; + baseHeight = hints->base_height; + } + else if (hints->flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) + { + baseWidth = hints->min_width; + baseHeight = hints->min_height; + } + else + baseWidth = baseHeight = 0; + + if (hints->flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) + { + maxWidth = hints->max_width; + maxHeight = hints->max_height; + } + else + { + maxWidth = INT_MAX; + maxHeight = INT_MAX; + } + + if (hints->flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC) + { + xinc = hints->width_inc; + yinc = hints->height_inc; + + /* Avoid divide-by-zero */ + if (xinc == 0) xinc = 1; + if (yinc == 0) yinc = 1; + } + else + xinc = yinc = 1; + + /* + * First, clamp to min and max values + */ + if (dwidth < minWidth) + dwidth = minWidth; + if (dheight < minHeight) + dheight = minHeight; + + if (dwidth > maxWidth) + dwidth = maxWidth; + if (dheight > maxHeight) + dheight = maxHeight; + + /* + * Second, fit to base + N * inc + */ + dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth; + dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight; + + /* + * Third, adjust for aspect ratio + */ + + /* + * The math looks like this: + * + * minAspectX dwidth maxAspectX + * ---------- <= ------- <= ---------- + * minAspectY dheight maxAspectY + * + * If that is multiplied out, then the width and height are + * invalid in the following situations: + * + * minAspectX * dheight > minAspectY * dwidth + * maxAspectX * dheight < maxAspectY * dwidth + * + */ + + if (hints->flags & XCB_ICCCM_SIZE_HINT_P_ASPECT) + { + if (hints->min_aspect_num * dheight > hints->min_aspect_den * dwidth) + { + delta = makemult(hints->min_aspect_num * dheight / hints->min_aspect_den - dwidth, xinc); + if (dwidth + delta <= maxWidth) + dwidth += delta; + else + { + delta = makemult(dheight - dwidth*hints->min_aspect_den/hints->min_aspect_num, yinc); + if (dheight - delta >= minHeight) + dheight -= delta; + } + } + + if (hints->max_aspect_num * dheight < hints->max_aspect_den * dwidth) + { + delta = makemult(dwidth * hints->max_aspect_den / hints->max_aspect_num - dheight, yinc); + if (dheight + delta <= maxHeight) + dheight += delta; + else + { + delta = makemult(dwidth - hints->max_aspect_num*dheight/hints->max_aspect_den, xinc); + if (dwidth - delta >= minWidth) + dwidth -= delta; + } + } + } + + /* Return computed values */ + *widthp = dwidth; + *heightp = dheight; +} +#undef makemult + + +void xcwm_window_iconify(xcwm_window_t *window) { _xcwm_atoms_set_wm_state(window, XCWM_WINDOW_STATE_ICONIC); |