Refactoring to avoid nested classes and multi-class files

Additionally don't expose plank in libgala
This commit is contained in:
Rico Tzschichholz 2015-03-04 09:36:08 +01:00
parent 88ef7e47e0
commit d588328a03
11 changed files with 547 additions and 454 deletions

View File

@ -35,6 +35,7 @@ libgala_la_VALASOURCES = \
ActivatableComponent.vala \
Plugin.vala \
Utils.vala \
WindowIcon.vala \
WindowManager.vala \
$(NULL)

View File

@ -32,6 +32,10 @@ namespace Gala
icon_pixbuf_cache = new HashTable<string, Gdk.Pixbuf> (str_hash, str_equal);
}
Utils ()
{
}
/**
* Clean icon caches
*/
@ -77,114 +81,6 @@ namespace Gala
});
}
/**
* Creates a new GtkClutterTexture with an icon for the window at the given size.
* This is recommended way to grab an icon for a window as this method will make
* sure the icon is updated if it becomes available at a later point.
*/
public class WindowIcon : GtkClutter.Texture
{
static Bamf.Matcher matcher;
static construct
{
matcher = Bamf.Matcher.get_default ();
}
public Meta.Window window { get; construct; }
public int icon_size { get; construct; }
/**
* If set to true, the SafeWindowClone will destroy itself when the connected
* window is unmanaged
*/
public bool destroy_on_unmanaged {
get {
return _destroy_on_unmanaged;
}
construct set {
if (_destroy_on_unmanaged == value)
return;
_destroy_on_unmanaged = value;
if (_destroy_on_unmanaged)
window.unmanaged.connect (unmanaged);
else
window.unmanaged.disconnect (unmanaged);
}
}
bool _destroy_on_unmanaged = false;
bool loaded = false;
uint32 xid;
/**
* Creates a new WindowIcon
*
* @param window The window for which to create the icon
* @param icon_size The size of the icon in pixels
* @param destroy_on_unmanaged @see destroy_on_unmanaged
*/
public WindowIcon (Meta.Window window, int icon_size, bool destroy_on_unmanaged = false)
{
Object (window: window,
icon_size: icon_size,
destroy_on_unmanaged: destroy_on_unmanaged);
}
construct
{
width = icon_size;
height = icon_size;
xid = (uint32) window.get_xwindow ();
// new windows often reach mutter earlier than bamf, that's why
// we have to wait until the next window opens and hope that it's
// ours so we can get a proper icon instead of the default fallback.
var app = matcher.get_application_for_xid (xid);
if (app == null)
matcher.view_opened.connect (retry_load);
else
loaded = true;
update_texture (true);
}
~WindowIcon ()
{
if (!loaded)
matcher.view_opened.disconnect (retry_load);
}
void retry_load (Bamf.View view)
{
var app = matcher.get_application_for_xid (xid);
// retry only once
loaded = true;
matcher.view_opened.disconnect (retry_load);
if (app == null)
return;
update_texture (false);
}
void update_texture (bool initial)
{
var pixbuf = get_icon_for_xid (xid, icon_size, !initial);
try {
set_from_pixbuf (pixbuf);
} catch (Error e) {}
}
void unmanaged (Meta.Window window)
{
destroy ();
}
}
/**
* Returns a pixbuf for the application of this window or a default icon
*
@ -392,55 +288,5 @@ namespace Gala
return texture;
}
/**
* Provides access to a PlankDrawingDockTheme and PlankDockPrefereces
*/
public class DockThemeManager : Object
{
Plank.DockPreferences? dock_settings = null;
Plank.Drawing.DockTheme? dock_theme = null;
public signal void dock_theme_changed (Plank.Drawing.DockTheme? old_theme,
Plank.Drawing.DockTheme new_theme);
DockThemeManager ()
{
var file = Environment.get_user_config_dir () + "/plank/dock1/settings";
dock_settings = new Plank.DockPreferences.with_filename (file);
dock_settings.notify["Theme"].connect (load_dock_theme);
}
public Plank.Drawing.DockTheme get_dock_theme ()
{
if (dock_theme == null)
load_dock_theme ();
return dock_theme;
}
public Plank.DockPreferences get_dock_settings ()
{
return dock_settings;
}
void load_dock_theme ()
{
var new_theme = new Plank.Drawing.DockTheme (dock_settings.Theme);
new_theme.load ("dock");
dock_theme_changed (dock_theme, new_theme);
dock_theme = new_theme;
}
static DockThemeManager? instance = null;
public static DockThemeManager get_default ()
{
if (instance == null)
instance = new DockThemeManager ();
return instance;
}
}
}
}

