mirror of
https://github.com/elementary/gala.git
synced 2024-11-24 04:21:04 +03:00
Removed MultitaskingView folder, use get_frame_rect when available, use TiledWindow/Container for WindowOverview
This commit is contained in:
parent
c399e882d8
commit
74f471d029
@ -48,16 +48,15 @@ gala_VALASOURCES = \
|
||||
Background/BackgroundManager.vala \
|
||||
Background/SlideShow.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/WindowSwitcher.vala \
|
||||
Widgets/WindowThumb.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 \
|
||||
Widgets/WorkspaceClone.vala \
|
||||
$(NULL)
|
||||
|
||||
nodist_gala_SOURCES = \
|
||||
|
@ -69,6 +69,8 @@ namespace Gala
|
||||
}
|
||||
}
|
||||
|
||||
public bool overview_mode { get; construct; }
|
||||
|
||||
DragDropAction drag_action;
|
||||
Clone? clone = null;
|
||||
|
||||
@ -81,9 +83,9 @@ namespace Gala
|
||||
Actor active_shape;
|
||||
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
|
||||
@ -92,23 +94,23 @@ namespace Gala
|
||||
|
||||
window.unmanaged.connect (unmanaged);
|
||||
|
||||
drag_action = new DragDropAction (DragDropActionType.SOURCE, "multitaskingview-window");
|
||||
drag_action.drag_begin.connect (drag_begin);
|
||||
drag_action.destination_crossed.connect (drag_destination_crossed);
|
||||
drag_action.drag_end.connect (drag_end);
|
||||
drag_action.drag_canceled.connect (drag_canceled);
|
||||
drag_action.actor_clicked.connect ((button) => {
|
||||
switch (button) {
|
||||
case 1:
|
||||
selected ();
|
||||
break;
|
||||
case 2:
|
||||
close_window ();
|
||||
break;
|
||||
}
|
||||
});
|
||||
if (overview_mode) {
|
||||
var click_action = new ClickAction ();
|
||||
click_action.clicked.connect (() => {
|
||||
actor_clicked (click_action.get_button ());
|
||||
});
|
||||
|
||||
add_action (drag_action);
|
||||
add_action (click_action);
|
||||
} else {
|
||||
drag_action = new DragDropAction (DragDropActionType.SOURCE, "multitaskingview-window");
|
||||
drag_action.drag_begin.connect (drag_begin);
|
||||
drag_action.destination_crossed.connect (drag_destination_crossed);
|
||||
drag_action.drag_end.connect (drag_end);
|
||||
drag_action.drag_canceled.connect (drag_canceled);
|
||||
drag_action.actor_clicked.connect (actor_clicked);
|
||||
|
||||
add_action (drag_action);
|
||||
}
|
||||
|
||||
close_button = Utils.create_close_button ();
|
||||
close_button.opacity = 0;
|
||||
@ -180,6 +182,9 @@ namespace Gala
|
||||
return;
|
||||
}
|
||||
|
||||
if (overview_mode)
|
||||
actor.hide ();
|
||||
|
||||
clone = new Clone (actor.get_texture ());
|
||||
add_child (clone);
|
||||
|
||||
@ -189,7 +194,11 @@ namespace Gala
|
||||
|
||||
transition_to_original_state (false);
|
||||
|
||||
#if HAS_MUTTER312
|
||||
var outer_rect = window.get_frame_rect ();
|
||||
#else
|
||||
var outer_rect = window.get_outer_rect ();
|
||||
#endif
|
||||
add_effect_with_name ("shadow", new ShadowEffect (outer_rect.width, outer_rect.height, 40, 5));
|
||||
#if HAS_MUTTER312
|
||||
window.size_changed.connect (update_shadow_size);
|
||||
@ -197,6 +206,9 @@ namespace Gala
|
||||
actor.size_changed.connect (update_shadow_size);
|
||||
#endif
|
||||
|
||||
if (should_fade ())
|
||||
opacity = 0;
|
||||
|
||||
// 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.
|
||||
// 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,
|
||||
* the shadow will be resized and a request_reposition() will be emitted to
|
||||
@ -221,7 +243,11 @@ namespace Gala
|
||||
Source.remove (shadow_update_timeout);
|
||||
|
||||
shadow_update_timeout = Timeout.add (500, () => {
|
||||
#if HAS_MUTTER312
|
||||
var rect = window.get_frame_rect ();
|
||||
#else
|
||||
var rect = window.get_outer_rect ();
|
||||
#endif
|
||||
var effect = get_effect ("shadow") as ShadowEffect;
|
||||
effect.update_size (rect.width, rect.height);
|
||||
|
||||
@ -241,13 +267,24 @@ namespace Gala
|
||||
*/
|
||||
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 ();
|
||||
#endif
|
||||
|
||||
float offset_x = 0, offset_y = 0;
|
||||
|
||||
var parent = get_parent ();
|
||||
if (parent != null)
|
||||
parent.get_transformed_position (out offset_x, out offset_y);
|
||||
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);
|
||||
}
|
||||
|
||||
set_easing_mode (AnimationMode.EASE_IN_OUT_CUBIC);
|
||||
set_easing_duration (animate ? 300 : 0);
|
||||
@ -256,6 +293,9 @@ namespace Gala
|
||||
set_size (outer_rect.width, outer_rect.height);
|
||||
|
||||
window_icon.opacity = 0;
|
||||
|
||||
if (should_fade ())
|
||||
opacity = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -272,6 +312,17 @@ namespace Gala
|
||||
set_position (rect.x, rect.y);
|
||||
|
||||
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
|
||||
var input_rect = window.get_input_rect ();
|
||||
#endif
|
||||
#if HAS_MUTTER312
|
||||
var outer_rect = window.get_frame_rect ();
|
||||
#else
|
||||
var outer_rect = window.get_outer_rect ();
|
||||
#endif
|
||||
var scale_factor = (float)width / outer_rect.width;
|
||||
|
||||
var shadow_effect = get_effect ("shadow") as ShadowEffect;
|
||||
@ -397,6 +452,17 @@ namespace Gala
|
||||
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
|
||||
* we can move freely, scale ourselves to a smaller scale and request that the
|
@ -32,6 +32,8 @@ namespace Gala
|
||||
public int padding_right { get; set; default = 12; }
|
||||
public int padding_bottom { get; set; default = 12; }
|
||||
|
||||
public bool overview_mode { get; construct; }
|
||||
|
||||
bool opened;
|
||||
|
||||
/**
|
||||
@ -40,8 +42,9 @@ namespace Gala
|
||||
*/
|
||||
TiledWindow? current_window;
|
||||
|
||||
public TiledWindowContainer ()
|
||||
public TiledWindowContainer (bool overview_mode = false)
|
||||
{
|
||||
Object (overview_mode: overview_mode);
|
||||
}
|
||||
|
||||
construct
|
||||
@ -70,7 +73,7 @@ namespace Gala
|
||||
|
||||
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.destroy.connect (window_destroyed);
|
||||
@ -180,13 +183,25 @@ namespace Gala
|
||||
var windows = new List<InternalUtils.TilableWindow?> ();
|
||||
foreach (var child in get_children ()) {
|
||||
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 });
|
||||
#endif
|
||||
}
|
||||
windows.reverse ();
|
||||
|
||||
if (windows.length () < 1)
|
||||
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 = {
|
||||
padding_left,
|
||||
padding_top,
|
@ -40,17 +40,16 @@ namespace Gala
|
||||
|
||||
bool ready;
|
||||
|
||||
//the workspaces which we expose right now
|
||||
// the workspaces which we expose right now
|
||||
List<Workspace> workspaces;
|
||||
|
||||
static const int PADDING = 50;
|
||||
|
||||
public WindowOverview (WindowManager _wm)
|
||||
{
|
||||
wm = _wm;
|
||||
screen = wm.get_screen ();
|
||||
|
||||
screen.workspace_switched.connect (() => close (false));
|
||||
screen.restacked.connect (restack_windows);
|
||||
|
||||
visible = false;
|
||||
ready = true;
|
||||
@ -59,11 +58,7 @@ namespace Gala
|
||||
|
||||
public override bool key_press_event (Clutter.KeyEvent event)
|
||||
{
|
||||
//FIXME need to figure out the actual keycombo, for now leave it by
|
||||
// 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) {
|
||||
if (event.keyval == Clutter.Key.Escape) {
|
||||
close (true);
|
||||
|
||||
return true;
|
||||
@ -85,86 +80,6 @@ namespace Gala
|
||||
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)
|
||||
{
|
||||
if (!ready)
|
||||
@ -225,27 +140,41 @@ namespace Gala
|
||||
|
||||
grab_key_focus ();
|
||||
|
||||
wm.block_keybindings_in_modal = false;
|
||||
wm.begin_modal ();
|
||||
|
||||
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) {
|
||||
var actor = window.get_compositor_private () as WindowActor;
|
||||
if (actor == null)
|
||||
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);
|
||||
((TiledWindowContainer) get_child_at_index (window.get_monitor ())).add_window (window);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -258,7 +187,7 @@ namespace Gala
|
||||
if (window.get_workspace () == workspace ||
|
||||
(window.is_on_all_workspaces () && window.get_screen () == workspace.get_screen ())) {
|
||||
#endif
|
||||
remove_window (window);
|
||||
((TiledWindowContainer) get_child_at_index (num)).remove_window (window);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -266,58 +195,19 @@ namespace Gala
|
||||
|
||||
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))
|
||||
return;
|
||||
|
||||
var actor = window.get_compositor_private () as WindowActor;
|
||||
if (actor == null) {
|
||||
//the window possibly hasn't reached the compositor yet
|
||||
Idle.add (() => {
|
||||
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 ());
|
||||
// make sure the window belongs to one of our workspaces
|
||||
foreach (var workspace in workspaces)
|
||||
if (window.get_workspace () == workspace)
|
||||
((TiledWindowContainer) get_child_at_index (window.get_monitor ())).add_window (window);
|
||||
}
|
||||
|
||||
void remove_window (Window window)
|
||||
{
|
||||
WindowThumb thumb = null;
|
||||
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);
|
||||
((TiledWindowContainer) get_child_at_index (window.get_monitor ())).remove_window (window);
|
||||
}
|
||||
|
||||
void thumb_selected (Window window)
|
||||
@ -349,34 +239,33 @@ namespace Gala
|
||||
ready = false;
|
||||
|
||||
wm.end_modal ();
|
||||
wm.block_keybindings_in_modal = true;
|
||||
wm.update_input_area ();
|
||||
|
||||
foreach (var child in get_children ()) {
|
||||
var exposed = child as WindowThumb;
|
||||
exposed.close (animate);
|
||||
exposed.selected.disconnect (thumb_selected);
|
||||
((TiledWindowContainer) child).close ();
|
||||
}
|
||||
|
||||
if (animate) {
|
||||
Clutter.Threads.Timeout.add (300, () => {
|
||||
visible = false;
|
||||
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 ();
|
||||
}
|
||||
cleanup ();
|
||||
|
||||
return false;
|
||||
});
|
||||
} else {
|
||||
ready = true;
|
||||
visible = false;
|
||||
} else
|
||||
cleanup ();
|
||||
}
|
||||
|
||||
foreach (var window in screen.get_active_workspace ().list_windows ())
|
||||
if (window.showing_on_its_workspace ())
|
||||
(window.get_compositor_private () as Actor).show ();
|
||||
}
|
||||
void cleanup ()
|
||||
{
|
||||
ready = true;
|
||||
visible = false;
|
||||
|
||||
foreach (var window in screen.get_active_workspace ().list_windows ())
|
||||
if (window.showing_on_its_workspace ())
|
||||
(window.get_compositor_private () as Actor).show ();
|
||||
|
||||
destroy_all_children ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user