summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon TURNEY <jon.turney@dronecode.org.uk>2012-10-30 22:39:00 +0000
committerJon TURNEY <jon.turney@dronecode.org.uk>2012-11-21 14:02:36 +0000
commitd20bbf60b5e0bbc6486d74b4648b3bcd578159a5 (patch)
tree04290f41fd06336ae62a1d79eccb9f44c389861d
parent81a3951f9062b684b0a36071207b60be691f72cb (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.h1
-rw-r--r--include/xcwm/window.h11
-rw-r--r--src/libxcwm/atoms.c10
-rw-r--r--src/libxcwm/window.c147
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);