Removed MultitaskingView folder, use get_frame_rect when available, use TiledWindow/Container for WindowOverview

This commit is contained in:
Tom Beckmann 2014-06-29 12:01:09 +02:00
parent c399e882d8
commit 74f471d029
10 changed files with 160 additions and 425 deletions

View File

@ -48,16 +48,15 @@ gala_VALASOURCES = \
Background/BackgroundManager.vala \ Background/BackgroundManager.vala \
Background/SlideShow.vala \ Background/SlideShow.vala \
Background/SystemBackground.vala \ Background/SystemBackground.vala \
Widgets/IconGroup.vala \
Widgets/IconGroupContainer.vala \
Widgets/MonitorClone.vala \
Widgets/MultitaskingView.vala \
Widgets/TiledWindow.vala \
Widgets/TiledWindowContainer.vala \
Widgets/WindowOverview.vala \ Widgets/WindowOverview.vala \
Widgets/WindowSwitcher.vala \ Widgets/WindowSwitcher.vala \
Widgets/WindowThumb.vala \ Widgets/WorkspaceClone.vala \
Widgets/MultitaskingView/IconGroup.vala \
Widgets/MultitaskingView/IconGroupContainer.vala \
Widgets/MultitaskingView/MonitorClone.vala \
Widgets/MultitaskingView/MultitaskingView.vala \
Widgets/MultitaskingView/TiledWindow.vala \
Widgets/MultitaskingView/TiledWindowContainer.vala \
Widgets/MultitaskingView/WorkspaceClone.vala \
$(NULL) $(NULL)
nodist_gala_SOURCES = \ nodist_gala_SOURCES = \

View File