127
lib/WindowIcon.vala Normal file
View File

@ -0,0 +1,127 @@
//
// Copyright (C) 2012 Tom Beckmann, Rico Tzschichholz
//
// 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/>.
//
namespace Gala
{
/**
* Creates a new GtkClutterTexture with an icon for the window at the given size.
* This is recommended way to grab an icon for a window as this method will make
* sure the icon is updated if it becomes available at a later point.
*/
public class WindowIcon : GtkClutter.Texture
{
static Bamf.Matcher matcher;
static construct
{
matcher = Bamf.Matcher.get_default ();
}
public Meta.Window window { get; construct; }
public int icon_size { get; construct; }
/**
* If set to true, the SafeWindowClone will destroy itself when the connected
* window is unmanaged
*/
public bool destroy_on_unmanaged {
get {
return _destroy_on_unmanaged;
}
construct set {
if (_destroy_on_unmanaged == value)
return;
_destroy_on_unmanaged = value;
if (_destroy_on_unmanaged)
window.unmanaged.connect (unmanaged);
else
window.unmanaged.disconnect (unmanaged);
}
}
bool _destroy_on_unmanaged = false;
bool loaded = false;
uint32 xid;
/**
* Creates a new WindowIcon
*
* @param window The window for which to create the icon
* @param icon_size The size of the icon in pixels
* @param destroy_on_unmanaged @see destroy_on_unmanaged
*/
public WindowIcon (Meta.Window window, int icon_size, bool destroy_on_unmanaged = false)
{
Object (window: window,
icon_size: icon_size,
destroy_on_unmanaged: destroy_on_unmanaged);
}
construct
{
width = icon_size;
height = icon_size;
xid = (uint32) window.get_xwindow ();
// new windows often reach mutter earlier than bamf, that's why
// we have to wait until the next window opens and hope that it's
// ours so we can get a proper icon instead of the default fallback.
var app = matcher.get_application_for_xid (xid);
if (app == null)
matcher.view_opened.connect (retry_load);
else
loaded = true;
update_texture (true);
}
~WindowIcon ()
{
if (!loaded)
matcher.view_opened.disconnect (retry_load);
}
void retry_load (Bamf.View view)
{
var app = matcher.get_application_for_xid (xid);
// retry only once
loaded = true;
matcher.view_opened.disconnect (retry_load);
if (app == null)
return;
update_texture (false);
}
void update_texture (bool initial)
{
var pixbuf = Gala.Utils.get_icon_for_xid (xid, icon_size, !initial);
try {
set_from_pixbuf (pixbuf);
} catch (Error e) {}
}
void unmanaged (Meta.Window window)
{
destroy ();
}
}
}

70
src/DockThemeManager.vala Normal file
View File

@ -0,0 +1,70 @@
//
// Copyright (C) 2012 Tom Beckmann, Rico Tzschichholz
//
// 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/>.
//
namespace Gala
{
/**
* Provides access to a PlankDrawingDockTheme and PlankDockPrefereces
*/
public class DockThemeManager : Object
{
static DockThemeManager? instance = null;
public static DockThemeManager get_default ()
{
if (instance == null)
instance = new DockThemeManager ();
return instance;
}
Plank.DockPreferences? dock_settings = null;
Plank.Drawing.DockTheme? dock_theme = null;
public signal void dock_theme_changed (Plank.Drawing.DockTheme? old_theme,
Plank.Drawing.DockTheme new_theme);
DockThemeManager ()
{
var file = Environment.get_user_config_dir () + "/plank/dock1/settings";
dock_settings = new Plank.DockPreferences.with_filename (file);
dock_settings.notify["Theme"].connect (load_dock_theme);
}
public Plank.Drawing.DockTheme get_dock_theme ()
{
if (dock_theme == null)
load_dock_theme ();
return dock_theme;
}
public Plank.DockPreferences get_dock_settings ()
{
return dock_settings;
}
void load_dock_theme ()
{
var new_theme = new Plank.Drawing.DockTheme (dock_settings.Theme);
new_theme.load ("dock");
dock_theme_changed (dock_theme, new_theme);
dock_theme = new_theme;
}
}
}

