Add "size states" which save window size information

https://bugzilla.gnome.org/show_bug.cgi?id=751857
This commit is contained in:
Jasper St. Pierre 2015-06-30 22:36:23 -07:00
parent 8bded7d497
commit 2c7ef2269f
5 changed files with 177 additions and 141 deletions

View File

@ -88,6 +88,20 @@ typedef enum
META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED = 1 << 2, META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED = 1 << 2,
} MetaMoveResizeResultFlags; } MetaMoveResizeResultFlags;
/* This contains all the "state" needed for a certain size configuration.
* We have three of these size configurations: normal, tiled, and
* maximized. The idea here is that if the user tiles a normal window,
* then maximizes it, we should, upon unmaximizing and untiling the window,
* return to a normal state. We need a way of storing this information
* while maximized, so we use this structure. */
struct _MetaWindowSizeState
{
guint maximized_horizontally : 1;
guint maximized_vertically : 1;
MetaRectangle rect;
};
typedef struct _MetaWindowSizeState MetaWindowSizeState;
struct _MetaWindow struct _MetaWindow
{ {
GObject parent_instance; GObject parent_instance;
@ -393,9 +407,6 @@ struct _MetaWindow
/* The current window geometry of the window. */ /* The current window geometry of the window. */
MetaRectangle rect; MetaRectangle rect;
/* The geometry to restore when we unmaximize. */
MetaRectangle saved_rect;
/* This is the geometry the window will have if no constraints have /* This is the geometry the window will have if no constraints have
* applied. We use this whenever we are moving implicitly (for example, * applied. We use this whenever we are moving implicitly (for example,
* if we move to avoid a panel, we can snap back to this position if * if we move to avoid a panel, we can snap back to this position if
@ -435,6 +446,12 @@ struct _MetaWindow
/* Bypass compositor hints */ /* Bypass compositor hints */
guint bypass_compositor; guint bypass_compositor;
/* This is where we store data while in another state. The information
* above in MetaWindow is always the current state of the window. */
struct {
MetaWindowSizeState normal, maximized;
} size_states;
}; };
struct _MetaWindowClass struct _MetaWindowClass

View File

