Moved to horizontal layout, added workspace overview

This commit is contained in:
Tom Beckmann 2012-06-01 20:54:17 +02:00
parent 1a29a1a5f0
commit 3fc7c5d689
6 changed files with 444 additions and 256 deletions

View File

@ -46,7 +46,7 @@ vala_precompile(VALA_C
src/TextShadowEffect.vala
src/Widgets/WorkspaceSwitcher.vala
src/Widgets/WindowSwitcher.vala
src/Widgets/CornerMenu.vala
src/Widgets/WorkspaceView.vala
${CMAKE_BINARY_DIR}/src/Config.vala
PACKAGES
granite

View File

@ -29,7 +29,7 @@ namespace Gala
{
WorkspaceSwitcher wswitcher;
WindowSwitcher winswitcher;
CornerMenu corner_menu;
WorkspaceView workspace_view;
Clutter.Actor elements;
public Plugin ()
@ -51,14 +51,14 @@ namespace Gala
Compositor.get_overlay_group_for_screen (screen).reparent (elements);
Compositor.get_stage_for_screen (screen).add_child (elements);
screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, -1, 4);
screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, 4, -1);
int width, height;
screen.get_size (out width, out height);
corner_menu = new CornerMenu (this);
elements.add_child (corner_menu);
corner_menu.visible = false;
workspace_view = new WorkspaceView (this);
elements.add_child (workspace_view);
workspace_view.visible = false;
wswitcher = new WorkspaceSwitcher (this);
wswitcher.workspaces = 4;
@ -73,7 +73,7 @@ namespace Gala
Settings.get_default().panel_main_menu_action);
} catch (Error e) { warning (e.message); }
});
KeyBinding.set_custom_handler ("toggle-recording", () => {
try {
Process.spawn_command_line_async (
@ -84,10 +84,10 @@ namespace Gala
KeyBinding.set_custom_handler ("switch-windows", winswitcher.handle_switch_windows);
KeyBinding.set_custom_handler ("switch-windows-backward", winswitcher.handle_switch_windows);
KeyBinding.set_custom_handler ("switch-to-workspace-left", () => {});
KeyBinding.set_custom_handler ("switch-to-workspace-right", () => {});
KeyBinding.set_custom_handler ("switch-to-workspace-up", wswitcher.handle_switch_to_workspace);
KeyBinding.set_custom_handler ("switch-to-workspace-down", wswitcher.handle_switch_to_workspace);
KeyBinding.set_custom_handler ("switch-to-workspace-up", () => {});
KeyBinding.set_custom_handler ("switch-to-workspace-down", () => {});
KeyBinding.set_custom_handler ("switch-to-workspace-left", wswitcher.handle_switch_to_workspace);
KeyBinding.set_custom_handler ("switch-to-workspace-right", wswitcher.handle_switch_to_workspace);
KeyBinding.set_custom_handler ("move-to-workspace-left", () => {});
KeyBinding.set_custom_handler ("move-to-workspace-right", () => {});
@ -99,14 +99,14 @@ namespace Gala
/*hot corner*/
var hot_corner = new Clutter.Rectangle ();
hot_corner.x = width - 2;
hot_corner.y = height - 2;
hot_corner.width = 2;
hot_corner.height = 2;
hot_corner.x = width - 1;
hot_corner.y = height - 1;
hot_corner.width = 1;
hot_corner.height = 1;
hot_corner.reactive = true;
hot_corner.enter_event.connect (() => {
corner_menu.show ();
workspace_view.show ();
return false;
});
@ -115,7 +115,7 @@ namespace Gala
update_input_area ();
Settings.get_default ().notify["enable-manager-corner"].connect (update_input_area);
}
void update_input_area ()
{
if (Settings.get_default ().enable_manager_corner)
@ -124,6 +124,31 @@ namespace Gala
set_input_area (InputArea.NONE);
}
/**
* returns a pixbuf for the application of this window or a default icon
**/
public Gdk.Pixbuf get_icon_for_window (Window window, int size) {
Gdk.Pixbuf image = null;
var app = Bamf.Matcher.get_default ().get_application_for_xid ((uint32)window.get_xwindow ());
if (app != null) {
var desktop = new GLib.DesktopAppInfo.from_filename (app.get_desktop_file ());
try {
image = Gtk.IconTheme.get_default ().lookup_by_gicon (desktop.get_icon (), size, 0).load_icon ();
} catch (Error e) { warning (e.message); }
}
if (image == null) {
try {
image = Gtk.IconTheme.get_default ().load_icon ("application-default-icon", size, 0);
} catch (Error e) {
warning (e.message);
}
}
return image;
}
/**
* set the area where clutter can receive events
**/
@ -171,13 +196,13 @@ namespace Gala
base.end_modal (get_screen ().get_display ().get_current_time ());
}
public int move_workspaces (bool up)
public int move_workspaces (bool left)
{
var i = screen.get_active_workspace_index ();
if (up && i - 1 >= 0) //move up
if (left && i - 1 >= 0) //move left
i --;
else if (!up && i + 1 < screen.n_workspaces) //move down
else if (!left && i + 1 < screen.n_workspaces) //move down
i ++;
if (i != screen.get_active_workspace_index ()) {
@ -305,20 +330,20 @@ namespace Gala
if (direction == MotionDirection.UP ||
direction == MotionDirection.UP_LEFT ||
direction == MotionDirection.UP_RIGHT)
y2 = h;
x2 = w;
else if (direction == MotionDirection.DOWN ||
direction == MotionDirection.DOWN_LEFT ||
direction == MotionDirection.DOWN_RIGHT)
y2 = -h;
x2 = -w;
if (direction == MotionDirection.LEFT ||
direction == MotionDirection.UP_LEFT ||
direction == MotionDirection.DOWN_LEFT)
y2 = h;
x2 = w;
else if (direction == MotionDirection.RIGHT ||
direction == MotionDirection.UP_RIGHT ||
direction == MotionDirection.DOWN_RIGHT)
y2 = -h;
x2 = -w;
var in_group = new Clutter.Group ();
var out_group = new Clutter.Group ();
@ -401,8 +426,8 @@ namespace Gala
{
unmaximize_completed (actor);
}
public override void kill_switch_workspace ()
public override void kill_switch_workspace ()
{
end_switch_workspace ();
}
@ -459,7 +484,7 @@ namespace Gala
Meta.init ();
GLib.Environment.unset_variable ("NO_GAIL");
GLib.Environment.unset_variable ("NO_AT_BRIDGE");
return Meta.run ();
}
}
}

View File

@ -1,174 +0,0 @@
//
// 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
{
public class CornerMenu : Clutter.Group
{
Gala.Plugin plugin;
Clutter.Box workspaces;
bool animating; // delay closing the popup
public CornerMenu (Gala.Plugin _plugin)
{
plugin = _plugin;
width = 100;
height = 100;
opacity = 0;
scale_gravity = Clutter.Gravity.SOUTH_EAST;
scale_x = scale_y = 0.0f;
reactive = true;
workspaces = new Clutter.Box (new Clutter.BoxLayout ());
(workspaces.layout_manager as Clutter.BoxLayout).spacing = 15;
(workspaces.layout_manager as Clutter.BoxLayout).vertical = true;
leave_event.connect ((e) => {
if (get_children ().index (e.related) == -1)
hide ();
return false;
});
var tile = new GtkClutter.Texture ();
try {
tile.set_from_pixbuf (Gtk.IconTheme.get_default ().load_icon ("preferences-desktop-display", 64, 0));
} catch (Error e) {
warning (e.message);
}
tile.x = 5;
tile.y = 5;
tile.reactive = true;
tile.button_release_event.connect (() => {
var windows = new GLib.List<Meta.Window> ();
plugin.screen.get_active_workspace ().list_windows ().foreach ( (w) => {
if (w.window_type != Meta.WindowType.NORMAL || w.minimized)
return;
windows.append (w);
});
//make sure active window is biggest
var active_idx = windows.index (plugin.screen.get_display ().get_focus_window ());
if (active_idx != -1 && active_idx != 0) {
windows.delete_link (windows.nth (active_idx));
windows.prepend (plugin.screen.get_display ().get_focus_window ());
}
unowned Meta.Rectangle area;
plugin.screen.get_active_workspace ().get_work_area_all_monitors (out area);
var n_wins = windows.length ();
var index = 0;
windows.foreach ( (w) => {
if (w.maximized_horizontally || w.maximized_vertically)
w.unmaximize (Meta.MaximizeFlags.VERTICAL | Meta.MaximizeFlags.HORIZONTAL);
switch (n_wins) {
case 1:
w.move_resize_frame (true, area.x, area.y, area.width, area.height);
break;
case 2:
w.move_resize_frame (true, area.x+area.width/2*index, area.y, area.width/2,
area.height);
break;
case 3:
if (index == 0)
w.move_resize_frame (true, area.x, area.y, area.width/2, area.height);
else {
w.move_resize_frame (true, area.x+area.width/2,
area.y+(area.height/2*(index-1)), area.width/2, area.height/2);
}
break;
case 4:
if (index < 2)
w.move_resize_frame (true, area.x+area.width/2*index, area.y,
area.width/2, area.height/2);
else
w.move_resize_frame (true, (index==3)?area.x+area.width/2:area.x,
area.y+area.height/2, area.width/2, area.height/2);
break;
case 5:
if (index < 2)
w.move_resize_frame (true, area.x, area.y+(area.height/2*index),
area.width/2, area.height/2);
else
w.move_resize_frame (true, area.x+area.width/2,
area.y+(area.height/3*(index-2)), area.width/2, area.height/3);
break;
case 6:
if (index < 3)
w.move_resize_frame (true, area.x, area.y+(area.height/3*index),
area.width/2, area.height/3);
else
w.move_resize_frame (true, area.x+area.width/2,
area.y+(area.height/3*(index-3)), area.width/2, area.height/3);
break;
default:
return;
}
index ++;
});
return true;
});
add_child (tile);
//add_child (workspaces);
}
public new void show ()
{
if (visible)
return;
plugin.set_input_area (Gala.InputArea.FULLSCREEN);
plugin.begin_modal ();
animating = true;
int width, height;
plugin.get_screen ().get_size (out width, out height);
x = width - this.width;
y = height - this.height;
visible = true;
grab_key_focus ();
animate (Clutter.AnimationMode.EASE_OUT_BOUNCE, 400, scale_x:1.0f, scale_y:1.0f, opacity:255).completed.connect (() => {
animating = false;
});
}
public new void hide ()
{
if (!visible || animating)
return;
plugin.end_modal ();
plugin.set_input_area (Gala.InputArea.HOT_CORNER);
animate (Clutter.AnimationMode.EASE_OUT_QUAD, 400, scale_x : 0.0f, scale_y : 0.0f, opacity : 0)
.completed.connect ( () => {
visible = false;
});
}
}
}

View File

@ -24,15 +24,15 @@ namespace Gala
{
const int ICON_SIZE = 128;
const int spacing = 12;
Gala.Plugin plugin;
GLib.List<unowned Meta.Window> window_list;
CairoTexture background;
CairoTexture current;
Text title;
int _windows = 1;
int windows {
get { return _windows; }
@ -41,7 +41,7 @@ namespace Gala
width = spacing + _windows * (ICON_SIZE + spacing);
}
}
Meta.Window? _current_window;
Meta.Window? current_window {
get { return _current_window; }
@ -51,7 +51,7 @@ namespace Gala
title.x = (int)(width / 2 - title.width / 2);
}
}
public WindowSwitcher (Gala.Plugin _plugin)
{
plugin = _plugin;
@ -86,7 +86,7 @@ namespace Gala
background.add_constraint (new BindConstraint (this, BindCoordinate.WIDTH, 0));
background.add_constraint (new BindConstraint (this, BindCoordinate.HEIGHT, 0));
}
public override bool key_release_event (Clutter.KeyEvent event)
{
if (((event.modifier_state & ModifierType.MOD1_MASK) == 0) ||
@ -177,40 +177,14 @@ namespace Gala
return;
}
var matcher = Bamf.Matcher.get_default ();
var i = 0;
window_list = display.get_tab_list (Meta.TabList.NORMAL, screen, screen.get_active_workspace ()).copy ();
window_list.foreach ((w) => {
if (w == null)
return;
Bamf.Window bamfwin = null;
matcher.get_windows ().foreach ( (bamfw) => {
if ((bamfw as Bamf.Window).get_pid () == (uint32)w.get_pid ()) {
bamfwin = bamfw as Bamf.Window;
}
});
Gdk.Pixbuf image = null;
if (bamfwin != null) {
var app = matcher.get_application_for_window (bamfwin);
if (app != null) {
var desktop = new GLib.DesktopAppInfo.from_filename (app.get_desktop_file ());
try {
image = Gtk.IconTheme.get_default ().lookup_by_gicon (desktop.get_icon (), ICON_SIZE, 0).load_icon ();
} catch (Error e) { warning (e.message); }
}
}
if (image == null) {
try {
image = Gtk.IconTheme.get_default ().load_icon ("application-default-icon", ICON_SIZE, 0);
} catch (Error e) {
warning (e.message);
}
}
var image = plugin.get_icon_for_window (w, ICON_SIZE);
var icon = new GtkClutter.Texture ();
try {

View File

@ -22,7 +22,7 @@ namespace Gala
{
public class WorkspaceSwitcher : Group
{
const float WIDTH = 200;
const float HEIGHT = 150;
const int spacing = 10;
float len;
@ -37,7 +37,7 @@ namespace Gala
get { return _workspaces; }
set {
_workspaces = value;
height = len * _workspaces + spacing;
width = len * _workspaces + spacing;
}
}
@ -46,7 +46,7 @@ namespace Gala
get { return _workspace; }
set {
_workspace = value;
current.animate (AnimationMode.EASE_OUT_QUAD, 300, y : _workspace * len + 1 + spacing);
current.animate (AnimationMode.EASE_OUT_QUAD, 300, x : _workspace * len + 1 + spacing);
}
}
@ -57,20 +57,21 @@ namespace Gala
int w, h;
plugin.screen.get_size (out w, out h);
len = (float)h / w * WIDTH;
len = (float)w / h * HEIGHT;
height = 100 + spacing * 2;
width = WIDTH + spacing * 2;
width = 100 + spacing * 2;
height = HEIGHT + spacing * 2;
opacity = 0;
background = new CairoTexture (100, (int)WIDTH);
background = new CairoTexture (100, (int)HEIGHT);
background.auto_resize = true;
background.draw.connect (draw_background);
current = new CairoTexture (100, 100);
current.x = spacing + 1;
current.width = width - 1 - spacing * 2;
current.height = len - 1 - spacing;
current.y = spacing + 1;
current.width = len - 1 - spacing;
current.height = height - 1 - spacing * 2;
current.auto_resize = true;
current.draw.connect (draw_current);
@ -82,7 +83,7 @@ namespace Gala
background.add_constraint (new BindConstraint (this, BindCoordinate.WIDTH, 0));
background.add_constraint (new BindConstraint (this, BindCoordinate.HEIGHT, 0));
}
public override bool key_release_event (KeyEvent event)
{
if (((event.modifier_state & ModifierType.MOD1_MASK) == 0) ||
@ -99,10 +100,10 @@ namespace Gala
public override bool key_press_event (KeyEvent event)
{
switch (event.keyval) {
case Key.Up:
case Key.Left:
workspace = plugin.move_workspaces (true);
return false;
case Key.Down:
case Key.Right:
workspace = plugin.move_workspaces (false);
return false;
default:
@ -123,8 +124,8 @@ namespace Gala
cr.fill ();
for (var i = 0; i < workspaces; i++) {
Utilities.cairo_rounded_rectangle (cr, 0.5 + spacing, i * len + 0.5 + spacing,
width - 1 - spacing * 2, len - 1 - spacing, 10);
Utilities.cairo_rounded_rectangle (cr, i * len + 0.5 + spacing, 0.5 + spacing,
len - 1 - spacing, height - 1 - spacing * 2, 10);
cr.set_line_width (1);
cr.set_source_rgba (0, 0, 0, 0.8);
cr.stroke_preserve ();
@ -134,10 +135,10 @@ namespace Gala
return true;
}
bool draw_current (Cairo.Context cr)
{
Utilities.cairo_rounded_rectangle (cr, 0.5, 0.5, current.width - 2, current.height - 1, 10);
Utilities.cairo_rounded_rectangle (cr, 0.5, 0.5, current.width - 2, current.height - 2, 10);
cr.set_line_width (1);
cr.set_source_rgba (0, 0, 0, 0.9);
cr.stroke_preserve ();
@ -156,9 +157,9 @@ namespace Gala
x = width / 2 - this.width / 2;
y = height / 2 - this.height / 2;
animate (Clutter.AnimationMode.EASE_OUT_QUAD, 100, opacity:255);
bool up = (binding.get_name () == "switch-to-workspace-up");
workspace = plugin.move_workspaces (up);;
bool left = (binding.get_name () == "switch-to-workspace-left");
workspace = plugin.move_workspaces (left);
plugin.begin_modal ();
grab_key_focus ();

View File

@ -0,0 +1,362 @@
//
// 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;
namespace Gala
{
public class WorkspaceView : Clutter.Group
{
Gala.Plugin plugin;
Clutter.Box workspaces;
Clutter.CairoTexture bg;
GtkClutter.Texture tile;
bool animating; // delay closing the popup
Gdk.Pixbuf background_pix;
Clutter.CairoTexture workspace_thumb;
Clutter.CairoTexture current_workspace;
const string CURRENT_WORKSPACE_STYLE = """
* {
border-style: solid;
border-width: 1px 1px 1px 1px;
-unico-inner-stroke-width: 1px 0 1px 0;
border-radius: 5px;
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 (shade (@selected_bg_color, 1.05)),
to (shade (@selected_bg_color, 0.88)));
-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;
height = 200;
opacity = 0;
scale_gravity = Clutter.Gravity.SOUTH_EAST;
reactive = true;
workspaces = new Clutter.Box (new Clutter.BoxLayout ());
(workspaces.layout_manager as Clutter.BoxLayout).spacing = 12;
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);
leave_event.connect ((e) => {
if (!contains (e.related))
hide ();
return false;
});
tile = new GtkClutter.Texture ();
try {
tile.set_from_pixbuf (Gtk.IconTheme.get_default ().load_icon ("preferences-desktop-display", 64, 0));
} catch (Error e) {
warning (e.message);
}
tile.x = 5;
tile.y = 5;
tile.reactive = true;
tile.button_release_event.connect (() => {
var windows = new GLib.List<Window> ();
plugin.screen.get_active_workspace ().list_windows ().foreach ( (w) => {
if (w.window_type != Meta.WindowType.NORMAL || w.minimized)
return;
windows.append (w);
});
//make sure active window is biggest
var active_idx = windows.index (plugin.screen.get_display ().get_focus_window ());
if (active_idx != -1 && active_idx != 0) {
windows.delete_link (windows.nth (active_idx));
windows.prepend (plugin.screen.get_display ().get_focus_window ());
}
unowned Rectangle area;
plugin.screen.get_active_workspace ().get_work_area_all_monitors (out area);
var n_wins = windows.length ();
var index = 0;
windows.foreach ( (w) => {
if (w.maximized_horizontally || w.maximized_vertically)
w.unmaximize (Meta.MaximizeFlags.VERTICAL | Meta.MaximizeFlags.HORIZONTAL);
switch (n_wins) {
case 1:
w.move_resize_frame (true, area.x, area.y, area.width, area.height);
break;
case 2:
w.move_resize_frame (true, area.x+area.width/2*index, area.y, area.width/2,
area.height);
break;
case 3:
if (index == 0)
w.move_resize_frame (true, area.x, area.y, area.width/2, area.height);
else {
w.move_resize_frame (true, area.x+area.width/2,
area.y+(area.height/2*(index-1)), area.width/2, area.height/2);
}
break;
case 4:
if (index < 2)
w.move_resize_frame (true, area.x+area.width/2*index, area.y,
area.width/2, area.height/2);
else
w.move_resize_frame (true, (index==3)?area.x+area.width/2:area.x,
area.y+area.height/2, area.width/2, area.height/2);
break;
case 5:
if (index < 2)
w.move_resize_frame (true, area.x, area.y+(area.height/2*index),
area.width/2, area.height/2);
else
w.move_resize_frame (true, area.x+area.width/2,
area.y+(area.height/3*(index-2)), area.width/2, area.height/3);
break;
case 6:
if (index < 3)
w.move_resize_frame (true, area.x, area.y+(area.height/3*index),
area.width/2, area.height/3);
else
w.move_resize_frame (true, area.x+area.width/2,
area.y+(area.height/3*(index-3)), area.width/2, area.height/3);
break;
default:
return;
}
index ++;
});
return true;
});
int width, height;
plugin.get_screen ().get_size (out width, out height);
workspace_thumb = new Clutter.CairoTexture (120, 120);
workspace_thumb.height = 120;
workspace_thumb.width = (workspace_thumb.height / height) * width;
workspace_thumb.auto_resize = true;
workspace_thumb.draw.connect (draw_workspace_thumb);
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);
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 path = File.new_for_uri (new GLib.Settings ("org.gnome.desktop.background").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 (tile);
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.5, 0.5,
current_workspace.width-1, current_workspace.height-1);
return false;
}
bool draw_workspace_thumb (Cairo.Context cr)
{
Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, 0.5, 0.5,
workspace_thumb.width-1, workspace_thumb.height-1, 5);
Gdk.cairo_set_source_pixbuf (cr, background_pix, 0.5, 0.5);
cr.fill_preserve ();
cr.set_line_width (1);
cr.set_source_rgba (0, 0, 0, 0.6);
cr.stroke_preserve ();
var grad = new Cairo.Pattern.linear (0, 0, 30, workspace_thumb.height-50);
grad.add_color_stop_rgba (0.99, 1, 1, 1, 0.2);
grad.add_color_stop_rgba (1, 1, 1, 1, 0);
cr.set_source (grad);
cr.fill ();
return false;
}
bool draw_background (Cairo.Context cr)
{
cr.rectangle (0, 0, width, height);
cr.set_source_rgb (0.15, 0.15, 0.15);
cr.fill ();
cr.move_to (0, 0);
cr.line_to (width, 0);
cr.set_line_width (1);
cr.set_source_rgb (1, 1, 1);
cr.stroke ();
var grad = new Cairo.Pattern.linear (0, 0, 0, 20);
grad.add_color_stop_rgba (0, 0, 0, 0, 0.4);
grad.add_color_stop_rgba (1, 0, 0, 0, 0);
cr.rectangle (0, 1, width, 20);
cr.set_source (grad);
cr.fill ();
return false;
}
//FIXME move all this positioning stuff to a separate function which is only called by screen size changes
public new void show ()
{
if (visible)
return;
plugin.set_input_area (Gala.InputArea.FULLSCREEN);
plugin.begin_modal ();
animating = true;
int width, height;
plugin.get_screen ().get_size (out width, out height);
tile.x = width - 80;
tile.y = 120;
y = height;
this.width = width;
/*get the workspaces together*/
workspaces.foreach ( (c) => workspaces.remove_child (c) );
for (var i=0;i<plugin.get_screen ().n_workspaces;i++) {
var space = plugin.get_screen ().get_workspace_by_index (i);
var group = new Clutter.Group ();
var icons = new Clutter.Box (new Clutter.BoxLayout ());
var backg = new Clutter.Clone (workspace_thumb);
space.list_windows ().foreach ((w) => {
if (w.window_type != Meta.WindowType.NORMAL)
return;
var pix = plugin.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 ( () => {
w.activate_with_workspace (plugin.screen.get_display ().get_current_time (),
space);
return false;
});
icons.add_child (icon);
});
group.add_child (icons);
group.add_child (backg);
icons.y = backg.height + 12;
icons.x = 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.screen.get_display ().get_current_time ());
current_workspace.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 300,
x : workspaces.x - 5 +
plugin.screen.get_active_workspace ().index () *
(workspaces.get_children ().nth_data (0).width + 10));
return true;
});
workspaces.add_child (group);
}
workspaces.x = this.width / 2 - workspaces.width / 2;
workspaces.y = 25;
current_workspace.x = workspaces.x - 5 +
plugin.screen.get_active_workspace ().index () *
(workspaces.get_children ().nth_data (0).width + 10);
current_workspace.y = workspaces.y - 5;
visible = true;
grab_key_focus ();
animate (Clutter.AnimationMode.EASE_OUT_SINE, 400, y : height-this.height, opacity : 255)
.completed.connect (() => {
animating = false;
});
}
public new void hide ()
{
if (!visible || animating)
return;
float width, height;
plugin.get_screen ().get_size (out width, out height);
plugin.end_modal ();
plugin.set_input_area (Gala.InputArea.HOT_CORNER);
animate (Clutter.AnimationMode.EASE_IN_SINE, 400, y : height)
.completed.connect ( () => {
visible = false;
});
}
}
}