fixed offsets when unmaximizing in most cases, prevented flickering sometimes

Offsets are now fixed for all windows that have ever been unmaximized.
Flickering is fixed for durations >=300ms, otherwise it's barely noticeable and
unfortunately not fixable.
This commit is contained in:
Tom Beckmann 2015-03-03 16:27:21 +00:00 committed by Rico Tzschichholz
parent 481da2cc71
commit e8d3b6a26b
3 changed files with 104 additions and 60 deletions

View File

@ -267,11 +267,9 @@ namespace Gala
void on_all_workspaces_changed ()
{
// we don't display windows that are on all workspaces
if (window.on_all_workspaces) {
WindowListener.get_default ().listen_on_window (window);
if (window.on_all_workspaces)
unmanaged ();
}
}
/**
* Place the window at the location of the original MetaWindow

View File

@ -20,6 +20,11 @@ using Meta;
namespace Gala
{
public struct WindowGeometry {
Meta.Rectangle inner;
Meta.Rectangle outer;
}
public class WindowListener : Object
{
static WindowListener? instance = null;
@ -34,9 +39,6 @@ namespace Gala
foreach (var actor in Compositor.get_window_actors (screen)) {
var window = actor.get_meta_window ();
if (window.on_all_workspaces)
instance.listen_on_window (window);
if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window);
}
@ -55,76 +57,77 @@ namespace Gala
public signal void window_no_longer_on_all_workspaces (Window window);
public Meta.Rectangle last_maximized_window_frame_rect;
public Meta.Rectangle last_maximized_window_buffer_rect;
Gee.List<Window> listened_windows_sticky;
Gee.HashMap<Meta.Window, WindowGeometry?> unmaximized_state_geometry;
WindowListener ()
{
listened_windows_sticky = new Gee.LinkedList<Window> ();
}
public void listen_on_window (Window window)
{
if (!window.on_all_workspaces)
return;
window.notify["on-all-workspaces"].connect (window_on_all_workspaces_changed);
window.unmanaged.connect (window_removed);
listened_windows_sticky.add (window);
}
void window_on_all_workspaces_changed (Object object, ParamSpec param)
{
var window = (Window) object;
if (window.on_all_workspaces)
return;
window.notify.disconnect (window_on_all_workspaces_changed);
window.unmanaged.disconnect (sticky_window_removed);
listened_windows_sticky.remove (window);
window_no_longer_on_all_workspaces (window);
unmaximized_state_geometry = new Gee.HashMap<Meta.Window, WindowGeometry?> ();
}
void monitor_window (Window window)
{
window.notify["maximized-horizontally"].connect (window_maximized_changed);
window.notify["maximized-vertically"].connect (window_maximized_changed);
window.notify.connect (window_notify);
window.unmanaged.connect (window_removed);
window_maximized_changed (window);
}
void window_maximized_changed (Object object, ParamSpec pspec)
void window_notify (Object object, ParamSpec pspec)
{
var window = (Window) object;
switch (pspec.name) {
case "maximized-horizontally":
case "maximized-vertically":
window_maximized_changed (window);
break;
case "on-all-workspaces":
window_on_all_workspaces_changed (window);
break;
}
}
void window_on_all_workspaces_changed (Window window)
{
if (window.on_all_workspaces)
return;
window_no_longer_on_all_workspaces (window);
}
void window_maximized_changed (Window window)
{
// we only need to save when we were unmaximized and now go maximized
if (!window.maximized_vertically || !window.maximized_horizontally)
return;
WindowGeometry window_geometry = {};
#if HAS_MUTTER312
last_maximized_window_frame_rect = window.get_frame_rect ();
window_geometry.inner = window.get_frame_rect ();
#else
last_maximized_window_frame_rect = window.get_outer_rect ();
window_geometry.inner = window.get_outer_rect ();
#endif
#if HAS_MUTTER314
last_maximized_window_buffer_rect = window.get_buffer_rect ();
window_geometry.outer = window.get_buffer_rect ();
#else
last_maximized_window_buffer_rect = window.get_input_rect ();
window_geometry.outer = window.get_input_rect ();
#endif
unmaximized_state_geometry.@set (window, window_geometry);
}
public WindowGeometry? get_unmaximized_state_geometry (Window window)
{
return unmaximized_state_geometry.@get (window);
}
void window_removed (Window window)
{
window.notify["maximized-horizontally"].disconnect (window_maximized_changed);
window.notify["maximized-vertically"].disconnect (window_maximized_changed);
window.notify.disconnect (window_notify);
window.unmanaged.disconnect (window_removed);
}
void sticky_window_removed (Window window)
{
listened_windows_sticky.remove (window);
}
}
}

View File

@ -736,9 +736,14 @@ namespace Gala
return;
}
if (actor.get_meta_window ().window_type == WindowType.NORMAL) {
var old_inner_rect = WindowListener.get_default ().last_maximized_window_frame_rect;
var old_outer_rect = WindowListener.get_default ().last_maximized_window_buffer_rect;
var window = actor.get_meta_window ();
if (window.window_type == WindowType.NORMAL) {
Meta.Rectangle fallback = { (int) actor.x, (int) actor.y, (int) actor.width, (int) actor.height };
var window_geometry = WindowListener.get_default ().get_unmaximized_state_geometry (window);
var old_inner_rect = window_geometry != null ? window_geometry.inner : fallback;
var old_outer_rect = window_geometry != null ? window_geometry.outer : fallback;
var old_actor = Utils.get_window_actor_snapshot (actor, old_inner_rect, old_outer_rect);
old_actor.set_position (old_inner_rect.x, old_inner_rect.y);
@ -761,6 +766,23 @@ namespace Gala
});
maximize_completed (actor);
// FIMXE that's a hacky part. There is a short moment right after maximized_completed
// where the texture is screwed up and shows things it's not supposed to show,
// resulting in flashing. Waiting here transparently shortly fixes that issue. There
// appears to be no signal that would inform when that moment happens.
// We can't spend arbitrary amounts of time transparent since the overlay fades away,
// about a third has proven to be a solid time. So this fix will only apply for
// durations >= FLASH_PREVENT_TIMEOUT*3
const int FLASH_PREVENT_TIMEOUT = 100;
if (FLASH_PREVENT_TIMEOUT <= duration / 3) {
actor.opacity = 0;
Timeout.add (FLASH_PREVENT_TIMEOUT, () => {
actor.opacity = 255;
return false;
});
}
actor.scale_gravity = Clutter.Gravity.NORTH_WEST;
actor.translation_x = old_inner_rect.x - ex;
actor.translation_y = old_inner_rect.y - ey;
@ -991,7 +1013,24 @@ namespace Gala
return;
}
if (actor.get_meta_window ().window_type == WindowType.NORMAL) {
var window = actor.get_meta_window ();
if (window.window_type == WindowType.NORMAL) {
float offset_x, offset_y, offset_width, offset_height;
var unmaximized_window_geometry = WindowListener.get_default ().get_unmaximized_state_geometry (window);
if (unmaximized_window_geometry != null) {
offset_x = unmaximized_window_geometry.outer.x - unmaximized_window_geometry.inner.x;
offset_y = unmaximized_window_geometry.outer.y - unmaximized_window_geometry.inner.y;
offset_width = unmaximized_window_geometry.outer.width - unmaximized_window_geometry.inner.width;
offset_height = unmaximized_window_geometry.outer.height - unmaximized_window_geometry.inner.height;
} else {
offset_x = 0;
offset_y = 0;
offset_width = 0;
offset_height = 0;
}
Meta.Rectangle old_rect = { (int) actor.x, (int) actor.y, (int) actor.width, (int) actor.height };
var old_actor = Utils.get_window_actor_snapshot (actor, old_rect, old_rect);
@ -999,22 +1038,26 @@ namespace Gala
ui_group.add_child (old_actor);
var scale_x = (double) ew / old_rect.width;
var scale_y = (double) eh / old_rect.height;
var scale_x = (double) (ew - offset_width) / old_rect.width;
var scale_y = (double) (eh - offset_height) / old_rect.height;
old_actor.animate (Clutter.AnimationMode.EASE_IN_OUT_QUAD, duration,
x: (float) ex,
y: (float) ey,
x: (float) (ex - offset_x),
y: (float) (ey - offset_y),
opacity: 0,
scale_x: scale_x,
scale_y: scale_y).completed.connect (() => {
old_actor.destroy ();
});
var maximized_x = actor.x;
var maximized_y = actor.y;
unmaximize_completed (actor);
actor.scale_gravity = Clutter.Gravity.NORTH_WEST;
actor.translation_x = -actor.x;
actor.translation_y = -actor.y;
actor.x = ex;
actor.y = ey;
actor.translation_x = -ex + offset_x * (float) (1.0 / scale_x) + maximized_x;
actor.translation_y = -ey + offset_y * (float) (1.0 / scale_y) + maximized_y;
actor.scale_x = 1.0 / scale_x;
actor.scale_y = 1.0 / scale_y;