[mutter] Allow breaking out from maximization during a mouse resize
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] Allow breaking out from maximization during a mouse resize
- Date: Thu, 23 Sep 2010 20:01:10 +0000 (UTC)
commit 1c3f7c408822ec55da3ea3c93d2d3b676046f2f8
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Sat Sep 18 22:28:30 2010 +0200
Allow breaking out from maximization during a mouse resize
A maximized window can't be resized from the screen edges (preserves
Fitts law goodness for the application), but it's still possible
to start a resize drag with alt-middle-button. Currently we just
don't let the user resize the window, while showing drag feedback;
it's more useful to let the user "break" out from the resize.
This provides a fast way to get a window partially aligned with
the screen edges - maximize, then alt-drag it out from one edge.
Behavior choices in this patch:
- You can drag out a window out of maximization in both directions -
smaller and larger. This can be potentilaly useful in multihead.
- Dragging a window in only one direction unmaximizes the window
fully, rather than leaving it in a horizontally/vertically
maximized state. This is done because the horizontally/vertically
maximzed states don't have clear visual representation and can
be confusing to the user.
- If you drag back to the maximized state after breaking out,
maximization is restored, but you can't maximize a window by
dragging to the full size if it didn't start out that way.
A new internal function meta_window_unmaximize_with_gravity() is
added for implementing this; it's a hybrid of
meta_window_unmaximize() and meta_window_resize_with_gravity().
Port of the metacity patch from Owen Taylor in bug 622517.
https://bugzilla.gnome.org/show_bug.cgi?id=629931
src/core/display-private.h | 3 +
src/core/display.c | 1 +
src/core/window-private.h | 5 +
src/core/window.c | 216 +++++++++++++++++++++++++++++++++++++++-----
4 files changed, 201 insertions(+), 24 deletions(-)
---
diff --git a/src/core/display-private.h b/src/core/display-private.h
index dc55338..b7a79cb 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -185,6 +185,9 @@ struct _MetaDisplay
guint grab_have_pointer : 1;
guint grab_have_keyboard : 1;
guint grab_frame_action : 1;
+ /* During a resize operation, the directions in which we've broken
+ * out of the initial maximization state */
+ guint grab_resize_unmaximize : 2; /* MetaMaximizeFlags */
MetaRectangle grab_initial_window_pos;
int grab_initial_x, grab_initial_y; /* These are only relevant for */
gboolean grab_threshold_movement_reached; /* raise_on_click == FALSE. */
diff --git a/src/core/display.c b/src/core/display.c
index 8c6b70d..c87bf11 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -3610,6 +3610,7 @@ meta_display_begin_grab_op (MetaDisplay *display,
display->grab_last_user_action_was_snap = FALSE;
#endif
display->grab_frame_action = frame_action;
+ display->grab_resize_unmaximize = 0;
if (display->grab_resize_timeout_id)
{
diff --git a/src/core/window-private.h b/src/core/window-private.h
index b2c903f..485a683 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -436,6 +436,11 @@ void meta_window_queue (MetaWindow *window,
void meta_window_maximize_internal (MetaWindow *window,
MetaMaximizeFlags directions,
MetaRectangle *saved_rect);
+void meta_window_unmaximize_with_gravity (MetaWindow *window,
+ MetaMaximizeFlags directions,
+ int new_width,
+ int new_height,
+ int gravity);
void meta_window_make_above (MetaWindow *window);
void meta_window_unmake_above (MetaWindow *window);
void meta_window_shade (MetaWindow *window,
diff --git a/src/core/window.c b/src/core/window.c
index a3c1666..d90ccf4 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -3250,9 +3250,11 @@ unmaximize_window_before_freeing (MetaWindow *window)
}
}
-void
-meta_window_unmaximize (MetaWindow *window,
- MetaMaximizeFlags directions)
+static void
+meta_window_unmaximize_internal (MetaWindow *window,
+ MetaMaximizeFlags directions,
+ MetaRectangle *desired_rect,
+ int gravity)
{
gboolean unmaximize_horizontally, unmaximize_vertically;
@@ -3297,13 +3299,13 @@ meta_window_unmaximize (MetaWindow *window,
meta_window_get_client_root_coords (window, &target_rect);
if (unmaximize_horizontally)
{
- target_rect.x = window->saved_rect.x;
- target_rect.width = window->saved_rect.width;
+ target_rect.x = desired_rect->x;
+ target_rect.width = desired_rect->width;
}
if (unmaximize_vertically)
{
- target_rect.y = window->saved_rect.y;
- target_rect.height = window->saved_rect.height;
+ target_rect.y = desired_rect->y;
+ target_rect.height = desired_rect->height;
}
/* Window's size hints may have changed while maximized, making
@@ -3317,12 +3319,13 @@ meta_window_unmaximize (MetaWindow *window,
meta_window_get_outer_rect (window, &old_rect);
- meta_window_move_resize (window,
- FALSE,
- target_rect.x,
- target_rect.y,
- target_rect.width,
- target_rect.height);
+ meta_window_move_resize_internal (window,
+ META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION,
+ gravity,
+ target_rect.x,
+ target_rect.y,
+ target_rect.width,
+ target_rect.height);
meta_window_get_outer_rect (window, &new_rect);
meta_compositor_unmaximize_window (window->display->compositor,
@@ -3332,12 +3335,13 @@ meta_window_unmaximize (MetaWindow *window,
}
else
{
- meta_window_move_resize (window,
- FALSE,
- target_rect.x,
- target_rect.y,
- target_rect.width,
- target_rect.height);
+ meta_window_move_resize_internal (window,
+ META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION,
+ gravity,
+ target_rect.x,
+ target_rect.y,
+ target_rect.width,
+ target_rect.height);
}
/* Make sure user_rect is current.
@@ -3368,6 +3372,36 @@ meta_window_unmaximize (MetaWindow *window,
}
void
+meta_window_unmaximize (MetaWindow *window,
+ MetaMaximizeFlags directions)
+{
+ meta_window_unmaximize_internal (window, directions, &window->saved_rect,
+ NorthWestGravity);
+}
+
+/* Like meta_window_unmaximize(), but instead of unmaximizing to the
+ * saved position, we give the new desired size, and the gravity that
+ * determines the positioning relationship between the area occupied
+ * maximized and the new are. The arguments are similar to
+ * meta_window_resize_with_gravity().
+ */
+void
+meta_window_unmaximize_with_gravity (MetaWindow *window,
+ MetaMaximizeFlags directions,
+ int new_width,
+ int new_height,
+ int gravity)
+{
+ MetaRectangle desired_rect;
+
+ meta_window_get_position (window, &desired_rect.x, &desired_rect.y);
+ desired_rect.width = new_width;
+ desired_rect.height = new_height;
+
+ meta_window_unmaximize_internal (window, directions, &desired_rect, gravity);
+}
+
+void
meta_window_make_above (MetaWindow *window)
{
g_return_if_fail (!window->override_redirect);
@@ -7880,6 +7914,112 @@ update_move (MetaWindow *window,
meta_window_move (window, TRUE, new_x, new_y);
}
+/* When resizing a maximized window by using alt-middle-drag (resizing
+ * with the grips or the menu for a maximized window is not enabled),
+ * the user can "break" out of the maximized state. This checks for
+ * that possibility. During such a break-out resize the user can also
+ * return to the previous maximization state by resizing back to near
+ * the original size.
+ */
+static MetaMaximizeFlags
+check_resize_unmaximize(MetaWindow *window,
+ int dx,
+ int dy)
+{
+ int threshold;
+ MetaMaximizeFlags new_unmaximize;
+
+#define DRAG_THRESHOLD_TO_RESIZE_THRESHOLD_FACTOR 3
+
+ threshold = meta_ui_get_drag_threshold (window->screen->ui) *
+ DRAG_THRESHOLD_TO_RESIZE_THRESHOLD_FACTOR;
+ new_unmaximize = 0;
+
+ if (window->maximized_horizontally ||
+ (window->display->grab_resize_unmaximize & META_MAXIMIZE_HORIZONTAL) != 0)
+ {
+ int x_amount;
+
+ /* We allow breaking out of maximization in either direction, to make
+ * the window larger than the monitor as well as smaller than the
+ * monitor. If we wanted to only allow resizing smaller than the
+ * monitor, we'd use - dx for NE/E/SE and dx for SW/W/NW.
+ */
+ switch (window->display->grab_op)
+ {
+ case META_GRAB_OP_RESIZING_NE:
+ case META_GRAB_OP_KEYBOARD_RESIZING_NE:
+ case META_GRAB_OP_RESIZING_E:
+ case META_GRAB_OP_KEYBOARD_RESIZING_E:
+ case META_GRAB_OP_RESIZING_SE:
+ case META_GRAB_OP_KEYBOARD_RESIZING_SE:
+ case META_GRAB_OP_RESIZING_SW:
+ case META_GRAB_OP_KEYBOARD_RESIZING_SW:
+ case META_GRAB_OP_RESIZING_W:
+ case META_GRAB_OP_KEYBOARD_RESIZING_W:
+ case META_GRAB_OP_RESIZING_NW:
+ case META_GRAB_OP_KEYBOARD_RESIZING_NW:
+ x_amount = dx < 0 ? - dx : dx;
+ break;
+ default:
+ x_amount = 0;
+ break;
+ }
+
+ if (x_amount > threshold)
+ new_unmaximize |= META_MAXIMIZE_HORIZONTAL;
+ }
+
+ if (window->maximized_vertically ||
+ (window->display->grab_resize_unmaximize & META_MAXIMIZE_VERTICAL) != 0)
+ {
+ int y_amount;
+
+ switch (window->display->grab_op)
+ {
+ case META_GRAB_OP_RESIZING_N:
+ case META_GRAB_OP_KEYBOARD_RESIZING_N:
+ case META_GRAB_OP_RESIZING_NE:
+ case META_GRAB_OP_KEYBOARD_RESIZING_NE:
+ case META_GRAB_OP_RESIZING_NW:
+ case META_GRAB_OP_KEYBOARD_RESIZING_NW:
+ case META_GRAB_OP_RESIZING_SE:
+ case META_GRAB_OP_KEYBOARD_RESIZING_SE:
+ case META_GRAB_OP_RESIZING_S:
+ case META_GRAB_OP_KEYBOARD_RESIZING_S:
+ case META_GRAB_OP_RESIZING_SW:
+ case META_GRAB_OP_KEYBOARD_RESIZING_SW:
+ y_amount = dy < 0 ? - dy : dy;
+ break;
+ default:
+ y_amount = 0;
+ break;
+ }
+
+ if (y_amount > threshold)
+ new_unmaximize |= META_MAXIMIZE_VERTICAL;
+ }
+
+ /* Metacity doesn't have a full user interface for only horizontally or
+ * vertically maximized, so while only unmaximizing in the direction drags
+ * has some advantages, it will also confuse the user. So, we always
+ * unmaximize both ways if possible.
+ */
+ if (new_unmaximize != 0)
+ {
+ new_unmaximize = 0;
+
+ if (window->maximized_horizontally ||
+ (window->display->grab_resize_unmaximize & META_MAXIMIZE_HORIZONTAL) != 0)
+ new_unmaximize |= META_MAXIMIZE_HORIZONTAL;
+ if (window->maximized_vertically ||
+ (window->display->grab_resize_unmaximize & META_MAXIMIZE_VERTICAL) != 0)
+ new_unmaximize |= META_MAXIMIZE_VERTICAL;
+ }
+
+ return new_unmaximize;
+}
+
static gboolean
update_resize_timeout (gpointer data)
{
@@ -7904,6 +8044,7 @@ update_resize (MetaWindow *window,
int gravity;
MetaRectangle old;
double remaining;
+ MetaMaximizeFlags new_unmaximize;
window->display->grab_latest_motion_x = x;
window->display->grab_latest_motion_y = y;
@@ -7965,6 +8106,8 @@ update_resize (MetaWindow *window,
}
}
+ new_unmaximize = check_resize_unmaximize (window, dx, dy);
+
switch (window->display->grab_op)
{
case META_GRAB_OP_RESIZING_SE:
@@ -8075,11 +8218,36 @@ update_resize (MetaWindow *window,
snap,
FALSE);
- /* We don't need to update unless the specified width and height
- * are actually different from what we had before.
- */
- if (old.width != new_w || old.height != new_h)
- meta_window_resize_with_gravity (window, TRUE, new_w, new_h, gravity);
+ if (new_unmaximize == window->display->grab_resize_unmaximize)
+ {
+ /* We don't need to update unless the specified width and height
+ * are actually different from what we had before.
+ */
+ if (old.width != new_w || old.height != new_h)
+ {
+ if ((window->display->grab_resize_unmaximize == new_unmaximize))
+ meta_window_resize_with_gravity (window, TRUE, new_w, new_h, gravity);
+ }
+ }
+ else
+ {
+ if ((new_unmaximize & ~window->display->grab_resize_unmaximize) != 0)
+ {
+ meta_window_unmaximize_with_gravity (window,
+ (new_unmaximize & ~window->display->grab_resize_unmaximize),
+ new_w, new_h, gravity);
+ }
+
+ if ((window->display->grab_resize_unmaximize & ~new_unmaximize))
+ {
+ MetaRectangle saved_rect = window->saved_rect;
+ meta_window_maximize (window,
+ (window->display->grab_resize_unmaximize & ~new_unmaximize));
+ window->saved_rect = saved_rect;
+ }
+ }
+
+ window->display->grab_resize_unmaximize = new_unmaximize;
/* Store the latest resize time, if we actually resized. */
if (window->rect.width != old.width || window->rect.height != old.height)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]