1
1
mirror of https://github.com/elementary/gala.git synced 2024-12-18 23:02:14 +03:00

Merge dynamic workspaces

This commit is contained in:
Tom Beckmann 2012-07-14 13:24:10 +02:00
commit 40f15e1487
5 changed files with 578 additions and 235 deletions

View File

@ -53,6 +53,7 @@ vala_precompile(VALA_C
src/TextShadowEffect.vala
src/Widgets/WindowSwitcher.vala
src/Widgets/WorkspaceView.vala
src/Widgets/WorkspaceThumb.vala
${CMAKE_BINARY_DIR}/src/Config.vala
PACKAGES
granite

View File

@ -48,10 +48,11 @@ namespace Gala
var screen = get_screen ();
var stage = Compositor.get_stage_for_screen (screen);
screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, 4, -1);
screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, 1, -1);
workspace_view = new WorkspaceView (this);
workspace_view.visible = false;
winswitcher = new WindowSwitcher (this);
stage.add_child (workspace_view);
@ -113,6 +114,7 @@ namespace Gala
stage.add_child (hot_corner);
update_input_area ();
BehaviorSettings.get_default ().notify["enable-manager-corner"].connect (update_input_area);
}
@ -133,13 +135,15 @@ namespace Gala
var screen = get_screen ();
var display = screen.get_display ();
var idx = screen.get_active_workspace ().index () + (reverse ? -1 : 1);
var active = screen.get_active_workspace ();
var idx = active.index () + (reverse ? -1 : 1);
if (idx < 0 || idx >= screen.n_workspaces)
if (idx < 0 || idx >= screen.n_workspaces ||
(active.n_windows == 1 && idx == screen.n_workspaces-1)) //dont allow empty workspaces to be created by moving
return;
if (!window.is_on_all_workspaces ())
window.change_workspace_by_index (idx, false, display.get_current_time ());
window.change_workspace_by_index (idx, true, display.get_current_time ());
moving = window;
screen.get_workspace_by_index (idx).activate_with_focus (window, display.get_current_time ());
@ -166,13 +170,14 @@ namespace Gala
public void dim_window (Window window, bool dim)
{
var win = window.get_compositor_private () as Clutter.Actor;
/*FIXME we need a super awesome blureffect here, the one from clutter is just... bah!
var win = window.get_compositor_private () as WindowActor;
if (dim) {
if (win.has_effects ())
return;
win.add_effect_with_name ("darken", new Clutter.ColorizeEffect ({180, 180, 180, 255}));
win.add_effect_with_name ("darken", new Clutter.BlurEffect ());
} else
win.clear_effects ();
win.clear_effects ();*/
}
/*
@ -440,10 +445,8 @@ namespace Gala
public override void kill_window_effects (WindowActor actor)
{
if (end_animation (ref mapping, actor)) {
if (end_animation (ref mapping, actor))
map_completed (actor);
print ("KILLED MAPPING ONE\n");
}
if (end_animation (ref minimizing, actor))
minimize_completed (actor);
if (end_animation (ref maximizing, actor))
@ -473,14 +476,12 @@ namespace Gala
get_screen ().get_size (out w, out h);
var x2 = 0.0f; var y2 = 0.0f;
if (direction == MotionDirection.UP ||
direction == MotionDirection.UP_LEFT ||
direction == MotionDirection.UP_RIGHT)
if (direction == MotionDirection.LEFT)
x2 = w;
else if (direction == MotionDirection.DOWN ||
direction == MotionDirection.DOWN_LEFT ||
direction == MotionDirection.DOWN_RIGHT)
else if (direction == MotionDirection.RIGHT)
x2 = -w;
else
return;
var group = Compositor.get_window_group_for_screen (get_screen ());
var wallpaper = Compositor.get_background_actor_for_screen (get_screen ());

View File

@ -124,4 +124,20 @@ namespace Gala.Utils
var xregion = X.Fixes.create_region (display.get_xdisplay (), {rect});
Util.set_stage_input_region (screen, xregion);
}
/**
* get the number of toplevel windows on a workspace
**/
public uint get_n_windows (Workspace workspace)
{
var n = 0;
foreach (var window in workspace.list_windows ()) {
if (window.window_type == WindowType.NORMAL ||
window.window_type == WindowType.DIALOG ||
window.window_type == WindowType.MODAL_DIALOG)
n ++;
}
return n;
}
}