View File

@ -32,6 +32,7 @@ gala_LDADD = \
gala_VALASOURCES = \
DBus.vala \
DockThemeManager.vala \
DragDropAction.vala \
InternalUtils.vala \
Main.vala \
@ -49,10 +50,12 @@ gala_VALASOURCES = \
Widgets/MultitaskingView.vala \
Widgets/WindowClone.vala \
Widgets/WindowCloneContainer.vala \
Widgets/WindowIconActor.vala \
Widgets/WindowMenu.vala \
Widgets/WindowOverview.vala \
Widgets/WindowSwitcher.vala \
Widgets/WorkspaceClone.vala \
Widgets/WorkspaceInsertThumb.vala \
$(NULL)
gala_background = \

View File

@ -21,177 +21,7 @@ using Meta;
namespace Gala
{
/**
* Private class which is basically just a container for the actual
* icon and takes care of blending the same icon in different sizes
* over each other and various animations related to the icons
*/
class WindowIcon : Actor
{
public Window window { get; construct; }
int _icon_size;
/**
* The icon size of the WindowIcon. Once set the new icon will be
* faded over the old one and the actor animates to the new size.
*/
public int icon_size {
get {
return _icon_size;
}
set {
if (value == _icon_size)
return;
_icon_size = value;
set_size (_icon_size, _icon_size);
fade_new_icon ();
}
}
bool _temporary;
/**
* Mark the WindowIcon as temporary. Only effect of this is that a pulse
* animation will be played on the actor. Used while DnDing window thumbs
* over the group.
*/
public bool temporary {
get {
return _temporary;
}
set {
if (_temporary && !value) {
remove_transition ("pulse");
} else if (!_temporary && value) {
var transition = new TransitionGroup ();
transition.duration = 800;
transition.auto_reverse = true;
transition.repeat_count = -1;
transition.progress_mode = AnimationMode.LINEAR;
var opacity_transition = new PropertyTransition ("opacity");
opacity_transition.set_from_value (100);
opacity_transition.set_to_value (255);
opacity_transition.auto_reverse = true;
var scale_x_transition = new PropertyTransition ("scale-x");
scale_x_transition.set_from_value (0.8);
scale_x_transition.set_to_value (1.1);
scale_x_transition.auto_reverse = true;
var scale_y_transition = new PropertyTransition ("scale-y");
scale_y_transition.set_from_value (0.8);
scale_y_transition.set_to_value (1.1);
scale_y_transition.auto_reverse = true;
transition.add_transition (opacity_transition);
transition.add_transition (scale_x_transition);
transition.add_transition (scale_y_transition);
add_transition ("pulse", transition);
}
_temporary = value;
}
}
bool initial = true;
Utils.WindowIcon? icon = null;
Utils.WindowIcon? old_icon = null;
public WindowIcon (Window window)
{
Object (window: window);
}
construct
{
set_pivot_point (0.5f, 0.5f);
set_easing_mode (AnimationMode.EASE_OUT_ELASTIC);
set_easing_duration (800);
window.notify["on-all-workspaces"].connect (on_all_workspaces_changed);
}
~WindowIcon ()
{
window.notify["on-all-workspaces"].disconnect (on_all_workspaces_changed);
}
void on_all_workspaces_changed ()
{
// we don't display windows that are on all workspaces
if (window.on_all_workspaces)
destroy ();
}
/**
* Shortcut to set both position and size of the icon
*
* @param x The x coordinate to which to animate to
* @param y The y coordinate to which to animate to
* @param size The size to which to animate to and display the icon in
*/
public void place (float x, float y, int size)
{
if (initial) {
save_easing_state ();
set_easing_duration (10);
}
set_position (x, y);
icon_size = size;
if (initial) {
restore_easing_state ();
initial = false;
}
}
/**
* Fades out the old icon and fades in the new icon
*/
void fade_new_icon ()
{
var new_icon = new Utils.WindowIcon (window, icon_size);
new_icon.add_constraint (new BindConstraint (this, BindCoordinate.SIZE, 0));
new_icon.opacity = 0;
add_child (new_icon);
new_icon.set_easing_mode (AnimationMode.EASE_OUT_QUAD);
new_icon.set_easing_duration (500);
if (icon == null) {
icon = new_icon;
} else {
old_icon = icon;
}
new_icon.opacity = 255;
if (old_icon != null) {
old_icon.opacity = 0;
var transition = old_icon.get_transition ("opacity");
if (transition != null) {
transition.completed.connect (() => {
old_icon.destroy ();
old_icon = null;
});
} else {
old_icon.destroy ();
old_icon = null;
}
}
icon = new_icon;
}
}
/**
* Container for WindowIcons which takes care of the scaling and positioning.
* Container for WindowIconActors which takes care of the scaling and positioning.
* It also decides whether to draw the container shape, a plus sign or an ellipsis.
* Lastly it also includes the drawing code for the active highlight.
*/
@ -410,7 +240,7 @@ namespace Gala
}
/**
* Remove all currently added WindowIcons
* Remove all currently added WindowIconActors
*/
public void clear ()
{
@ -418,17 +248,17 @@ namespace Gala
}
/**
* Creates a WindowIcon for the given window and adds it to the group
* Creates a WindowIconActor for the given window and adds it to the group
*
* @param window The MetaWindow for which to create the WindowIcon
* @param window The MetaWindow for which to create the WindowIconActor
* @param no_redraw If you add multiple windows at once you may want to consider
* settings this to true and when done calling redraw() manually
* @param temporary Mark the WindowIcon as temporary. Used for windows dragged over
* @param temporary Mark the WindowIconActor as temporary. Used for windows dragged over
* the group.
*/
public void add_window (Window window, bool no_redraw = false, bool temporary = false)
{
var new_window = new WindowIcon (window);
var new_window = new WindowIconActor (window);
new_window.save_easing_state ();
new_window.set_easing_duration (0);
@ -443,14 +273,14 @@ namespace Gala
}
/**
* Remove the WindowIcon for a MetaWindow from the group
* Remove the WindowIconActor for a MetaWindow from the group
*
* @param animate Whether to fade the icon out before removing it
*/
public void remove_window (Window window, bool animate = true)
{
foreach (var child in icon_container.get_children ()) {
unowned WindowIcon w = (WindowIcon) child;
unowned WindowIconActor w = (WindowIconActor) child;
if (w.window == window) {
if (animate) {
w.set_easing_mode (AnimationMode.LINEAR);
@ -513,7 +343,7 @@ namespace Gala
// single icon => big icon
if (n_windows == 1) {
var icon = (WindowIcon) icon_container.get_child_at_index (0);
var icon = (WindowIconActor) icon_container.get_child_at_index (0);
icon.place (0, 0, 64);
return false;
@ -607,7 +437,7 @@ namespace Gala
var x = x_offset;
var y = y_offset;
for (var i = 0; i < n_windows; i++) {
var window = (WindowIcon) icon_container.get_child_at_index (i);
var window = (WindowIconActor) icon_container.get_child_at_index (i);
// draw an ellipsis at the 9th position if we need one
if (show_ellipsis && i == 8) {

View File

@ -20,111 +20,6 @@ using Meta;
namespace Gala
{
public class WorkspaceInsertThumb : Actor
{
public const int EXPAND_DELAY = 300;
public int workspace_index { get; construct set; }
public bool expanded { get; private set; default = false; }
uint expand_timeout = 0;
public WorkspaceInsertThumb (int workspace_index)
{
Object (workspace_index: workspace_index);
width = IconGroupContainer.SPACING;
height = IconGroupContainer.GROUP_WIDTH;
y = (IconGroupContainer.GROUP_WIDTH - IconGroupContainer.SPACING) / 2;
opacity = 0;
set_pivot_point (0.5f, 0.5f);
reactive = true;
layout_manager = new BinLayout (BinAlignment.CENTER);
var drop = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
drop.crossed.connect ((hovered) => {
if (!Prefs.get_dynamic_workspaces ())
return;
if (!hovered) {
if (expand_timeout != 0) {
Source.remove (expand_timeout);
expand_timeout = 0;
}
transform (false);
} else
expand_timeout = Timeout.add (EXPAND_DELAY, expand);
});
add_action (drop);
}
public void set_window_thumb (Window window)
{
destroy_all_children ();
var icon = new Utils.WindowIcon (window, IconGroupContainer.GROUP_WIDTH);
icon.x_align = ActorAlign.CENTER;
add_child (icon);
}
bool expand ()
{
expand_timeout = 0;
transform (true);
return false;
}
void transform (bool expand)
{
save_easing_state ();
set_easing_mode (AnimationMode.EASE_OUT_QUAD);
set_easing_duration (200);
if (!expand) {
remove_transition ("pulse");
opacity = 0;
width = IconGroupContainer.SPACING;
expanded = false;
} else {
add_pulse_animation ();
opacity = 200;
width = IconGroupContainer.GROUP_WIDTH + IconGroupContainer.SPACING * 2;
expanded = true;
}
restore_easing_state ();
}
void add_pulse_animation ()
{
var transition = new TransitionGroup ();
transition.duration = 800;
transition.auto_reverse = true;
transition.repeat_count = -1;
transition.progress_mode = AnimationMode.LINEAR;
var scale_x_transition = new PropertyTransition ("scale-x");
scale_x_transition.set_from_value (0.8);
scale_x_transition.set_to_value (1.1);
scale_x_transition.auto_reverse = true;
var scale_y_transition = new PropertyTransition ("scale-y");
scale_y_transition.set_from_value (0.8);
scale_y_transition.set_to_value (1.1);
scale_y_transition.auto_reverse = true;
transition.add_transition (scale_x_transition);
transition.add_transition (scale_y_transition);
add_transition ("pulse", transition);
}
}
/**
* This class contains the icon groups at the bottom and will take
* care of displaying actors for inserting windows between the groups

View File

@ -131,7 +131,7 @@ namespace Gala
return false;
});
window_icon = new Utils.WindowIcon (window, WINDOW_ICON_SIZE);
window_icon = new WindowIcon (window, WINDOW_ICON_SIZE);
window_icon.opacity = 0;
window_icon.set_pivot_point (0.5f, 0.5f);

View File

@ -0,0 +1,193 @@
//
// Copyright (C) 2014 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 Clutter;
using Meta;
namespace Gala
{
/**
* Private class which is basically just a container for the actual
* icon and takes care of blending the same icon in different sizes
* over each other and various animations related to the icons
*/
public class WindowIconActor : Actor
{
public Window window { get; construct; }
int _icon_size;
/**
* The icon size of the WindowIcon. Once set the new icon will be
* faded over the old one and the actor animates to the new size.
*/
public int icon_size {
get {
return _icon_size;
}
set {
if (value == _icon_size)
return;
_icon_size = value;
set_size (_icon_size, _icon_size);
fade_new_icon ();
}
}
bool _temporary;
/**
* Mark the WindowIcon as temporary. Only effect of this is that a pulse
* animation will be played on the actor. Used while DnDing window thumbs
* over the group.
*/
public bool temporary {
get {
return _temporary;
}
set {
if (_temporary && !value) {
remove_transition ("pulse");
} else if (!_temporary && value) {
var transition = new TransitionGroup ();
transition.duration = 800;
transition.auto_reverse = true;
transition.repeat_count = -1;
transition.progress_mode = AnimationMode.LINEAR;
var opacity_transition = new PropertyTransition ("opacity");
opacity_transition.set_from_value (100);
opacity_transition.set_to_value (255);
opacity_transition.auto_reverse = true;
var scale_x_transition = new PropertyTransition ("scale-x");
scale_x_transition.set_from_value (0.8);
scale_x_transition.set_to_value (1.1);
scale_x_transition.auto_reverse = true;
var scale_y_transition = new PropertyTransition ("scale-y");
scale_y_transition.set_from_value (0.8);
scale_y_transition.set_to_value (1.1);
scale_y_transition.auto_reverse = true;
transition.add_transition (opacity_transition);
transition.add_transition (scale_x_transition);
transition.add_transition (scale_y_transition);
add_transition ("pulse", transition);
}
_temporary = value;
}
}
bool initial = true;
WindowIcon? icon = null;
WindowIcon? old_icon = null;
public WindowIconActor (Window window)
{
Object (window: window);
}
construct
{
set_pivot_point (0.5f, 0.5f);
set_easing_mode (AnimationMode.EASE_OUT_ELASTIC);
set_easing_duration (800);
window.notify["on-all-workspaces"].connect (on_all_workspaces_changed);
}
~WindowIconActor ()
{
window.notify["on-all-workspaces"].disconnect (on_all_workspaces_changed);
}
void on_all_workspaces_changed ()
{
// we don't display windows that are on all workspaces
if (window.on_all_workspaces)
destroy ();
}
/**
* Shortcut to set both position and size of the icon
*
* @param x The x coordinate to which to animate to
* @param y The y coordinate to which to animate to
* @param size The size to which to animate to and display the icon in
*/
public void place (float x, float y, int size)
{
if (initial) {
save_easing_state ();
set_easing_duration (10);
}
set_position (x, y);
icon_size = size;
if (initial) {
restore_easing_state ();
initial = false;
}
}
/**
* Fades out the old icon and fades in the new icon
*/
void fade_new_icon ()
{
var new_icon = new WindowIcon (window, icon_size);
new_icon.add_constraint (new BindConstraint (this, BindCoordinate.SIZE, 0));
new_icon.opacity = 0;
add_child (new_icon);
new_icon.set_easing_mode (AnimationMode.EASE_OUT_QUAD);
new_icon.set_easing_duration (500);
if (icon == null) {
icon = new_icon;
} else {
old_icon = icon;
}
new_icon.opacity = 255;
if (old_icon != null) {
old_icon.opacity = 0;
var transition = old_icon.get_transition ("opacity");
if (transition != null) {
transition.completed.connect (() => {
old_icon.destroy ();
old_icon = null;
});
} else {
old_icon.destroy ();
old_icon = null;
}
}
icon = new_icon;
}
}
}

View File

@ -26,7 +26,7 @@ namespace Gala
public WindowManager wm { get; construct; }
Utils.WindowIcon? current_window = null;
WindowIcon? current_window = null;
Actor window_clones;
List<Actor> clone_sort_order;
@ -276,7 +276,7 @@ namespace Gala
}
bool clicked_icon (Clutter.ButtonEvent event) {
unowned Utils.WindowIcon icon = (Utils.WindowIcon) event.source;
unowned WindowIcon icon = (WindowIcon) event.source;
if (current_window != icon) {
current_window = icon;
@ -306,9 +306,9 @@ namespace Gala
}
if (actor == current_window) {
current_window = (Utils.WindowIcon) current_window.get_next_sibling ();
current_window = (WindowIcon) current_window.get_next_sibling ();
if (current_window == null)
current_window = (Utils.WindowIcon) dock.get_first_child ();
current_window = (WindowIcon) dock.get_first_child ();
dim_windows ();
}
@ -493,7 +493,7 @@ namespace Gala
close_cleanup ();
}
Utils.WindowIcon? add_window (Window window)
WindowIcon? add_window (Window window)
{
var actor = window.get_compositor_private () as WindowActor;
if (actor == null)
@ -507,7 +507,7 @@ namespace Gala
window_clones.add_child (clone);
var icon = new Utils.WindowIcon (window, dock_settings.IconSize, true);
var icon = new WindowIcon (window, dock_settings.IconSize, true);
icon.reactive = true;
icon.opacity = 100;
icon.x_expand = true;
@ -545,7 +545,7 @@ namespace Gala
}
foreach (var actor in dock.get_children ()) {
unowned Utils.WindowIcon icon = (Utils.WindowIcon) actor;
unowned WindowIcon icon = (WindowIcon) actor;
icon.save_easing_state ();
icon.set_easing_duration (100);
icon.set_easing_mode (AnimationMode.LINEAR);
@ -602,7 +602,7 @@ namespace Gala
clone_sort_order = window_clones.get_children ().copy ();
if (current_window == null)
current_window = (Utils.WindowIcon) dock.get_child_at_index (0);
current_window = (WindowIcon) dock.get_child_at_index (0);
// hide the others
foreach (var actor in Compositor.get_window_actors (screen)) {
@ -624,7 +624,7 @@ namespace Gala
return true;
}
Utils.WindowIcon next_window (Workspace workspace, bool backward)
WindowIcon next_window (Workspace workspace, bool backward)
{
Actor actor;
if (!backward) {
@ -637,7 +637,7 @@ namespace Gala
actor = dock.get_last_child ();
}
return (Utils.WindowIcon) actor;
return (WindowIcon) actor;
}
/**

View File

@ -0,0 +1,128 @@
//
// Copyright (C) 2014 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 Clutter;
using Meta;
namespace Gala
{
public class WorkspaceInsertThumb : Actor
{
public const int EXPAND_DELAY = 300;
public int workspace_index { get; construct set; }
public bool expanded { get; private set; default = false; }
uint expand_timeout = 0;
public WorkspaceInsertThumb (int workspace_index)
{
Object (workspace_index: workspace_index);
width = IconGroupContainer.SPACING;
height = IconGroupContainer.GROUP_WIDTH;
y = (IconGroupContainer.GROUP_WIDTH - IconGroupContainer.SPACING) / 2;
opacity = 0;
set_pivot_point (0.5f, 0.5f);
reactive = true;
layout_manager = new BinLayout (BinAlignment.CENTER);
var drop = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
drop.crossed.connect ((hovered) => {
if (!Prefs.get_dynamic_workspaces ())
return;
if (!hovered) {
if (expand_timeout != 0) {
Source.remove (expand_timeout);
expand_timeout = 0;
}
transform (false);
} else
expand_timeout = Timeout.add (EXPAND_DELAY, expand);
});
add_action (drop);
}
public void set_window_thumb (Window window)
{
destroy_all_children ();
var icon = new WindowIcon (window, IconGroupContainer.GROUP_WIDTH);
icon.x_align = ActorAlign.CENTER;
add_child (icon);
}
bool expand ()
{
expand_timeout = 0;
transform (true);
return false;
}
void transform (bool expand)
{
save_easing_state ();
set_easing_mode (AnimationMode.EASE_OUT_QUAD);
set_easing_duration (200);
if (!expand) {
remove_transition ("pulse");
opacity = 0;
width = IconGroupContainer.SPACING;
expanded = false;
} else {
add_pulse_animation ();
opacity = 200;
width = IconGroupContainer.GROUP_WIDTH + IconGroupContainer.SPACING * 2;
expanded = true;
}
restore_easing_state ();
}
void add_pulse_animation ()
{
var transition = new TransitionGroup ();
transition.duration = 800;
transition.auto_reverse = true;
transition.repeat_count = -1;
transition.progress_mode = AnimationMode.LINEAR;
var scale_x_transition = new PropertyTransition ("scale-x");
scale_x_transition.set_from_value (0.8);
scale_x_transition.set_to_value (1.1);
scale_x_transition.auto_reverse = true;
var scale_y_transition = new PropertyTransition ("scale-y");
scale_y_transition.set_from_value (0.8);
scale_y_transition.set_to_value (1.1);
scale_y_transition.auto_reverse = true;
transition.add_transition (scale_x_transition);
transition.add_transition (scale_y_transition);
add_transition ("pulse", transition);
}
}
}