@ -89,8 +89,6 @@ static void meta_window_force_placement (MetaWindow *window);
static void meta_window_show (MetaWindow *window); static void meta_window_show (MetaWindow *window);
static void meta_window_hide (MetaWindow *window); static void meta_window_hide (MetaWindow *window);
static void meta_window_save_rect (MetaWindow *window);
static void ensure_mru_position_after (MetaWindow *window, static void ensure_mru_position_after (MetaWindow *window,
MetaWindow *after_this_one); MetaWindow *after_this_one);
@ -872,7 +870,7 @@ _meta_window_shared_new (MetaDisplay *display,
meta_set_normal_hints (window, NULL); meta_set_normal_hints (window, NULL);
/* And this is our unmaximized size */ /* And this is our unmaximized size */
window->saved_rect = window->rect; window->size_states.normal.rect = window->rect;
window->unconstrained_rect = window->rect; window->unconstrained_rect = window->rect;
window->depth = attrs->depth; window->depth = attrs->depth;
@ -2606,23 +2604,23 @@ ensure_size_hints_satisfied (MetaRectangle *rect,
rect->height += ((minh - rect->height)/hinc + 1)*hinc; rect->height += ((minh - rect->height)/hinc + 1)*hinc;
} }
static void static inline MetaWindowSizeState *
meta_window_save_rect (MetaWindow *window) get_current_size_state (MetaWindow *window)
{ {
if (!(META_WINDOW_MAXIMIZED (window) || window->fullscreen)) if (META_WINDOW_MAXIMIZED (window))
{ return &window->size_states.maximized;
/* save size/pos as appropriate args for move_resize */ else
if (!window->maximized_horizontally) return &window->size_states.normal;
{ }
window->saved_rect.x = window->rect.x;
window->saved_rect.width = window->rect.width; static void
} save_size_state (MetaWindow *window,
if (!window->maximized_vertically) MetaWindowSizeState *size_state,
{ MetaRectangle *saved_rect)
window->saved_rect.y = window->rect.y; {
window->saved_rect.height = window->rect.height; size_state->rect = *saved_rect;
} size_state->maximized_horizontally = window->maximized_horizontally;
} size_state->maximized_vertically = window->maximized_vertically;
} }
void void
@ -2643,10 +2641,11 @@ meta_window_maximize_internal (MetaWindow *window,
maximize_horizontally ? " horizontally" : maximize_horizontally ? " horizontally" :
maximize_vertically ? " vertically" : "BUGGGGG"); maximize_vertically ? " vertically" : "BUGGGGG");
if (saved_rect != NULL) if (!saved_rect)
window->saved_rect = *saved_rect; saved_rect = &window->rect;
else
meta_window_save_rect (window); MetaWindowSizeState *size_state = get_current_size_state (window);
save_size_state (window, size_state, saved_rect);
window->maximized_horizontally = window->maximized_horizontally =
window->maximized_horizontally || maximize_horizontally; window->maximized_horizontally || maximize_horizontally;
@ -2924,7 +2923,7 @@ unmaximize_window_before_freeing (MetaWindow *window)
if (window->withdrawn) /* See bug #137185 */ if (window->withdrawn) /* See bug #137185 */
{ {
window->rect = window->saved_rect; window->rect = window->size_states.normal.rect;
set_net_wm_state (window); set_net_wm_state (window);
} }
else if (window->screen->closing) /* See bug #358042 */ else if (window->screen->closing) /* See bug #358042 */
@ -2937,53 +2936,26 @@ unmaximize_window_before_freeing (MetaWindow *window)
* before closing it. */ * before closing it. */
meta_window_move_resize_frame (window, meta_window_move_resize_frame (window,
FALSE, FALSE,
window->saved_rect.x, window->size_states.normal.rect.x,
window->saved_rect.y, window->size_states.normal.rect.y,
window->saved_rect.width, window->size_states.normal.rect.width,
window->saved_rect.height); window->size_states.normal.rect.height);
} }
} }
void static void
meta_window_unmaximize (MetaWindow *window, meta_window_unmaximize_internal (MetaWindow *window,
MetaMaximizeFlags directions) MetaWindowSizeState *size_state)
{ {
gboolean unmaximize_horizontally, unmaximize_vertically; MetaRectangle old_frame_rect, old_buffer_rect, target_rect;
MetaRectangle new_rect;
g_return_if_fail (!window->override_redirect); g_return_if_fail (!window->override_redirect);
/* At least one of the two directions ought to be set */
unmaximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
unmaximize_vertically = directions & META_MAXIMIZE_VERTICAL;
g_assert (unmaximize_horizontally || unmaximize_vertically);
/* Only do something if the window isn't already maximized in the
* given direction(s).
*/
if ((unmaximize_horizontally && window->maximized_horizontally) ||
(unmaximize_vertically && window->maximized_vertically))
{
MetaRectangle *desired_rect;
MetaRectangle target_rect;
MetaRectangle work_area;
MetaRectangle old_frame_rect, old_buffer_rect;
meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
meta_window_get_frame_rect (window, &old_frame_rect); meta_window_get_frame_rect (window, &old_frame_rect);
meta_window_get_buffer_rect (window, &old_buffer_rect); meta_window_get_buffer_rect (window, &old_buffer_rect);
meta_topic (META_DEBUG_WINDOW_OPS, window->maximized_horizontally = size_state->maximized_horizontally;
"Unmaximizing %s%s\n", window->maximized_vertically = size_state->maximized_vertically;
window->desc,
unmaximize_horizontally && unmaximize_vertically ? "" :
unmaximize_horizontally ? " horizontally" :
unmaximize_vertically ? " vertically" : "BUGGGGG");
window->maximized_horizontally =
window->maximized_horizontally && !unmaximize_horizontally;
window->maximized_vertically =
window->maximized_vertically && !unmaximize_vertically;
/* recalc_features() will eventually clear the cached frame /* recalc_features() will eventually clear the cached frame
* extents, but we need the correct frame extents in the code below, * extents, but we need the correct frame extents in the code below,
@ -2991,44 +2963,7 @@ meta_window_unmaximize (MetaWindow *window,
*/ */
meta_window_frame_size_changed (window); meta_window_frame_size_changed (window);
desired_rect = &window->saved_rect; target_rect = size_state->rect;
/* Unmaximize to the saved_rect position in the direction(s)
* being unmaximized.
*/
target_rect = old_frame_rect;
/* Avoid unmaximizing to "almost maximized" size when the previous size
* is greater then 80% of the work area use MAX_UNMAXIMIZED_WINDOW_AREA of the work area as upper limit
* while maintaining the aspect ratio.
*/
if (unmaximize_horizontally && unmaximize_vertically &&
desired_rect->width * desired_rect->height > work_area.width * work_area.height * MAX_UNMAXIMIZED_WINDOW_AREA)
{
if (desired_rect->width > desired_rect->height)
{
float aspect = (float)desired_rect->height / (float)desired_rect->width;
desired_rect->width = MAX (work_area.width * sqrt (MAX_UNMAXIMIZED_WINDOW_AREA), window->size_hints.min_width);
desired_rect->height = MAX (desired_rect->width * aspect, window->size_hints.min_height);
}
else
{
float aspect = (float)desired_rect->width / (float)desired_rect->height;
desired_rect->height = MAX (work_area.height * sqrt (MAX_UNMAXIMIZED_WINDOW_AREA), window->size_hints.min_height);
desired_rect->width = MAX (desired_rect->height * aspect, window->size_hints.min_width);
}
}
if (unmaximize_horizontally)
{
target_rect.x = desired_rect->x;
target_rect.width = desired_rect->width;
}
if (unmaximize_vertically)
{
target_rect.y = desired_rect->y;
target_rect.height = desired_rect->height;
}
/* Window's size hints may have changed while maximized, making /* Window's size hints may have changed while maximized, making
* saved_rect invalid. #329152 * saved_rect invalid. #329152
@ -3045,7 +2980,6 @@ meta_window_unmaximize (MetaWindow *window,
NorthWestGravity, NorthWestGravity,
target_rect); target_rect);
meta_window_get_frame_rect (window, &new_rect);
meta_compositor_size_change_window (window->display->compositor, window, meta_compositor_size_change_window (window->display->compositor, window,
META_SIZE_CHANGE_UNMAXIMIZE, META_SIZE_CHANGE_UNMAXIMIZE,
&old_frame_rect, &old_buffer_rect); &old_frame_rect, &old_buffer_rect);
@ -3067,7 +3001,6 @@ meta_window_unmaximize (MetaWindow *window,
set_net_wm_state (window); set_net_wm_state (window);
if (!window->monitor->in_fullscreen) if (!window->monitor->in_fullscreen)
meta_screen_queue_check_fullscreen (window->screen); meta_screen_queue_check_fullscreen (window->screen);
}
g_object_freeze_notify (G_OBJECT (window)); g_object_freeze_notify (G_OBJECT (window));
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_HORIZONTALLY]); g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_MAXIMIZED_HORIZONTALLY]);
@ -3075,6 +3008,87 @@ meta_window_unmaximize (MetaWindow *window,
g_object_thaw_notify (G_OBJECT (window)); g_object_thaw_notify (G_OBJECT (window));
} }
void
meta_window_unmaximize (MetaWindow *window,
MetaMaximizeFlags directions)
{
gboolean unmaximize_horizontally, unmaximize_vertically;
g_return_if_fail (!window->override_redirect);
/* At least one of the two directions ought to be set */
unmaximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
unmaximize_vertically = directions & META_MAXIMIZE_VERTICAL;
g_assert (unmaximize_horizontally || unmaximize_vertically);
MetaWindowSizeState *size_state;
size_state = &window->size_states.normal;
/* Special-case unmaximizing both directions to restoring the
* last state. This makes the unmaximize buttons go back to the
* tiled state... */
if (META_WINDOW_MAXIMIZED (window) && directions == META_MAXIMIZE_BOTH)
{
meta_window_unmaximize_internal (window, size_state);
}
else if ((unmaximize_horizontally && window->maximized_horizontally) ||
(unmaximize_vertically && window->maximized_vertically))
{
MetaWindowSizeState new_size_state;
MetaRectangle *desired_rect;
MetaRectangle target_rect;
MetaRectangle work_area;
meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
new_size_state.maximized_horizontally = window->maximized_horizontally && !unmaximize_horizontally;
new_size_state.maximized_vertically = window->maximized_vertically && !unmaximize_vertically;
/* Unmaximize to the saved_rect position in the direction(s)
* being unmaximized.
*/
target_rect = window->rect;
desired_rect = &size_state->rect;
if (unmaximize_horizontally)
{
target_rect.x = desired_rect->x;
target_rect.width = desired_rect->width;
}
if (unmaximize_vertically)
{
target_rect.y = desired_rect->y;
target_rect.height = desired_rect->height;
}
/* Avoid unmaximizing to "almost maximized" size when the previous size
* is greater then 80% of the work area use MAX_UNMAXIMIZED_WINDOW_AREA of the work area as upper limit
* while maintaining the aspect ratio.
*/
if (unmaximize_horizontally && unmaximize_vertically &&
desired_rect->width * desired_rect->height > work_area.width * work_area.height * MAX_UNMAXIMIZED_WINDOW_AREA)
{
if (desired_rect->width > desired_rect->height)
{
float aspect = (float)desired_rect->height / (float)desired_rect->width;
target_rect.width = MAX (work_area.width * sqrt (MAX_UNMAXIMIZED_WINDOW_AREA), window->size_hints.min_width);
target_rect.height = MAX (desired_rect->width * aspect, window->size_hints.min_height);
}
else
{
float aspect = (float)desired_rect->width / (float)desired_rect->height;
target_rect.height = MAX (work_area.height * sqrt (MAX_UNMAXIMIZED_WINDOW_AREA), window->size_hints.min_height);
target_rect.width = MAX (desired_rect->height * aspect, window->size_hints.min_width);
}
}
new_size_state.rect = target_rect;
meta_window_unmaximize_internal (window, &new_size_state);
}
}
void void
meta_window_make_above (MetaWindow *window) meta_window_make_above (MetaWindow *window)
{ {
@ -3126,7 +3140,8 @@ meta_window_make_fullscreen_internal (MetaWindow *window)
meta_window_unshade (window, timestamp); meta_window_unshade (window, timestamp);
} }
meta_window_save_rect (window); MetaWindowSizeState *size_state = get_current_size_state (window);
save_size_state (window, size_state, &window->rect);
window->fullscreen = TRUE; window->fullscreen = TRUE;
@ -3186,7 +3201,9 @@ meta_window_unmake_fullscreen (MetaWindow *window)
"Unfullscreening %s\n", window->desc); "Unfullscreening %s\n", window->desc);
window->fullscreen = FALSE; window->fullscreen = FALSE;
target_rect = window->saved_rect;
MetaWindowSizeState *size_state = get_current_size_state (window);
target_rect = size_state->rect;
meta_window_frame_size_changed (window); meta_window_frame_size_changed (window);
meta_window_get_frame_rect (window, &old_frame_rect); meta_window_get_frame_rect (window, &old_frame_rect);
@ -3736,8 +3753,8 @@ meta_window_move_between_rects (MetaWindow *window,
window->unconstrained_rect.x = new_area->x + rel_x * scale_x; window->unconstrained_rect.x = new_area->x + rel_x * scale_x;
window->unconstrained_rect.y = new_area->y + rel_y * scale_y; window->unconstrained_rect.y = new_area->y + rel_y * scale_y;
window->saved_rect.x = window->unconstrained_rect.x; window->size_states.normal.rect.x = window->unconstrained_rect.x;
window->saved_rect.y = window->unconstrained_rect.y; window->size_states.normal.rect.y = window->unconstrained_rect.y;
meta_window_move_resize_now (window); meta_window_move_resize_now (window);
} }
@ -5532,7 +5549,7 @@ update_move (MetaWindow *window,
((double)(x - display->grab_initial_window_pos.x)) / ((double)(x - display->grab_initial_window_pos.x)) /
((double)display->grab_initial_window_pos.width); ((double)display->grab_initial_window_pos.width);
display->grab_initial_window_pos.x = x - window->saved_rect.width * prop; display->grab_initial_window_pos.x = x - window->size_states.normal.rect.width * prop;
/* If we started dragging the window from above the top of the window, /* If we started dragging the window from above the top of the window,
* pretend like we started dragging from the middle of the titlebar * pretend like we started dragging from the middle of the titlebar
@ -5544,10 +5561,10 @@ update_move (MetaWindow *window,
display->grab_anchor_root_y = display->grab_initial_window_pos.y + titlebar_rect.height / 2; display->grab_anchor_root_y = display->grab_initial_window_pos.y + titlebar_rect.height / 2;
} }
window->saved_rect.x = display->grab_initial_window_pos.x; window->size_states.normal.rect.x = display->grab_initial_window_pos.x;
window->saved_rect.y = display->grab_initial_window_pos.y; window->size_states.normal.rect.y = display->grab_initial_window_pos.y;
meta_window_unmaximize (window, META_MAXIMIZE_BOTH); meta_window_unmaximize_internal (window, &window->size_states.normal);
return; return;
} }
@ -5577,17 +5594,17 @@ update_move (MetaWindow *window,
*/ */
if (wmonitor->number != monitor) if (wmonitor->number != monitor)
{ {
window->saved_rect.x = work_area.x; window->size_states.normal.rect.x = work_area.x;
window->saved_rect.y = work_area.y; window->size_states.normal.rect.y = work_area.y;
if (window->frame) if (window->frame)
{ {
window->saved_rect.x += window->frame->child_x; window->size_states.normal.rect.x += window->frame->child_x;
window->saved_rect.y += window->frame->child_y; window->size_states.normal.rect.y += window->frame->child_y;
} }
window->unconstrained_rect.x = window->saved_rect.x; window->unconstrained_rect.x = window->size_states.normal.rect.x;
window->unconstrained_rect.y = window->saved_rect.y; window->unconstrained_rect.y = window->size_states.normal.rect.y;
meta_window_unmaximize (window, META_MAXIMIZE_BOTH); meta_window_unmaximize (window, META_MAXIMIZE_BOTH);

View File

@ -362,7 +362,9 @@ meta_window_wayland_main_monitor_changed (MetaWindow *window,
/* Window size. */ /* Window size. */
scale_rect_size (&window->rect, scale_factor); scale_rect_size (&window->rect, scale_factor);
scale_rect_size (&window->unconstrained_rect, scale_factor); scale_rect_size (&window->unconstrained_rect, scale_factor);
scale_rect_size (&window->saved_rect, scale_factor); scale_rect_size (&window->size_states.normal.rect, scale_factor);
scale_rect_size (&window->size_states.tiled.rect, scale_factor);
scale_rect_size (&window->size_states.maximized.rect, scale_factor);
/* Window geometry offset (XXX: Need a better place, see /* Window geometry offset (XXX: Need a better place, see
* meta_window_wayland_move_resize). */ * meta_window_wayland_move_resize). */

View File

@ -965,10 +965,10 @@ save_state (void)
{ {
fprintf (outfile, fprintf (outfile,
" <maximized saved_x=\"%d\" saved_y=\"%d\" saved_width=\"%d\" saved_height=\"%d\"/>\n", " <maximized saved_x=\"%d\" saved_y=\"%d\" saved_width=\"%d\" saved_height=\"%d\"/>\n",
window->saved_rect.x, window->size_states.normal.rect.x,
window->saved_rect.y, window->size_states.normal.rect.y,
window->saved_rect.width, window->size_states.normal.rect.width,
window->saved_rect.height); window->size_states.normal.rect.height);
} }
/* Gravity */ /* Gravity */

View File

@ -413,10 +413,10 @@ meta_window_apply_session_info (MetaWindow *window,
info->saved_rect.height, info->saved_rect.height,
window->desc); window->desc);
window->saved_rect.x = info->saved_rect.x; window->size_states.normal.rect.x = info->saved_rect.x;
window->saved_rect.y = info->saved_rect.y; window->size_states.normal.rect.y = info->saved_rect.y;
window->saved_rect.width = info->saved_rect.width; window->size_states.normal.rect.width = info->saved_rect.width;
window->saved_rect.height = info->saved_rect.height; window->size_states.normal.rect.height = info->saved_rect.height;
} }
} }
} }