View File

@ -0,0 +1,392 @@
//
// 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/>.
//
using Meta;
using Clutter;
namespace Gala
{
public class WorkspaceThumb : Clutter.Actor
{
static const int INDICATOR_BORDER = 5;
static const int APP_ICON_SIZE = 32;
static const float THUMBNAIL_HEIGHT = 80.0f;
static const uint CLOSE_BUTTON_DELAY = 500;
public signal void clicked ();
public signal void closed ();
public signal void window_on_last ();
public unowned Workspace? workspace { get; set; }
unowned Screen screen;
static GtkClutter.Texture? plus = null;
Clone wallpaper;
Clutter.Actor windows;
Clutter.Actor icons;
CairoTexture indicator;
GtkClutter.Texture close_button;
uint hover_timer = 0;
public WorkspaceThumb (Workspace _workspace)
{
workspace = _workspace;
screen = workspace.get_screen ();
screen.workspace_switched.connect (handle_workspace_switched);
screen.workspace_added.connect (workspace_added);
workspace.window_added.connect (handle_window_added);
workspace.window_removed.connect (handle_window_removed);
int swidth, sheight;
screen.get_size (out swidth, out sheight);
var width = Math.floorf ((THUMBNAIL_HEIGHT / sheight) * swidth);
reactive = true;
indicator = new Clutter.CairoTexture ((uint)width + 2 * INDICATOR_BORDER, (uint)THUMBNAIL_HEIGHT + 2 * INDICATOR_BORDER);
indicator.draw.connect (draw_indicator);
indicator.auto_resize = true;
indicator.opacity = 0;
handle_workspace_switched (-1, screen.get_active_workspace_index (), MotionDirection.LEFT);
// FIXME find a nice way to draw a border around it, maybe combinable with the indicator using a ShaderEffect
wallpaper = new Clone (Compositor.get_background_actor_for_screen (screen));
wallpaper.x = INDICATOR_BORDER;
wallpaper.y = INDICATOR_BORDER;
wallpaper.height = THUMBNAIL_HEIGHT;
wallpaper.width = width;
close_button = new GtkClutter.Texture ();
try {
close_button.set_from_pixbuf (Granite.Widgets.get_close_pixbuf ());
} catch (Error e) { warning (e.message); }
close_button.x = -12.0f;
close_button.y = -10.0f;
close_button.reactive = true;
close_button.scale_gravity = Clutter.Gravity.CENTER;
close_button.scale_x = 0;
close_button.scale_y = 0;
icons = new Actor ();
icons.layout_manager = new BoxLayout ();
(icons.layout_manager as Clutter.BoxLayout).spacing = 6;
icons.height = APP_ICON_SIZE;
windows = new Actor ();
windows.x = INDICATOR_BORDER;
windows.y = INDICATOR_BORDER;
windows.height = THUMBNAIL_HEIGHT;
windows.width = width;
windows.clip_to_allocation = true;
add_child (indicator);
add_child (wallpaper);
add_child (windows);
add_child (icons);
add_child (close_button);
//kill the workspace
close_button.button_release_event.connect (close_workspace);
if (plus == null) {
var css = new Gtk.CssProvider ();
var img = new Gtk.Image ();
try {
css.load_from_data ("*{text-shadow:0 1 #f00;color:alpha(#fff, 0.8);}", -1);
} catch (Error e) { warning(e.message); }
img.get_style_context ().add_provider (css, 20000);
plus = new GtkClutter.Texture ();
try {
var pix = Gtk.IconTheme.get_default ().choose_icon ({"list-add-symbolic", "list-add"}, (int)THUMBNAIL_HEIGHT / 2, 0).
load_symbolic_for_context (img.get_style_context ());
plus.set_from_pixbuf (pix);
} catch (Error e) { warning (e.message); }
plus.x = wallpaper.x + wallpaper.width / 2 - plus.width / 2;
plus.y = wallpaper.y + wallpaper.height / 2 - plus.height / 2;
}
check_last_workspace ();
visible = false;
}
~WorkspaceThumb ()
{
screen.workspace_switched.disconnect (handle_workspace_switched);
screen.workspace_added.disconnect (workspace_added);
}
bool close_workspace (Clutter.ButtonEvent event)
{
workspace.list_windows ().foreach ((w) => {
if (w.window_type != WindowType.DOCK) {
w.delete (event.time);
}
});
GLib.Timeout.add (250, () => {
//wait for confirmation dialogs to popup
if (Utils.get_n_windows (workspace) == 0) {
workspace.window_added.disconnect (handle_window_added);
workspace.window_removed.disconnect (handle_window_removed);
animate (Clutter.AnimationMode.LINEAR, 250, width : 0.0f, opacity : 0);
closed ();
} else
workspace.activate (workspace.get_screen ().get_display ().get_current_time ());
return false;
});
return true;
}
bool draw_indicator (Cairo.Context cr)
{
Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, 0, 0, indicator.width, indicator.height, 8);
cr.set_source_rgb (0.35, 0.75, 1.0);
cr.fill_preserve ();
cr.set_line_width (1);
cr.set_source_rgba (0.0, 0.0, 0.0, 0.8);
cr.stroke ();
return false;
}
void workspace_added (int index)
{
check_last_workspace ();
}
void update_windows ()
{
windows.remove_all_children ();
if (workspace == null)
return;
int swidth, sheight;
screen.get_size (out swidth, out sheight);
// add window thumbnails
var aspect = windows.width / swidth;
Compositor.get_window_actors (screen).foreach ((w) => {
var meta_window = w.get_meta_window ();
var type = meta_window.window_type;
if ((!(w.get_workspace () == workspace.index ()) &&
!meta_window.is_on_all_workspaces ()) ||
meta_window.minimized ||
(type != WindowType.NORMAL &&
type != WindowType.DIALOG &&
type != WindowType.MODAL_DIALOG))
return;
var clone = new Clone (w.get_texture ());
clone.width = aspect * clone.width;
clone.height = aspect * clone.height;
clone.x = aspect * w.x;
clone.y = aspect * w.y;
windows.add_child (clone);
});
}
void update_icons ()
{
icons.remove_all_children ();
if (workspace == null)
return;
//show each icon only once, so log the ones added
var shown_applications = new List<Bamf.Application> ();
workspace.list_windows ().foreach ((w) => {
if (w.window_type != Meta.WindowType.NORMAL || w.minimized)
return;
var app = Bamf.Matcher.get_default ().get_application_for_xid ((uint32)w.get_xwindow ());
if (shown_applications.index (app) != -1)
return;
if (app != null)
shown_applications.append (app);
var icon = new GtkClutter.Texture ();
try {
icon.set_from_pixbuf (Utils.get_icon_for_window (w, APP_ICON_SIZE));
} catch (Error e) { warning (e.message); }
icon.reactive = true;
icon.button_release_event.connect ( () => {
workspace.activate_with_focus (w, workspace.get_screen ().get_display ().get_current_time ());
return false;
});
icons.add_child (icon);
});
icons.x = Math.floorf (wallpaper.x + wallpaper.width / 2 - icons.width / 2);
icons.y = Math.floorf (wallpaper.y + wallpaper.height - 5);
}
void check_last_workspace ()
{
//last workspace, show plus button and so on
//give the last one a different style
var index = screen.get_workspaces ().index (workspace);
if (index < 0) {
closed ();
return;
}
if (index == screen.n_workspaces - 1) {
wallpaper.opacity = 127;
if (plus.get_parent () == null)
add_child (plus);
} else {
wallpaper.opacity = 255;
if (contains (plus))
remove_child (plus);
}
}
void handle_workspace_switched (int index_old, int index_new, Meta.MotionDirection direction)
{
if (index_old == index_new)
return;
if (workspace == null)
return;
if (workspace.index () == index_old)
indicator.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 200, opacity : 0);
else if (workspace.index () == index_new)
indicator.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 200, opacity : 255);
}
void handle_window_added (Meta.Window window)
{
if (workspace != null && workspace.index () == screen.n_workspaces - 1 && Utils.get_n_windows (workspace) > 0)
window_on_last ();
}
void handle_window_removed (Meta.Window window)
{
//dont remove workspaces when for example slingshot was closed
if (window.window_type != WindowType.NORMAL &&
window.window_type != WindowType.DIALOG &&
window.window_type != WindowType.MODAL_DIALOG)
return;
if (workspace != null && Utils.get_n_windows (workspace) == 0) {
workspace.window_added.disconnect (handle_window_added);
workspace.window_removed.disconnect (handle_window_removed);
closed ();
}
}
public override void hide ()
{
base.hide ();
icons.remove_all_children ();
windows.remove_all_children ();
}
public override void show ()
{
check_last_workspace ();
update_icons ();
update_windows ();
base.show ();
}
public override bool button_release_event (ButtonEvent event)
{
if (workspace == null)
return true;
workspace.activate (screen.get_display ().get_current_time ());
clicked ();
return true;
}
public override bool enter_event (CrossingEvent event)
{
if (workspace == null)
return true;
if (workspace.index () == screen.n_workspaces - 1) {
wallpaper.animate (AnimationMode.EASE_OUT_QUAD, 300, opacity : 210);
return true;
}
if (hover_timer > 0)
GLib.Source.remove (hover_timer);
hover_timer = Timeout.add (CLOSE_BUTTON_DELAY, () => {
close_button.visible = true;
close_button.animate (AnimationMode.EASE_OUT_ELASTIC, 400, scale_x : 1.0f, scale_y : 1.0f);
return false;
});
return true;
}
public override bool leave_event (CrossingEvent event)
{
if (contains (event.related))
return false;
if (hover_timer > 0) {
GLib.Source.remove (hover_timer);
hover_timer = 0;
}
if (workspace == null)
return false;
if (workspace.index () == screen.n_workspaces - 1)
wallpaper.animate (AnimationMode.EASE_OUT_QUAD, 400, opacity : 127);
else
close_button.animate (AnimationMode.EASE_IN_QUAD, 400, scale_x : 0.0f, scale_y : 0.0f)
.completed.connect (() => close_button.visible = false );
return false;
}
}
}

