summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog24
-rw-r--r--doc/how-to-get-focus-right.txt12
-rw-r--r--src/constraints.c23
-rw-r--r--src/window-props.c291
-rw-r--r--src/window.c54
5 files changed, 311 insertions, 93 deletions
diff --git a/ChangeLog b/ChangeLog
index 4c16134..e426ca8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2004-04-04 Elijah Newren <newren gmail com>
+
+ Fix lots of little issues with min/max constraints and size
+ increment constraints. Fixes #329152, #418395, and possibly
+ others.
+
+ * src/window-props.c (meta_set_normal_hints):
+ Do more checking to make sure application specified constraints
+ are self-consistent, modifying the size_hints as necessary to
+ achieve self-consistency.
+
+ * src/constraints.c (setup_constraint_info): remove ugly
+ copy-pasto, (constrain_size_increments): be careful that fixing
+ violation of the constraints doesn't cause a violation of the
+ minimum size constraints.
+
+ * src/window.c (ensure_size_hints_satisfied): new function,
+ (meta_window_unmaximize, meta_window_unmake_fullscreen): the
+ saved_rect may no longer be valid (as in the case of #329152) so
+ call ensure_size_hints_satisfied to fix it up.
+
+ * doc/how-to-get-focus-right.txt: Some minor spacing and wording
+ fixes completely unrelated to the rest of this commit
+
2007-04-03 Elijah Newren <newren gmail com>
* src/window.c (meta_window_unmaximize):
diff --git a/doc/how-to-get-focus-right.txt b/doc/how-to-get-focus-right.txt
index c7d807b..53cfa52 100644
--- a/doc/how-to-get-focus-right.txt
+++ b/doc/how-to-get-focus-right.txt
@@ -21,7 +21,6 @@ Focus method Invariant
sloppy If the mouse is in a window, then it is focused; if the
mouse is not in a window, then the most recently used
window is focused.
-
mouse If the mouse is in a non-DESKTOP window, then it is focused;
otherwise, the designated "no_focus_window" is focused
@@ -36,7 +35,6 @@ Focus method Behavior
on top)
sloppy Focus the window containing the pointer if there is such
a window, otherwise focus the most recently used window.
-
mouse Focus the non-DESKTOP window containing the pointer if
there is one, otherwise focus the designated
"no_focus_window".
@@ -66,9 +64,9 @@ cases in which a new window shouldn't be focused:
To handle these cases, Metacity compares timestamps of the event that
caused the launch and the timestamp of the last interaction with the
-focused window. (Case 2 is handled by providing a special timestamp
-of 0 for the launch time, which ensures that the window that appears
-doesn't get focus)
+focused window. (Case 2 is handled by the application providing a
+special timestamp of 0 for the launch time, which ensures that the
+window that appears doesn't get focus)
If the newly launched window isn't focused, some things should be done
to alert the user that there is a window to work with:
@@ -88,10 +86,10 @@ attempt to handle the INHERENTLY CONFLICTING CONSTRAINTS. Metacity does
this by having a mouse_mode boolean used to determine which of the two
sets of invariants holds. This mode is set according to which method was
most recently used to choose a focus window:
- 1) When receiving EnterNotify/LeaveNotify events from mouse movement, set
+ 1) When receiving EnterNotify events from mouse movement, set
mouse_mode to TRUE.
2) When using keynav to choose a focus window (e.g. alt-tab, alt-esc,
- move-window-to-workspace keybindings), set mouse_mode to FALSE.
+ alt-f2, move-window-to-workspace keybindings), set mouse_mode to FALSE.
3) When handling events that don't choose a focus window but rather need
a focus_window chosen for them (e.g. switch-to-workspace keybindings),
don't change the mouse_mode and just use the current value.
diff --git a/src/constraints.c b/src/constraints.c
index 250ca7c..8cba3bf 100644
--- a/src/constraints.c
+++ b/src/constraints.c
@@ -350,7 +350,7 @@ setup_constraint_info (ConstraintInfo *info,
else if (flags & META_IS_RESIZE_ACTION)
info->action_type = ACTION_RESIZE;
else if (flags & META_IS_MOVE_ACTION)
- info->action_type = ACTION_MOVE_AND_RESIZE;
+ info->action_type = ACTION_MOVE;
else
g_error ("BAD, BAD developer! No treat for you! (Fix your calls to "
"meta_window_move_resize_internal()).\n");
@@ -809,6 +809,7 @@ constrain_size_increments (MetaWindow *window,
gboolean check_only)
{
int bh, hi, bw, wi, extra_height, extra_width;
+ int new_width, new_height;
gboolean constraint_already_satisfied;
if (priority > PRIORITY_SIZE_HINTS_INCREMENTS)
@@ -826,10 +827,12 @@ constrain_size_increments (MetaWindow *window,
wi = window->size_hints.width_inc;
extra_height = (info->current.height - bh) % hi;
extra_width = (info->current.width - bw) % wi;
+ /* ignore size increments for maximized windows */
if (window->maximized_horizontally)
extra_width *= 0;
if (window->maximized_vertically)
extra_height *= 0;
+ /* constraint is satisfied iff there is no extra height or width */
constraint_already_satisfied =
(extra_height == 0 && extra_width == 0);
@@ -837,12 +840,24 @@ constrain_size_increments (MetaWindow *window,
return constraint_already_satisfied;
/*** Enforce constraint ***/
- /* Shrink to base + N * inc */
+ new_width = info->current.width - extra_width;
+ new_height = info->current.height - extra_height;
+
+ /* Adjusting down instead of up (as done in the above two lines) may
+ * violate minimum size constraints; fix the adjustment if this
+ * happens.
+ */
+ if (new_width < window->size_hints.min_width)
+ new_width += ((window->size_hints.min_width - new_width)/wi + 1)*wi;
+ if (new_height < window->size_hints.min_height)
+ new_height += ((window->size_hints.min_height - new_height)/hi + 1)*hi;
+
+ /* Resize to the new size */
meta_rectangle_resize_with_gravity (&info->orig,
&info->current,
info->resize_gravity,
- info->current.width - extra_width,
- info->current.height - extra_height);
+ new_width,
+ new_height);
return TRUE;
}
diff --git a/src/window-props.c b/src/window-props.c
index ff08734..8e2d1b0 100644
--- a/src/window-props.c
+++ b/src/window-props.c
@@ -909,9 +909,14 @@ spew_size_hints_differences (const XSizeHints *old,
void
meta_set_normal_hints (MetaWindow *window,
- XSizeHints *hints)
+ XSizeHints *hints)
{
int x, y, w, h;
+ double minr, maxr;
+ /* Some convenience vars */
+ int minw, minh, maxw, maxh; /* min/max width/height */
+ int basew, baseh, winc, hinc; /* base width/height, width/height increment */
+
/* Save the last ConfigureRequest, which we put here.
* Values here set in the hints are supposed to
* be ignored.
@@ -944,12 +949,13 @@ meta_set_normal_hints (MetaWindow *window,
window->size_hints.width = w;
window->size_hints.height = h;
+ /* Get base size hints */
if (window->size_hints.flags & PBaseSize)
{
meta_topic (META_DEBUG_GEOMETRY, "Window %s sets base size %d x %d\n",
- window->desc,
- window->size_hints.base_width,
- window->size_hints.base_height);
+ window->desc,
+ window->size_hints.base_width,
+ window->size_hints.base_height);
}
else if (window->size_hints.flags & PMinSize)
{
@@ -963,12 +969,13 @@ meta_set_normal_hints (MetaWindow *window,
}
window->size_hints.flags |= PBaseSize;
+ /* Get min size hints */
if (window->size_hints.flags & PMinSize)
{
meta_topic (META_DEBUG_GEOMETRY, "Window %s sets min size %d x %d\n",
- window->desc,
- window->size_hints.min_width,
- window->size_hints.min_height);
+ window->desc,
+ window->size_hints.min_width,
+ window->size_hints.min_height);
}
else if (window->size_hints.flags & PBaseSize)
{
@@ -982,12 +989,13 @@ meta_set_normal_hints (MetaWindow *window,
}
window->size_hints.flags |= PMinSize;
+ /* Get max size hints */
if (window->size_hints.flags & PMaxSize)
{
meta_topic (META_DEBUG_GEOMETRY, "Window %s sets max size %d x %d\n",
- window->desc,
- window->size_hints.max_width,
- window->size_hints.max_height);
+ window->desc,
+ window->size_hints.max_width,
+ window->size_hints.max_height);
}
else
{
@@ -996,121 +1004,248 @@ meta_set_normal_hints (MetaWindow *window,
window->size_hints.flags |= PMaxSize;
}
- if (window->size_hints.max_width < window->size_hints.min_width)
+ /* Get resize increment hints */
+ if (window->size_hints.flags & PResizeInc)
{
- /* someone is on crack */
meta_topic (META_DEBUG_GEOMETRY,
- "Window %s sets max width %d less than min width %d, disabling resize\n",
- window->desc,
- window->size_hints.max_width,
- window->size_hints.min_width);
- window->size_hints.max_width = window->size_hints.min_width;
+ "Window %s sets resize width inc: %d height inc: %d\n",
+ window->desc,
+ window->size_hints.width_inc,
+ window->size_hints.height_inc);
+ }
+ else
+ {
+ window->size_hints.width_inc = 1;
+ window->size_hints.height_inc = 1;
+ window->size_hints.flags |= PResizeInc;
}
- if (window->size_hints.max_height < window->size_hints.min_height)
+ /* Get aspect ratio hints */
+ if (window->size_hints.flags & PAspect)
{
- /* another cracksmoker */
meta_topic (META_DEBUG_GEOMETRY,
- "Window %s sets max height %d less than min height %d, disabling resize\n",
- window->desc,
- window->size_hints.max_height,
- window->size_hints.min_height);
- window->size_hints.max_height = window->size_hints.min_height;
+ "Window %s sets min_aspect: %d/%d max_aspect: %d/%d\n",
+ window->desc,
+ window->size_hints.min_aspect.x,
+ window->size_hints.min_aspect.y,
+ window->size_hints.max_aspect.x,
+ window->size_hints.max_aspect.y);
+ }
+ else
+ {
+ window->size_hints.min_aspect.x = 1;
+ window->size_hints.min_aspect.y = G_MAXINT;
+ window->size_hints.max_aspect.x = G_MAXINT;
+ window->size_hints.max_aspect.y = 1;
+ window->size_hints.flags |= PAspect;
}
+ /* Get gravity hint */
+ if (window->size_hints.flags & PWinGravity)
+ {
+ meta_topic (META_DEBUG_GEOMETRY, "Window %s sets gravity %d\n",
+ window->desc,
+ window->size_hints.win_gravity);
+ }
+ else
+ {
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Window %s doesn't set gravity, using NW\n",
+ window->desc);
+ window->size_hints.win_gravity = NorthWestGravity;
+ window->size_hints.flags |= PWinGravity;
+ }
+
+ /*** Lots of sanity checking ***/
+
+ /* Verify all min & max hints are at least 1 pixel */
if (window->size_hints.min_width < 1)
{
- /* another cracksmoker */
+ /* someone is on crack */
meta_topic (META_DEBUG_GEOMETRY,
- "Window %s sets min width to 0, which makes no sense\n",
- window->desc);
+ "Window %s sets min width to 0, which makes no sense\n",
+ window->desc);
window->size_hints.min_width = 1;
}
if (window->size_hints.max_width < 1)
{
/* another cracksmoker */
meta_topic (META_DEBUG_GEOMETRY,
- "Window %s sets max width to 0, which makes no sense\n",
- window->desc);
+ "Window %s sets max width to 0, which makes no sense\n",
+ window->desc);
window->size_hints.max_width = 1;
}
if (window->size_hints.min_height < 1)
{
/* another cracksmoker */
meta_topic (META_DEBUG_GEOMETRY,
- "Window %s sets min height to 0, which makes no sense\n",
- window->desc);
+ "Window %s sets min height to 0, which makes no sense\n",
+ window->desc);
window->size_hints.min_height = 1;
}
if (window->size_hints.max_height < 1)
{
/* another cracksmoker */
meta_topic (META_DEBUG_GEOMETRY,
- "Window %s sets max height to 0, which makes no sense\n",
- window->desc);
+ "Window %s sets max height to 0, which makes no sense\n",
+ window->desc);
window->size_hints.max_height = 1;
}
- if (window->size_hints.flags & PResizeInc)
+ /* Verify size increment hints are at least 1 pixel */
+ if (window->size_hints.width_inc < 1)
{
- meta_topic (META_DEBUG_GEOMETRY, "Window %s sets resize width inc: %d height inc: %d\n",
- window->desc,
- window->size_hints.width_inc,
- window->size_hints.height_inc);
- if (window->size_hints.width_inc == 0)
- {
- window->size_hints.width_inc = 1;
- meta_topic (META_DEBUG_GEOMETRY, "Corrected 0 width_inc to 1\n");
- }
- if (window->size_hints.height_inc == 0)
- {
- window->size_hints.height_inc = 1;
- meta_topic (META_DEBUG_GEOMETRY, "Corrected 0 height_inc to 1\n");
- }
+ /* app authors find so many ways to smoke crack */
+ window->size_hints.width_inc = 1;
+ meta_topic (META_DEBUG_GEOMETRY, "Corrected 0 width_inc to 1\n");
}
- else
+ if (window->size_hints.height_inc < 1)
{
- window->size_hints.width_inc = 1;
+ /* another cracksmoker */
window->size_hints.height_inc = 1;
- window->size_hints.flags |= PResizeInc;
+ meta_topic (META_DEBUG_GEOMETRY, "Corrected 0 height_inc to 1\n");
+ }
+ /* divide by 0 cracksmokers; note that x & y in (min|max)_aspect are
+ * numerator & denominator
+ */
+ if (window->size_hints.min_aspect.y < 1)
+ window->size_hints.min_aspect.y = 1;
+ if (window->size_hints.max_aspect.y < 1)
+ window->size_hints.max_aspect.y = 1;
+
+ minw = window->size_hints.min_width; minh = window->size_hints.min_height;
+ maxw = window->size_hints.max_width; maxh = window->size_hints.max_height;
+ basew = window->size_hints.base_width; baseh = window->size_hints.base_height;
+ winc = window->size_hints.width_inc; hinc = window->size_hints.height_inc;
+
+ /* Make sure min and max size hints are consistent with the base + increment
+ * size hints. If they're not, it's not a real big deal, but it means the
+ * effective min and max size are more restrictive than the application
+ * specified values.
+ */
+ if ((minw - basew) % winc != 0)
+ {
+ /* Take advantage of integer division throwing away the remainder... */
+ window->size_hints.min_width = basew + ((minw - basew)/winc + 1)*winc;
+
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Window %s has width_inc (%d) that does not evenly divide "
+ "min_width - base_width (%d - %d); thus effective "
+ "min_width is really %d\n",
+ window->desc,
+ winc, minw, basew, window->size_hints.min_width);
+ minw = window->size_hints.min_width;
}
+ if (maxw != G_MAXINT && (maxw - basew) % winc != 0)
+ {
+ /* Take advantage of integer division throwing away the remainder... */
+ window->size_hints.max_width = basew + ((maxw - basew)/winc)*winc;
- if (window->size_hints.flags & PAspect)
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Window %s has width_inc (%d) that does not evenly divide "
+ "max_width - base_width (%d - %d); thus effective "
+ "max_width is really %d\n",
+ window->desc,
+ winc, maxw, basew, window->size_hints.max_width);
+ maxw = window->size_hints.max_width;
+ }
+ if ((minh - baseh) % hinc != 0)
{
- meta_topic (META_DEBUG_GEOMETRY, "Window %s sets min_aspect: %d/%d max_aspect: %d/%d\n",
- window->desc,
- window->size_hints.min_aspect.x,
- window->size_hints.min_aspect.y,
- window->size_hints.max_aspect.x,
- window->size_hints.max_aspect.y);
-
- /* don't divide by 0 */
- if (window->size_hints.min_aspect.y < 1)
- window->size_hints.min_aspect.y = 1;
- if (window->size_hints.max_aspect.y < 1)
- window->size_hints.max_aspect.y = 1;
+ /* Take advantage of integer division throwing away the remainder... */
+ window->size_hints.min_height = baseh + ((minh - baseh)/hinc + 1)*hinc;
+
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Window %s has height_inc (%d) that does not evenly divide "
+ "min_height - base_height (%d - %d); thus effective "
+ "min_height is really %d\n",
+ window->desc,
+ hinc, minh, baseh, window->size_hints.min_height);
+ minh = window->size_hints.min_height;
}
- else
+ if (maxh != G_MAXINT && (maxh - baseh) % hinc != 0)
{
+ /* Take advantage of integer division throwing away the remainder... */
+ window->size_hints.max_height = baseh + ((maxh - baseh)/hinc)*hinc;
+
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Window %s has height_inc (%d) that does not evenly divide "
+ "max_height - base_height (%d - %d); thus effective "
+ "max_height is really %d\n",
+ window->desc,
+ hinc, maxh, baseh, window->size_hints.max_height);
+ maxh = window->size_hints.max_height;
+ }
+
+ /* make sure maximum size hints are compatible with minimum size hints; min
+ * size hints take precedence.
+ */
+ if (window->size_hints.max_width < window->size_hints.min_width)
+ {
+ /* another cracksmoker */
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Window %s sets max width %d less than min width %d, "
+ "disabling resize\n",
+ window->desc,
+ window->size_hints.max_width,
+ window->size_hints.min_width);
+ maxw = window->size_hints.max_width = window->size_hints.min_width;
+ }
+ if (window->size_hints.max_height < window->size_hints.min_height)
+ {
+ /* another cracksmoker */
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Window %s sets max height %d less than min height %d, "
+ "disabling resize\n",
+ window->desc,
+ window->size_hints.max_height,
+ window->size_hints.min_height);
+ maxh = window->size_hints.max_height = window->size_hints.min_height;
+ }
+
+ /* Make sure the aspect ratio hints are sane. */
+ minr = window->size_hints.min_aspect.x /
+ (double)window->size_hints.min_aspect.y;
+ maxr = window->size_hints.max_aspect.x /
+ (double)window->size_hints.max_aspect.y;
+ if (minr > maxr)
+ {
+ /* another cracksmoker; not even minimally (self) consistent */
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Window %s sets min aspect ratio larger than max aspect "
+ "ratio; disabling aspect ratio constraints.\n",
+ window->desc);
window->size_hints.min_aspect.x = 1;
window->size_hints.min_aspect.y = G_MAXINT;
window->size_hints.max_aspect.x = G_MAXINT;
window->size_hints.max_aspect.y = 1;
- window->size_hints.flags |= PAspect;
}
-
- if (window->size_hints.flags & PWinGravity)
+ else /* check consistency of aspect ratio hints with other hints */
{
- meta_topic (META_DEBUG_GEOMETRY, "Window %s sets gravity %d\n",
- window->desc,
- window->size_hints.win_gravity);
- }
- else
- {
- meta_topic (META_DEBUG_GEOMETRY, "Window %s doesn't set gravity, using NW\n",
- window->desc);
- window->size_hints.win_gravity = NorthWestGravity;
- window->size_hints.flags |= PWinGravity;
+ if (minh > 0 && minr > (maxw / (double)minh))
+ {
+ /* another cracksmoker */
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Window %s sets min aspect ratio larger than largest "
+ "aspect ratio possible given min/max size constraints; "
+ "disabling min aspect ratio constraint.\n",
+ window->desc);
+ window->size_hints.min_aspect.x = 1;
+ window->size_hints.min_aspect.y = G_MAXINT;
+ }
+ if (maxr < (minw / (double)maxh))
+ {
+ /* another cracksmoker */
+ meta_topic (META_DEBUG_GEOMETRY,
+ "Window %s sets max aspect ratio smaller than smallest "
+ "aspect ratio possible given min/max size constraints; "
+ "disabling max aspect ratio constraint.\n",
+ window->desc);
+ window->size_hints.max_aspect.x = G_MAXINT;
+ window->size_hints.max_aspect.y = 1;
+ }
+ /* FIXME: Would be nice to check that aspect ratios are
+ * consistent with base and size increment constraints.
+ */
}
}
diff --git a/src/window.c b/src/window.c
index d670b31..c00a698 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2233,6 +2233,39 @@ meta_window_unminimize (MetaWindow *window)
}
static void
+ensure_size_hints_satisfied (MetaRectangle *rect,
+ const XSizeHints *size_hints)
+{
+ int minw, minh, maxw, maxh; /* min/max width/height */
+ int basew, baseh, winc, hinc; /* base width/height, width/height increment */
+ int extra_width, extra_height;
+
+ minw = size_hints->min_width; minh = size_hints->min_height;
+ maxw = size_hints->max_width; maxh = size_hints->max_height;
+ basew = size_hints->base_width; baseh = size_hints->base_height;
+ winc = size_hints->width_inc; hinc = size_hints->height_inc;
+
+ /* First, enforce min/max size constraints */
+ rect->width = CLAMP (rect->width, minw, maxw);
+ rect->height = CLAMP (rect->height, minh, maxh);
+
+ /* Now, verify size increment constraints are satisfied, or make them be */
+ extra_width = (rect->width - basew) % winc;
+ extra_height = (rect->height - baseh) % hinc;
+
+ rect->width -= extra_width;
+ rect->height -= extra_height;
+
+ /* Adjusting width/height down, as done above, may violate minimum size
+ * constraints, so one last fix.
+ */
+ if (rect->width < minw)
+ rect->width += ((minw - rect->width)/winc + 1)*winc;
+ if (rect->height < minh)
+ rect->height += ((minh - rect->height)/hinc + 1)*hinc;
+}
+
+static void
meta_window_save_rect (MetaWindow *window)
{
if (!(META_WINDOW_MAXIMIZED (window) || window->fullscreen))
@@ -2424,6 +2457,11 @@ meta_window_unmaximize (MetaWindow *window,
target_rect.height = window->saved_rect.height;
}
+ /* Window's size hints may have changed while maximized, making
+ * saved_rect invalid. #329152
+ */
+ ensure_size_hints_satisfied (&target_rect, &window->size_hints);
+
/* When we unmaximize, if we're doing a mouse move also we could
* get the window suddenly jumping to the upper left corner of
* the workspace, since that's where it was when the grab op
@@ -2520,17 +2558,25 @@ meta_window_unmake_fullscreen (MetaWindow *window)
{
if (window->fullscreen)
{
+ MetaRectangle target_rect;
+
meta_topic (META_DEBUG_WINDOW_OPS,
"Unfullscreening %s\n", window->desc);
window->fullscreen = FALSE;
+ target_rect = window->saved_rect;
+
+ /* Window's size hints may have changed while maximized, making
+ * saved_rect invalid. #329152
+ */
+ ensure_size_hints_satisfied (&target_rect, &window->size_hints);
meta_window_move_resize (window,
FALSE,
- window->saved_rect.x,
- window->saved_rect.y,
- window->saved_rect.width,
- window->saved_rect.height);
+ target_rect.x,
+ target_rect.y,
+ target_rect.width,
+ target_rect.height);
meta_window_update_layer (window);