mirror of
https://github.com/elementary/gala.git
synced 2024-09-17 10:27:37 +03:00
Various small fixes, added workspace manager, new animations for IconGroup
This commit is contained in:
parent
0af86fdbf9
commit
ff48c641fd
@ -1,5 +1,5 @@
|
||||
stylesdir = $(pkgdatadir)
|
||||
styles_DATA = gala.css texture.png
|
||||
styles_DATA = gala.css texture.png close.png
|
||||
|
||||
applicationsdir = $(datadir)/applications
|
||||
applications_DATA = gala.desktop
|
||||
@ -22,6 +22,7 @@ EXTRA_DIST = \
|
||||
gala.css \
|
||||
gala.desktop \
|
||||
texture.png \
|
||||
close.png \
|
||||
org.pantheon.desktop.gala.gschema.xml.in.in \
|
||||
$(NULL)
|
||||
|
||||
|
BIN
data/close.png
Normal file
BIN
data/close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
@ -24,6 +24,8 @@ namespace Gala
|
||||
static Gee.HashMap<string, Gdk.Pixbuf> icon_pixbuf_cache;
|
||||
static uint cache_clear_timeout = 0;
|
||||
|
||||
static Gdk.Pixbuf? close_pixbuf = null;
|
||||
|
||||
static construct
|
||||
{
|
||||
xid_pixbuf_cache = new Gee.HashMap<string, Gdk.Pixbuf> ();
|
||||
@ -72,7 +74,7 @@ namespace Gala
|
||||
/**
|
||||
* returns a pixbuf for the application of this window or a default icon
|
||||
**/
|
||||
public static Gdk.Pixbuf get_icon_for_window (Meta.Window window, int size)
|
||||
public static Gdk.Pixbuf? get_icon_for_window (Meta.Window window, int size)
|
||||
{
|
||||
Gdk.Pixbuf? result = null;
|
||||
|
||||
@ -220,6 +222,49 @@ namespace Gala
|
||||
screen.get_display ().get_compositor ().flash_screen (screen);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the close button pixbuf or null if it failed to load
|
||||
*/
|
||||
public static Gdk.Pixbuf? get_close_button_pixbuf ()
|
||||
{
|
||||
if (close_pixbuf == null) {
|
||||
try {
|
||||
close_pixbuf = new Gdk.Pixbuf.from_file (Config.PKGDATADIR + "/close.png");
|
||||
} catch (Error e) {
|
||||
warning (e.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return close_pixbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new reactive ClutterActor at 28x28 with the close pixbuf
|
||||
* @return The close button actor
|
||||
*/
|
||||
public static GtkClutter.Texture create_close_button ()
|
||||
{
|
||||
var texture = new GtkClutter.Texture ();
|
||||
var pixbuf = get_close_button_pixbuf ();
|
||||
|
||||
texture.reactive = true;
|
||||
texture.set_size (28, 28);
|
||||
|
||||
if (pixbuf != null) {
|
||||
try {
|
||||
texture.set_from_pixbuf (pixbuf);
|
||||
} catch (Error e) {}
|
||||
} else {
|
||||
// we'll just make this red so there's at least something as an
|
||||
// indicator that loading failed. Should never happen and this
|
||||
// works as good as some weird fallback-image-failed-to-load pixbuf
|
||||
texture.background_color = { 255, 0, 0, 255 };
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plank DockTheme
|
||||
*/
|
||||
|
@ -41,6 +41,7 @@ gala_VALASOURCES = \
|
||||
Settings.vala \
|
||||
TextShadowEffect.vala \
|
||||
WindowManager.vala \
|
||||
WorkspaceManager.vala \
|
||||
Background/Background.vala \
|
||||
Background/BackgroundCache.vala \
|
||||
Background/BackgroundManager.vala \
|
||||
|
@ -2,23 +2,184 @@ using Clutter;
|
||||
|
||||
namespace Gala
|
||||
{
|
||||
class WindowIcon : Actor
|
||||
{
|
||||
static Gdk.Pixbuf? app_fallback_icon_64 = null;
|
||||
static Gdk.Pixbuf? app_fallback_icon_22 = null;
|
||||
static Gdk.Pixbuf? app_fallback_icon_16 = null;
|
||||
static bool fallback_attempted_loading = false;
|
||||
static const string FALLBACK_ICON = "application-default-icon";
|
||||
|
||||
public Meta.Window window { get; construct; }
|
||||
|
||||
int _icon_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 ();
|
||||
//get_transition ("size").completed.connect (fade_new_icon);
|
||||
}
|
||||
}
|
||||
|
||||
bool _temporary;
|
||||
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.3);
|
||||
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.3);
|
||||
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;
|
||||
|
||||
GtkClutter.Texture? icon = null;
|
||||
GtkClutter.Texture? old_icon = null;
|
||||
|
||||
public WindowIcon (Meta.Window window)
|
||||
{
|
||||
Object (window: window);
|
||||
|
||||
set_pivot_point (0.5f, 0.5f);
|
||||
set_easing_mode (AnimationMode.EASE_OUT_ELASTIC);
|
||||
set_easing_duration (800);
|
||||
|
||||
if (!fallback_attempted_loading) {
|
||||
fallback_attempted_loading = true;
|
||||
try {
|
||||
app_fallback_icon_64 = Gtk.IconTheme.get_default ().load_icon (FALLBACK_ICON, 64, 0);
|
||||
app_fallback_icon_22 = Gtk.IconTheme.get_default ().load_icon (FALLBACK_ICON, 22, 0);
|
||||
app_fallback_icon_16 = Gtk.IconTheme.get_default ().load_icon (FALLBACK_ICON, 16, 0);
|
||||
} catch (Error e) {
|
||||
warning (e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void fade_new_icon ()
|
||||
{
|
||||
var new_icon = new GtkClutter.Texture ();
|
||||
new_icon.add_constraint (new BindConstraint (this, BindCoordinate.SIZE, 0));
|
||||
new_icon.opacity = 0;
|
||||
|
||||
var pixbuf = Utils.get_icon_for_window (window, icon_size);
|
||||
if (pixbuf == null) {
|
||||
switch (icon_size) {
|
||||
case 16:
|
||||
pixbuf = app_fallback_icon_16;
|
||||
break;
|
||||
case 22:
|
||||
pixbuf = app_fallback_icon_22;
|
||||
break;
|
||||
case 64:
|
||||
pixbuf = app_fallback_icon_64;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pixbuf != null)
|
||||
new_icon.set_from_pixbuf (pixbuf);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public class IconGroup : Actor
|
||||
{
|
||||
const int SIZE = 64;
|
||||
const string FALLBACK_ICON = "application-default-icon";
|
||||
|
||||
static const int PLUS_SIZE = 8;
|
||||
static const int PLUS_WIDTH = 24;
|
||||
|
||||
Gdk.Pixbuf? app_fallback_icon_64 = null;
|
||||
Gdk.Pixbuf? app_fallback_icon_22 = null;
|
||||
Gdk.Pixbuf? app_fallback_icon_16 = null;
|
||||
|
||||
public signal void selected ();
|
||||
|
||||
public Meta.Workspace workspace { get; construct; }
|
||||
|
||||
List<Meta.Window> windows;
|
||||
List<string> windows;
|
||||
|
||||
int current_icon_size = -1;
|
||||
|
||||
public IconGroup (Meta.Workspace workspace)
|
||||
{
|
||||
@ -34,14 +195,6 @@ namespace Gala
|
||||
canvas.set_size (SIZE, SIZE);
|
||||
canvas.draw.connect (draw);
|
||||
content = canvas;
|
||||
|
||||
try {
|
||||
app_fallback_icon_64 = Gtk.IconTheme.get_default ().load_icon (FALLBACK_ICON, 64, 0);
|
||||
app_fallback_icon_22 = Gtk.IconTheme.get_default ().load_icon (FALLBACK_ICON, 22, 0);
|
||||
app_fallback_icon_16 = Gtk.IconTheme.get_default ().load_icon (FALLBACK_ICON, 16, 0);
|
||||
} catch (Error e) {
|
||||
warning (e.message);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool button_release_event (ButtonEvent event)
|
||||
@ -53,21 +206,46 @@ namespace Gala
|
||||
|
||||
public void clear ()
|
||||
{
|
||||
windows = new List<Meta.Window> ();
|
||||
destroy_all_children ();
|
||||
}
|
||||
|
||||
public void add_window (Meta.Window window, bool no_redraw = false)
|
||||
public void add_window (Meta.Window window, bool no_redraw = false, bool temporary = false)
|
||||
{
|
||||
windows.append (window);
|
||||
var new_window = new WindowIcon (window);
|
||||
|
||||
new_window.save_easing_state ();
|
||||
new_window.set_easing_duration (0);
|
||||
new_window.set_position (32, 32);
|
||||
new_window.restore_easing_state ();
|
||||
new_window.temporary = temporary;
|
||||
|
||||
add_child (new_window);
|
||||
|
||||
if (!no_redraw)
|
||||
redraw ();
|
||||
}
|
||||
|
||||
public void remove_window (Meta.Window window)
|
||||
public void remove_window (Meta.Window window, bool animate = true)
|
||||
{
|
||||
windows.remove (window);
|
||||
redraw ();
|
||||
foreach (var child in get_children ()) {
|
||||
var w = child as WindowIcon;
|
||||
if (w.window == window) {
|
||||
if (animate) {
|
||||
w.set_easing_mode (AnimationMode.LINEAR);
|
||||
w.set_easing_duration (200);
|
||||
w.opacity = 0;
|
||||
|
||||
print ("c\n");
|
||||
w.get_transition ("opacity").completed.connect (() => {
|
||||
w.destroy ();
|
||||
redraw ();
|
||||
});
|
||||
print ("d\n");
|
||||
} else
|
||||
w.destroy ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void redraw ()
|
||||
@ -75,30 +253,27 @@ namespace Gala
|
||||
content.invalidate ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the background or plus sign and do layouting. We won't lose performance here
|
||||
* by relayouting in the same function, as it's only ever called when we invalidate it.
|
||||
*/
|
||||
bool draw (Cairo.Context cr)
|
||||
{
|
||||
cr.set_operator (Cairo.Operator.CLEAR);
|
||||
cr.paint ();
|
||||
cr.set_operator (Cairo.Operator.OVER);
|
||||
|
||||
// we never show more than 9, TODO: show an ellipsis when we do cut
|
||||
var n_windows = uint.min (windows.length (), 9);
|
||||
var n_windows = get_n_children ();
|
||||
|
||||
// single icon => big icon
|
||||
if (n_windows == 1) {
|
||||
var pix = Utils.get_icon_for_window (windows.nth_data (0), 64);
|
||||
if (pix == null) {
|
||||
if (app_fallback_icon_64 != null)
|
||||
pix = app_fallback_icon_64;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
var icon = get_child_at_index (0) as WindowIcon;
|
||||
icon.place (0, 0, 64);
|
||||
|
||||
Gdk.cairo_set_source_pixbuf (cr, pix, 0, 0);
|
||||
cr.paint ();
|
||||
return false;
|
||||
}
|
||||
|
||||
// folder
|
||||
// more than one => we need a folder
|
||||
Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, 0.5, 0.5, (int)width - 1, (int)height - 1, 5);
|
||||
|
||||
cr.set_source_rgba (0, 0, 0, 0.1);
|
||||
@ -157,8 +332,9 @@ namespace Gala
|
||||
else
|
||||
size = 16;
|
||||
|
||||
var columns = (int)Math.ceil (Math.sqrt (n_windows));
|
||||
var rows = (int)Math.ceil (n_windows / (double)columns);
|
||||
var n_tiled_windows = uint.min (n_windows, 9);
|
||||
var columns = (int)Math.ceil (Math.sqrt (n_tiled_windows));
|
||||
var rows = (int)Math.ceil (n_tiled_windows / (double)columns);
|
||||
|
||||
const int spacing = 6;
|
||||
|
||||
@ -167,28 +343,45 @@ namespace Gala
|
||||
var x_offset = SIZE / 2 - width / 2;
|
||||
var y_offset = SIZE / 2 - height / 2;
|
||||
|
||||
var show_ellipsis = false;
|
||||
var n_shown_windows = n_windows;
|
||||
// make place for an ellipsis
|
||||
if (n_shown_windows > 9) {
|
||||
n_shown_windows = 8;
|
||||
show_ellipsis = true;
|
||||
}
|
||||
|
||||
var x = x_offset;
|
||||
var y = y_offset;
|
||||
for (var i = 0; i < n_windows; i++) {
|
||||
var pix = Utils.get_icon_for_window (windows.nth_data (i), size);
|
||||
if (pix == null) {
|
||||
if (size == 22 && app_fallback_icon_22 != null)
|
||||
pix = app_fallback_icon_22;
|
||||
else if (size == 16 && app_fallback_icon_16 != null)
|
||||
pix = app_fallback_icon_16;
|
||||
else
|
||||
continue;
|
||||
var window = get_child_at_index (i) as WindowIcon;
|
||||
|
||||
// draw an ellipsis at the 9th position if we need one
|
||||
if (show_ellipsis && i == 8) {
|
||||
const int top_offset = 10;
|
||||
const int left_offset = 2;
|
||||
const int radius = 2;
|
||||
const int spacing = 3;
|
||||
cr.arc (left_offset + x, y + top_offset, radius, 0, 2 * Math.PI);
|
||||
cr.arc (left_offset + x + radius + spacing, y + top_offset, radius, 0, 2 * Math.PI);
|
||||
cr.arc (left_offset + x + radius * 2 + spacing * 2, y + top_offset, radius, 0, 2 * Math.PI);
|
||||
|
||||
cr.set_source_rgb (0.3, 0.3, 0.3);
|
||||
cr.fill ();
|
||||
}
|
||||
|
||||
Gdk.cairo_set_source_pixbuf (cr, pix, x, y);
|
||||
if (i >= n_shown_windows) {
|
||||
window.visible = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
window.place (x, y, size);
|
||||
|
||||
x += size + spacing;
|
||||
if (x + size >= SIZE) {
|
||||
x = x_offset;
|
||||
y += size + spacing;
|
||||
}
|
||||
|
||||
cr.paint ();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -22,6 +22,7 @@ namespace Gala
|
||||
reactive = true;
|
||||
|
||||
workspaces = new Actor ();
|
||||
workspaces.set_easing_mode (AnimationMode.EASE_OUT_QUAD);
|
||||
|
||||
icon_groups = new Actor ();
|
||||
icon_groups.layout_manager = new BoxLayout ();
|
||||
@ -35,7 +36,7 @@ namespace Gala
|
||||
|
||||
screen.workspace_added.connect (add_workspace);
|
||||
screen.workspace_removed.connect (remove_workspace);
|
||||
screen.workspace_switched.connect ((from, to, direction) => {
|
||||
screen.workspace_switched.connect_after ((from, to, direction) => {
|
||||
update_positions (opened);
|
||||
});
|
||||
}
|
||||
@ -53,29 +54,25 @@ namespace Gala
|
||||
return false;
|
||||
}
|
||||
|
||||
void update_positions (bool animate = false, bool closing = false)
|
||||
void update_positions (bool animate = false)
|
||||
{
|
||||
float x = 0;
|
||||
WorkspaceClone? active = null;
|
||||
var active_index = screen.get_active_workspace ().index ();
|
||||
var active_x = 0.0f;
|
||||
|
||||
foreach (var child in workspaces.get_children ()) {
|
||||
var workspace_clone = child as WorkspaceClone;
|
||||
var index = workspace_clone.workspace.index ();
|
||||
var dest_x = index * (workspace_clone.width - 150);
|
||||
|
||||
if (index == active_index)
|
||||
active = workspace_clone;
|
||||
active_x = dest_x;
|
||||
|
||||
workspace_clone.x = index * (workspace_clone.width - 150);
|
||||
workspace_clone.set_easing_duration (animate ? 200 : 0);
|
||||
workspace_clone.x = dest_x;
|
||||
}
|
||||
|
||||
if (active != null) {
|
||||
var dest_x = -active.x;
|
||||
if (animate)
|
||||
workspaces.animate (AnimationMode.EASE_OUT_QUAD, 300, x: dest_x);
|
||||
else
|
||||
workspaces.x = dest_x;
|
||||
}
|
||||
workspaces.set_easing_duration (animate ? 300 : 0);
|
||||
workspaces.x = -active_x;
|
||||
}
|
||||
|
||||
void add_workspace (int num)
|
||||
@ -88,6 +85,9 @@ namespace Gala
|
||||
icon_groups.insert_child_at_index (workspace.icon_group, num);
|
||||
|
||||
update_positions ();
|
||||
|
||||
if (opened)
|
||||
workspace.open ();
|
||||
}
|
||||
|
||||
void remove_workspace (int num)
|
||||
@ -111,10 +111,20 @@ namespace Gala
|
||||
|
||||
workspace.window_selected.disconnect (window_selected);
|
||||
workspace.selected.disconnect (activate_workspace);
|
||||
workspace.icon_group.destroy ();
|
||||
|
||||
workspace.icon_group.set_easing_duration (200);
|
||||
workspace.icon_group.set_easing_mode (AnimationMode.LINEAR);
|
||||
workspace.icon_group.opacity = 0;
|
||||
var transition = workspace.icon_group.get_transition ("opacity");
|
||||
if (transition != null)
|
||||
transition.completed.connect (() => {
|
||||
workspace.icon_group.destroy ();
|
||||
});
|
||||
else
|
||||
workspace.icon_group.destroy ();
|
||||
workspace.destroy ();
|
||||
|
||||
update_positions ();
|
||||
update_positions (opened);
|
||||
}
|
||||
|
||||
void activate_workspace (WorkspaceClone clone, bool close_view)
|
||||
@ -228,10 +238,10 @@ namespace Gala
|
||||
/**
|
||||
* checks if val1 is about the same as val2 with a threshold of 2 by default
|
||||
*/
|
||||
private bool about_same (float val1, float val2, float threshold = 2.0f)
|
||||
/*private bool about_same (float val1, float val2, float threshold = 2.0f)
|
||||
{
|
||||
return Math.fabsf (val1 - val2) <= threshold;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,10 +12,13 @@ namespace Gala
|
||||
|
||||
DragDropAction drag_action;
|
||||
Clone? clone = null;
|
||||
Meta.Rectangle? slot = null;
|
||||
|
||||
Actor prev_parent = null;
|
||||
int prev_index = -1;
|
||||
|
||||
Actor close_button;
|
||||
|
||||
public TiledWindow (Meta.Window window)
|
||||
{
|
||||
Object (window: window);
|
||||
@ -34,6 +37,9 @@ namespace Gala
|
||||
drag_action.actor_clicked.connect (() => { selected (); });
|
||||
|
||||
add_action (drag_action);
|
||||
|
||||
close_button = Utils.create_close_button ();
|
||||
add_child (close_button);
|
||||
}
|
||||
|
||||
~TiledWindow ()
|
||||
@ -55,24 +61,77 @@ namespace Gala
|
||||
}
|
||||
|
||||
clone = new Clone (actor);
|
||||
clone.add_constraint (new BindConstraint (this, BindCoordinate.SIZE, 0));
|
||||
add_child (clone);
|
||||
|
||||
set_easing_duration (250);
|
||||
set_easing_mode (AnimationMode.EASE_OUT_QUAD);
|
||||
set_position (actor.x, actor.y);
|
||||
var outer_rect = window.get_outer_rect ();
|
||||
|
||||
request_reposition ();
|
||||
set_position (outer_rect.x, outer_rect.y);
|
||||
set_size (outer_rect.width, outer_rect.height);
|
||||
}
|
||||
|
||||
public void transition_to_original_state ()
|
||||
{
|
||||
var actor = window.get_compositor_private () as Actor;
|
||||
var outer_rect = window.get_outer_rect ();
|
||||
|
||||
set_easing_mode (AnimationMode.EASE_IN_OUT_CUBIC);
|
||||
set_easing_duration (300);
|
||||
set_size (actor.width, actor.height);
|
||||
set_position (actor.x, actor.y);
|
||||
|
||||
set_position (outer_rect.x, outer_rect.y);
|
||||
set_size (outer_rect.width, outer_rect.height);
|
||||
}
|
||||
|
||||
public void take_slot (Meta.Rectangle rect)
|
||||
{
|
||||
slot = rect;
|
||||
|
||||
set_easing_duration (250);
|
||||
set_easing_mode (AnimationMode.EASE_OUT_QUAD);
|
||||
|
||||
set_size (rect.width, rect.height);
|
||||
set_position (rect.x, rect.y);
|
||||
}
|
||||
|
||||
public override void allocate (ActorBox box, AllocationFlags flags)
|
||||
{
|
||||
base.allocate (box, flags);
|
||||
|
||||
foreach (var child in get_children ()) {
|
||||
if (child != clone)
|
||||
// child.allocate ({ child.x, child.y, child.x + child.width, child.y + child.height }, flags);
|
||||
child.allocate_preferred_size (flags);
|
||||
}
|
||||
|
||||
if (clone == null)
|
||||
return;
|
||||
|
||||
var actor = window.get_compositor_private () as WindowActor;
|
||||
var input_rect = window.get_input_rect ();
|
||||
var outer_rect = window.get_outer_rect ();
|
||||
var scale_factor = (float)width / outer_rect.width;
|
||||
|
||||
var alloc = ActorBox ();
|
||||
alloc.set_origin ((input_rect.x - outer_rect.x) * scale_factor,
|
||||
(input_rect.y - outer_rect.y) * scale_factor);
|
||||
alloc.set_size (actor.width * scale_factor, actor.height * scale_factor);
|
||||
|
||||
clone.allocate (alloc, flags);
|
||||
}
|
||||
|
||||
public void place_widgets (int dest_width, int dest_height)
|
||||
{
|
||||
Granite.CloseButtonPosition pos;
|
||||
Granite.Widgets.Utils.get_default_close_button_position (out pos);
|
||||
|
||||
close_button.y = 0;
|
||||
|
||||
switch (pos) {
|
||||
case Granite.CloseButtonPosition.RIGHT:
|
||||
close_button.x = dest_width;
|
||||
break;
|
||||
case Granite.CloseButtonPosition.LEFT:
|
||||
close_button.x = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void unmanaged ()
|
||||
@ -115,8 +174,13 @@ namespace Gala
|
||||
if (!(destination is IconGroup))
|
||||
return;
|
||||
|
||||
var scale = hovered ? 0.2 : 0.4;
|
||||
var opacity = hovered ? 100 : 255;
|
||||
var icon_group = destination as IconGroup;
|
||||
|
||||
if (icon_group.workspace == window.get_workspace ())
|
||||
return;
|
||||
|
||||
var scale = hovered ? 0.1 : 0.4;
|
||||
var opacity = hovered ? 50 : 255;
|
||||
var mode = hovered ? AnimationMode.EASE_IN_OUT_BACK : AnimationMode.EASE_OUT_ELASTIC;
|
||||
|
||||
save_easing_state ();
|
||||
@ -129,6 +193,12 @@ namespace Gala
|
||||
set_opacity (opacity);
|
||||
|
||||
restore_easing_state ();
|
||||
|
||||
if (hovered) {
|
||||
icon_group.add_window (window, false, true);
|
||||
} else {
|
||||
icon_group.remove_window (window);
|
||||
}
|
||||
}
|
||||
|
||||
void drag_end (Actor destination)
|
||||
@ -279,8 +349,8 @@ namespace Gala
|
||||
|
||||
foreach (var tilable in result) {
|
||||
var window = (TiledWindow)tilable.id;
|
||||
window.set_position (tilable.rect.x, tilable.rect.y);
|
||||
window.set_size (tilable.rect.width, tilable.rect.height);
|
||||
window.take_slot (tilable.rect);
|
||||
window.place_widgets (tilable.rect.width, tilable.rect.height);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,8 @@ namespace Gala
|
||||
public signal void window_selected (Meta.Window window);
|
||||
public signal void selected (bool close_view);
|
||||
|
||||
bool opened = false;
|
||||
|
||||
uint hover_activate_timeout = 0;
|
||||
|
||||
public WorkspaceClone (Meta.Workspace workspace, WindowManager wm)
|
||||
@ -171,8 +173,7 @@ namespace Gala
|
||||
|
||||
private void remove_window (Meta.Window window)
|
||||
{
|
||||
icon_group.remove_window (window);
|
||||
// TODO ?
|
||||
icon_group.remove_window (window, opened);
|
||||
}
|
||||
|
||||
private void shrink_rectangle (ref Meta.Rectangle rect, int amount)
|
||||
@ -202,9 +203,10 @@ namespace Gala
|
||||
};
|
||||
shrink_rectangle (ref area, 32);
|
||||
|
||||
icon_group.clear ();
|
||||
opened = true;
|
||||
|
||||
// TODO this can be optimized
|
||||
icon_group.clear ();
|
||||
window_container.destroy_all_children ();
|
||||
window_container.padding_top = TOP_OFFSET;
|
||||
window_container.padding_left =
|
||||
@ -226,6 +228,8 @@ namespace Gala
|
||||
|
||||
public void close ()
|
||||
{
|
||||
opened = false;
|
||||
|
||||
background.animate (AnimationMode.EASE_IN_OUT_CUBIC, 300, scale_x: 1.0f, scale_y: 1.0f);
|
||||
|
||||
window_container.transition_to_original_state ();
|
||||
|
@ -29,6 +29,8 @@ namespace Gala
|
||||
public Meta.BackgroundGroup background_group { get; protected set; }
|
||||
public HashTable<int,int> window_stacking_order { get; protected set; }
|
||||
|
||||
public WorkspaceManager workspace_manager { get; private set; }
|
||||
|
||||
Meta.PluginInfo info;
|
||||
|
||||
WindowSwitcher? winswitcher = null;
|
||||
@ -92,8 +94,7 @@ namespace Gala
|
||||
var color = BackgroundSettings.get_default ().primary_color;
|
||||
stage.background_color = Clutter.Color.from_string (color);
|
||||
|
||||
if (Prefs.get_dynamic_workspaces ())
|
||||
screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, 1, -1);
|
||||
workspace_manager = new WorkspaceManager (screen);
|
||||
|
||||
/* our layer structure, copied from gnome-shell (from bottom to top):
|
||||
* stage
|
||||
|
144
src/WorkspaceManager.vala
Normal file
144
src/WorkspaceManager.vala
Normal file
@ -0,0 +1,144 @@
|
||||
//
|
||||
// Copyright (C) 2014 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 WorkspaceManager : Object
|
||||
{
|
||||
public Screen screen { get; construct; }
|
||||
|
||||
public WorkspaceManager (Screen screen)
|
||||
{
|
||||
Object (screen: screen);
|
||||
|
||||
if (Prefs.get_dynamic_workspaces ())
|
||||
screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, 1, -1);
|
||||
|
||||
for (var i = 0; i < screen.get_n_workspaces (); i++)
|
||||
workspace_added (screen, i);
|
||||
|
||||
Prefs.add_listener (prefs_listener);
|
||||
|
||||
screen.workspace_added.connect (workspace_added);
|
||||
screen.workspace_switched.connect_after (workspace_switched);
|
||||
|
||||
// make sure the last workspace has no windows on it
|
||||
if (Prefs.get_dynamic_workspaces ()
|
||||
&& Utils.get_n_windows (screen.get_workspace_by_index (screen.get_n_workspaces () - 1)) > 0)
|
||||
append_workspace ();
|
||||
}
|
||||
|
||||
~WorkspaceManager ()
|
||||
{
|
||||
Prefs.remove_listener (prefs_listener);
|
||||
|
||||
screen.workspace_added.disconnect (workspace_added);
|
||||
screen.workspace_switched.disconnect (workspace_switched);
|
||||
}
|
||||
|
||||
void workspace_added (Screen screen, int index)
|
||||
{
|
||||
var workspace = screen.get_workspace_by_index (index);
|
||||
if (workspace == null)
|
||||
return;
|
||||
|
||||
workspace.window_added.connect (window_added);
|
||||
workspace.window_removed.connect (window_removed);
|
||||
}
|
||||
|
||||
void workspace_switched (Screen screen, int from, int to, MotionDirection direction)
|
||||
{
|
||||
if (!Prefs.get_dynamic_workspaces ())
|
||||
return;
|
||||
|
||||
// remove empty workspaces after we switched away from them unless it's the last one
|
||||
var prev_workspace = screen.get_workspace_by_index (from);
|
||||
if (Utils.get_n_windows (prev_workspace) < 1
|
||||
&& from != screen.get_n_workspaces () - 1) {
|
||||
screen.remove_workspace (prev_workspace, screen.get_display ().get_current_time ());
|
||||
}
|
||||
}
|
||||
|
||||
void window_added (Workspace workspace, Window window)
|
||||
{
|
||||
if (!Prefs.get_dynamic_workspaces ())
|
||||
return;
|
||||
|
||||
if ((window.window_type == WindowType.NORMAL
|
||||
|| window.window_type == WindowType.DIALOG
|
||||
|| window.window_type == WindowType.MODAL_DIALOG)
|
||||
&& workspace.index () == screen.get_n_workspaces () - 1)
|
||||
append_workspace ();
|
||||
}
|
||||
|
||||
void window_removed (Workspace workspace, Window window)
|
||||
{
|
||||
if (!Prefs.get_dynamic_workspaces ())
|
||||
return;
|
||||
|
||||
if (window.window_type != WindowType.NORMAL
|
||||
&& window.window_type != WindowType.DIALOG
|
||||
&& window.window_type != WindowType.MODAL_DIALOG)
|
||||
return;
|
||||
|
||||
var index = screen.get_workspaces ().index (workspace);
|
||||
// has already been removed
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
// remove it right away if it was the active workspace and it's not the very last
|
||||
if (workspace != screen.get_active_workspace ()
|
||||
&& Utils.get_n_windows (workspace) < 1
|
||||
&& index != screen.get_n_workspaces () - 1)
|
||||
screen.remove_workspace (workspace, screen.get_display ().get_current_time ());
|
||||
}
|
||||
|
||||
void prefs_listener (Meta.Preference pref)
|
||||
{
|
||||
if (pref == Preference.DYNAMIC_WORKSPACES && Prefs.get_dynamic_workspaces ()) {
|
||||
// if the last workspace has a window, we need to append a new workspace
|
||||
if (Utils.get_n_windows (screen.get_workspace_by_index (screen.get_n_workspaces () - 1)) > 0)
|
||||
append_workspace ();
|
||||
|
||||
} else if ((pref == Preference.DYNAMIC_WORKSPACES
|
||||
|| pref == Preference.NUM_WORKSPACES)
|
||||
&& !Prefs.get_dynamic_workspaces ()) {
|
||||
|
||||
var time = screen.get_display ().get_current_time ();
|
||||
var n_workspaces = screen.get_n_workspaces ();
|
||||
|
||||
/* TODO check if this is still needed
|
||||
// only need to listen for the case when workspaces were removed.
|
||||
// Any other case will be caught by the workspace_added signal.
|
||||
// For some reason workspace_removed is not emitted, when changing the workspace number
|
||||
if (Prefs.get_num_workspaces () < n_workspaces) {
|
||||
for (int i = Prefs.get_num_workspaces () - 1; i < n_workspaces; i++) {
|
||||
screen.remove_workspace (screen.get_workspace_by_index (i), time);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
void append_workspace ()
|
||||
{
|
||||
screen.append_new_workspace (false, screen.get_display ().get_current_time ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user