@ -69,6 +69,8 @@ namespace Gala
} }
} }
public bool overview_mode { get; construct; }
DragDropAction drag_action; DragDropAction drag_action;
Clone? clone = null; Clone? clone = null;
@ -81,9 +83,9 @@ namespace Gala
Actor active_shape; Actor active_shape;
GtkClutter.Texture window_icon; GtkClutter.Texture window_icon;
public TiledWindow (Meta.Window window) public TiledWindow (Meta.Window window, bool overview_mode = false)
{ {
Object (window: window); Object (window: window, overview_mode: overview_mode);
} }
construct construct
@ -92,23 +94,23 @@ namespace Gala
window.unmanaged.connect (unmanaged); window.unmanaged.connect (unmanaged);
if (overview_mode) {
var click_action = new ClickAction ();
click_action.clicked.connect (() => {
actor_clicked (click_action.get_button ());
});
add_action (click_action);
} else {
drag_action = new DragDropAction (DragDropActionType.SOURCE, "multitaskingview-window"); drag_action = new DragDropAction (DragDropActionType.SOURCE, "multitaskingview-window");
drag_action.drag_begin.connect (drag_begin); drag_action.drag_begin.connect (drag_begin);
drag_action.destination_crossed.connect (drag_destination_crossed); drag_action.destination_crossed.connect (drag_destination_crossed);
drag_action.drag_end.connect (drag_end); drag_action.drag_end.connect (drag_end);
drag_action.drag_canceled.connect (drag_canceled); drag_action.drag_canceled.connect (drag_canceled);
drag_action.actor_clicked.connect ((button) => { drag_action.actor_clicked.connect (actor_clicked);
switch (button) {
case 1:
selected ();
break;
case 2:
close_window ();
break;
}
});
add_action (drag_action); add_action (drag_action);
}
close_button = Utils.create_close_button (); close_button = Utils.create_close_button ();
close_button.opacity = 0; close_button.opacity = 0;
@ -180,6 +182,9 @@ namespace Gala
return; return;
} }
if (overview_mode)
actor.hide ();
clone = new Clone (actor.get_texture ()); clone = new Clone (actor.get_texture ());
add_child (clone); add_child (clone);
@ -189,7 +194,11 @@ namespace Gala
transition_to_original_state (false); transition_to_original_state (false);
#if HAS_MUTTER312
var outer_rect = window.get_frame_rect ();
#else
var outer_rect = window.get_outer_rect (); var outer_rect = window.get_outer_rect ();
#endif
add_effect_with_name ("shadow", new ShadowEffect (outer_rect.width, outer_rect.height, 40, 5)); add_effect_with_name ("shadow", new ShadowEffect (outer_rect.width, outer_rect.height, 40, 5));
#if HAS_MUTTER312 #if HAS_MUTTER312
window.size_changed.connect (update_shadow_size); window.size_changed.connect (update_shadow_size);
@ -197,6 +206,9 @@ namespace Gala
actor.size_changed.connect (update_shadow_size); actor.size_changed.connect (update_shadow_size);
#endif #endif
if (should_fade ())
opacity = 0;
// if we were waiting the view was most probably already opened when our window // if we were waiting the view was most probably already opened when our window
// finally got available. So we fade-in and make sure we took the took place. // finally got available. So we fade-in and make sure we took the took place.
// If the slot is not available however, the view was probably closed while this // If the slot is not available however, the view was probably closed while this
@ -210,6 +222,16 @@ namespace Gala
} }
} }
/**
* If we are in overview mode, we may display windows from workspaces other than
* the current one. To ease their appearance we have to fade them in.
*/
bool should_fade ()
{
return overview_mode
&& window.get_workspace () != window.get_screen ().get_active_workspace ();
}
/** /**
* Sets a timeout of 500ms after which, if no new resize action reset it, * Sets a timeout of 500ms after which, if no new resize action reset it,
* the shadow will be resized and a request_reposition() will be emitted to * the shadow will be resized and a request_reposition() will be emitted to
@ -221,7 +243,11 @@ namespace Gala
Source.remove (shadow_update_timeout); Source.remove (shadow_update_timeout);
shadow_update_timeout = Timeout.add (500, () => { shadow_update_timeout = Timeout.add (500, () => {
#if HAS_MUTTER312
var rect = window.get_frame_rect ();
#else
var rect = window.get_outer_rect (); var rect = window.get_outer_rect ();
#endif
var effect = get_effect ("shadow") as ShadowEffect; var effect = get_effect ("shadow") as ShadowEffect;
effect.update_size (rect.width, rect.height); effect.update_size (rect.width, rect.height);
@ -241,13 +267,24 @@ namespace Gala
*/ */
public void transition_to_original_state (bool animate) public void transition_to_original_state (bool animate)
{ {
#if HAS_MUTTER312
var outer_rect = window.get_frame_rect ();
#else
var outer_rect = window.get_outer_rect (); var outer_rect = window.get_outer_rect ();
#endif
float offset_x = 0, offset_y = 0; float offset_x = 0, offset_y = 0;
var parent = get_parent (); var parent = get_parent ();
if (parent != null) if (parent != null) {
// in overview_mode the parent has just been added to the stage, so the
// transforme position is not set yet. However, the set position is correct
// for overview anyway, so we can just use that.
if (overview_mode)
parent.get_position (out offset_x, out offset_y);
else
parent.get_transformed_position (out offset_x, out offset_y); parent.get_transformed_position (out offset_x, out offset_y);
}
set_easing_mode (AnimationMode.EASE_IN_OUT_CUBIC); set_easing_mode (AnimationMode.EASE_IN_OUT_CUBIC);
set_easing_duration (animate ? 300 : 0); set_easing_duration (animate ? 300 : 0);
@ -256,6 +293,9 @@ namespace Gala
set_size (outer_rect.width, outer_rect.height); set_size (outer_rect.width, outer_rect.height);
window_icon.opacity = 0; window_icon.opacity = 0;
if (should_fade ())
opacity = 0;
} }
/** /**
@ -272,6 +312,17 @@ namespace Gala
set_position (rect.x, rect.y); set_position (rect.x, rect.y);
window_icon.opacity = 255; window_icon.opacity = 255;
// for overview mode, windows may be faded out initially. Make sure
// to fade those in.
if (overview_mode) {
save_easing_state ();
set_easing_mode (AnimationMode.EASE_OUT_QUAD);
set_easing_duration (300);
opacity = 255;
restore_easing_state ();
}
} }
/** /**
@ -305,7 +356,11 @@ namespace Gala
#else #else
var input_rect = window.get_input_rect (); var input_rect = window.get_input_rect ();
#endif #endif
#if HAS_MUTTER312
var outer_rect = window.get_frame_rect ();
#else
var outer_rect = window.get_outer_rect (); var outer_rect = window.get_outer_rect ();
#endif
var scale_factor = (float)width / outer_rect.width; var scale_factor = (float)width / outer_rect.width;
var shadow_effect = get_effect ("shadow") as ShadowEffect; var shadow_effect = get_effect ("shadow") as ShadowEffect;
@ -397,6 +452,17 @@ namespace Gala
destroy (); destroy ();
} }
void actor_clicked (uint32 button) {
switch (button) {
case 1:
selected ();
break;
case 2:
close_window ();
break;
}
}
/** /**
* A drag action has been initiated on us, we reparent ourselves to the stage so * A drag action has been initiated on us, we reparent ourselves to the stage so
* we can move freely, scale ourselves to a smaller scale and request that the * we can move freely, scale ourselves to a smaller scale and request that the

View File

@ -32,6 +32,8 @@ namespace Gala
public int padding_right { get; set; default = 12; } public int padding_right { get; set; default = 12; }
public int padding_bottom { get; set; default = 12; } public int padding_bottom { get; set; default = 12; }
public bool overview_mode { get; construct; }
bool opened; bool opened;
/** /**
@ -40,8 +42,9 @@ namespace Gala
*/ */
TiledWindow? current_window; TiledWindow? current_window;
public TiledWindowContainer () public TiledWindowContainer (bool overview_mode = false)
{ {
Object (overview_mode: overview_mode);
} }
construct construct
@ -70,7 +73,7 @@ namespace Gala
var windows_ordered = display.sort_windows_by_stacking (windows); var windows_ordered = display.sort_windows_by_stacking (windows);
var new_window = new TiledWindow (window); var new_window = new TiledWindow (window, overview_mode);
new_window.selected.connect (window_selected_cb); new_window.selected.connect (window_selected_cb);
new_window.destroy.connect (window_destroyed); new_window.destroy.connect (window_destroyed);
@ -180,13 +183,25 @@ namespace Gala
var windows = new List<InternalUtils.TilableWindow?> (); var windows = new List<InternalUtils.TilableWindow?> ();
foreach (var child in get_children ()) { foreach (var child in get_children ()) {
unowned TiledWindow window = (TiledWindow) child; unowned TiledWindow window = (TiledWindow) child;
#if HAS_MUTTER312
windows.prepend ({ window.window.get_frame_rect (), window });
#else
windows.prepend ({ window.window.get_outer_rect (), window }); windows.prepend ({ window.window.get_outer_rect (), window });
#endif
} }
windows.reverse ();
if (windows.length () < 1) if (windows.length () < 1)
return; return;
// make sure the windows are always in the same order so the algorithm
// doesn't give us different slots based on stacking order, which can lead
// to windows flying around weirdly
windows.sort ((a, b) => {
var seq_a = ((TiledWindow) a.id).window.get_stable_sequence ();
var seq_b = ((TiledWindow) b.id).window.get_stable_sequence ();
return (int) (seq_b - seq_a);
});
Meta.Rectangle area = { Meta.Rectangle area = {
padding_left, padding_left,
padding_top, padding_top,

View File

@ -43,14 +43,13 @@ namespace Gala
// the workspaces which we expose right now // the workspaces which we expose right now
List<Workspace> workspaces; List<Workspace> workspaces;
static const int PADDING = 50;
public WindowOverview (WindowManager _wm) public WindowOverview (WindowManager _wm)
{ {
wm = _wm; wm = _wm;
screen = wm.get_screen (); screen = wm.get_screen ();
screen.workspace_switched.connect (() => close (false)); screen.workspace_switched.connect (() => close (false));
screen.restacked.connect (restack_windows);
visible = false; visible = false;
ready = true; ready = true;
@ -59,11 +58,7 @@ namespace Gala
public override bool key_press_event (Clutter.KeyEvent event) public override bool key_press_event (Clutter.KeyEvent event)
{ {
//FIXME need to figure out the actual keycombo, for now leave it by if (event.keyval == Clutter.Key.Escape) {
// default and others will close it by selecting a window!
if (event.keyval == Clutter.Key.w ||
event.keyval == Clutter.Key.a ||
event.keyval == Clutter.Key.Escape) {
close (true); close (true);
return true; return true;
@ -85,86 +80,6 @@ namespace Gala
return true; return true;
} }
void calculate_places (List<Actor> windows)
{
var clones = windows.copy ();
clones.sort ((a, b) => {
return (int)(a as WindowThumb).window.get_stable_sequence () -
(int)(b as WindowThumb).window.get_stable_sequence ();
});
// sort windows by monitor
List<InternalUtils.TilableWindow?>[] monitors = {};
monitors.resize (screen.get_n_monitors ());
foreach (var clone in clones) {
// we had some crashes here so there's a reasonable suspicion
// that get_monitor() could be larger than get_n_monitors()
var thumb = clone as WindowThumb;
var index = thumb.window.get_monitor ();
if (index >= screen.get_n_monitors ()) {
critical ("Window '%s' has a monitor assigned that does not actually exists",
(clone as WindowThumb).window.get_title ());
index = screen.get_n_monitors () - 1;
}
monitors[index].append ({ thumb.window.get_outer_rect (), thumb });
}
for (var i = 0; i < screen.get_n_monitors (); i++) {
if (monitors[i].length () == 0)
continue;
// get the area used by the expo algorithms together
var geom = screen.get_monitor_geometry (i);
Meta.Rectangle area = {(int)Math.floorf (geom.x + BORDER),
(int)Math.floorf (geom.y + TOP_GAP),
(int)Math.floorf (geom.width - BORDER * 2),
(int)Math.floorf (geom.height - BOTTOM_GAP)};
/*TODO if (BehaviorSettings.get_default ().schema.get_enum ("window-overview-type") == WindowOverviewType.GRID)
grid_placement (area, monitors[i], place_window);
else
natural_placement (area, monitors[i]);*/
var result = InternalUtils.calculate_grid_placement (area, monitors[i]);
foreach (var window in result) {
place_window ((WindowThumb)window.id, window.rect);
}
}
}
// animate a window to the given position
void place_window (WindowThumb clone, Meta.Rectangle rect)
{
var fscale = rect.width / clone.width;
//animate the windows and icons to the calculated positions
clone.icon.x = rect.x + Math.floorf (clone.width * fscale / 2.0f - clone.icon.width / 2.0f);
clone.icon.y = rect.y + Math.floorf (clone.height * fscale - 50.0f);
clone.icon.get_parent ().set_child_above_sibling (clone.icon, null);
float offset_x, offset_y, offset_width;
Utils.get_window_frame_offset (clone.window, out offset_x, out offset_y, out offset_width, null);
float button_offset = clone.close_button.width * 0.25f;
Granite.CloseButtonPosition pos;
Granite.Widgets.Utils.get_default_close_button_position (out pos);
switch (pos) {
case Granite.CloseButtonPosition.LEFT:
clone.close_button.x = rect.x - offset_x * fscale - button_offset;
break;
case Granite.CloseButtonPosition.RIGHT:
clone.close_button.x = rect.x + rect.width - offset_width * fscale - clone.close_button.width / 2;
break;
}
clone.close_button.y = rect.y - offset_y * fscale - button_offset;
clone.animate (Clutter.AnimationMode.EASE_OUT_CUBIC, 250, scale_x:fscale, scale_y:fscale, x:rect.x+0.0f, y:rect.y+0.0f)
.completed.connect (() => ready = true );
clone.icon.opacity = 0;
clone.icon.animate (Clutter.AnimationMode.EASE_OUT_CUBIC, 350, scale_x:1.0f, scale_y:1.0f, opacity:255);
}
public void open (bool animate = true, bool all_windows = false) public void open (bool animate = true, bool all_windows = false)
{ {
if (!ready) if (!ready)
@ -225,27 +140,41 @@ namespace Gala
grab_key_focus (); grab_key_focus ();
wm.block_keybindings_in_modal = false;
wm.begin_modal (); wm.begin_modal ();
visible = true; visible = true;
for (var i = 0; i < screen.get_n_monitors (); i++) {
var geometry = screen.get_monitor_geometry (i);
var container = new TiledWindowContainer (true);
container.set_position (geometry.x, geometry.y);
container.set_size (geometry.width, geometry.height);
container.window_selected.connect (thumb_selected);
add_child (container);
}
foreach (var window in windows) { foreach (var window in windows) {
var actor = window.get_compositor_private () as WindowActor; var actor = window.get_compositor_private () as WindowActor;
if (actor == null) if (actor == null)
return; return;
actor.hide (); actor.hide ();
var clone = new WindowThumb (window); ((TiledWindowContainer) get_child_at_index (window.get_monitor ())).add_window (window);
clone.x = actor.x;
clone.y = actor.y;
clone.selected.connect (thumb_selected);
clone.closed.connect (thumb_closed);
add_child (clone);
} }
calculate_places (get_children ()); foreach (var child in get_children ())
((TiledWindowContainer) child).open ();
ready = true;
}
void restack_windows (Screen screen)
{
foreach (var child in get_children ())
((TiledWindowContainer) child).restack_windows (screen);
} }
void window_left_monitor (int num, Window window) void window_left_monitor (int num, Window window)
@ -258,7 +187,7 @@ namespace Gala
if (window.get_workspace () == workspace || if (window.get_workspace () == workspace ||
(window.is_on_all_workspaces () && window.get_screen () == workspace.get_screen ())) { (window.is_on_all_workspaces () && window.get_screen () == workspace.get_screen ())) {
#endif #endif
remove_window (window); ((TiledWindowContainer) get_child_at_index (num)).remove_window (window);
return; return;
} }
} }
@ -266,58 +195,19 @@ namespace Gala
void add_window (Window window) void add_window (Window window)
{ {
if (!visible || window.get_workspace () != screen.get_active_workspace () if (!visible
|| (window.window_type != WindowType.NORMAL && window.window_type != WindowType.DIALOG)) || (window.window_type != WindowType.NORMAL && window.window_type != WindowType.DIALOG))
return; return;
var actor = window.get_compositor_private () as WindowActor; // make sure the window belongs to one of our workspaces
if (actor == null) { foreach (var workspace in workspaces)
//the window possibly hasn't reached the compositor yet if (window.get_workspace () == workspace)
Idle.add (() => { ((TiledWindowContainer) get_child_at_index (window.get_monitor ())).add_window (window);
if (window.get_compositor_private () != null &&
window.get_workspace () == screen.get_active_workspace ())
add_window (window);
return false;
});
return;
}
actor.hide ();
var clone = new WindowThumb (window);
clone.x = actor.x;
clone.y = actor.y;
clone.selected.connect (thumb_selected);
clone.closed.connect (thumb_closed);
add_child (clone);
calculate_places (get_children ());
} }
void remove_window (Window window) void remove_window (Window window)
{ {
WindowThumb thumb = null; ((TiledWindowContainer) get_child_at_index (window.get_monitor ())).remove_window (window);
foreach (var child in get_children ()) {
if ((child as WindowThumb).window == window)
thumb = child as WindowThumb;
}
if (thumb != null) {
thumb_closed (thumb);
}
}
void thumb_closed (WindowThumb thumb)
{
thumb.destroy ();
var children = get_children ();
if (children.length () > 0)
calculate_places (children);
else
close (false);
} }
void thumb_selected (Window window) void thumb_selected (Window window)
@ -349,34 +239,33 @@ namespace Gala
ready = false; ready = false;
wm.end_modal (); wm.end_modal ();
wm.block_keybindings_in_modal = true;
wm.update_input_area (); wm.update_input_area ();
foreach (var child in get_children ()) { foreach (var child in get_children ()) {
var exposed = child as WindowThumb; ((TiledWindowContainer) child).close ();
exposed.close (animate);
exposed.selected.disconnect (thumb_selected);
} }
if (animate) { if (animate) {
Clutter.Threads.Timeout.add (300, () => { Clutter.Threads.Timeout.add (300, () => {
visible = false; cleanup ();
ready = true;
foreach (var window in screen.get_active_workspace ().list_windows ()) {
if (window.showing_on_its_workspace ())
(window.get_compositor_private () as Actor).show ();
}
return false; return false;
}); });
} else { } else
cleanup ();
}
void cleanup ()
{
ready = true; ready = true;
visible = false; visible = false;
foreach (var window in screen.get_active_workspace ().list_windows ()) foreach (var window in screen.get_active_workspace ().list_windows ())
if (window.showing_on_its_workspace ()) if (window.showing_on_its_workspace ())
(window.get_compositor_private () as Actor).show (); (window.get_compositor_private () as Actor).show ();
}
destroy_all_children ();
} }
} }
} }

