mirror of
https://github.com/elementary/gala.git
synced 2024-10-05 19:27:25 +03:00
Moved to horizontal layout, added workspace overview
This commit is contained in:
parent
1a29a1a5f0
commit
3fc7c5d689
@ -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
|
||||
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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 ();
|
||||
|
362
src/Widgets/WorkspaceView.vala
Normal file
362
src/Widgets/WorkspaceView.vala
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user