View File

@ -21,161 +21,72 @@ namespace Gala
{
public class WorkspaceView : Clutter.Actor
{
Gala.Plugin plugin;
static const float VIEW_HEIGHT = 140.0f;
Clutter.Actor workspaces;
Clutter.CairoTexture bg;
Gala.Plugin plugin;
Screen screen;
Clutter.Actor thumbnails;
Clutter.CairoTexture background;
Clutter.CairoTexture scroll;
bool animating; // delay closing the popup
Gdk.Pixbuf? background_pix;
Clutter.CairoTexture workspace_thumb;
Clutter.CairoTexture current_workspace;
float last_workspace_x = 0;
int _workspace;
int workspace {
get {
return _workspace;
}
set {
if (_workspace == value)
return;
_workspace = value;
if ((int) workspaces.get_children ().nth_data (_workspace).x != 0 || _workspace == 0)
last_workspace_x = workspaces.get_children ().nth_data (_workspace).x;
current_workspace.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, 400,
x : workspaces.x + last_workspace_x - 5);
}
}
const string CURRENT_WORKSPACE_STYLE = """
* {
border-style: solid;
border-width: 1px 1px 1px 1px;
-unico-inner-stroke-width: 1px 0 1px 0;
border-radius: 8px;
background-image: -gtk-gradient (linear,
left top,
left bottom,
from (shade (@selected_bg_color, 1.4)),
to (shade (@selected_bg_color, 0.98)));
-unico-border-gradient: -gtk-gradient (linear,
left top, left bottom,
from (alpha (#000, 0.5)),
to (alpha (#000, 0.6)));
-unico-inner-stroke-gradient: -gtk-gradient (linear,
left top, left bottom,
from (alpha (#fff, 0.90)),
to (alpha (#fff, 0.06)));
}
""";
Gtk.Menu current_workspace_style; //dummy item for drawing
public WorkspaceView (Gala.Plugin _plugin)
{
plugin = _plugin;
screen = plugin.get_screen ();
height = 128;
height = VIEW_HEIGHT;
opacity = 0;
reactive = true;
workspaces = new Clutter.Actor ();
var box_layout = new Clutter.BoxLayout ();
box_layout.spacing = 12;
workspaces.set_layout_manager (box_layout);
thumbnails = new Clutter.Actor ();
thumbnails.layout_manager = new Clutter.BoxLayout ();
(thumbnails.layout_manager as Clutter.BoxLayout).spacing = 12;
(thumbnails.layout_manager as Clutter.BoxLayout).homogeneous = true;
bg = new Clutter.CairoTexture (500, (uint)height);
bg.auto_resize = true;
bg.add_constraint (new Clutter.BindConstraint (this, Clutter.BindCoordinate.WIDTH, 0));
bg.add_constraint (new Clutter.BindConstraint (this, Clutter.BindCoordinate.HEIGHT, 0));
bg.draw.connect (draw_background);
background = new Clutter.CairoTexture (500, (uint)height);
background.auto_resize = true;
background.add_constraint (new Clutter.BindConstraint (this, Clutter.BindCoordinate.WIDTH, 0));
background.add_constraint (new Clutter.BindConstraint (this, Clutter.BindCoordinate.HEIGHT, 0));
background.draw.connect (draw_background);
leave_event.connect ((e) => {
if (!contains (e.related))
hide ();
return false;
});
scroll = new Clutter.CairoTexture (100, 12);
scroll.height = 12;
scroll.auto_resize = true;
scroll.draw.connect (draw_scroll);
int width, height;
var area = plugin.get_screen ().get_monitor_geometry (plugin.get_screen ().get_primary_monitor ());
width = area.width;
height = area.height;
add_child (background);
add_child (thumbnails);
add_child (scroll);
workspace_thumb = new Clutter.CairoTexture (120, 120);
workspace_thumb.height = 80;
workspace_thumb.width = (workspace_thumb.height / height) * width;
workspace_thumb.auto_resize = true;
workspace_thumb.draw.connect (draw_workspace_thumb);
screen.workareas_changed.connect (initial_configuration);
}
//method that waits for the workspaces to be configured on first run
void initial_configuration ()
{
screen.workareas_changed.disconnect (initial_configuration);
current_workspace_style = new Gtk.Menu ();
var provider = new Gtk.CssProvider ();
try {
provider.load_from_data (CURRENT_WORKSPACE_STYLE, -1);
} catch (Error e) { warning (e.message); }
current_workspace_style.get_style_context ().add_provider (provider, 20000);
//remove everything except for the first
for (var i=1;i<screen.get_workspaces ().length ();i++) {
screen.remove_workspace (screen.get_workspaces ().nth_data (i), screen.get_display ().get_current_time ());
}
current_workspace = new Clutter.CairoTexture (120, 120);
current_workspace.height = workspace_thumb.height + 10;
current_workspace.width = workspace_thumb.width + 10;
current_workspace.auto_resize = true;
current_workspace.draw.connect (draw_current_workspace);
var thumb = new WorkspaceThumb (screen.get_workspaces ().nth_data (0));
thumb.clicked.connect (hide);
thumb.closed.connect (remove_workspace);
thumb.window_on_last.connect (add_workspace);
var settings = new GLib.Settings ("org.gnome.desktop.background");
thumbnails.add_child (thumb);
settings.changed.connect ((key) => {
if (key == "picture-uri") {
var path = File.new_for_uri (settings.get_string ("picture-uri")).get_path ();
try {
background_pix = new Gdk.Pixbuf.from_file (path).scale_simple
((int)workspace_thumb.width, (int)workspace_thumb.height, Gdk.InterpType.HYPER);
} catch (Error e) { warning (e.message); }
//do a second run if necessary
if (screen.n_workspaces != 1) {
for (var i=1;i<screen.get_workspaces ().length ();i++) {
screen.remove_workspace (screen.get_workspaces ().nth_data (i), screen.get_display ().get_current_time ());
}
});
var path = File.new_for_uri (settings.get_string ("picture-uri")).get_path ();
try {
background_pix = new Gdk.Pixbuf.from_file (path).scale_simple
((int)workspace_thumb.width, (int)workspace_thumb.height, Gdk.InterpType.HYPER);
} catch (Error e) { warning (e.message); }
add_child (workspace_thumb);
add_child (bg);
add_child (current_workspace);
add_child (workspaces);
workspace_thumb.visible = false; //will only be used for cloning
}
bool draw_current_workspace (Cairo.Context cr)
{
current_workspace_style.get_style_context ().render_activity (cr, 0, 0,
current_workspace.width, current_workspace.height);
return false;
}
bool draw_workspace_thumb (Cairo.Context cr)
{
Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, 0, 0,
workspace_thumb.width, workspace_thumb.height, 5);
if (background_pix != null)
Gdk.cairo_set_source_pixbuf (cr, background_pix, 0, 0);
else
cr.set_source_rgb (0, 0, 0);
cr.fill_preserve ();
cr.set_line_width (1);
cr.set_source_rgba (0, 0, 0, 1);
cr.stroke_preserve ();
return false;
}
}
bool draw_background (Cairo.Context cr)
@ -201,19 +112,83 @@ namespace Gala
return false;
}
bool draw_scroll (Cairo.Context cr)
{
Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, 4, 4, scroll.width-32, 4, 2);
cr.set_source_rgba (1, 1, 1, 0.8);
cr.fill ();
return false;
}
void add_workspace ()
{
var screen = plugin.get_screen ();
var wp = screen.append_new_workspace (false, screen.get_display ().get_current_time ());
if (wp == null)
return;
var thumb = new WorkspaceThumb (wp);
thumb.clicked.connect (hide);
thumb.closed.connect (remove_workspace);
thumb.window_on_last.connect (add_workspace);
thumbnails.add_child (thumb);
check_scrollbar ();
}
void remove_workspace (WorkspaceThumb thumb)
{
thumb.clicked.disconnect (hide);
thumb.closed.disconnect (remove_workspace);
thumb.window_on_last.disconnect (add_workspace);
var workspace = thumb.workspace;
if (workspace != null && workspace.index () > -1) { //dont remove non existing workspaces
var screen = workspace.get_screen ();
screen.remove_workspace (workspace, screen.get_display ().get_current_time ());
}
thumb.workspace = null;
thumbnails.remove_child (thumb);
thumb.destroy ();
check_scrollbar ();
}
void check_scrollbar ()
{
scroll.visible = thumbnails.width > width;
if (scroll.visible) {
if (thumbnails.x + thumbnails.width < width)
thumbnails.x = width - thumbnails.width;
scroll.width = width / thumbnails.width * width;
} else {
thumbnails.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 400, x : width / 2 - thumbnails.width / 2);
}
}
void switch_to_next_workspace (bool reverse)
{
var screen = plugin.get_screen ();
var display = screen.get_display ();
var idx = screen.get_active_workspace_index () + (reverse ? -1 : 1);
var neighbor = screen.get_active_workspace ().get_neighbor (reverse ? MotionDirection.LEFT : MotionDirection.RIGHT);
if (idx < 0 || idx >= screen.n_workspaces)
if (neighbor == null)
return;
screen.get_workspace_by_index (idx).activate (display.get_current_time ());
if (workspaces.x != 0)
workspace = idx;
neighbor.activate (display.get_current_time ());
}
public override bool leave_event (Clutter.CrossingEvent event) {
if (!contains (event.related))
hide ();
return false;
}
public override bool key_press_event (Clutter.KeyEvent event)
@ -245,7 +220,21 @@ namespace Gala
return false;
}
//FIXME move all this positioning stuff to a separate function which is only called by screen size changes
const float scroll_speed = 30.0f;
public override bool scroll_event (Clutter.ScrollEvent event)
{
if ((event.direction == Clutter.ScrollDirection.DOWN || event.direction == Clutter.ScrollDirection.RIGHT)
&& thumbnails.width + thumbnails.x > width) { //left
thumbnails.x -= scroll_speed;
} else if ((event.direction == Clutter.ScrollDirection.UP || event.direction == Clutter.ScrollDirection.LEFT)
&& thumbnails.x < 0) { //right
thumbnails.x += scroll_speed;
}
scroll.x = Math.floorf (width / thumbnails.width * thumbnails.x);
return false;
}
public new void show ()
{
if (visible)
@ -256,92 +245,34 @@ namespace Gala
Utils.set_input_area (screen, Utils.InputArea.FULLSCREEN);
plugin.begin_modal ();
animating = true;
var area = screen.get_monitor_geometry (screen.get_primary_monitor ());
y = area.height;
width = area.width;
/*get the workspaces together*/
workspaces.remove_all_children ();
thumbnails.get_children ().foreach ((thumb) => {
thumb.show ();
});
for (var i = 0; i < screen.n_workspaces; i++) {
var space = screen.get_workspace_by_index (i);
var group = new Clutter.Actor ();
var icons = new Clutter.Actor ();
icons.set_layout_manager (new Clutter.BoxLayout ());
var backg = new Clutter.Clone (workspace_thumb);
var shown_applications = new List<Bamf.Application> ();
space.list_windows ().foreach ((w) => {
if (w.window_type != Meta.WindowType.NORMAL || w.minimized)
return;
var app = Bamf.Matcher.get_default ().get_application_for_xid ((uint32)w.get_xwindow ());
if (shown_applications.index (app) != -1)
return;
if (app != null)
shown_applications.append (app);
var pix = Utils.get_icon_for_window (w, 32);
var icon = new GtkClutter.Texture ();
try {
icon.set_from_pixbuf (pix);
} catch (Error e) { warning (e.message); }
icon.reactive = true;
icon.button_release_event.connect ( () => {
space.activate_with_focus (w, screen.get_display ().get_current_time ());
hide ();
return false;
});
icons.add_child (icon);
});
group.add_child (backg);
group.add_child (icons);
icons.y = Math.floorf (backg.height - 16);
icons.x = Math.floorf (group.width / 2 - icons.width / 2);
(icons.layout_manager as Clutter.BoxLayout).spacing = 6;
group.height = 160;
group.reactive = true;
group.button_release_event.connect (() => {
space.activate (plugin.get_screen ().get_display ().get_current_time ());
workspace = plugin.get_screen ().get_active_workspace ().index ();
hide ();
return true;
});
workspaces.add_child (group);
thumbnails.x = width / 2 - thumbnails.width / 2;
thumbnails.y = 15;
scroll.visible = thumbnails.width > width;
if (scroll.visible) {
scroll.y = height - 12;
scroll.x = 0.0f;
scroll.width = width / thumbnails.width * width;
thumbnails.x = 4.0f;
}
var new_idx = screen.get_active_workspace ().index ();
bool recalc = current_workspace.x == 0;
workspaces.x = width / 2 - workspaces.width / 2;
workspaces.y = 25;
current_workspace.y = workspaces.y - 5;
animating = true;
Timeout.add (50, () => {
animating = false;
return false;
}); //catch hot corner hiding problem and indicator placement
visible = true;
grab_key_focus ();
Timeout.add (50, () => animating = false ); //catch hot corner hiding problem
animate (Clutter.AnimationMode.EASE_OUT_QUAD, 250, y : area.height - height, opacity : 255)
.completed.connect (() => {
});
if (recalc)
current_workspace.x = width / 2 - workspaces.width / 2 + (workspaces.get_children ().nth_data (0).width+12)*new_idx - 5;
else
workspace = new_idx;
animate (Clutter.AnimationMode.EASE_OUT_QUAD, 250, y : area.height - height, opacity : 255);
}
public new void hide ()
@ -355,8 +286,10 @@ namespace Gala
plugin.end_modal ();
plugin.update_input_area ();
animate (Clutter.AnimationMode.EASE_OUT_QUAD, 500, y : height)
.completed.connect ( () => {
animate (Clutter.AnimationMode.EASE_OUT_QUAD, 500, y : height).completed.connect (() => {
thumbnails.get_children ().foreach ((thumb) => {
thumb.hide ();
});
visible = false;
});
}