View File

@ -1,234 +0,0 @@
//
// Copyright (C) 2012 Tom Beckmann
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
using Meta;
using Clutter;
namespace Gala
{
public class WindowThumb : Actor
{
const int WAIT_FOR_CONFIRMATION_DIALOG = 100;
public signal void selected (Window window);
public signal void closed ();
public weak Window window;
Clone clone;
public GtkClutter.Texture icon;
public GtkClutter.Texture close_button;
public WindowThumb (Window _window, bool add_children_to_stage = true)
{
window = _window;
reactive = true;
var actor = window.get_compositor_private () as WindowActor;
clone = new Clone (actor);
clone.add_constraint (new BindConstraint (this, BindCoordinate.SIZE, 0));
icon = new GtkClutter.Texture ();
icon.scale_x = 0.0f;
icon.scale_y = 0.0f;
icon.opacity = 0;
icon.scale_gravity = Gravity.CENTER;
try {
icon.set_from_pixbuf (Utils.get_icon_for_window (window, 64));
} catch (Error e) { warning (e.message); }
close_button = new GtkClutter.Texture ();
close_button.reactive = true;
close_button.visible = false;
close_button.scale_x = 0.0f;
close_button.scale_y = 0.0f;
close_button.scale_gravity = Gravity.CENTER;
close_button.button_release_event.connect (close_button_clicked);
close_button.leave_event.connect ((e) => leave_event (e));
try {
close_button.set_from_pixbuf (Granite.Widgets.Utils.get_close_pixbuf ());
} catch (Error e) { warning (e.message); }
add_child (clone);
if (add_children_to_stage) {
var stage = Compositor.get_stage_for_screen (window.get_screen ());
stage.add_child (icon);
stage.add_child (close_button);
} else {
add_child (close_button);
add_child (icon);
}
}
public void place_children (int width, int height)
{
float offset_x, offset_y, offset_width;
Utils.get_window_frame_offset (window, out offset_x, out offset_y, out offset_width, null);
float button_offset = close_button.width * 0.25f;
float scale = width / (window.get_compositor_private () as WindowActor).width;
Granite.CloseButtonPosition pos;
Granite.Widgets.Utils.get_default_close_button_position (out pos);
switch (pos) {
case Granite.CloseButtonPosition.LEFT:
close_button.x = -offset_x * scale - button_offset;
break;
case Granite.CloseButtonPosition.RIGHT:
close_button.x = width - offset_width * scale - close_button.width / 2;
break;
}
close_button.y = -offset_y * scale - button_offset;
icon.x = Math.floorf (width / 2.0f - icon.width / 2.0f);
icon.y = Math.floorf (height - 50.0f);
icon.animate (AnimationMode.EASE_OUT_CUBIC, 350, scale_x: 1.0f, scale_y: 1.0f, opacity: 255);
}
bool close_button_clicked (ButtonEvent event)
{
if (event.button != 1)
return false;
close_window ();
return true;
}
public void close_window ()
{
get_parent ().set_child_below_sibling (this, null);
// make sure we dont see a window closing animation in the background
clone.source.opacity = 0;
window.delete (window.get_screen ().get_display ().get_current_time ());
// see if the window is still alive after the animation ended. If it is, it's pretty certain that it
// popped up some kind of confirmation dialog, so we focus it
Clutter.Threads.Timeout.add (AnimationSettings.get_default ().close_duration + WAIT_FOR_CONFIRMATION_DIALOG, () => {
if (clone != null && clone.source != null && !(clone.source as Meta.WindowActor).is_destroyed ()) {
clone.source.opacity = 255;
selected (window);
}
return false;
});
}
public override void destroy ()
{
clone.destroy ();
close_button.destroy ();
icon.destroy ();
base.destroy ();
}
public override bool enter_event (CrossingEvent event)
{
//if we're still animating don't show the close button
if (get_animation () != null)
return false;
close_button.visible = true;
close_button.animate (AnimationMode.EASE_OUT_ELASTIC, 400, scale_x : 1.0f, scale_y : 1.0f);
return true;
}
public override bool motion_event (MotionEvent event)
{
if (get_animation () != null)
return false;
close_button.visible = true;
close_button.animate (AnimationMode.EASE_OUT_ELASTIC, 400, scale_x : 1.0f, scale_y : 1.0f);
return true;
}
public override bool leave_event (CrossingEvent event)
{
if (event.related == close_button)
return false;
close_button.animate (AnimationMode.EASE_IN_QUAD, 200, scale_x : 0.0f, scale_y : 0.0f)
.completed.connect (() => close_button.visible = false );
return true;
}
public override bool button_release_event (ButtonEvent event)
{
switch (event.button) {
case 1:
get_parent ().set_child_above_sibling (this, null);
selected (window);
break;
case 2:
close_window ();
break;
}
return true;
}
public void close (bool do_animate = true, bool use_scale = true)
{
unowned Meta.Rectangle rect = window.get_outer_rect ();
float x, y, w, h;
Utils.get_window_frame_offset (window, out x, out y, out w, out h);
float dest_x = rect.x + x;
float dest_y = rect.y + y;
//stop all running animations
detach_animation ();
icon.detach_animation ();
close_button.detach_animation ();
bool dont_show = window.minimized || window.get_workspace () != window.get_screen ().get_active_workspace ();
do_animate = do_animate && !dont_show;
if (do_animate) {
icon.animate (AnimationMode.EASE_IN_CUBIC, 100, scale_x:0.0f, scale_y:0.0f);
close_button.animate (AnimationMode.EASE_IN_QUAD, 200, scale_x : 0.0f, scale_y : 0.0f);
Animation a;
if (use_scale) {
a = animate (AnimationMode.EASE_IN_OUT_CUBIC, 300, scale_x: 1.0f, scale_y: 1.0f,
x: dest_x, y: dest_y);
} else {
var window = window.get_compositor_private () as WindowActor;
a = animate (AnimationMode.EASE_IN_OUT_CUBIC, 300, width: window.width, height: window.height,
x: dest_x, y: dest_y);
}
a.completed.connect (() => {
clone.source.show ();
destroy ();
});
} else {
if (!dont_show)
clone.source.show ();
destroy ();
}
}
}
}