Convert all tabs to spaces (#684)

This commit is contained in:
Daniel Foré 2020-01-09 11:26:30 -08:00 committed by GitHub
parent 548ec08d89
commit 97cb42fb2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 11058 additions and 11058 deletions

View File

@ -20,209 +20,209 @@ using Meta;
namespace Gala.Plugins.MaskCorners namespace Gala.Plugins.MaskCorners
{ {
public class Main : Gala.Plugin public class Main : Gala.Plugin
{ {
Gala.WindowManager? wm = null; Gala.WindowManager? wm = null;
#if HAS_MUTTER330 #if HAS_MUTTER330
Display display; Display display;
#else #else
Screen screen; Screen screen;
#endif #endif
Settings settings; Settings settings;
List<Actor>[] cornermasks; List<Actor>[] cornermasks;
int corner_radius = 4; int corner_radius = 4;
public override void initialize (Gala.WindowManager wm) public override void initialize (Gala.WindowManager wm)
{ {
this.wm = wm; this.wm = wm;
#if HAS_MUTTER330 #if HAS_MUTTER330
display = wm.get_display (); display = wm.get_display ();
#else #else
screen = wm.get_screen (); screen = wm.get_screen ();
#endif #endif
settings = Settings.get_default (); settings = Settings.get_default ();
setup_cornermasks (); setup_cornermasks ();
settings.changed.connect (resetup_cornermasks); settings.changed.connect (resetup_cornermasks);
} }
public override void destroy () public override void destroy ()
{ {
destroy_cornermasks (); destroy_cornermasks ();
} }
void setup_cornermasks () void setup_cornermasks ()
{ {
if (!settings.enable) if (!settings.enable)
return; return;
var scale = Utils.get_ui_scaling_factor (); var scale = Utils.get_ui_scaling_factor ();
#if HAS_MUTTER330 #if HAS_MUTTER330
int n_monitors = display.get_n_monitors (); int n_monitors = display.get_n_monitors ();
#else #else
int n_monitors = screen.get_n_monitors (); int n_monitors = screen.get_n_monitors ();
#endif #endif
cornermasks = new List<Actor>[n_monitors]; cornermasks = new List<Actor>[n_monitors];
corner_radius = settings.corner_radius * scale; corner_radius = settings.corner_radius * scale;
if (settings.only_on_primary) { if (settings.only_on_primary) {
#if HAS_MUTTER330 #if HAS_MUTTER330
add_cornermasks (display.get_primary_monitor ()); add_cornermasks (display.get_primary_monitor ());
#else #else
add_cornermasks (screen.get_primary_monitor ()); add_cornermasks (screen.get_primary_monitor ());
#endif #endif
} else { } else {
for (int m = 0; m < n_monitors; m++) for (int m = 0; m < n_monitors; m++)
add_cornermasks (m); add_cornermasks (m);
} }
#if HAS_MUTTER330 #if HAS_MUTTER330
if (settings.disable_on_fullscreen) if (settings.disable_on_fullscreen)
display.in_fullscreen_changed.connect (fullscreen_changed); display.in_fullscreen_changed.connect (fullscreen_changed);
unowned Meta.MonitorManager monitor_manager = Meta.MonitorManager.@get (); unowned Meta.MonitorManager monitor_manager = Meta.MonitorManager.@get ();
monitor_manager.monitors_changed.connect (resetup_cornermasks); monitor_manager.monitors_changed.connect (resetup_cornermasks);
display.gl_video_memory_purged.connect (resetup_cornermasks); display.gl_video_memory_purged.connect (resetup_cornermasks);
#else #else
if (settings.disable_on_fullscreen) if (settings.disable_on_fullscreen)
screen.in_fullscreen_changed.connect (fullscreen_changed); screen.in_fullscreen_changed.connect (fullscreen_changed);
screen.monitors_changed.connect (resetup_cornermasks); screen.monitors_changed.connect (resetup_cornermasks);
screen.get_display ().gl_video_memory_purged.connect (resetup_cornermasks); screen.get_display ().gl_video_memory_purged.connect (resetup_cornermasks);
#endif #endif
} }
void destroy_cornermasks () void destroy_cornermasks ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
display.gl_video_memory_purged.disconnect (resetup_cornermasks); display.gl_video_memory_purged.disconnect (resetup_cornermasks);
#else #else
screen.get_display ().gl_video_memory_purged.disconnect (resetup_cornermasks); screen.get_display ().gl_video_memory_purged.disconnect (resetup_cornermasks);
#endif #endif
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.MonitorManager monitor_manager = Meta.MonitorManager.@get (); unowned Meta.MonitorManager monitor_manager = Meta.MonitorManager.@get ();
monitor_manager.monitors_changed.disconnect (resetup_cornermasks); monitor_manager.monitors_changed.disconnect (resetup_cornermasks);
display.in_fullscreen_changed.disconnect (fullscreen_changed); display.in_fullscreen_changed.disconnect (fullscreen_changed);
#else #else
screen.monitors_changed.disconnect (resetup_cornermasks); screen.monitors_changed.disconnect (resetup_cornermasks);
screen.in_fullscreen_changed.disconnect (fullscreen_changed); screen.in_fullscreen_changed.disconnect (fullscreen_changed);
#endif #endif
foreach (unowned List<Actor> list in cornermasks) { foreach (unowned List<Actor> list in cornermasks) {
foreach (Actor actor in list) foreach (Actor actor in list)
actor.destroy (); actor.destroy ();
} }
} }
void resetup_cornermasks () void resetup_cornermasks ()
{ {
destroy_cornermasks (); destroy_cornermasks ();
setup_cornermasks (); setup_cornermasks ();
} }
void fullscreen_changed () void fullscreen_changed ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
for (int i = 0; i < display.get_n_monitors (); i++) { for (int i = 0; i < display.get_n_monitors (); i++) {
foreach (Actor actor in cornermasks[i]) { foreach (Actor actor in cornermasks[i]) {
if (display.get_monitor_in_fullscreen (i)) if (display.get_monitor_in_fullscreen (i))
actor.hide (); actor.hide ();
else else
actor.show (); actor.show ();
} }
} }
#else #else
for (int i = 0; i < screen.get_n_monitors (); i++) { for (int i = 0; i < screen.get_n_monitors (); i++) {
foreach (Actor actor in cornermasks[i]) { foreach (Actor actor in cornermasks[i]) {
if (screen.get_monitor_in_fullscreen (i)) if (screen.get_monitor_in_fullscreen (i))
actor.hide (); actor.hide ();
else else
actor.show (); actor.show ();
} }
} }
#endif #endif
} }
void add_cornermasks (int monitor_no) void add_cornermasks (int monitor_no)
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
var monitor_geometry = display.get_monitor_geometry (monitor_no); var monitor_geometry = display.get_monitor_geometry (monitor_no);
#else #else
var monitor_geometry = screen.get_monitor_geometry (monitor_no); var monitor_geometry = screen.get_monitor_geometry (monitor_no);
#endif #endif
Canvas canvas = new Canvas (); Canvas canvas = new Canvas ();
canvas.set_size (corner_radius, corner_radius); canvas.set_size (corner_radius, corner_radius);
canvas.draw.connect (draw_cornermask); canvas.draw.connect (draw_cornermask);
canvas.invalidate (); canvas.invalidate ();
Actor actor = new Actor (); Actor actor = new Actor ();
actor.set_content (canvas); actor.set_content (canvas);
actor.set_size (corner_radius, corner_radius); actor.set_size (corner_radius, corner_radius);
actor.set_position (monitor_geometry.x, monitor_geometry.y); actor.set_position (monitor_geometry.x, monitor_geometry.y);
actor.set_pivot_point ((float) 0.5, (float) 0.5); actor.set_pivot_point ((float) 0.5, (float) 0.5);
cornermasks[monitor_no].append (actor); cornermasks[monitor_no].append (actor);
wm.stage.add_child (actor); wm.stage.add_child (actor);
for (int p = 1; p < 4; p++) { for (int p = 1; p < 4; p++) {
Clone clone = new Clone (actor); Clone clone = new Clone (actor);
clone.rotation_angle_z = p * 90; clone.rotation_angle_z = p * 90;
switch (p) { switch (p) {
case 1: case 1:
clone.set_position (monitor_geometry.x + monitor_geometry.width, monitor_geometry.y); clone.set_position (monitor_geometry.x + monitor_geometry.width, monitor_geometry.y);
break; break;
case 2: case 2:
clone.set_position (monitor_geometry.x + monitor_geometry.width, monitor_geometry.y + monitor_geometry.height); clone.set_position (monitor_geometry.x + monitor_geometry.width, monitor_geometry.y + monitor_geometry.height);
break; break;
case 3: case 3:
clone.set_position (monitor_geometry.x, monitor_geometry.y + monitor_geometry.height); clone.set_position (monitor_geometry.x, monitor_geometry.y + monitor_geometry.height);
break; break;
} }
cornermasks[monitor_no].append (clone); cornermasks[monitor_no].append (clone);
wm.stage.add_child (clone); wm.stage.add_child (clone);
} }
} }
bool draw_cornermask (Cairo.Context context) bool draw_cornermask (Cairo.Context context)
{ {
var buffer = new Granite.Drawing.BufferSurface (corner_radius, corner_radius); var buffer = new Granite.Drawing.BufferSurface (corner_radius, corner_radius);
var buffer_context = buffer.context; var buffer_context = buffer.context;
buffer_context.arc (corner_radius, corner_radius, corner_radius, Math.PI, 1.5 * Math.PI); buffer_context.arc (corner_radius, corner_radius, corner_radius, Math.PI, 1.5 * Math.PI);
buffer_context.line_to (0, 0); buffer_context.line_to (0, 0);
buffer_context.line_to (0, corner_radius); buffer_context.line_to (0, corner_radius);
buffer_context.set_source_rgb (0, 0, 0); buffer_context.set_source_rgb (0, 0, 0);
buffer_context.fill (); buffer_context.fill ();
context.set_operator (Cairo.Operator.CLEAR); context.set_operator (Cairo.Operator.CLEAR);
context.paint (); context.paint ();
context.set_operator (Cairo.Operator.OVER); context.set_operator (Cairo.Operator.OVER);
context.set_source_surface (buffer.surface, 0, 0); context.set_source_surface (buffer.surface, 0, 0);
context.paint (); context.paint ();
return true; return true;
} }
} }
} }
public Gala.PluginInfo register_plugin () public Gala.PluginInfo register_plugin ()
{ {
return return
{ {
"Mask Corners", "Mask Corners",
"Gala Developers", "Gala Developers",
typeof (Gala.Plugins.MaskCorners.Main), typeof (Gala.Plugins.MaskCorners.Main),
Gala.PluginFunction.ADDITION, Gala.PluginFunction.ADDITION,
Gala.LoadPriority.IMMEDIATE Gala.LoadPriority.IMMEDIATE
}; };
} }

View File

@ -17,26 +17,26 @@
namespace Gala.Plugins.MaskCorners namespace Gala.Plugins.MaskCorners
{ {
class Settings : Granite.Services.Settings class Settings : Granite.Services.Settings
{ {
static Settings? instance = null; static Settings? instance = null;
public static unowned Settings get_default () public static unowned Settings get_default ()
{ {
if (instance == null) if (instance == null)
instance = new Settings (); instance = new Settings ();
return instance; return instance;
} }
public bool enable { get; set; default = true; } public bool enable { get; set; default = true; }
public int corner_radius { get; set; default = 4; } public int corner_radius { get; set; default = 4; }
public bool disable_on_fullscreen { get; set; default = true; } public bool disable_on_fullscreen { get; set; default = true; }
public bool only_on_primary { get; set; default = false; } public bool only_on_primary { get; set; default = false; }
Settings () Settings ()
{ {
base (Config.SCHEMA + ".mask-corners"); base (Config.SCHEMA + ".mask-corners");
} }
} }
} }

View File

@ -20,115 +20,115 @@ using Meta;
namespace Gala.Plugins.Notify namespace Gala.Plugins.Notify
{ {
public class ConfirmationNotification : Notification public class ConfirmationNotification : Notification
{ {
const int DURATION = 2000; const int DURATION = 2000;
const int PROGRESS_HEIGHT = 6; const int PROGRESS_HEIGHT = 6;
public bool has_progress { get; private set; } public bool has_progress { get; private set; }
int _progress; int _progress;
public int progress { public int progress {
get { get {
return _progress; return _progress;
} }
private set { private set {
_progress = value; _progress = value;
content.invalidate (); content.invalidate ();
} }
} }
public string confirmation_type { get; private set; } public string confirmation_type { get; private set; }
int old_progress; int old_progress;
public ConfirmationNotification (uint32 id, Gdk.Pixbuf? icon, bool icon_only, public ConfirmationNotification (uint32 id, Gdk.Pixbuf? icon, bool icon_only,
int progress, string confirmation_type) int progress, string confirmation_type)
{ {
Object (id: id, icon: icon, urgency: NotificationUrgency.LOW, expire_timeout: DURATION); Object (id: id, icon: icon, urgency: NotificationUrgency.LOW, expire_timeout: DURATION);
this.icon_only = icon_only; this.icon_only = icon_only;
this.has_progress = progress > -1; this.has_progress = progress > -1;
this.progress = progress; this.progress = progress;
this.confirmation_type = confirmation_type; this.confirmation_type = confirmation_type;
} }
public override void update_allocation (out float content_height, AllocationFlags flags) public override void update_allocation (out float content_height, AllocationFlags flags)
{ {
content_height = ICON_SIZE * style_context.get_scale (); content_height = ICON_SIZE * style_context.get_scale ();
} }
public override void draw_content (Cairo.Context cr) public override void draw_content (Cairo.Context cr)
{ {
if (!has_progress) if (!has_progress)
return; return;
var scale = style_context.get_scale (); var scale = style_context.get_scale ();
var scaled_margin = MARGIN * scale; var scaled_margin = MARGIN * scale;
var scaled_width = WIDTH * scale; var scaled_width = WIDTH * scale;
var x = (MARGIN + PADDING + ICON_SIZE + SPACING) * scale; var x = (MARGIN + PADDING + ICON_SIZE + SPACING) * scale;
var y = (MARGIN + PADDING + (ICON_SIZE - PROGRESS_HEIGHT) / 2) * scale; var y = (MARGIN + PADDING + (ICON_SIZE - PROGRESS_HEIGHT) / 2) * scale;
var width = scaled_width - x - scaled_margin; var width = scaled_width - x - scaled_margin;
if (!transitioning) if (!transitioning)
draw_progress_bar (cr, x, y, width, progress); draw_progress_bar (cr, x, y, width, progress);
else { else {
Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, scaled_margin, scaled_margin, scaled_width - scaled_margin * 2, ICON_SIZE * scale + PADDING * 2 * scale, 4 * scale); Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, scaled_margin, scaled_margin, scaled_width - scaled_margin * 2, ICON_SIZE * scale + PADDING * 2 * scale, 4 * scale);
cr.clip (); cr.clip ();
draw_progress_bar (cr, x, y + animation_slide_y_offset, width, old_progress); draw_progress_bar (cr, x, y + animation_slide_y_offset, width, old_progress);
draw_progress_bar (cr, x, y + animation_slide_y_offset - animation_slide_height, width, progress); draw_progress_bar (cr, x, y + animation_slide_y_offset - animation_slide_height, width, progress);
cr.reset_clip (); cr.reset_clip ();
} }
} }
void draw_progress_bar (Cairo.Context cr, int x, float y, int width, int progress) void draw_progress_bar (Cairo.Context cr, int x, float y, int width, int progress)
{ {
var fraction = (int) Math.floor (progress.clamp (0, 100) / 100.0 * width); var fraction = (int) Math.floor (progress.clamp (0, 100) / 100.0 * width);
var scale = style_context.get_scale (); var scale = style_context.get_scale ();
var scaled_progress_height = PROGRESS_HEIGHT * scale; var scaled_progress_height = PROGRESS_HEIGHT * scale;
Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, x, y, width, Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, x, y, width,
scaled_progress_height, scaled_progress_height / 2); scaled_progress_height, scaled_progress_height / 2);
cr.set_source_rgb (0.8, 0.8, 0.8); cr.set_source_rgb (0.8, 0.8, 0.8);
cr.fill (); cr.fill ();
if (progress > 0) { if (progress > 0) {
Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, x, y, fraction, Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, x, y, fraction,
scaled_progress_height, scaled_progress_height / 2); scaled_progress_height, scaled_progress_height / 2);
cr.set_source_rgb (0.3, 0.3, 0.3); cr.set_source_rgb (0.3, 0.3, 0.3);
cr.fill (); cr.fill ();
} }
} }
protected override void update_slide_animation () protected override void update_slide_animation ()
{ {
// just trigger the draw function, which will move our progress bar down // just trigger the draw function, which will move our progress bar down
content.invalidate (); content.invalidate ();
} }
public void update (Gdk.Pixbuf? icon, int progress, string confirmation_type, public void update (Gdk.Pixbuf? icon, int progress, string confirmation_type,
bool icon_only) bool icon_only)
{ {
if (this.confirmation_type != confirmation_type) { if (this.confirmation_type != confirmation_type) {
this.confirmation_type = confirmation_type; this.confirmation_type = confirmation_type;
old_progress = this.progress; old_progress = this.progress;
var scale = style_context.get_scale (); var scale = style_context.get_scale ();
play_update_transition ((ICON_SIZE + PADDING * 2) * scale); play_update_transition ((ICON_SIZE + PADDING * 2) * scale);
} }
if (this.icon_only != icon_only) { if (this.icon_only != icon_only) {
this.icon_only = icon_only; this.icon_only = icon_only;
queue_relayout (); queue_relayout ();
} }
this.has_progress = progress > -1; this.has_progress = progress > -1;
this.progress = progress; this.progress = progress;
update_base (icon, DURATION); update_base (icon, DURATION);
} }
} }
} }

View File

@ -20,97 +20,97 @@ using Meta;
namespace Gala.Plugins.Notify namespace Gala.Plugins.Notify
{ {
public class Main : Gala.Plugin public class Main : Gala.Plugin
{ {
Gala.WindowManager? wm = null; Gala.WindowManager? wm = null;
NotifyServer server; NotifyServer server;
NotificationStack stack; NotificationStack stack;
public override void initialize (Gala.WindowManager wm) public override void initialize (Gala.WindowManager wm)
{ {
this.wm = wm; this.wm = wm;
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.Display display = wm.get_display (); unowned Meta.Display display = wm.get_display ();
#else #else
var screen = wm.get_screen (); var screen = wm.get_screen ();
#endif #endif
#if HAS_MUTTER330 #if HAS_MUTTER330
stack = new NotificationStack (display); stack = new NotificationStack (display);
#else #else
stack = new NotificationStack (screen); stack = new NotificationStack (screen);
#endif #endif
wm.ui_group.add_child (stack); wm.ui_group.add_child (stack);
track_actor (stack); track_actor (stack);
stack.animations_changed.connect ((running) => { stack.animations_changed.connect ((running) => {
freeze_track = running; freeze_track = running;
}); });
server = new NotifyServer (stack); server = new NotifyServer (stack);
update_position (); update_position ();
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.MonitorManager monitor_manager = Meta.MonitorManager.@get (); unowned Meta.MonitorManager monitor_manager = Meta.MonitorManager.@get ();
monitor_manager.monitors_changed.connect (update_position); monitor_manager.monitors_changed.connect (update_position);
display.workareas_changed.connect (update_position); display.workareas_changed.connect (update_position);
#else #else
screen.monitors_changed.connect (update_position); screen.monitors_changed.connect (update_position);
screen.workareas_changed.connect (update_position); screen.workareas_changed.connect (update_position);
#endif #endif
Bus.own_name (BusType.SESSION, "org.freedesktop.Notifications", BusNameOwnerFlags.NONE, Bus.own_name (BusType.SESSION, "org.freedesktop.Notifications", BusNameOwnerFlags.NONE,
(connection) => { (connection) => {
try { try {
connection.register_object ("/org/freedesktop/Notifications", server); connection.register_object ("/org/freedesktop/Notifications", server);
} catch (Error e) { } catch (Error e) {
warning ("Registring notification server failed: %s", e.message); warning ("Registring notification server failed: %s", e.message);
destroy (); destroy ();
} }
}, },
() => {}, () => {},
(con, name) => { (con, name) => {
warning ("Could not aquire bus %s", name); warning ("Could not aquire bus %s", name);
destroy (); destroy ();
}); });
} }
void update_position () void update_position ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.Display display = wm.get_display (); unowned Meta.Display display = wm.get_display ();
var primary = display.get_primary_monitor (); var primary = display.get_primary_monitor ();
var area = display.get_workspace_manager ().get_active_workspace ().get_work_area_for_monitor (primary); var area = display.get_workspace_manager ().get_active_workspace ().get_work_area_for_monitor (primary);
#else #else
var screen = wm.get_screen (); var screen = wm.get_screen ();
var primary = screen.get_primary_monitor (); var primary = screen.get_primary_monitor ();
var area = screen.get_active_workspace ().get_work_area_for_monitor (primary); var area = screen.get_active_workspace ().get_work_area_for_monitor (primary);
#endif #endif
stack.x = area.x + area.width - stack.width; stack.x = area.x + area.width - stack.width;
stack.y = area.y; stack.y = area.y;
} }
public override void destroy () public override void destroy ()
{ {
if (wm == null) if (wm == null)
return; return;
untrack_actor (stack); untrack_actor (stack);
stack.destroy (); stack.destroy ();
} }
} }
} }
public Gala.PluginInfo register_plugin () public Gala.PluginInfo register_plugin ()
{ {
return Gala.PluginInfo () { return Gala.PluginInfo () {
name = "Notify", name = "Notify",
author = "Gala Developers", author = "Gala Developers",
plugin_type = typeof (Gala.Plugins.Notify.Main), plugin_type = typeof (Gala.Plugins.Notify.Main),
provides = Gala.PluginFunction.ADDITION, provides = Gala.PluginFunction.ADDITION,
load_priority = Gala.LoadPriority.IMMEDIATE load_priority = Gala.LoadPriority.IMMEDIATE
}; };
} }

View File

@ -20,354 +20,354 @@ using Meta;
namespace Gala.Plugins.Notify namespace Gala.Plugins.Notify
{ {
/** /**
* Wrapper class only containing the summary and body label. Allows us to * Wrapper class only containing the summary and body label. Allows us to
* instantiate the content very easily for when we need to slide the old * instantiate the content very easily for when we need to slide the old
* and new content down. * and new content down.
*/ */
class NormalNotificationContent : Actor class NormalNotificationContent : Actor
{ {
static Regex entity_regex; static Regex entity_regex;
static Regex tag_regex; static Regex tag_regex;
static construct static construct
{ {
try { try {
entity_regex = new Regex ("&(?!amp;|quot;|apos;|lt;|gt;)"); entity_regex = new Regex ("&(?!amp;|quot;|apos;|lt;|gt;)");
tag_regex = new Regex ("<(?!\\/?[biu]>)"); tag_regex = new Regex ("<(?!\\/?[biu]>)");
} catch (Error e) {} } catch (Error e) {}
} }
const int LABEL_SPACING = 2; const int LABEL_SPACING = 2;
Text summary_label; Text summary_label;
Text body_label; Text body_label;
construct construct
{ {
summary_label = new Text.with_text (null, ""); summary_label = new Text.with_text (null, "");
summary_label.line_wrap = true; summary_label.line_wrap = true;
summary_label.use_markup = true; summary_label.use_markup = true;
summary_label.line_wrap_mode = Pango.WrapMode.WORD_CHAR; summary_label.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
body_label = new Text.with_text (null, ""); body_label = new Text.with_text (null, "");
body_label.line_wrap = true; body_label.line_wrap = true;
body_label.use_markup = true; body_label.use_markup = true;
body_label.line_wrap_mode = Pango.WrapMode.WORD_CHAR; body_label.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
var style_path = new Gtk.WidgetPath (); var style_path = new Gtk.WidgetPath ();
style_path.append_type (typeof (Gtk.Window)); style_path.append_type (typeof (Gtk.Window));
style_path.append_type (typeof (Gtk.EventBox)); style_path.append_type (typeof (Gtk.EventBox));
style_path.iter_add_class (1, "gala-notification"); style_path.iter_add_class (1, "gala-notification");
style_path.append_type (typeof (Gtk.Label)); style_path.append_type (typeof (Gtk.Label));
var label_style_context = new Gtk.StyleContext (); var label_style_context = new Gtk.StyleContext ();
label_style_context.add_provider (Gala.Utils.get_gala_css (), Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK); label_style_context.add_provider (Gala.Utils.get_gala_css (), Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK);
label_style_context.set_path (style_path); label_style_context.set_path (style_path);
Gdk.RGBA color; Gdk.RGBA color;
label_style_context.save (); label_style_context.save ();
label_style_context.add_class ("title"); label_style_context.add_class ("title");
color = label_style_context.get_color (Gtk.StateFlags.NORMAL); color = label_style_context.get_color (Gtk.StateFlags.NORMAL);
summary_label.color = { summary_label.color = {
(uint8) (color.red * 255), (uint8) (color.red * 255),
(uint8) (color.green * 255), (uint8) (color.green * 255),
(uint8) (color.blue * 255), (uint8) (color.blue * 255),
(uint8) (color.alpha * 255) (uint8) (color.alpha * 255)
}; };
label_style_context.restore (); label_style_context.restore ();
label_style_context.save (); label_style_context.save ();
label_style_context.add_class ("label"); label_style_context.add_class ("label");
color = label_style_context.get_color (Gtk.StateFlags.NORMAL); color = label_style_context.get_color (Gtk.StateFlags.NORMAL);
body_label.color = { body_label.color = {
(uint8) (color.red * 255), (uint8) (color.red * 255),
(uint8) (color.green * 255), (uint8) (color.green * 255),
(uint8) (color.blue * 255), (uint8) (color.blue * 255),
(uint8) (color.alpha * 255) (uint8) (color.alpha * 255)
}; };
label_style_context.restore (); label_style_context.restore ();
add_child (summary_label); add_child (summary_label);
add_child (body_label); add_child (body_label);
} }
public void set_values (string summary, string body) public void set_values (string summary, string body)
{ {
summary_label.set_markup ("<b>%s</b>".printf (fix_markup (summary))); summary_label.set_markup ("<b>%s</b>".printf (fix_markup (summary)));
body_label.set_markup (fix_markup (body)); body_label.set_markup (fix_markup (body));
} }
public override void get_preferred_height (float for_width, out float min_height, out float nat_height) public override void get_preferred_height (float for_width, out float min_height, out float nat_height)
{ {
var scale = Utils.get_ui_scaling_factor (); var scale = Utils.get_ui_scaling_factor ();
float label_height; float label_height;
get_allocation_values (null, null, null, null, out label_height, null, scale); get_allocation_values (null, null, null, null, out label_height, null, scale);
min_height = nat_height = label_height; min_height = nat_height = label_height;
} }
public override void allocate (ActorBox box, AllocationFlags flags) public override void allocate (ActorBox box, AllocationFlags flags)
{ {
var scale = Utils.get_ui_scaling_factor (); var scale = Utils.get_ui_scaling_factor ();
float label_x, label_width, summary_height, body_height, label_height, label_y; float label_x, label_width, summary_height, body_height, label_height, label_y;
get_allocation_values (out label_x, out label_width, out summary_height, get_allocation_values (out label_x, out label_width, out summary_height,
out body_height, out label_height, out label_y, scale); out body_height, out label_height, out label_y, scale);
var summary_alloc = ActorBox (); var summary_alloc = ActorBox ();
summary_alloc.set_origin (label_x, label_y); summary_alloc.set_origin (label_x, label_y);
summary_alloc.set_size (label_width, summary_height); summary_alloc.set_size (label_width, summary_height);
summary_label.allocate (summary_alloc, flags); summary_label.allocate (summary_alloc, flags);
var body_alloc = ActorBox (); var body_alloc = ActorBox ();
body_alloc.set_origin (label_x, label_y + summary_height + LABEL_SPACING * scale); body_alloc.set_origin (label_x, label_y + summary_height + LABEL_SPACING * scale);
body_alloc.set_size (label_width, body_height); body_alloc.set_size (label_width, body_height);
body_label.allocate (body_alloc, flags); body_label.allocate (body_alloc, flags);
base.allocate (box, flags); base.allocate (box, flags);
} }
void get_allocation_values (out float label_x, out float label_width, out float summary_height, void get_allocation_values (out float label_x, out float label_width, out float summary_height,
out float body_height, out float label_height, out float label_y, int scale) out float body_height, out float label_height, out float label_y, int scale)
{ {
var height = Notification.ICON_SIZE * scale; var height = Notification.ICON_SIZE * scale;
var margin = Notification.MARGIN * scale; var margin = Notification.MARGIN * scale;
var padding = Notification.PADDING * scale; var padding = Notification.PADDING * scale;
var spacing = Notification.SPACING * scale; var spacing = Notification.SPACING * scale;
label_x = margin + padding + height + spacing; label_x = margin + padding + height + spacing;
label_width = Notification.WIDTH * scale - label_x - margin - spacing; label_width = Notification.WIDTH * scale - label_x - margin - spacing;
summary_label.get_preferred_height (label_width, null, out summary_height); summary_label.get_preferred_height (label_width, null, out summary_height);
body_label.get_preferred_height (label_width, null, out body_height); body_label.get_preferred_height (label_width, null, out body_height);
label_height = summary_height + LABEL_SPACING * scale + body_height; label_height = summary_height + LABEL_SPACING * scale + body_height;
label_y = margin + padding; label_y = margin + padding;
// center // center
if (label_height < height) { if (label_height < height) {
label_y += (height - (int) label_height) / 2; label_y += (height - (int) label_height) / 2;
label_height = height; label_height = height;
} }
} }
/** /**
* Copied from gnome-shell, fixes the mess of markup that is sent to us * Copied from gnome-shell, fixes the mess of markup that is sent to us
*/ */
string fix_markup (string markup) string fix_markup (string markup)
{ {
var text = markup; var text = markup;
try { try {
text = entity_regex.replace (markup, markup.length, 0, "&amp;"); text = entity_regex.replace (markup, markup.length, 0, "&amp;");
text = tag_regex.replace (text, text.length, 0, "&lt;"); text = tag_regex.replace (text, text.length, 0, "&lt;");
} catch (Error e) {} } catch (Error e) {}
return text; return text;
} }
} }
public class NormalNotification : Notification public class NormalNotification : Notification
{ {
public string summary { get; construct set; } public string summary { get; construct set; }
public string body { get; construct set; } public string body { get; construct set; }
public uint32 sender_pid { get; construct; } public uint32 sender_pid { get; construct; }
public string[] notification_actions { get; construct set; } public string[] notification_actions { get; construct set; }
#if HAS_MUTTER330 #if HAS_MUTTER330
public Meta.Display display { get; construct; } public Meta.Display display { get; construct; }
#else #else
public Screen screen { get; construct; } public Screen screen { get; construct; }
#endif #endif
Actor content_container; Actor content_container;
NormalNotificationContent notification_content; NormalNotificationContent notification_content;
NormalNotificationContent? old_notification_content = null; NormalNotificationContent? old_notification_content = null;
#if HAS_MUTTER330 #if HAS_MUTTER330
public NormalNotification (Meta.Display display, uint32 id, string summary, string body, Gdk.Pixbuf? icon, public NormalNotification (Meta.Display display, uint32 id, string summary, string body, Gdk.Pixbuf? icon,
NotificationUrgency urgency, int32 expire_timeout, uint32 pid, string[] actions) NotificationUrgency urgency, int32 expire_timeout, uint32 pid, string[] actions)
{ {
Object ( Object (
id: id, id: id,
icon: icon, icon: icon,
urgency: urgency, urgency: urgency,
expire_timeout: expire_timeout, expire_timeout: expire_timeout,
display: display, display: display,
summary: summary, summary: summary,
body: body, body: body,
sender_pid: pid, sender_pid: pid,
notification_actions: actions notification_actions: actions
); );
} }
#else #else
public NormalNotification (Screen screen, uint32 id, string summary, string body, Gdk.Pixbuf? icon, public NormalNotification (Screen screen, uint32 id, string summary, string body, Gdk.Pixbuf? icon,
NotificationUrgency urgency, int32 expire_timeout, uint32 pid, string[] actions) NotificationUrgency urgency, int32 expire_timeout, uint32 pid, string[] actions)
{ {
Object ( Object (
id: id, id: id,
icon: icon, icon: icon,
urgency: urgency, urgency: urgency,
expire_timeout: expire_timeout, expire_timeout: expire_timeout,
screen: screen, screen: screen,
summary: summary, summary: summary,
body: body, body: body,
sender_pid: pid, sender_pid: pid,
notification_actions: actions notification_actions: actions
); );
} }
#endif #endif
construct construct
{ {
content_container = new Actor (); content_container = new Actor ();
notification_content = new NormalNotificationContent (); notification_content = new NormalNotificationContent ();
notification_content.set_values (summary, body); notification_content.set_values (summary, body);
content_container.add_child (notification_content); content_container.add_child (notification_content);
insert_child_below (content_container, null); insert_child_below (content_container, null);
} }
public void update (string summary, string body, Gdk.Pixbuf? icon, int32 expire_timeout, public void update (string summary, string body, Gdk.Pixbuf? icon, int32 expire_timeout,
string[] actions) string[] actions)
{ {
var visible_change = this.summary != summary || this.body != body; var visible_change = this.summary != summary || this.body != body;
if (visible_change) { if (visible_change) {
if (old_notification_content != null) if (old_notification_content != null)
old_notification_content.destroy (); old_notification_content.destroy ();
old_notification_content = new NormalNotificationContent (); old_notification_content = new NormalNotificationContent ();
old_notification_content.set_values (this.summary, this.body); old_notification_content.set_values (this.summary, this.body);
content_container.add_child (old_notification_content); content_container.add_child (old_notification_content);
this.summary = summary; this.summary = summary;
this.body = body; this.body = body;
notification_content.set_values (summary, body); notification_content.set_values (summary, body);
float content_height, old_content_height; float content_height, old_content_height;
notification_content.get_preferred_height (0, null, out content_height); notification_content.get_preferred_height (0, null, out content_height);
old_notification_content.get_preferred_height (0, null, out old_content_height); old_notification_content.get_preferred_height (0, null, out old_content_height);
content_height = float.max (content_height, old_content_height); content_height = float.max (content_height, old_content_height);
play_update_transition (content_height + PADDING * 2 * style_context.get_scale ()); play_update_transition (content_height + PADDING * 2 * style_context.get_scale ());
get_transition ("switch").completed.connect (() => { get_transition ("switch").completed.connect (() => {
if (old_notification_content != null) if (old_notification_content != null)
old_notification_content.destroy (); old_notification_content.destroy ();
old_notification_content = null; old_notification_content = null;
}); });
} }
notification_actions = actions; notification_actions = actions;
update_base (icon, expire_timeout); update_base (icon, expire_timeout);
} }
protected override void update_slide_animation () protected override void update_slide_animation ()
{ {
if (old_notification_content != null) if (old_notification_content != null)
old_notification_content.y = animation_slide_y_offset; old_notification_content.y = animation_slide_y_offset;
notification_content.y = animation_slide_y_offset - animation_slide_height; notification_content.y = animation_slide_y_offset - animation_slide_height;
} }
public override void update_allocation (out float content_height, AllocationFlags flags) public override void update_allocation (out float content_height, AllocationFlags flags)
{ {
var box = ActorBox (); var box = ActorBox ();
box.set_origin (0, 0); box.set_origin (0, 0);
box.set_size (width, height); box.set_size (width, height);
content_container.allocate (box, flags); content_container.allocate (box, flags);
// the for_width is not needed in our implementation of get_preferred_height as we // the for_width is not needed in our implementation of get_preferred_height as we
// assume a constant width // assume a constant width
notification_content.get_preferred_height (0, null, out content_height); notification_content.get_preferred_height (0, null, out content_height);
var scale = style_context.get_scale (); var scale = style_context.get_scale ();
var scaled_margin = MARGIN * scale; var scaled_margin = MARGIN * scale;
content_container.set_clip (scaled_margin, scaled_margin, scaled_margin * 2 + WIDTH * scale, content_height + PADDING * 2 * scale); content_container.set_clip (scaled_margin, scaled_margin, scaled_margin * 2 + WIDTH * scale, content_height + PADDING * 2 * scale);
} }
public override void get_preferred_height (float for_width, out float min_height, out float nat_height) public override void get_preferred_height (float for_width, out float min_height, out float nat_height)
{ {
float content_height; float content_height;
notification_content.get_preferred_height (for_width, null, out content_height); notification_content.get_preferred_height (for_width, null, out content_height);
min_height = nat_height = content_height + (MARGIN + PADDING) * 2 * style_context.get_scale (); min_height = nat_height = content_height + (MARGIN + PADDING) * 2 * style_context.get_scale ();
} }
public override void activate () public override void activate ()
{ {
// we currently only support the default action, which can be triggered by clicking // we currently only support the default action, which can be triggered by clicking
// on the notification according to spec // on the notification according to spec
for (var i = 0; i < notification_actions.length; i += 2) { for (var i = 0; i < notification_actions.length; i += 2) {
if (notification_actions[i] == "default") { if (notification_actions[i] == "default") {
action_invoked (id, "default"); action_invoked (id, "default");
dismiss (); dismiss ();
return; return;
} }
} }
// if no default action has been set, we fallback to trying to find a window for the // if no default action has been set, we fallback to trying to find a window for the
// notification's sender process // notification's sender process
unowned Meta.Window? window = get_window (); unowned Meta.Window? window = get_window ();
if (window != null) { if (window != null) {
unowned Meta.Workspace workspace = window.get_workspace (); unowned Meta.Workspace workspace = window.get_workspace ();
#if HAS_MUTTER330 #if HAS_MUTTER330
var time = display.get_current_time (); var time = display.get_current_time ();
if (workspace != display.get_workspace_manager ().get_active_workspace ()) if (workspace != display.get_workspace_manager ().get_active_workspace ())
workspace.activate_with_focus (window, time); workspace.activate_with_focus (window, time);
else else
window.activate (time); window.activate (time);
#else #else
var time = screen.get_display ().get_current_time (); var time = screen.get_display ().get_current_time ();
if (workspace != screen.get_active_workspace ()) if (workspace != screen.get_active_workspace ())
workspace.activate_with_focus (window, time); workspace.activate_with_focus (window, time);
else else
window.activate (time); window.activate (time);
#endif #endif
dismiss (); dismiss ();
} }
} }
unowned Meta.Window? get_window () unowned Meta.Window? get_window ()
{ {
if (sender_pid == 0) if (sender_pid == 0)
return null; return null;
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned GLib.List<Meta.WindowActor> actors = display.get_window_actors (); unowned GLib.List<Meta.WindowActor> actors = display.get_window_actors ();
#else #else
unowned GLib.List<Meta.WindowActor> actors = screen.get_window_actors (); unowned GLib.List<Meta.WindowActor> actors = screen.get_window_actors ();
#endif #endif
foreach (unowned Meta.WindowActor actor in actors) { foreach (unowned Meta.WindowActor actor in actors) {
if (actor.is_destroyed ()) if (actor.is_destroyed ())
continue; continue;
unowned Meta.Window window = actor.get_meta_window (); unowned Meta.Window window = actor.get_meta_window ();
// the windows are sorted by stacking order when returned // the windows are sorted by stacking order when returned
// from meta_get_window_actors, so we can just pick the first // from meta_get_window_actors, so we can just pick the first
// one we find and have a pretty good match // one we find and have a pretty good match
if (window.get_pid () == sender_pid) if (window.get_pid () == sender_pid)
return window; return window;
} }
return null; return null;
} }
void dismiss () void dismiss ()
{ {
closed (id, NotificationClosedReason.DISMISSED); closed (id, NotificationClosedReason.DISMISSED);
close (); close ();
} }
} }
} }

View File

@ -20,384 +20,384 @@ using Meta;
namespace Gala.Plugins.Notify namespace Gala.Plugins.Notify
{ {
public abstract class Notification : Actor public abstract class Notification : Actor
{ {
public const int WIDTH = 300; public const int WIDTH = 300;
public const int ICON_SIZE = 48; public const int ICON_SIZE = 48;
public const int MARGIN = 12; public const int MARGIN = 12;
public const int SPACING = 6; public const int SPACING = 6;
public const int PADDING = 4; public const int PADDING = 4;
public signal void action_invoked (uint32 id, string action); public signal void action_invoked (uint32 id, string action);
public signal void closed (uint32 id, uint32 reason); public signal void closed (uint32 id, uint32 reason);
public uint32 id { get; construct; } public uint32 id { get; construct; }
public Gdk.Pixbuf? icon { get; construct set; } public Gdk.Pixbuf? icon { get; construct set; }
public NotificationUrgency urgency { get; construct; } public NotificationUrgency urgency { get; construct; }
public int32 expire_timeout { get; construct set; } public int32 expire_timeout { get; construct set; }
public uint64 relevancy_time { get; private set; } public uint64 relevancy_time { get; private set; }
public bool being_destroyed { get; private set; default = false; } public bool being_destroyed { get; private set; default = false; }
protected bool icon_only { get; protected set; default = false; } protected bool icon_only { get; protected set; default = false; }
protected Clutter.Texture icon_texture { get; private set; } protected Clutter.Texture icon_texture { get; private set; }
protected Actor icon_container { get; private set; } protected Actor icon_container { get; private set; }
/** /**
* Whether we're currently sliding content for an update animation * Whether we're currently sliding content for an update animation
*/ */
protected bool transitioning { get; private set; default = false; } protected bool transitioning { get; private set; default = false; }
Clutter.Actor close_button; Clutter.Actor close_button;
protected Gtk.StyleContext style_context { get; private set; } protected Gtk.StyleContext style_context { get; private set; }
uint remove_timeout = 0; uint remove_timeout = 0;
// temporary things needed for the slide transition // temporary things needed for the slide transition
protected float animation_slide_height { get; private set; } protected float animation_slide_height { get; private set; }
Clutter.Texture old_texture; Clutter.Texture old_texture;
float _animation_slide_y_offset = 0.0f; float _animation_slide_y_offset = 0.0f;
public float animation_slide_y_offset { public float animation_slide_y_offset {
get { get {
return _animation_slide_y_offset; return _animation_slide_y_offset;
} }
set { set {
_animation_slide_y_offset = value; _animation_slide_y_offset = value;
icon_texture.y = -animation_slide_height + _animation_slide_y_offset; icon_texture.y = -animation_slide_height + _animation_slide_y_offset;
old_texture.y = _animation_slide_y_offset; old_texture.y = _animation_slide_y_offset;
update_slide_animation (); update_slide_animation ();
} }
} }
protected Notification (uint32 id, Gdk.Pixbuf? icon, NotificationUrgency urgency, protected Notification (uint32 id, Gdk.Pixbuf? icon, NotificationUrgency urgency,
int32 expire_timeout) int32 expire_timeout)
{ {
Object ( Object (
id: id, id: id,
icon: icon, icon: icon,
urgency: urgency, urgency: urgency,
expire_timeout: expire_timeout expire_timeout: expire_timeout
); );
} }
construct construct
{ {
var scale = Utils.get_ui_scaling_factor (); var scale = Utils.get_ui_scaling_factor ();
relevancy_time = new DateTime.now_local ().to_unix (); relevancy_time = new DateTime.now_local ().to_unix ();
width = (WIDTH + MARGIN * 2) * scale; width = (WIDTH + MARGIN * 2) * scale;
reactive = true; reactive = true;
set_pivot_point (0.5f, 0.5f); set_pivot_point (0.5f, 0.5f);
icon_texture = new Clutter.Texture (); icon_texture = new Clutter.Texture ();
icon_texture.set_pivot_point (0.5f, 0.5f); icon_texture.set_pivot_point (0.5f, 0.5f);
icon_container = new Actor (); icon_container = new Actor ();
icon_container.add_child (icon_texture); icon_container.add_child (icon_texture);
close_button = Utils.create_close_button (); close_button = Utils.create_close_button ();
close_button.opacity = 0; close_button.opacity = 0;
close_button.reactive = true; close_button.reactive = true;
close_button.set_easing_duration (300); close_button.set_easing_duration (300);
var close_click = new ClickAction (); var close_click = new ClickAction ();
close_click.clicked.connect (() => { close_click.clicked.connect (() => {
closed (id, NotificationClosedReason.DISMISSED); closed (id, NotificationClosedReason.DISMISSED);
close (); close ();
}); });
close_button.add_action (close_click); close_button.add_action (close_click);
add_child (icon_container); add_child (icon_container);
add_child (close_button); add_child (close_button);
var style_path = new Gtk.WidgetPath (); var style_path = new Gtk.WidgetPath ();
style_path.append_type (typeof (Gtk.Window)); style_path.append_type (typeof (Gtk.Window));
style_path.append_type (typeof (Gtk.EventBox)); style_path.append_type (typeof (Gtk.EventBox));
style_context = new Gtk.StyleContext (); style_context = new Gtk.StyleContext ();
style_context.add_provider (Gala.Utils.get_gala_css (), Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK); style_context.add_provider (Gala.Utils.get_gala_css (), Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK);
style_context.add_class ("gala-notification"); style_context.add_class ("gala-notification");
style_context.set_path (style_path); style_context.set_path (style_path);
style_context.set_scale (scale); style_context.set_scale (scale);
var label_style_path = style_path.copy (); var label_style_path = style_path.copy ();
label_style_path.iter_add_class (1, "gala-notification"); label_style_path.iter_add_class (1, "gala-notification");
label_style_path.append_type (typeof (Gtk.Label)); label_style_path.append_type (typeof (Gtk.Label));
var canvas = new Canvas (); var canvas = new Canvas ();
canvas.draw.connect (draw); canvas.draw.connect (draw);
content = canvas; content = canvas;
set_values (); set_values ();
var click = new ClickAction (); var click = new ClickAction ();
click.clicked.connect (() => { click.clicked.connect (() => {
activate (); activate ();
}); });
add_action (click); add_action (click);
open (); open ();
} }
public void open () { public void open () {
var entry = new TransitionGroup (); var entry = new TransitionGroup ();
entry.remove_on_complete = true; entry.remove_on_complete = true;
entry.duration = 400; entry.duration = 400;
var opacity_transition = new PropertyTransition ("opacity"); var opacity_transition = new PropertyTransition ("opacity");
opacity_transition.set_from_value (0); opacity_transition.set_from_value (0);
opacity_transition.set_to_value (255); opacity_transition.set_to_value (255);
var flip_transition = new KeyframeTransition ("rotation-angle-x"); var flip_transition = new KeyframeTransition ("rotation-angle-x");
flip_transition.set_from_value (90.0); flip_transition.set_from_value (90.0);
flip_transition.set_to_value (0.0); flip_transition.set_to_value (0.0);
flip_transition.set_key_frames ({ 0.6 }); flip_transition.set_key_frames ({ 0.6 });
flip_transition.set_values ({ -10.0 }); flip_transition.set_values ({ -10.0 });
entry.add_transition (opacity_transition); entry.add_transition (opacity_transition);
entry.add_transition (flip_transition); entry.add_transition (flip_transition);
add_transition ("entry", entry); add_transition ("entry", entry);
switch (urgency) { switch (urgency) {
case NotificationUrgency.LOW: case NotificationUrgency.LOW:
case NotificationUrgency.NORMAL: case NotificationUrgency.NORMAL:
return; return;
case NotificationUrgency.CRITICAL: case NotificationUrgency.CRITICAL:
var icon_entry = new TransitionGroup (); var icon_entry = new TransitionGroup ();
icon_entry.duration = 1000; icon_entry.duration = 1000;
icon_entry.remove_on_complete = true; icon_entry.remove_on_complete = true;
icon_entry.progress_mode = AnimationMode.EASE_IN_OUT_CUBIC; icon_entry.progress_mode = AnimationMode.EASE_IN_OUT_CUBIC;
double[] keyframes = { 0.2, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 }; double[] keyframes = { 0.2, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 };
GLib.Value[] scale = { 0.0, 1.2, 1.6, 1.6, 1.6, 1.6, 1.2, 1.0 }; GLib.Value[] scale = { 0.0, 1.2, 1.6, 1.6, 1.6, 1.6, 1.2, 1.0 };
var rotate_transition = new KeyframeTransition ("rotation-angle-z"); var rotate_transition = new KeyframeTransition ("rotation-angle-z");
rotate_transition.set_from_value (30.0); rotate_transition.set_from_value (30.0);
rotate_transition.set_to_value (0.0); rotate_transition.set_to_value (0.0);
rotate_transition.set_key_frames (keyframes); rotate_transition.set_key_frames (keyframes);
rotate_transition.set_values ({ 30.0, -30.0, 30.0, -20.0, 10.0, -5.0, 2.0, 0.0 }); rotate_transition.set_values ({ 30.0, -30.0, 30.0, -20.0, 10.0, -5.0, 2.0, 0.0 });
var scale_x_transition = new KeyframeTransition ("scale-x"); var scale_x_transition = new KeyframeTransition ("scale-x");
scale_x_transition.set_from_value (0.0); scale_x_transition.set_from_value (0.0);
scale_x_transition.set_to_value (1.0); scale_x_transition.set_to_value (1.0);
scale_x_transition.set_key_frames (keyframes); scale_x_transition.set_key_frames (keyframes);
scale_x_transition.set_values (scale); scale_x_transition.set_values (scale);
var scale_y_transition = new KeyframeTransition ("scale-y"); var scale_y_transition = new KeyframeTransition ("scale-y");
scale_y_transition.set_from_value (0.0); scale_y_transition.set_from_value (0.0);
scale_y_transition.set_to_value (1.0); scale_y_transition.set_to_value (1.0);
scale_y_transition.set_key_frames (keyframes); scale_y_transition.set_key_frames (keyframes);
scale_y_transition.set_values (scale); scale_y_transition.set_values (scale);
icon_entry.add_transition (rotate_transition); icon_entry.add_transition (rotate_transition);
icon_entry.add_transition (scale_x_transition); icon_entry.add_transition (scale_x_transition);
icon_entry.add_transition (scale_y_transition); icon_entry.add_transition (scale_y_transition);
icon_texture.add_transition ("entry", icon_entry); icon_texture.add_transition ("entry", icon_entry);
return; return;
} }
} }
public void close () public void close ()
{ {
set_easing_duration (100); set_easing_duration (100);
set_easing_mode (AnimationMode.EASE_IN_QUAD); set_easing_mode (AnimationMode.EASE_IN_QUAD);
opacity = 0; opacity = 0;
x = (WIDTH + MARGIN * 2) * style_context.get_scale (); x = (WIDTH + MARGIN * 2) * style_context.get_scale ();
being_destroyed = true; being_destroyed = true;
var transition = get_transition ("x"); var transition = get_transition ("x");
if (transition != null) if (transition != null)
transition.completed.connect (() => destroy ()); transition.completed.connect (() => destroy ());
else else
destroy (); destroy ();
} }
protected void update_base (Gdk.Pixbuf? icon, int32 expire_timeout) protected void update_base (Gdk.Pixbuf? icon, int32 expire_timeout)
{ {
this.icon = icon; this.icon = icon;
this.expire_timeout = expire_timeout; this.expire_timeout = expire_timeout;
this.relevancy_time = new DateTime.now_local ().to_unix (); this.relevancy_time = new DateTime.now_local ().to_unix ();
set_values (); set_values ();
} }
void set_values () void set_values ()
{ {
if (icon != null) { if (icon != null) {
try { try {
icon_texture.set_from_rgb_data (icon.get_pixels (), icon.get_has_alpha (), icon_texture.set_from_rgb_data (icon.get_pixels (), icon.get_has_alpha (),
icon.get_width (), icon.get_height (), icon.get_width (), icon.get_height (),
icon.get_rowstride (), (icon.get_has_alpha () ? 4 : 3), 0); icon.get_rowstride (), (icon.get_has_alpha () ? 4 : 3), 0);
} catch (Error e) {} } catch (Error e) {}
} }
set_timeout (); set_timeout ();
} }
void set_timeout () void set_timeout ()
{ {
// crtitical notifications have to be dismissed manually // crtitical notifications have to be dismissed manually
if (expire_timeout <= 0 || urgency == NotificationUrgency.CRITICAL) if (expire_timeout <= 0 || urgency == NotificationUrgency.CRITICAL)
return; return;
clear_timeout (); clear_timeout ();
remove_timeout = Timeout.add (expire_timeout, () => { remove_timeout = Timeout.add (expire_timeout, () => {
closed (id, NotificationClosedReason.EXPIRED); closed (id, NotificationClosedReason.EXPIRED);
close (); close ();
remove_timeout = 0; remove_timeout = 0;
return false; return false;
}); });
} }
void clear_timeout () void clear_timeout ()
{ {
if (remove_timeout != 0) { if (remove_timeout != 0) {
Source.remove (remove_timeout); Source.remove (remove_timeout);
remove_timeout = 0; remove_timeout = 0;
} }
} }
public override bool enter_event (CrossingEvent event) public override bool enter_event (CrossingEvent event)
{ {
close_button.opacity = 255; close_button.opacity = 255;
clear_timeout (); clear_timeout ();
return true; return true;
} }
public override bool leave_event (CrossingEvent event) public override bool leave_event (CrossingEvent event)
{ {
close_button.opacity = 0; close_button.opacity = 0;
// TODO consider decreasing the timeout now or calculating the remaining // TODO consider decreasing the timeout now or calculating the remaining
set_timeout (); set_timeout ();
return true; return true;
} }
public virtual void activate () public virtual void activate ()
{ {
} }
public virtual void draw_content (Cairo.Context cr) public virtual void draw_content (Cairo.Context cr)
{ {
} }
public abstract void update_allocation (out float content_height, AllocationFlags flags); public abstract void update_allocation (out float content_height, AllocationFlags flags);
public override void allocate (ActorBox box, AllocationFlags flags) public override void allocate (ActorBox box, AllocationFlags flags)
{ {
var icon_alloc = ActorBox (); var icon_alloc = ActorBox ();
var scale = style_context.get_scale (); var scale = style_context.get_scale ();
var scaled_width = WIDTH * scale; var scaled_width = WIDTH * scale;
var scaled_icon_size = ICON_SIZE * scale; var scaled_icon_size = ICON_SIZE * scale;
var scaled_margin_padding = (MARGIN + PADDING) * scale; var scaled_margin_padding = (MARGIN + PADDING) * scale;
icon_alloc.set_origin (icon_only ? (scaled_width - scaled_icon_size) / 2 : scaled_margin_padding, scaled_margin_padding); icon_alloc.set_origin (icon_only ? (scaled_width - scaled_icon_size) / 2 : scaled_margin_padding, scaled_margin_padding);
icon_alloc.set_size (scaled_icon_size, scaled_icon_size); icon_alloc.set_size (scaled_icon_size, scaled_icon_size);
icon_container.allocate (icon_alloc, flags); icon_container.allocate (icon_alloc, flags);
var close_alloc = ActorBox (); var close_alloc = ActorBox ();
close_alloc.set_origin (scaled_margin_padding - close_button.width / 2, close_alloc.set_origin (scaled_margin_padding - close_button.width / 2,
scaled_margin_padding - close_button.height / 2); scaled_margin_padding - close_button.height / 2);
close_alloc.set_size (close_button.width, close_button.height); close_alloc.set_size (close_button.width, close_button.height);
close_button.allocate (close_alloc, flags); close_button.allocate (close_alloc, flags);
float content_height; float content_height;
update_allocation (out content_height, flags); update_allocation (out content_height, flags);
box.set_size (MARGIN * 2 * scale + scaled_width, scaled_margin_padding * 2 + content_height); box.set_size (MARGIN * 2 * scale + scaled_width, scaled_margin_padding * 2 + content_height);
base.allocate (box, flags); base.allocate (box, flags);
var canvas = (Canvas) content; var canvas = (Canvas) content;
var canvas_width = (int) box.get_width (); var canvas_width = (int) box.get_width ();
var canvas_height = (int) box.get_height (); var canvas_height = (int) box.get_height ();
if (canvas.width != canvas_width || canvas.height != canvas_height) if (canvas.width != canvas_width || canvas.height != canvas_height)
canvas.set_size (canvas_width, canvas_height); canvas.set_size (canvas_width, canvas_height);
} }
public override void get_preferred_height (float for_width, out float min_height, out float nat_height) public override void get_preferred_height (float for_width, out float min_height, out float nat_height)
{ {
min_height = nat_height = (ICON_SIZE + (MARGIN + PADDING) * 2) * style_context.get_scale (); min_height = nat_height = (ICON_SIZE + (MARGIN + PADDING) * 2) * style_context.get_scale ();
} }
protected void play_update_transition (float slide_height) protected void play_update_transition (float slide_height)
{ {
Transition transition; Transition transition;
if ((transition = get_transition ("switch")) != null) { if ((transition = get_transition ("switch")) != null) {
transition.completed (); transition.completed ();
remove_transition ("switch"); remove_transition ("switch");
} }
animation_slide_height = slide_height; animation_slide_height = slide_height;
var scale = style_context.get_scale (); var scale = style_context.get_scale ();
var scaled_padding = PADDING * scale; var scaled_padding = PADDING * scale;
var scaled_icon_size = ICON_SIZE * scale; var scaled_icon_size = ICON_SIZE * scale;
old_texture = new Clutter.Texture (); old_texture = new Clutter.Texture ();
icon_container.add_child (old_texture); icon_container.add_child (old_texture);
icon_container.set_clip (0, -scaled_padding, scaled_icon_size, scaled_icon_size + scaled_padding * 2); icon_container.set_clip (0, -scaled_padding, scaled_icon_size, scaled_icon_size + scaled_padding * 2);
if (icon != null) { if (icon != null) {
try { try {
old_texture.set_from_rgb_data (icon.get_pixels (), icon.get_has_alpha (), old_texture.set_from_rgb_data (icon.get_pixels (), icon.get_has_alpha (),
icon.get_width (), icon.get_height (), icon.get_width (), icon.get_height (),
icon.get_rowstride (), (icon.get_has_alpha () ? 4 : 3), 0); icon.get_rowstride (), (icon.get_has_alpha () ? 4 : 3), 0);
} catch (Error e) {} } catch (Error e) {}
} }
transition = new PropertyTransition ("animation-slide-y-offset"); transition = new PropertyTransition ("animation-slide-y-offset");
transition.duration = 200; transition.duration = 200;
transition.progress_mode = AnimationMode.EASE_IN_OUT_QUAD; transition.progress_mode = AnimationMode.EASE_IN_OUT_QUAD;
transition.set_from_value (0.0f); transition.set_from_value (0.0f);
transition.set_to_value (animation_slide_height); transition.set_to_value (animation_slide_height);
transition.remove_on_complete = true; transition.remove_on_complete = true;
transition.completed.connect (() => { transition.completed.connect (() => {
old_texture.destroy (); old_texture.destroy ();
icon_container.remove_clip (); icon_container.remove_clip ();
_animation_slide_y_offset = 0; _animation_slide_y_offset = 0;
transitioning = false; transitioning = false;
}); });
add_transition ("switch", transition); add_transition ("switch", transition);
transitioning = true; transitioning = true;
} }
protected virtual void update_slide_animation () protected virtual void update_slide_animation ()
{ {
} }
bool draw (Cairo.Context cr) bool draw (Cairo.Context cr)
{ {
var canvas = (Canvas) content; var canvas = (Canvas) content;
var scale = style_context.get_scale (); var scale = style_context.get_scale ();
var x = MARGIN; var x = MARGIN;
var y = MARGIN; var y = MARGIN;
var width = canvas.width / scale - MARGIN * 2; var width = canvas.width / scale - MARGIN * 2;
var height = canvas.height / scale - MARGIN * 2; var height = canvas.height / scale - MARGIN * 2;
cr.set_operator (Cairo.Operator.CLEAR); cr.set_operator (Cairo.Operator.CLEAR);
cr.paint (); cr.paint ();
cr.set_operator (Cairo.Operator.OVER); cr.set_operator (Cairo.Operator.OVER);
cr.save (); cr.save ();
cr.scale (scale, scale); cr.scale (scale, scale);
style_context.render_background (cr, x, y, width, height); style_context.render_background (cr, x, y, width, height);
style_context.render_frame (cr, x, y, width, height); style_context.render_frame (cr, x, y, width, height);
cr.restore (); cr.restore ();
draw_content (cr); draw_content (cr);
return false; return false;
} }
} }
} }

View File

@ -20,99 +20,99 @@ using Meta;
namespace Gala.Plugins.Notify namespace Gala.Plugins.Notify
{ {
public class NotificationStack : Actor public class NotificationStack : Actor
{ {
// we need to keep a small offset to the top, because we clip the container to // we need to keep a small offset to the top, because we clip the container to
// its allocations and the close button would be off for the first notification // its allocations and the close button would be off for the first notification
const int TOP_OFFSET = 2; const int TOP_OFFSET = 2;
const int ADDITIONAL_MARGIN = 12; const int ADDITIONAL_MARGIN = 12;
public signal void animations_changed (bool running); public signal void animations_changed (bool running);
#if HAS_MUTTER330 #if HAS_MUTTER330
public Meta.Display display { get; construct; } public Meta.Display display { get; construct; }
public NotificationStack (Meta.Display display) public NotificationStack (Meta.Display display)
{ {
Object (display: display); Object (display: display);
} }
#else #else
public Screen screen { get; construct; } public Screen screen { get; construct; }
public new float width public new float width
{ {
get get
{ {
var scale = Utils.get_ui_scaling_factor (); var scale = Utils.get_ui_scaling_factor ();
return (Notification.WIDTH + 2 * Notification.MARGIN + ADDITIONAL_MARGIN) * scale; return (Notification.WIDTH + 2 * Notification.MARGIN + ADDITIONAL_MARGIN) * scale;
} }
} }
public NotificationStack (Screen screen) public NotificationStack (Screen screen)
{ {
Object (screen: screen); Object (screen: screen);
} }
#endif #endif
construct construct
{ {
clip_to_allocation = true; clip_to_allocation = true;
} }
public void show_notification (Notification notification) public void show_notification (Notification notification)
{ {
animations_changed (true); animations_changed (true);
var scale = Utils.get_ui_scaling_factor (); var scale = Utils.get_ui_scaling_factor ();
// raise ourselves when we got something to show // raise ourselves when we got something to show
get_parent ().set_child_above_sibling (this, null); get_parent ().set_child_above_sibling (this, null);
// we have a shoot-over on the start of the close animation, which gets clipped // we have a shoot-over on the start of the close animation, which gets clipped
// unless we make our container a bit wider and move the notifications over // unless we make our container a bit wider and move the notifications over
notification.margin_left = ADDITIONAL_MARGIN * scale; notification.margin_left = ADDITIONAL_MARGIN * scale;
notification.notify["being-destroyed"].connect (() => { notification.notify["being-destroyed"].connect (() => {
animations_changed (true); animations_changed (true);
}); });
notification.destroy.connect (() => { notification.destroy.connect (() => {
animations_changed (false); animations_changed (false);
update_positions (); update_positions ();
}); });
notification.get_transition ("entry").completed.connect (() => { notification.get_transition ("entry").completed.connect (() => {
animations_changed (false); animations_changed (false);
}); });
float height; float height;
notification.get_preferred_height (Notification.WIDTH * scale, out height, null); notification.get_preferred_height (Notification.WIDTH * scale, out height, null);
update_positions (height); update_positions (height);
notification.y = TOP_OFFSET * scale; notification.y = TOP_OFFSET * scale;
insert_child_at_index (notification, 0); insert_child_at_index (notification, 0);
} }
void update_positions (float add_y = 0.0f) void update_positions (float add_y = 0.0f)
{ {
var scale = Utils.get_ui_scaling_factor (); var scale = Utils.get_ui_scaling_factor ();
var y = add_y + TOP_OFFSET * scale; var y = add_y + TOP_OFFSET * scale;
var i = get_n_children (); var i = get_n_children ();
var delay_step = i > 0 ? 150 / i : 0; var delay_step = i > 0 ? 150 / i : 0;
foreach (var child in get_children ()) { foreach (var child in get_children ()) {
if (((Notification) child).being_destroyed) if (((Notification) child).being_destroyed)
continue; continue;
child.save_easing_state (); child.save_easing_state ();
child.set_easing_mode (AnimationMode.EASE_OUT_BACK); child.set_easing_mode (AnimationMode.EASE_OUT_BACK);
child.set_easing_duration (200); child.set_easing_duration (200);
child.set_easing_delay ((i--) * delay_step); child.set_easing_delay ((i--) * delay_step);
child.y = y; child.y = y;
child.restore_easing_state (); child.restore_easing_state ();
y += child.height; y += child.height;
} }
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -20,23 +20,23 @@
namespace Gala.Plugins.Notify namespace Gala.Plugins.Notify
{ {
public class NotifySettings : Granite.Services.Settings public class NotifySettings : Granite.Services.Settings
{ {
public bool do_not_disturb { get; set; } public bool do_not_disturb { get; set; }
static NotifySettings? instance = null; static NotifySettings? instance = null;
private NotifySettings () private NotifySettings ()
{ {
base (Config.SCHEMA + ".notifications"); base (Config.SCHEMA + ".notifications");
} }
public static unowned NotifySettings get_default () public static unowned NotifySettings get_default ()
{ {
if (instance == null) if (instance == null)
instance = new NotifySettings (); instance = new NotifySettings ();
return instance; return instance;
} }
} }
} }

View File

@ -17,216 +17,216 @@
public class Gala.Plugins.PIP.Plugin : Gala.Plugin public class Gala.Plugins.PIP.Plugin : Gala.Plugin
{ {
private const int MIN_SELECTION_SIZE = 30; private const int MIN_SELECTION_SIZE = 30;
private Gee.ArrayList<PopupWindow> windows; private Gee.ArrayList<PopupWindow> windows;
private Gala.WindowManager? wm = null; private Gala.WindowManager? wm = null;
private SelectionArea? selection_area; private SelectionArea? selection_area;
static inline bool meta_rectangle_contains (Meta.Rectangle rect, int x, int y) static inline bool meta_rectangle_contains (Meta.Rectangle rect, int x, int y)
{ {
return x >= rect.x && x < rect.x + rect.width return x >= rect.x && x < rect.x + rect.width
&& y >= rect.y && y < rect.y + rect.height; && y >= rect.y && y < rect.y + rect.height;
} }
construct construct
{ {
windows = new Gee.ArrayList<PopupWindow> (); windows = new Gee.ArrayList<PopupWindow> ();
} }
public override void initialize (Gala.WindowManager wm) public override void initialize (Gala.WindowManager wm)
{ {
this.wm = wm; this.wm = wm;
#if HAS_MUTTER330 #if HAS_MUTTER330
var display = wm.get_display (); var display = wm.get_display ();
#else #else
var display = wm.get_screen ().get_display (); var display = wm.get_screen ().get_display ();
#endif #endif
var settings = new GLib.Settings (Config.SCHEMA + ".keybindings"); var settings = new GLib.Settings (Config.SCHEMA + ".keybindings");
display.add_keybinding ("pip", settings, Meta.KeyBindingFlags.NONE, (Meta.KeyHandlerFunc) on_initiate); display.add_keybinding ("pip", settings, Meta.KeyBindingFlags.NONE, (Meta.KeyHandlerFunc) on_initiate);
} }
public override void destroy () public override void destroy ()
{ {
clear_selection_area (); clear_selection_area ();
foreach (var popup_window in windows) { foreach (var popup_window in windows) {
untrack_window (popup_window); untrack_window (popup_window);
} }
windows.clear (); windows.clear ();
} }
[CCode (instance_pos = -1)] [CCode (instance_pos = -1)]
#if HAS_MUTTER330 #if HAS_MUTTER330
void on_initiate (Meta.Display display, Meta.Window? window, Clutter.KeyEvent event, void on_initiate (Meta.Display display, Meta.Window? window, Clutter.KeyEvent event,
Meta.KeyBinding binding) Meta.KeyBinding binding)
#else #else
void on_initiate (Meta.Display display, Meta.Screen screen, void on_initiate (Meta.Display display, Meta.Screen screen,
Meta.Window? window, Clutter.KeyEvent event, Meta.KeyBinding binding) Meta.Window? window, Clutter.KeyEvent event, Meta.KeyBinding binding)
#endif #endif
{ {
selection_area = new SelectionArea (wm); selection_area = new SelectionArea (wm);
selection_area.selected.connect (on_selection_actor_selected); selection_area.selected.connect (on_selection_actor_selected);
selection_area.captured.connect (on_selection_actor_captured); selection_area.captured.connect (on_selection_actor_captured);
selection_area.closed.connect (clear_selection_area); selection_area.closed.connect (clear_selection_area);
track_actor (selection_area); track_actor (selection_area);
wm.ui_group.add_child (selection_area); wm.ui_group.add_child (selection_area);
selection_area.start_selection (); selection_area.start_selection ();
} }
private void on_selection_actor_selected (int x, int y) private void on_selection_actor_selected (int x, int y)
{ {
clear_selection_area (); clear_selection_area ();
select_window_at (x, y); select_window_at (x, y);
} }
private void on_selection_actor_captured (int x, int y, int width, int height) private void on_selection_actor_captured (int x, int y, int width, int height)
{ {
clear_selection_area (); clear_selection_area ();
if (width < MIN_SELECTION_SIZE || height < MIN_SELECTION_SIZE) { if (width < MIN_SELECTION_SIZE || height < MIN_SELECTION_SIZE) {
select_window_at (x, y); select_window_at (x, y);
} else { } else {
var active = get_active_window_actor (); var active = get_active_window_actor ();
if (active != null) { if (active != null) {
int point_x = x - (int)active.x; int point_x = x - (int)active.x;
int point_y = y - (int)active.y; int point_y = y - (int)active.y;
var rect = Clutter.Rect.alloc (); var rect = Clutter.Rect.alloc ();
var clip = rect.init (point_x, point_y, width, height); var clip = rect.init (point_x, point_y, width, height);
var popup_window = new PopupWindow (wm, active, clip); var popup_window = new PopupWindow (wm, active, clip);
popup_window.show.connect (on_popup_window_show); popup_window.show.connect (on_popup_window_show);
popup_window.hide.connect (on_popup_window_hide); popup_window.hide.connect (on_popup_window_hide);
add_window (popup_window); add_window (popup_window);
} }
} }
} }
private void on_popup_window_show (Clutter.Actor popup_window) private void on_popup_window_show (Clutter.Actor popup_window)
{ {
track_actor (popup_window); track_actor (popup_window);
update_region (); update_region ();
} }
private void on_popup_window_hide (Clutter.Actor popup_window) private void on_popup_window_hide (Clutter.Actor popup_window)
{ {
untrack_actor (popup_window); untrack_actor (popup_window);
update_region (); update_region ();
} }
private void select_window_at (int x, int y) private void select_window_at (int x, int y)
{ {
var selected = get_window_actor_at (x, y); var selected = get_window_actor_at (x, y);
if (selected != null) { if (selected != null) {
var popup_window = new PopupWindow (wm, selected, null); var popup_window = new PopupWindow (wm, selected, null);
popup_window.show.connect (on_popup_window_show); popup_window.show.connect (on_popup_window_show);
popup_window.hide.connect (on_popup_window_hide); popup_window.hide.connect (on_popup_window_hide);
add_window (popup_window); add_window (popup_window);
} }
} }
private void clear_selection_area () private void clear_selection_area ()
{ {
if (selection_area != null) { if (selection_area != null) {
untrack_actor (selection_area); untrack_actor (selection_area);
update_region (); update_region ();
selection_area.destroy (); selection_area.destroy ();
selection_area = null; selection_area = null;
} }
} }
private Meta.WindowActor? get_window_actor_at (int x, int y) private Meta.WindowActor? get_window_actor_at (int x, int y)
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.Display display = wm.get_display (); unowned Meta.Display display = wm.get_display ();
unowned List<Meta.WindowActor> actors = display.get_window_actors (); unowned List<Meta.WindowActor> actors = display.get_window_actors ();
#else #else
var screen = wm.get_screen (); var screen = wm.get_screen ();
unowned List<Meta.WindowActor> actors = screen.get_window_actors (); unowned List<Meta.WindowActor> actors = screen.get_window_actors ();
#endif #endif
var copy = actors.copy (); var copy = actors.copy ();
copy.reverse (); copy.reverse ();
weak Meta.WindowActor? selected = null; weak Meta.WindowActor? selected = null;
copy.@foreach ((actor) => { copy.@foreach ((actor) => {
if (selected != null) { if (selected != null) {
return; return;
} }
var window = actor.get_meta_window (); var window = actor.get_meta_window ();
var rect = window.get_frame_rect (); var rect = window.get_frame_rect ();
if (!actor.is_destroyed () && !window.is_hidden () && !window.is_skip_taskbar () && meta_rectangle_contains (rect, x, y)) { if (!actor.is_destroyed () && !window.is_hidden () && !window.is_skip_taskbar () && meta_rectangle_contains (rect, x, y)) {
selected = actor; selected = actor;
} }
}); });
return selected; return selected;
} }
private Meta.WindowActor? get_active_window_actor () private Meta.WindowActor? get_active_window_actor ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.Display display = wm.get_display (); unowned Meta.Display display = wm.get_display ();
unowned List<Meta.WindowActor> actors = display.get_window_actors (); unowned List<Meta.WindowActor> actors = display.get_window_actors ();
#else #else
var screen = wm.get_screen (); var screen = wm.get_screen ();
unowned List<Meta.WindowActor> actors = screen.get_window_actors (); unowned List<Meta.WindowActor> actors = screen.get_window_actors ();
#endif #endif
var copy = actors.copy (); var copy = actors.copy ();
copy.reverse (); copy.reverse ();
weak Meta.WindowActor? active = null; weak Meta.WindowActor? active = null;
actors.@foreach ((actor) => { actors.@foreach ((actor) => {
if (active != null) { if (active != null) {
return; return;
} }
var window = actor.get_meta_window (); var window = actor.get_meta_window ();
if (!actor.is_destroyed () && !window.is_hidden () && !window.is_skip_taskbar () && window.has_focus ()) { if (!actor.is_destroyed () && !window.is_hidden () && !window.is_skip_taskbar () && window.has_focus ()) {
active = actor; active = actor;
} }
}); });
return active; return active;
} }
private void add_window (PopupWindow popup_window) private void add_window (PopupWindow popup_window)
{ {
popup_window.closed.connect (() => remove_window (popup_window)); popup_window.closed.connect (() => remove_window (popup_window));
windows.add (popup_window); windows.add (popup_window);
wm.ui_group.add_child (popup_window); wm.ui_group.add_child (popup_window);
} }
private void remove_window (PopupWindow popup_window) private void remove_window (PopupWindow popup_window)
{ {
windows.remove (popup_window); windows.remove (popup_window);
untrack_window (popup_window); untrack_window (popup_window);
} }
private void untrack_window (PopupWindow popup_window) private void untrack_window (PopupWindow popup_window)
{ {
untrack_actor (popup_window); untrack_actor (popup_window);
update_region (); update_region ();
popup_window.destroy (); popup_window.destroy ();
} }
} }
public Gala.PluginInfo register_plugin () public Gala.PluginInfo register_plugin ()
{ {
return Gala.PluginInfo () { return Gala.PluginInfo () {
name = "Popup Window", name = "Popup Window",
author = "Adam Bieńkowski <donadigos159@gmail.com>", author = "Adam Bieńkowski <donadigos159@gmail.com>",
plugin_type = typeof (Gala.Plugins.PIP.Plugin), plugin_type = typeof (Gala.Plugins.PIP.Plugin),
provides = Gala.PluginFunction.ADDITION, provides = Gala.PluginFunction.ADDITION,
load_priority = Gala.LoadPriority.IMMEDIATE load_priority = Gala.LoadPriority.IMMEDIATE
}; };
} }

View File

@ -17,11 +17,11 @@
public class Gala.Plugins.PIP.MoveAction : Clutter.DragAction public class Gala.Plugins.PIP.MoveAction : Clutter.DragAction
{ {
public signal void move (); public signal void move ();
public override bool drag_progress (Clutter.Actor actor, float delta_x, float delta_y) public override bool drag_progress (Clutter.Actor actor, float delta_x, float delta_y)
{ {
move (); move ();
return false; return false;
} }
} }

View File

@ -17,452 +17,452 @@
public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor
{ {
private int button_size; private int button_size;
private int container_margin; private int container_margin;
private const int SHADOW_SIZE = 100; private const int SHADOW_SIZE = 100;
private const uint FADE_OUT_TIMEOUT = 200; private const uint FADE_OUT_TIMEOUT = 200;
private const float MINIMUM_SCALE = 0.1f; private const float MINIMUM_SCALE = 0.1f;
private const float MAXIMUM_SCALE = 1.0f; private const float MAXIMUM_SCALE = 1.0f;
private const int SCREEN_MARGIN = 0; private const int SCREEN_MARGIN = 0;
public signal void closed (); public signal void closed ();
public Gala.WindowManager wm { get; construct; } public Gala.WindowManager wm { get; construct; }
public Meta.WindowActor window_actor { get; construct; } public Meta.WindowActor window_actor { get; construct; }
public Clutter.Rect? container_clip { get; construct; } public Clutter.Rect? container_clip { get; construct; }
private Clutter.Actor clone; private Clutter.Actor clone;
private Clutter.Actor container; private Clutter.Actor container;
private Clutter.Actor close_button; private Clutter.Actor close_button;
private Clutter.Actor resize_button; private Clutter.Actor resize_button;
private Clutter.Actor resize_handle; private Clutter.Actor resize_handle;
private Clutter.ClickAction close_action; private Clutter.ClickAction close_action;
private Clutter.DragAction resize_action; private Clutter.DragAction resize_action;
private MoveAction move_action; private MoveAction move_action;
private bool dragging = false; private bool dragging = false;
private bool clicked = false; private bool clicked = false;
private int x_offset_press = 0; private int x_offset_press = 0;
private int y_offset_press = 0; private int y_offset_press = 0;
private float begin_resize_width = 0.0f; private float begin_resize_width = 0.0f;
private float begin_resize_height = 0.0f; private float begin_resize_height = 0.0f;
static unowned Meta.Window? previous_focus = null; static unowned Meta.Window? previous_focus = null;
// From https://opensourcehacker.com/2011/12/01/calculate-aspect-ratio-conserving-resize-for-images-in-javascript/ // From https://opensourcehacker.com/2011/12/01/calculate-aspect-ratio-conserving-resize-for-images-in-javascript/
static void calculate_aspect_ratio_size_fit (float src_width, float src_height, float max_width, float max_height, static void calculate_aspect_ratio_size_fit (float src_width, float src_height, float max_width, float max_height,
out float width, out float height) out float width, out float height)
{ {
float ratio = float.min (max_width / src_width, max_height / src_height); float ratio = float.min (max_width / src_width, max_height / src_height);
width = src_width * ratio; width = src_width * ratio;
height = src_height * ratio; height = src_height * ratio;
} }
static bool get_window_is_normal (Meta.Window window) static bool get_window_is_normal (Meta.Window window)
{ {
var window_type = window.get_window_type (); var window_type = window.get_window_type ();
return window_type == Meta.WindowType.NORMAL return window_type == Meta.WindowType.NORMAL
|| window_type == Meta.WindowType.DIALOG || window_type == Meta.WindowType.DIALOG
|| window_type == Meta.WindowType.MODAL_DIALOG; || window_type == Meta.WindowType.MODAL_DIALOG;
} }
static void get_current_cursor_position (out int x, out int y) static void get_current_cursor_position (out int x, out int y)
{ {
Gdk.Display.get_default ().get_device_manager ().get_client_pointer ().get_position (null, out x, out y); Gdk.Display.get_default ().get_device_manager ().get_client_pointer ().get_position (null, out x, out y);
} }
public PopupWindow (Gala.WindowManager wm, Meta.WindowActor window_actor, Clutter.Rect? container_clip) public PopupWindow (Gala.WindowManager wm, Meta.WindowActor window_actor, Clutter.Rect? container_clip)
{ {
Object (wm: wm, window_actor: window_actor, container_clip: container_clip); Object (wm: wm, window_actor: window_actor, container_clip: container_clip);
} }
construct construct
{ {
var scale = Utils.get_ui_scaling_factor (); var scale = Utils.get_ui_scaling_factor ();
button_size = 36 * scale; button_size = 36 * scale;
container_margin = button_size / 2; container_margin = button_size / 2;
reactive = true; reactive = true;
set_pivot_point (0.5f, 0.5f); set_pivot_point (0.5f, 0.5f);
set_easing_mode (Clutter.AnimationMode.EASE_IN_QUAD); set_easing_mode (Clutter.AnimationMode.EASE_IN_QUAD);
var window = window_actor.get_meta_window (); var window = window_actor.get_meta_window ();
window.unmanaged.connect (on_close_click_clicked); window.unmanaged.connect (on_close_click_clicked);
window.notify["appears-focused"].connect (() => { window.notify["appears-focused"].connect (() => {
Idle.add (() => { Idle.add (() => {
update_window_focus (); update_window_focus ();
return false; return false;
}); });
}); });
clone = new Clutter.Clone (window_actor); clone = new Clutter.Clone (window_actor);
move_action = new MoveAction (); move_action = new MoveAction ();
move_action.drag_begin.connect (on_move_begin); move_action.drag_begin.connect (on_move_begin);
move_action.drag_end.connect (on_move_end); move_action.drag_end.connect (on_move_end);
move_action.move.connect (on_move); move_action.move.connect (on_move);
container = new Clutter.Actor (); container = new Clutter.Actor ();
container.reactive = true; container.reactive = true;
container.set_scale (0.35f, 0.35f); container.set_scale (0.35f, 0.35f);
container.clip_rect = container_clip; container.clip_rect = container_clip;
container.add_effect (new ShadowEffect (SHADOW_SIZE, 2)); container.add_effect (new ShadowEffect (SHADOW_SIZE, 2));
container.add_child (clone); container.add_child (clone);
container.add_action (move_action); container.add_action (move_action);
if (container_clip == null) { if (container_clip == null) {
window_actor.notify["allocation"].connect (on_allocation_changed); window_actor.notify["allocation"].connect (on_allocation_changed);
container.set_position (container_margin, container_margin); container.set_position (container_margin, container_margin);
update_clone_clip (); update_clone_clip ();
} }
update_size (); update_size ();
update_container_position (); update_container_position ();
Meta.Rectangle monitor_rect; Meta.Rectangle monitor_rect;
get_current_monitor_rect (out monitor_rect); get_current_monitor_rect (out monitor_rect);
float x_position, y_position; float x_position, y_position;
if (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL) { if (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL) {
x_position = SCREEN_MARGIN + monitor_rect.x; x_position = SCREEN_MARGIN + monitor_rect.x;
} else { } else {
x_position = monitor_rect.width + monitor_rect.x - SCREEN_MARGIN - width; x_position = monitor_rect.width + monitor_rect.x - SCREEN_MARGIN - width;
} }
y_position = monitor_rect.height + monitor_rect.y - SCREEN_MARGIN - height; y_position = monitor_rect.height + monitor_rect.y - SCREEN_MARGIN - height;
set_position (x_position, y_position); set_position (x_position, y_position);
close_action = new Clutter.ClickAction (); close_action = new Clutter.ClickAction ();
close_action.clicked.connect (on_close_click_clicked); close_action.clicked.connect (on_close_click_clicked);
close_button = Gala.Utils.create_close_button (); close_button = Gala.Utils.create_close_button ();
close_button.opacity = 0; close_button.opacity = 0;
close_button.reactive = true; close_button.reactive = true;
close_button.set_easing_duration (300); close_button.set_easing_duration (300);
close_button.add_action (close_action); close_button.add_action (close_action);
resize_action = new Clutter.DragAction (); resize_action = new Clutter.DragAction ();
resize_action.drag_begin.connect (on_resize_drag_begin); resize_action.drag_begin.connect (on_resize_drag_begin);
resize_action.drag_end.connect (on_resize_drag_end); resize_action.drag_end.connect (on_resize_drag_end);
resize_action.drag_motion.connect (on_resize_drag_motion); resize_action.drag_motion.connect (on_resize_drag_motion);
resize_handle = new Clutter.Actor (); resize_handle = new Clutter.Actor ();
resize_handle.set_size (button_size, button_size); resize_handle.set_size (button_size, button_size);
resize_handle.set_pivot_point (0.5f, 0.5f); resize_handle.set_pivot_point (0.5f, 0.5f);
resize_handle.set_position (width - button_size, height - button_size); resize_handle.set_position (width - button_size, height - button_size);
resize_handle.reactive = true; resize_handle.reactive = true;
resize_handle.add_action (resize_action); resize_handle.add_action (resize_action);
resize_button = Utils.create_resize_button (); resize_button = Utils.create_resize_button ();
resize_button.set_pivot_point (0.5f, 0.5f); resize_button.set_pivot_point (0.5f, 0.5f);
resize_button.set_position (width - button_size, height - button_size); resize_button.set_position (width - button_size, height - button_size);
resize_button.opacity = 0; resize_button.opacity = 0;
resize_button.reactive = true; resize_button.reactive = true;
add_child (container); add_child (container);
add_child (close_button); add_child (close_button);
add_child (resize_button); add_child (resize_button);
add_child (resize_handle); add_child (resize_handle);
} }
public override void show () public override void show ()
{ {
base.show (); base.show ();
opacity = 0; opacity = 0;
set_easing_duration (200); set_easing_duration (200);
opacity = 255; opacity = 255;
set_easing_duration (0); set_easing_duration (0);
} }
public override void hide () public override void hide ()
{ {
opacity = 255; opacity = 255;
set_easing_duration (200); set_easing_duration (200);
opacity = 0; opacity = 0;
set_easing_duration (0); set_easing_duration (0);
ulong completed_id = 0UL; ulong completed_id = 0UL;
completed_id = transitions_completed.connect (() => { completed_id = transitions_completed.connect (() => {
disconnect (completed_id); disconnect (completed_id);
base.hide (); base.hide ();
}); });
} }
public override bool enter_event (Clutter.CrossingEvent event) public override bool enter_event (Clutter.CrossingEvent event)
{ {
close_button.opacity = 255; close_button.opacity = 255;
resize_button.set_easing_duration (300); resize_button.set_easing_duration (300);
resize_button.opacity = 255; resize_button.opacity = 255;
resize_button.set_easing_duration (0); resize_button.set_easing_duration (0);
return true; return true;
} }
public override bool leave_event (Clutter.CrossingEvent event) public override bool leave_event (Clutter.CrossingEvent event)
{ {
close_button.opacity = 0; close_button.opacity = 0;
resize_button.set_easing_duration (300); resize_button.set_easing_duration (300);
resize_button.opacity = 0; resize_button.opacity = 0;
resize_button.set_easing_duration (0); resize_button.set_easing_duration (0);
return true; return true;
} }
private void on_move_begin () private void on_move_begin ()
{ {
int px, py; int px, py;
get_current_cursor_position (out px, out py); get_current_cursor_position (out px, out py);
x_offset_press = (int)(px - x); x_offset_press = (int)(px - x);
y_offset_press = (int)(py - y); y_offset_press = (int)(py - y);
clicked = true; clicked = true;
dragging = false; dragging = false;
} }
private void on_move_end () private void on_move_end ()
{ {
clicked = false; clicked = false;
if (dragging) { if (dragging) {
update_screen_position (); update_screen_position ();
dragging = false; dragging = false;
} else { } else {
activate (); activate ();
} }
} }
private void on_move () private void on_move ()
{ {
if (!clicked) { if (!clicked) {
return; return;
} }
float motion_x, motion_y; float motion_x, motion_y;
move_action.get_motion_coords (out motion_x, out motion_y); move_action.get_motion_coords (out motion_x, out motion_y);
x = (int)motion_x - x_offset_press; x = (int)motion_x - x_offset_press;
y = (int)motion_y - y_offset_press; y = (int)motion_y - y_offset_press;
if (!dragging) { if (!dragging) {
dragging = true; dragging = true;
} }
} }
private void on_resize_drag_begin (Clutter.Actor actor, float event_x, float event_y, Clutter.ModifierType type) private void on_resize_drag_begin (Clutter.Actor actor, float event_x, float event_y, Clutter.ModifierType type)
{ {
begin_resize_width = width; begin_resize_width = width;
begin_resize_height = height; begin_resize_height = height;
} }
private void on_resize_drag_end (Clutter.Actor actor, float event_x, float event_y, Clutter.ModifierType type) private void on_resize_drag_end (Clutter.Actor actor, float event_x, float event_y, Clutter.ModifierType type)
{ {
reposition_resize_handle (); reposition_resize_handle ();
update_screen_position (); update_screen_position ();
} }
private void on_resize_drag_motion (Clutter.Actor actor, float delta_x, float delta_y) private void on_resize_drag_motion (Clutter.Actor actor, float delta_x, float delta_y)
{ {
float press_x, press_y; float press_x, press_y;
resize_action.get_press_coords (out press_x, out press_y); resize_action.get_press_coords (out press_x, out press_y);
int motion_x, motion_y; int motion_x, motion_y;
get_current_cursor_position (out motion_x, out motion_y); get_current_cursor_position (out motion_x, out motion_y);
float diff_x = motion_x - press_x; float diff_x = motion_x - press_x;
float diff_y = motion_y - press_y; float diff_y = motion_y - press_y;
width = begin_resize_width + diff_x; width = begin_resize_width + diff_x;
height = begin_resize_height + diff_y; height = begin_resize_height + diff_y;
update_container_scale (); update_container_scale ();
update_size (); update_size ();
reposition_resize_button (); reposition_resize_button ();
} }
private void on_allocation_changed () private void on_allocation_changed ()
{ {
update_clone_clip (); update_clone_clip ();
update_size (); update_size ();
reposition_resize_button (); reposition_resize_button ();
reposition_resize_handle (); reposition_resize_handle ();
} }
private void on_close_click_clicked () private void on_close_click_clicked ()
{ {
set_easing_duration (FADE_OUT_TIMEOUT); set_easing_duration (FADE_OUT_TIMEOUT);
opacity = 0; opacity = 0;
Clutter.Threads.Timeout.add (FADE_OUT_TIMEOUT, () => { Clutter.Threads.Timeout.add (FADE_OUT_TIMEOUT, () => {
closed (); closed ();
return false; return false;
}); });
} }
private void update_window_focus () private void update_window_focus ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.Window focus_window = wm.get_display ().get_focus_window (); unowned Meta.Window focus_window = wm.get_display ().get_focus_window ();
#else #else
unowned Meta.Window focus_window = wm.get_screen ().get_display ().get_focus_window (); unowned Meta.Window focus_window = wm.get_screen ().get_display ().get_focus_window ();
#endif #endif
if ((focus_window != null && !get_window_is_normal (focus_window)) if ((focus_window != null && !get_window_is_normal (focus_window))
|| (previous_focus != null && !get_window_is_normal (previous_focus))) { || (previous_focus != null && !get_window_is_normal (previous_focus))) {
previous_focus = focus_window; previous_focus = focus_window;
return; return;
} }
var window = window_actor.get_meta_window (); var window = window_actor.get_meta_window ();
if (window.appears_focused) { if (window.appears_focused) {
hide (); hide ();
} else if (!window_actor.is_destroyed ()) { } else if (!window_actor.is_destroyed ()) {
show (); show ();
} }
previous_focus = focus_window; previous_focus = focus_window;
} }
private void update_size () private void update_size ()
{ {
if (container_clip != null) { if (container_clip != null) {
width = (int)(container_clip.get_width () * container.scale_x + button_size); width = (int)(container_clip.get_width () * container.scale_x + button_size);
height = (int)(container_clip.get_height () * container.scale_y + button_size); height = (int)(container_clip.get_height () * container.scale_y + button_size);
} else { } else {
width = (int)(container.width * container.scale_x + button_size); width = (int)(container.width * container.scale_x + button_size);
height = (int)(container.height * container.scale_y + button_size); height = (int)(container.height * container.scale_y + button_size);
} }
} }
private void update_clone_clip () private void update_clone_clip ()
{ {
var rect = window_actor.get_meta_window ().get_frame_rect (); var rect = window_actor.get_meta_window ().get_frame_rect ();
float x_offset = rect.x - window_actor.x; float x_offset = rect.x - window_actor.x;
float y_offset = rect.y - window_actor.y; float y_offset = rect.y - window_actor.y;
clone.set_clip (x_offset, y_offset, rect.width, rect.height); clone.set_clip (x_offset, y_offset, rect.width, rect.height);
clone.set_position (-x_offset, -y_offset); clone.set_position (-x_offset, -y_offset);
container.set_size (rect.width, rect.height); container.set_size (rect.width, rect.height);
} }
private void update_container_scale () private void update_container_scale ()
{ {
float src_width; float src_width;
float src_height; float src_height;
if (container_clip != null) { if (container_clip != null) {
src_width = container_clip.get_width (); src_width = container_clip.get_width ();
src_height = container_clip.get_height (); src_height = container_clip.get_height ();
} else { } else {
src_width = container.width; src_width = container.width;
src_height = container.height; src_height = container.height;
} }
float max_width = width - button_size; float max_width = width - button_size;
float max_height = height - button_size; float max_height = height - button_size;
float new_width, new_height; float new_width, new_height;
calculate_aspect_ratio_size_fit ( calculate_aspect_ratio_size_fit (
src_width, src_height, src_width, src_height,
max_width, max_height, max_width, max_height,
out new_width, out new_height out new_width, out new_height
); );
float window_width, window_height; float window_width, window_height;
get_target_window_size (out window_width, out window_height); get_target_window_size (out window_width, out window_height);
float new_scale_x = new_width / window_width; float new_scale_x = new_width / window_width;
float new_scale_y = new_height / window_height; float new_scale_y = new_height / window_height;
container.scale_x = new_scale_x.clamp (MINIMUM_SCALE, MAXIMUM_SCALE); container.scale_x = new_scale_x.clamp (MINIMUM_SCALE, MAXIMUM_SCALE);
container.scale_y = new_scale_y.clamp (MINIMUM_SCALE, MAXIMUM_SCALE); container.scale_y = new_scale_y.clamp (MINIMUM_SCALE, MAXIMUM_SCALE);
update_container_position (); update_container_position ();
} }
private void update_container_position () private void update_container_position ()
{ {
if (container_clip != null) { if (container_clip != null) {
container.x = (float)(-container_clip.get_x () * container.scale_x + container_margin); container.x = (float)(-container_clip.get_x () * container.scale_x + container_margin);
container.y = (float)(-container_clip.get_y () * container.scale_y + container_margin); container.y = (float)(-container_clip.get_y () * container.scale_y + container_margin);
} }
} }
private void update_screen_position () private void update_screen_position ()
{ {
Meta.Rectangle monitor_rect; Meta.Rectangle monitor_rect;
get_current_monitor_rect (out monitor_rect); get_current_monitor_rect (out monitor_rect);
int monitor_x = monitor_rect.x; int monitor_x = monitor_rect.x;
int monitor_y = monitor_rect.y; int monitor_y = monitor_rect.y;
int monitor_width = monitor_rect.width; int monitor_width = monitor_rect.width;
int monitor_height = monitor_rect.height; int monitor_height = monitor_rect.height;
set_easing_duration (300); set_easing_duration (300);
set_easing_mode (Clutter.AnimationMode.EASE_OUT_BACK); set_easing_mode (Clutter.AnimationMode.EASE_OUT_BACK);
var screen_limit_start = SCREEN_MARGIN + monitor_x; var screen_limit_start = SCREEN_MARGIN + monitor_x;
var screen_limit_end = monitor_width + monitor_x - SCREEN_MARGIN - width; var screen_limit_end = monitor_width + monitor_x - SCREEN_MARGIN - width;
x = x.clamp (screen_limit_start, screen_limit_end); x = x.clamp (screen_limit_start, screen_limit_end);
screen_limit_start = SCREEN_MARGIN + monitor_y; screen_limit_start = SCREEN_MARGIN + monitor_y;
screen_limit_end = monitor_height + monitor_y - SCREEN_MARGIN - height; screen_limit_end = monitor_height + monitor_y - SCREEN_MARGIN - height;
y = y.clamp (screen_limit_start, screen_limit_end); y = y.clamp (screen_limit_start, screen_limit_end);
set_easing_mode (Clutter.AnimationMode.EASE_IN_QUAD); set_easing_mode (Clutter.AnimationMode.EASE_IN_QUAD);
set_easing_duration (0); set_easing_duration (0);
} }
private void reposition_resize_button () private void reposition_resize_button ()
{ {
resize_button.set_position (width - button_size, height - button_size); resize_button.set_position (width - button_size, height - button_size);
} }
private void reposition_resize_handle () private void reposition_resize_handle ()
{ {
resize_handle.set_position (width - button_size, height - button_size); resize_handle.set_position (width - button_size, height - button_size);
} }
private void get_current_monitor_rect (out Meta.Rectangle rect) private void get_current_monitor_rect (out Meta.Rectangle rect)
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
var display = wm.get_display (); var display = wm.get_display ();
rect = display.get_monitor_geometry (display.get_current_monitor ()); rect = display.get_monitor_geometry (display.get_current_monitor ());
#else #else
var screen = wm.get_screen (); var screen = wm.get_screen ();
rect = screen.get_monitor_geometry (screen.get_current_monitor ()); rect = screen.get_monitor_geometry (screen.get_current_monitor ());
#endif #endif
} }
private void get_target_window_size (out float width, out float height) private void get_target_window_size (out float width, out float height)
{ {
if (container_clip != null) { if (container_clip != null) {
width = container_clip.get_width (); width = container_clip.get_width ();
height = container_clip.get_height (); height = container_clip.get_height ();
} else if (clone.has_clip) { } else if (clone.has_clip) {
float clone_clip_width = 0.0f, clone_clip_height = 0.0f; float clone_clip_width = 0.0f, clone_clip_height = 0.0f;
clone.get_clip (null, null, out clone_clip_width, out clone_clip_height); clone.get_clip (null, null, out clone_clip_width, out clone_clip_height);
width = clone_clip_width; width = clone_clip_width;
height = clone_clip_height; height = clone_clip_height;
} else { } else {
width = clone.width; width = clone.width;
height = clone.height; height = clone.height;
} }
} }
private void activate () private void activate ()
{ {
var window = window_actor.get_meta_window (); var window = window_actor.get_meta_window ();
window.activate (Clutter.get_current_event_time ()); window.activate (Clutter.get_current_event_time ());
} }
} }

View File

@ -17,170 +17,170 @@
public class Gala.Plugins.PIP.SelectionArea : Clutter.Actor public class Gala.Plugins.PIP.SelectionArea : Clutter.Actor
{ {
public signal void captured (int x, int y, int width, int height); public signal void captured (int x, int y, int width, int height);
public signal void selected (int x, int y); public signal void selected (int x, int y);
public signal void closed (); public signal void closed ();
public Gala.WindowManager wm { get; construct; } public Gala.WindowManager wm { get; construct; }
private Gala.ModalProxy? modal_proxy; private Gala.ModalProxy? modal_proxy;
private Gdk.Point start_point; private Gdk.Point start_point;
private Gdk.Point end_point; private Gdk.Point end_point;
private bool dragging = false; private bool dragging = false;
private bool clicked = false; private bool clicked = false;
public SelectionArea (Gala.WindowManager wm) public SelectionArea (Gala.WindowManager wm)
{ {
Object (wm: wm); Object (wm: wm);
} }
construct construct
{ {
start_point = { 0, 0 }; start_point = { 0, 0 };
end_point = { 0, 0 }; end_point = { 0, 0 };
visible = true; visible = true;
reactive = true; reactive = true;
int screen_width, screen_height; int screen_width, screen_height;
#if HAS_MUTTER330 #if HAS_MUTTER330
wm.get_display ().get_size (out screen_width, out screen_height); wm.get_display ().get_size (out screen_width, out screen_height);
#else #else
wm.get_screen ().get_size (out screen_width, out screen_height); wm.get_screen ().get_size (out screen_width, out screen_height);
#endif #endif
width = screen_width; width = screen_width;
height = screen_height; height = screen_height;
var canvas = new Clutter.Canvas (); var canvas = new Clutter.Canvas ();
canvas.set_size (screen_width, screen_height); canvas.set_size (screen_width, screen_height);
canvas.draw.connect (draw_area); canvas.draw.connect (draw_area);
set_content (canvas); set_content (canvas);
canvas.invalidate (); canvas.invalidate ();
} }
public override bool key_press_event (Clutter.KeyEvent e) public override bool key_press_event (Clutter.KeyEvent e)
{ {
if (e.keyval == Clutter.Key.Escape) { if (e.keyval == Clutter.Key.Escape) {
close (); close ();
closed (); closed ();
return true; return true;
} }
return false; return false;
} }
public override bool button_press_event (Clutter.ButtonEvent e) public override bool button_press_event (Clutter.ButtonEvent e)
{ {
if (dragging || e.button != 1) { if (dragging || e.button != 1) {
return true; return true;
} }
clicked = true; clicked = true;
start_point.x = (int) e.x; start_point.x = (int) e.x;
start_point.y = (int) e.y; start_point.y = (int) e.y;
return true; return true;
} }
public override bool button_release_event (Clutter.ButtonEvent e) public override bool button_release_event (Clutter.ButtonEvent e)
{ {
if (e.button != 1) { if (e.button != 1) {
return true; return true;
} }
if (!dragging) { if (!dragging) {
selected ((int) e.x, (int) e.y); selected ((int) e.x, (int) e.y);
close (); close ();
return true; return true;
} }
dragging = false; dragging = false;
clicked = false; clicked = false;
int x, y, w, h; int x, y, w, h;
get_selection_rectangle (out x, out y, out w, out h); get_selection_rectangle (out x, out y, out w, out h);
close (); close ();
start_point = { 0, 0 }; start_point = { 0, 0 };
end_point = { 0, 0 }; end_point = { 0, 0 };
this.hide (); this.hide ();
content.invalidate (); content.invalidate ();
captured (x, y, w, h); captured (x, y, w, h);
return true; return true;
} }
public override bool motion_event (Clutter.MotionEvent e) public override bool motion_event (Clutter.MotionEvent e)
{ {
if (!clicked) { if (!clicked) {
return true; return true;
} }
end_point.x = (int) e.x; end_point.x = (int) e.x;
end_point.y = (int) e.y; end_point.y = (int) e.y;
content.invalidate (); content.invalidate ();
if (!dragging) { if (!dragging) {
dragging = true; dragging = true;
} }
return true; return true;
} }
public void close () public void close ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
wm.get_display ().set_cursor (Meta.Cursor.DEFAULT); wm.get_display ().set_cursor (Meta.Cursor.DEFAULT);
#else #else
wm.get_screen ().set_cursor (Meta.Cursor.DEFAULT); wm.get_screen ().set_cursor (Meta.Cursor.DEFAULT);
#endif #endif
if (modal_proxy != null) { if (modal_proxy != null) {
wm.pop_modal (modal_proxy); wm.pop_modal (modal_proxy);
} }
} }
public void start_selection () public void start_selection ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
wm.get_display ().set_cursor (Meta.Cursor.CROSSHAIR); wm.get_display ().set_cursor (Meta.Cursor.CROSSHAIR);
#else #else
wm.get_screen ().set_cursor (Meta.Cursor.CROSSHAIR); wm.get_screen ().set_cursor (Meta.Cursor.CROSSHAIR);
#endif #endif
grab_key_focus (); grab_key_focus ();
modal_proxy = wm.push_modal (); modal_proxy = wm.push_modal ();
} }
private void get_selection_rectangle (out int x, out int y, out int width, out int height) private void get_selection_rectangle (out int x, out int y, out int width, out int height)
{ {
x = int.min (start_point.x, end_point.x); x = int.min (start_point.x, end_point.x);
y = int.min (start_point.y, end_point.y); y = int.min (start_point.y, end_point.y);
width = (start_point.x - end_point.x).abs (); width = (start_point.x - end_point.x).abs ();
height = (start_point.y - end_point.y).abs (); height = (start_point.y - end_point.y).abs ();
} }
private bool draw_area (Cairo.Context ctx) private bool draw_area (Cairo.Context ctx)
{ {
Clutter.cairo_clear (ctx); Clutter.cairo_clear (ctx);
if (!dragging) { if (!dragging) {
return true; return true;
} }
int x, y, w, h; int x, y, w, h;
get_selection_rectangle (out x, out y, out w, out h); get_selection_rectangle (out x, out y, out w, out h);
ctx.rectangle (x, y, w, h); ctx.rectangle (x, y, w, h);
ctx.set_source_rgba (0.1, 0.1, 0.1, 0.2); ctx.set_source_rgba (0.1, 0.1, 0.1, 0.2);
ctx.fill (); ctx.fill ();
ctx.rectangle (x, y, w, h); ctx.rectangle (x, y, w, h);
ctx.set_source_rgb (0.7, 0.7, 0.7); ctx.set_source_rgb (0.7, 0.7, 0.7);
ctx.set_line_width (1.0); ctx.set_line_width (1.0);
ctx.stroke (); ctx.stroke ();
return true; return true;
} }
} }

View File

@ -19,135 +19,135 @@ using Clutter;
namespace Gala.Plugins.PIP namespace Gala.Plugins.PIP
{ {
public class ShadowEffect : Effect public class ShadowEffect : Effect
{ {
private class Shadow private class Shadow
{ {
public int users; public int users;
public Cogl.Texture texture; public Cogl.Texture texture;
public Shadow (Cogl.Texture _texture) public Shadow (Cogl.Texture _texture)
{ {
texture = _texture; texture = _texture;
users = 1; users = 1;
} }
} }
// the sizes of the textures often repeat, especially for the background actor // the sizes of the textures often repeat, especially for the background actor
// so we keep a cache to avoid creating the same texture all over again. // so we keep a cache to avoid creating the same texture all over again.
static Gee.HashMap<string,Shadow> shadow_cache; static Gee.HashMap<string,Shadow> shadow_cache;
static construct static construct
{ {
shadow_cache = new Gee.HashMap<string,Shadow> (); shadow_cache = new Gee.HashMap<string,Shadow> ();
} }
public int shadow_size { get; construct; } public int shadow_size { get; construct; }
public int shadow_spread { get; construct; } public int shadow_spread { get; construct; }
public float scale_factor { get; set; default = 1; } public float scale_factor { get; set; default = 1; }
public uint8 shadow_opacity { get; set; default = 255; } public uint8 shadow_opacity { get; set; default = 255; }
Cogl.Material material; Cogl.Material material;
string? current_key = null; string? current_key = null;
public ShadowEffect (int shadow_size, int shadow_spread) public ShadowEffect (int shadow_size, int shadow_spread)
{ {
Object (shadow_size: shadow_size, shadow_spread: shadow_spread); Object (shadow_size: shadow_size, shadow_spread: shadow_spread);
} }
construct construct
{ {
material = new Cogl.Material (); material = new Cogl.Material ();
} }
~ShadowEffect () ~ShadowEffect ()
{ {
if (current_key != null) if (current_key != null)
decrement_shadow_users (current_key); decrement_shadow_users (current_key);
} }
Cogl.Texture? get_shadow (int width, int height, int shadow_size, int shadow_spread) Cogl.Texture? get_shadow (int width, int height, int shadow_size, int shadow_spread)
{ {
var old_key = current_key; var old_key = current_key;
current_key = "%ix%i:%i:%i".printf (width, height, shadow_size, shadow_spread); current_key = "%ix%i:%i:%i".printf (width, height, shadow_size, shadow_spread);
if (old_key == current_key) if (old_key == current_key)
return null; return null;
if (old_key != null) if (old_key != null)
decrement_shadow_users (old_key); decrement_shadow_users (old_key);
Shadow? shadow = null; Shadow? shadow = null;
if ((shadow = shadow_cache.@get (current_key)) != null) { if ((shadow = shadow_cache.@get (current_key)) != null) {
shadow.users++; shadow.users++;
return shadow.texture; return shadow.texture;
} }
// fill a new texture for this size // fill a new texture for this size
var buffer = new Granite.Drawing.BufferSurface (width, height); var buffer = new Granite.Drawing.BufferSurface (width, height);
buffer.context.rectangle (shadow_size - shadow_spread, shadow_size - shadow_spread, buffer.context.rectangle (shadow_size - shadow_spread, shadow_size - shadow_spread,
width - shadow_size * 2 + shadow_spread * 2, height - shadow_size * 2 + shadow_spread * 2); width - shadow_size * 2 + shadow_spread * 2, height - shadow_size * 2 + shadow_spread * 2);
buffer.context.set_source_rgba (0, 0, 0, 0.7); buffer.context.set_source_rgba (0, 0, 0, 0.7);
buffer.context.fill (); buffer.context.fill ();
buffer.exponential_blur (shadow_size / 2); buffer.exponential_blur (shadow_size / 2);
var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height); var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
var cr = new Cairo.Context (surface); var cr = new Cairo.Context (surface);
cr.set_source_surface (buffer.surface, 0, 0); cr.set_source_surface (buffer.surface, 0, 0);
cr.paint (); cr.paint ();
var texture = new Cogl.Texture.from_data (width, height, 0, Cogl.PixelFormat.BGRA_8888_PRE, var texture = new Cogl.Texture.from_data (width, height, 0, Cogl.PixelFormat.BGRA_8888_PRE,
Cogl.PixelFormat.ANY, surface.get_stride (), surface.get_data ()); Cogl.PixelFormat.ANY, surface.get_stride (), surface.get_data ());
shadow_cache.@set (current_key, new Shadow (texture)); shadow_cache.@set (current_key, new Shadow (texture));
return texture; return texture;
} }
void decrement_shadow_users (string key) void decrement_shadow_users (string key)
{ {
var shadow = shadow_cache.@get (key); var shadow = shadow_cache.@get (key);
if (shadow == null) if (shadow == null)
return; return;
if (--shadow.users == 0) if (--shadow.users == 0)
shadow_cache.unset (key); shadow_cache.unset (key);
} }
public override void paint (EffectPaintFlags flags) public override void paint (EffectPaintFlags flags)
{ {
var bounding_box = get_bounding_box (); var bounding_box = get_bounding_box ();
var shadow = get_shadow ((int) (bounding_box.x2 - bounding_box.x1), (int) (bounding_box.y2 - bounding_box.y1), var shadow = get_shadow ((int) (bounding_box.x2 - bounding_box.x1), (int) (bounding_box.y2 - bounding_box.y1),
shadow_size, shadow_spread); shadow_size, shadow_spread);
if (shadow != null) if (shadow != null)
material.set_layer (0, shadow); material.set_layer (0, shadow);
var opacity = actor.get_paint_opacity () * shadow_opacity / 255; var opacity = actor.get_paint_opacity () * shadow_opacity / 255;
var alpha = Cogl.Color.from_4ub (255, 255, 255, opacity); var alpha = Cogl.Color.from_4ub (255, 255, 255, opacity);
alpha.premultiply (); alpha.premultiply ();
material.set_color (alpha); material.set_color (alpha);
Cogl.set_source (material); Cogl.set_source (material);
Cogl.rectangle (bounding_box.x1, bounding_box.y1, bounding_box.x2, bounding_box.y2); Cogl.rectangle (bounding_box.x1, bounding_box.y1, bounding_box.x2, bounding_box.y2);
actor.continue_paint (); actor.continue_paint ();
} }
public virtual ActorBox get_bounding_box () public virtual ActorBox get_bounding_box ()
{ {
var size = shadow_size * scale_factor; var size = shadow_size * scale_factor;
var bounding_box = ActorBox (); var bounding_box = ActorBox ();
bounding_box.set_origin (-size, -size); bounding_box.set_origin (-size, -size);
bounding_box.set_size (actor.width + size * 2, actor.height + size * 2); bounding_box.set_size (actor.width + size * 2, actor.height + size * 2);
return bounding_box; return bounding_box;
} }
} }
} }

View File

@ -22,79 +22,79 @@
namespace Gala.Plugins.Template namespace Gala.Plugins.Template
{ {
public class Main : Gala.Plugin public class Main : Gala.Plugin
{ {
const int PADDING = 50; const int PADDING = 50;
Gala.WindowManager? wm = null; Gala.WindowManager? wm = null;
Clutter.Actor red_box; Clutter.Actor red_box;
// This function is called as soon as Gala has started and gives you // This function is called as soon as Gala has started and gives you
// an instance of the GalaWindowManager class. // an instance of the GalaWindowManager class.
public override void initialize (Gala.WindowManager wm) public override void initialize (Gala.WindowManager wm)
{ {
// we will save the instance to our wm property so we can use it later again // we will save the instance to our wm property so we can use it later again
// especially helpful when you have larger plugins with more functions, // especially helpful when you have larger plugins with more functions,
// we won't need it here // we won't need it here
this.wm = wm; this.wm = wm;
// for demonstration purposes we'll add a red quad to the stage which will // for demonstration purposes we'll add a red quad to the stage which will
// turn green when clicked // turn green when clicked
red_box = new Clutter.Actor (); red_box = new Clutter.Actor ();
red_box.set_size (100, 100); red_box.set_size (100, 100);
red_box.background_color = { 255, 0, 0, 255 }; red_box.background_color = { 255, 0, 0, 255 };
red_box.reactive = true; red_box.reactive = true;
red_box.button_press_event.connect (turn_green); red_box.button_press_event.connect (turn_green);
// we want to place it in the lower right of the primary monitor with a bit // we want to place it in the lower right of the primary monitor with a bit
// of padding. refer to vapi/libmutter.vapi in gala's source for something // of padding. refer to vapi/libmutter.vapi in gala's source for something
// remotely similar to a documentation // remotely similar to a documentation
#if HAS_MUTTER330 #if HAS_MUTTER330
var display = wm.get_display (); var display = wm.get_display ();
var rect = display.get_monitor_geometry (display.get_primary_monitor ()); var rect = display.get_monitor_geometry (display.get_primary_monitor ());
#else #else
var screen = wm.get_screen (); var screen = wm.get_screen ();
var rect = screen.get_monitor_geometry (screen.get_primary_monitor ()); var rect = screen.get_monitor_geometry (screen.get_primary_monitor ());
#endif #endif
red_box.x = rect.x + rect.width - red_box.width - PADDING; red_box.x = rect.x + rect.width - red_box.width - PADDING;
red_box.y = rect.y + rect.height - red_box.height - PADDING; red_box.y = rect.y + rect.height - red_box.height - PADDING;
// to order Gala to deliver mouse events to our box instead of the underlying // to order Gala to deliver mouse events to our box instead of the underlying
// windows, we need to mark the region where the quad is located. // windows, we need to mark the region where the quad is located.
// The plugin class offers an utility function for this purpose, the track_actor // The plugin class offers an utility function for this purpose, the track_actor
// function. It will update the region with the allocation of the actor // function. It will update the region with the allocation of the actor
// whenever its allocation changes. Make sure to set freeze_track to // whenever its allocation changes. Make sure to set freeze_track to
// true while animating the actor to not make gala update the region // true while animating the actor to not make gala update the region
// every single frame. // every single frame.
// You can also handle the region manually by setting the custom_region // You can also handle the region manually by setting the custom_region
// property. The tracked actors and custom regions will be merged by // property. The tracked actors and custom regions will be merged by
// the plugin. // the plugin.
track_actor (red_box); track_actor (red_box);
// now we'll add our box into the ui_group. This is where all the shell // now we'll add our box into the ui_group. This is where all the shell
// elements and also the windows and backgrouds are located. // elements and also the windows and backgrouds are located.
wm.ui_group.add_child (red_box); wm.ui_group.add_child (red_box);
} }
bool turn_green (Clutter.ButtonEvent event) bool turn_green (Clutter.ButtonEvent event)
{ {
red_box.background_color = { 0, 255, 0, 255 }; red_box.background_color = { 0, 255, 0, 255 };
return true; return true;
} }
// This function is actually not even called by Gala at the moment, // This function is actually not even called by Gala at the moment,
// still it might be a good idea to implement it anyway to make sure // still it might be a good idea to implement it anyway to make sure
// your plugin is compatible in case we'd add disabling specific plugins // your plugin is compatible in case we'd add disabling specific plugins
// in the future // in the future
public override void destroy () public override void destroy ()
{ {
// here you would destroy actors you added to the stage or remove // here you would destroy actors you added to the stage or remove
// keybindings // keybindings
red_box.destroy (); red_box.destroy ();
} }
} }
} }
// this little function just tells Gala which class of those you may have in // this little function just tells Gala which class of those you may have in
@ -104,20 +104,20 @@ namespace Gala.Plugins.Template
// no duplicate functionality. // no duplicate functionality.
public Gala.PluginInfo register_plugin () public Gala.PluginInfo register_plugin ()
{ {
return { return {
"template-plugin", // the plugin's name "template-plugin", // the plugin's name
"Tom Beckmann <tomjonabc@gmail.com>", // you, the author "Tom Beckmann <tomjonabc@gmail.com>", // you, the author
typeof (Gala.Plugins.Template.Main), // the type of your plugin class typeof (Gala.Plugins.Template.Main), // the type of your plugin class
Gala.PluginFunction.ADDITION, // the function which your plugin Gala.PluginFunction.ADDITION, // the function which your plugin
// fulfils, ADDITION means nothing // fulfils, ADDITION means nothing
// specific // specific
Gala.LoadPriority.IMMEDIATE // indicates whether your plugin's Gala.LoadPriority.IMMEDIATE // indicates whether your plugin's
// start can be delayed until gala // start can be delayed until gala
// has loaded the important stuff or // has loaded the important stuff or
// if you want your plugin to start // if you want your plugin to start
// right away. False means wait. // right away. False means wait.
}; };
} }

View File

@ -17,147 +17,147 @@
namespace Gala.Plugins.Zoom namespace Gala.Plugins.Zoom
{ {
public class Main : Gala.Plugin public class Main : Gala.Plugin
{ {
const uint MOUSE_POLL_TIME = 50; const uint MOUSE_POLL_TIME = 50;
Gala.WindowManager? wm = null; Gala.WindowManager? wm = null;
uint mouse_poll_timer = 0; uint mouse_poll_timer = 0;
float current_zoom = 1.0f; float current_zoom = 1.0f;
ulong wins_handler_id = 0UL; ulong wins_handler_id = 0UL;
public override void initialize (Gala.WindowManager wm) public override void initialize (Gala.WindowManager wm)
{ {
this.wm = wm; this.wm = wm;
#if HAS_MUTTER330 #if HAS_MUTTER330
var display = wm.get_display (); var display = wm.get_display ();
#else #else
var display = wm.get_screen ().get_display (); var display = wm.get_screen ().get_display ();
#endif #endif
var schema = new GLib.Settings (Config.SCHEMA + ".keybindings"); var schema = new GLib.Settings (Config.SCHEMA + ".keybindings");
display.add_keybinding ("zoom-in", schema, 0, (Meta.KeyHandlerFunc) zoom_in); display.add_keybinding ("zoom-in", schema, 0, (Meta.KeyHandlerFunc) zoom_in);
display.add_keybinding ("zoom-out", schema, 0, (Meta.KeyHandlerFunc) zoom_out); display.add_keybinding ("zoom-out", schema, 0, (Meta.KeyHandlerFunc) zoom_out);
} }
public override void destroy () public override void destroy ()
{ {
if (wm == null) if (wm == null)
return; return;
#if HAS_MUTTER330 #if HAS_MUTTER330
var display = wm.get_display (); var display = wm.get_display ();
#else #else
var display = wm.get_screen ().get_display (); var display = wm.get_screen ().get_display ();
#endif #endif
display.remove_keybinding ("zoom-in"); display.remove_keybinding ("zoom-in");
display.remove_keybinding ("zoom-out"); display.remove_keybinding ("zoom-out");
if (mouse_poll_timer > 0) if (mouse_poll_timer > 0)
Source.remove (mouse_poll_timer); Source.remove (mouse_poll_timer);
mouse_poll_timer = 0; mouse_poll_timer = 0;
} }
[CCode (instance_pos = -1)] [CCode (instance_pos = -1)]
#if HAS_MUTTER330 #if HAS_MUTTER330
void zoom_in (Meta.Display display, Meta.Window? window, void zoom_in (Meta.Display display, Meta.Window? window,
Clutter.KeyEvent event, Meta.KeyBinding binding) Clutter.KeyEvent event, Meta.KeyBinding binding)
#else #else
void zoom_in (Meta.Display display, Meta.Screen screen, void zoom_in (Meta.Display display, Meta.Screen screen,
Meta.Window? window, Clutter.KeyEvent event, Meta.KeyBinding binding) Meta.Window? window, Clutter.KeyEvent event, Meta.KeyBinding binding)
#endif #endif
{ {
zoom (true); zoom (true);
} }
[CCode (instance_pos = -1)] [CCode (instance_pos = -1)]
#if HAS_MUTTER330 #if HAS_MUTTER330
void zoom_out (Meta.Display display, Meta.Window? window, void zoom_out (Meta.Display display, Meta.Window? window,
Clutter.KeyEvent event, Meta.KeyBinding binding) Clutter.KeyEvent event, Meta.KeyBinding binding)
#else #else
void zoom_out (Meta.Display display, Meta.Screen screen, void zoom_out (Meta.Display display, Meta.Screen screen,
Meta.Window? window, Clutter.KeyEvent event, Meta.KeyBinding binding) Meta.Window? window, Clutter.KeyEvent event, Meta.KeyBinding binding)
#endif #endif
{ {
zoom (false); zoom (false);
} }
void zoom (bool @in) void zoom (bool @in)
{ {
// Nothing to do if zooming out of our bounds is requested // Nothing to do if zooming out of our bounds is requested
if (current_zoom <= 1.0f && !@in) if (current_zoom <= 1.0f && !@in)
return; return;
else if (current_zoom >= 2.5f && @in) else if (current_zoom >= 2.5f && @in)
return; return;
var wins = wm.ui_group; var wins = wm.ui_group;
// Add timer to poll current mouse position to reposition window-group // Add timer to poll current mouse position to reposition window-group
// to show requested zoomed area // to show requested zoomed area
if (mouse_poll_timer == 0) { if (mouse_poll_timer == 0) {
float mx, my; float mx, my;
var client_pointer = Gdk.Display.get_default ().get_device_manager ().get_client_pointer (); var client_pointer = Gdk.Display.get_default ().get_device_manager ().get_client_pointer ();
client_pointer.get_position (null, out mx, out my); client_pointer.get_position (null, out mx, out my);
wins.set_pivot_point (mx / wins.width, my / wins.height); wins.set_pivot_point (mx / wins.width, my / wins.height);
mouse_poll_timer = Timeout.add (MOUSE_POLL_TIME, () => { mouse_poll_timer = Timeout.add (MOUSE_POLL_TIME, () => {
client_pointer.get_position (null, out mx, out my); client_pointer.get_position (null, out mx, out my);
var new_pivot = Clutter.Point.alloc (); var new_pivot = Clutter.Point.alloc ();
new_pivot.init (mx / wins.width, my / wins.height); new_pivot.init (mx / wins.width, my / wins.height);
if (wins.pivot_point.equals (new_pivot)) if (wins.pivot_point.equals (new_pivot))
return true; return true;
wins.save_easing_state (); wins.save_easing_state ();
wins.set_easing_mode (Clutter.AnimationMode.LINEAR); wins.set_easing_mode (Clutter.AnimationMode.LINEAR);
wins.set_easing_duration (MOUSE_POLL_TIME); wins.set_easing_duration (MOUSE_POLL_TIME);
wins.pivot_point = new_pivot; wins.pivot_point = new_pivot;
wins.restore_easing_state (); wins.restore_easing_state ();
return true; return true;
}); });
} }
current_zoom += (@in ? 0.5f : -0.5f); current_zoom += (@in ? 0.5f : -0.5f);
if (current_zoom <= 1.0f) { if (current_zoom <= 1.0f) {
current_zoom = 1.0f; current_zoom = 1.0f;
if (mouse_poll_timer > 0) if (mouse_poll_timer > 0)
Source.remove (mouse_poll_timer); Source.remove (mouse_poll_timer);
mouse_poll_timer = 0; mouse_poll_timer = 0;
wins.save_easing_state (); wins.save_easing_state ();
wins.set_easing_mode (Clutter.AnimationMode.EASE_OUT_CUBIC); wins.set_easing_mode (Clutter.AnimationMode.EASE_OUT_CUBIC);
wins.set_easing_duration (300); wins.set_easing_duration (300);
wins.set_scale (1.0f, 1.0f); wins.set_scale (1.0f, 1.0f);
wins.restore_easing_state (); wins.restore_easing_state ();
wins_handler_id = wins.transitions_completed.connect (() => { wins_handler_id = wins.transitions_completed.connect (() => {
wins.disconnect (wins_handler_id); wins.disconnect (wins_handler_id);
wins.set_pivot_point (0.0f, 0.0f); wins.set_pivot_point (0.0f, 0.0f);
}); });
return; return;
} }
wins.save_easing_state (); wins.save_easing_state ();
wins.set_easing_mode (Clutter.AnimationMode.EASE_OUT_CUBIC); wins.set_easing_mode (Clutter.AnimationMode.EASE_OUT_CUBIC);
wins.set_easing_duration (300); wins.set_easing_duration (300);
wins.set_scale (current_zoom, current_zoom); wins.set_scale (current_zoom, current_zoom);
wins.restore_easing_state (); wins.restore_easing_state ();
} }
} }
} }
public Gala.PluginInfo register_plugin () public Gala.PluginInfo register_plugin ()
{ {
return Gala.PluginInfo () { return Gala.PluginInfo () {
name = "Zoom", name = "Zoom",
author = "Gala Developers", author = "Gala Developers",
plugin_type = typeof (Gala.Plugins.Zoom.Main), plugin_type = typeof (Gala.Plugins.Zoom.Main),
provides = Gala.PluginFunction.ADDITION, provides = Gala.PluginFunction.ADDITION,
load_priority = Gala.LoadPriority.IMMEDIATE load_priority = Gala.LoadPriority.IMMEDIATE
}; };
} }

View File

@ -17,60 +17,60 @@
namespace Gala namespace Gala
{ {
public class Animation : Object public class Animation : Object
{ {
public string filename { get; construct; } public string filename { get; construct; }
public string[] key_frame_files { get; private set; default = {}; } public string[] key_frame_files { get; private set; default = {}; }
public double transition_progress { get; private set; default = 0.0; } public double transition_progress { get; private set; default = 0.0; }
public double transition_duration { get; private set; default = 0.0; } public double transition_duration { get; private set; default = 0.0; }
public bool loaded { get; private set; default = false; } public bool loaded { get; private set; default = false; }
Gnome.BGSlideShow? show = null; Gnome.BGSlideShow? show = null;
public Animation (string filename) public Animation (string filename)
{ {
Object (filename: filename); Object (filename: filename);
} }
public async void load () public async void load ()
{ {
show = new Gnome.BGSlideShow (filename); show = new Gnome.BGSlideShow (filename);
show.load_async (null, (obj, res) => { show.load_async (null, (obj, res) => {
loaded = true; loaded = true;
load.callback (); load.callback ();
}); });
yield; yield;
} }
public void update (Meta.Rectangle monitor) public void update (Meta.Rectangle monitor)
{ {
string[] key_frame_files = {}; string[] key_frame_files = {};
if (show == null) if (show == null)
return; return;
if (show.get_num_slides () < 1) if (show.get_num_slides () < 1)
return; return;
double progress, duration; double progress, duration;
bool is_fixed; bool is_fixed;
string file1, file2; string file1, file2;
show.get_current_slide (monitor.width, monitor.height, out progress, out duration, out is_fixed, out file1, out file2); show.get_current_slide (monitor.width, monitor.height, out progress, out duration, out is_fixed, out file1, out file2);
transition_duration = duration; transition_duration = duration;
transition_progress = progress; transition_progress = progress;
if (file1 != null) if (file1 != null)
key_frame_files += file1; key_frame_files += file1;
if (file2 != null) if (file2 != null)
key_frame_files += file2; key_frame_files += file2;
this.key_frame_files = key_frame_files; this.key_frame_files = key_frame_files;
} }
} }
} }

View File

@ -17,274 +17,274 @@
namespace Gala namespace Gala
{ {
public class Background : Object public class Background : Object
{ {
const double ANIMATION_OPACITY_STEP_INCREMENT = 4.0; const double ANIMATION_OPACITY_STEP_INCREMENT = 4.0;
const double ANIMATION_MIN_WAKEUP_INTERVAL = 1.0; const double ANIMATION_MIN_WAKEUP_INTERVAL = 1.0;
public signal void changed (); public signal void changed ();
public signal void loaded (); public signal void loaded ();
#if HAS_MUTTER330 #if HAS_MUTTER330
public Meta.Display display { get; construct; } public Meta.Display display { get; construct; }
#else #else
public Meta.Screen screen { get; construct; } public Meta.Screen screen { get; construct; }
#endif #endif
public int monitor_index { get; construct; } public int monitor_index { get; construct; }
public BackgroundSource background_source { get; construct; } public BackgroundSource background_source { get; construct; }
public bool is_loaded { get; private set; default = false; } public bool is_loaded { get; private set; default = false; }
public GDesktop.BackgroundStyle style { get; construct; } public GDesktop.BackgroundStyle style { get; construct; }
public string? filename { get; construct; } public string? filename { get; construct; }
public Meta.Background background { get; private set; } public Meta.Background background { get; private set; }
Animation? animation = null; Animation? animation = null;
Gee.HashMap<string,ulong> file_watches; Gee.HashMap<string,ulong> file_watches;
Cancellable cancellable; Cancellable cancellable;
uint update_animation_timeout_id = 0; uint update_animation_timeout_id = 0;
#if HAS_MUTTER330 #if HAS_MUTTER330
public Background (Meta.Display display, int monitor_index, string? filename, public Background (Meta.Display display, int monitor_index, string? filename,
BackgroundSource background_source, GDesktop.BackgroundStyle style) BackgroundSource background_source, GDesktop.BackgroundStyle style)
{ {
Object (display: display, Object (display: display,
monitor_index: monitor_index, monitor_index: monitor_index,
background_source: background_source, background_source: background_source,
style: style, style: style,
filename: filename); filename: filename);
} }
#else #else
public Background (Meta.Screen screen, int monitor_index, string? filename, public Background (Meta.Screen screen, int monitor_index, string? filename,
BackgroundSource background_source, GDesktop.BackgroundStyle style) BackgroundSource background_source, GDesktop.BackgroundStyle style)
{ {
Object (screen: screen, Object (screen: screen,
monitor_index: monitor_index, monitor_index: monitor_index,
background_source: background_source, background_source: background_source,
style: style, style: style,
filename: filename); filename: filename);
} }
#endif #endif
construct construct
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
background = new Meta.Background (display); background = new Meta.Background (display);
#else #else
background = new Meta.Background (screen); background = new Meta.Background (screen);
#endif #endif
background.set_data<unowned Background> ("delegate", this); background.set_data<unowned Background> ("delegate", this);
file_watches = new Gee.HashMap<string,ulong> (); file_watches = new Gee.HashMap<string,ulong> ();
cancellable = new Cancellable (); cancellable = new Cancellable ();
background_source.changed.connect (settings_changed); background_source.changed.connect (settings_changed);
load (); load ();
} }
public void destroy () public void destroy ()
{ {
cancellable.cancel (); cancellable.cancel ();
remove_animation_timeout (); remove_animation_timeout ();
var cache = BackgroundCache.get_default (); var cache = BackgroundCache.get_default ();
foreach (var watch in file_watches.values) { foreach (var watch in file_watches.values) {
SignalHandler.disconnect (cache, watch); SignalHandler.disconnect (cache, watch);
} }
background_source.changed.disconnect (settings_changed); background_source.changed.disconnect (settings_changed);
} }
public void update_resolution () public void update_resolution ()
{ {
if (animation != null) { if (animation != null) {
remove_animation_timeout (); remove_animation_timeout ();
update_animation (); update_animation ();
} }
} }
void set_loaded () void set_loaded ()
{ {
if (is_loaded) if (is_loaded)
return; return;
is_loaded = true; is_loaded = true;
Idle.add (() => { Idle.add (() => {
loaded (); loaded ();
return false; return false;
}); });
} }
void load_pattern () void load_pattern ()
{ {
string color_string; string color_string;
var settings = background_source.settings; var settings = background_source.settings;
color_string = settings.get_string ("primary-color"); color_string = settings.get_string ("primary-color");
var color = Clutter.Color.from_string (color_string); var color = Clutter.Color.from_string (color_string);
color_string = settings.get_string("secondary-color"); color_string = settings.get_string("secondary-color");
var second_color = Clutter.Color.from_string (color_string); var second_color = Clutter.Color.from_string (color_string);
var shading_type = settings.get_enum ("color-shading-type"); var shading_type = settings.get_enum ("color-shading-type");
if (shading_type == GDesktop.BackgroundShading.SOLID) if (shading_type == GDesktop.BackgroundShading.SOLID)
background.set_color (color); background.set_color (color);
else else
background.set_gradient ((GDesktop.BackgroundShading) shading_type, color, second_color); background.set_gradient ((GDesktop.BackgroundShading) shading_type, color, second_color);
} }
void watch_file (string filename) void watch_file (string filename)
{ {
if (file_watches.has_key (filename)) if (file_watches.has_key (filename))
return; return;
var cache = BackgroundCache.get_default (); var cache = BackgroundCache.get_default ();
cache.monitor_file (filename); cache.monitor_file (filename);
file_watches[filename] = cache.file_changed.connect ((changed_file) => { file_watches[filename] = cache.file_changed.connect ((changed_file) => {
if (changed_file == filename) { if (changed_file == filename) {
var image_cache = Meta.BackgroundImageCache.get_default (); var image_cache = Meta.BackgroundImageCache.get_default ();
image_cache.purge (File.new_for_path (changed_file)); image_cache.purge (File.new_for_path (changed_file));
changed (); changed ();
} }
}); });
} }
void remove_animation_timeout () void remove_animation_timeout ()
{ {
if (update_animation_timeout_id != 0) { if (update_animation_timeout_id != 0) {
Source.remove (update_animation_timeout_id); Source.remove (update_animation_timeout_id);
update_animation_timeout_id = 0; update_animation_timeout_id = 0;
} }
} }
void update_animation () void update_animation ()
{ {
update_animation_timeout_id = 0; update_animation_timeout_id = 0;
#if HAS_MUTTER330 #if HAS_MUTTER330
animation.update (display.get_monitor_geometry (monitor_index)); animation.update (display.get_monitor_geometry (monitor_index));
#else #else
animation.update (screen.get_monitor_geometry (monitor_index)); animation.update (screen.get_monitor_geometry (monitor_index));
#endif #endif
var files = animation.key_frame_files; var files = animation.key_frame_files;
Clutter.Callback finish = () => { Clutter.Callback finish = () => {
set_loaded (); set_loaded ();
if (files.length > 1) if (files.length > 1)
background.set_blend (File.new_for_path (files[0]), File.new_for_path (files[1]), animation.transition_progress, style); background.set_blend (File.new_for_path (files[0]), File.new_for_path (files[1]), animation.transition_progress, style);
else if (files.length > 0) else if (files.length > 0)
background.set_file (File.new_for_path (files[0]), style); background.set_file (File.new_for_path (files[0]), style);
else else
background.set_file (null, style); background.set_file (null, style);
queue_update_animation (); queue_update_animation ();
}; };
var cache = Meta.BackgroundImageCache.get_default (); var cache = Meta.BackgroundImageCache.get_default ();
var num_pending_images = files.length; var num_pending_images = files.length;
for (var i = 0; i < files.length; i++) { for (var i = 0; i < files.length; i++) {
watch_file (files[i]); watch_file (files[i]);
var image = cache.load (File.new_for_path (files[i])); var image = cache.load (File.new_for_path (files[i]));
if (image.is_loaded ()) { if (image.is_loaded ()) {
num_pending_images--; num_pending_images--;
if (num_pending_images == 0) if (num_pending_images == 0)
finish (null); finish (null);
} else { } else {
ulong handler = 0; ulong handler = 0;
handler = image.loaded.connect (() => { handler = image.loaded.connect (() => {
SignalHandler.disconnect (image, handler); SignalHandler.disconnect (image, handler);
if (--num_pending_images == 0) if (--num_pending_images == 0)
finish (null); finish (null);
}); });
} }
} }
} }
void queue_update_animation () { void queue_update_animation () {
if (update_animation_timeout_id != 0) if (update_animation_timeout_id != 0)
return; return;
if (cancellable == null || cancellable.is_cancelled ()) if (cancellable == null || cancellable.is_cancelled ())
return; return;
if (animation.transition_duration == 0) if (animation.transition_duration == 0)
return; return;
var n_steps = 255.0 / ANIMATION_OPACITY_STEP_INCREMENT; var n_steps = 255.0 / ANIMATION_OPACITY_STEP_INCREMENT;
var time_per_step = (animation.transition_duration * 1000) / n_steps; var time_per_step = (animation.transition_duration * 1000) / n_steps;
var interval = (uint32) Math.fmax (ANIMATION_MIN_WAKEUP_INTERVAL * 1000, time_per_step); var interval = (uint32) Math.fmax (ANIMATION_MIN_WAKEUP_INTERVAL * 1000, time_per_step);
if (interval > uint32.MAX) if (interval > uint32.MAX)
return; return;
update_animation_timeout_id = Timeout.add (interval, () => { update_animation_timeout_id = Timeout.add (interval, () => {
update_animation_timeout_id = 0; update_animation_timeout_id = 0;
update_animation (); update_animation ();
return false; return false;
}); });
} }
async void load_animation (string filename) async void load_animation (string filename)
{ {
animation = yield BackgroundCache.get_default ().get_animation (filename); animation = yield BackgroundCache.get_default ().get_animation (filename);
if (animation == null || cancellable.is_cancelled ()) { if (animation == null || cancellable.is_cancelled ()) {
set_loaded(); set_loaded();
return; return;
} }
update_animation (); update_animation ();
watch_file (filename); watch_file (filename);
} }
void load_image (string filename) void load_image (string filename)
{ {
background.set_file (File.new_for_path (filename), style); background.set_file (File.new_for_path (filename), style);
watch_file (filename); watch_file (filename);
var cache = Meta.BackgroundImageCache.get_default (); var cache = Meta.BackgroundImageCache.get_default ();
var image = cache.load (File.new_for_path (filename)); var image = cache.load (File.new_for_path (filename));
if (image.is_loaded ()) if (image.is_loaded ())
set_loaded(); set_loaded();
else { else {
ulong handler = 0; ulong handler = 0;
handler = image.loaded.connect (() => { handler = image.loaded.connect (() => {
set_loaded (); set_loaded ();
SignalHandler.disconnect (image, handler); SignalHandler.disconnect (image, handler);
}); });
} }
} }
void load_file (string filename) void load_file (string filename)
{ {
if (filename.has_suffix (".xml")) if (filename.has_suffix (".xml"))
load_animation.begin (filename); load_animation.begin (filename);
else else
load_image (filename); load_image (filename);
} }
void load () void load ()
{ {
load_pattern (); load_pattern ();
if (filename == null) if (filename == null)
set_loaded (); set_loaded ();
else else
load_file (filename); load_file (filename);
} }
void settings_changed () void settings_changed ()
{ {
changed (); changed ();
} }
} }
} }

View File

@ -17,110 +17,110 @@
namespace Gala namespace Gala
{ {
public class BackgroundCache : Object public class BackgroundCache : Object
{ {
static BackgroundCache? instance = null; static BackgroundCache? instance = null;
public static unowned BackgroundCache get_default () public static unowned BackgroundCache get_default ()
{ {
if (instance == null) if (instance == null)
instance = new BackgroundCache (); instance = new BackgroundCache ();
return instance; return instance;
} }
public signal void file_changed (string filename); public signal void file_changed (string filename);
Gee.HashMap<string,FileMonitor> file_monitors; Gee.HashMap<string,FileMonitor> file_monitors;
Gee.HashMap<string,BackgroundSource> background_sources; Gee.HashMap<string,BackgroundSource> background_sources;
Animation animation; Animation animation;
string animation_filename; string animation_filename;
public BackgroundCache () public BackgroundCache ()
{ {
Object (); Object ();
} }
construct construct
{ {
file_monitors = new Gee.HashMap<string,FileMonitor> (); file_monitors = new Gee.HashMap<string,FileMonitor> ();
background_sources = new Gee.HashMap<string,BackgroundSource> (); background_sources = new Gee.HashMap<string,BackgroundSource> ();
} }
public void monitor_file (string filename) public void monitor_file (string filename)
{ {
if (file_monitors.has_key (filename)) if (file_monitors.has_key (filename))
return; return;
var file = File.new_for_path (filename); var file = File.new_for_path (filename);
try { try {
var monitor = file.monitor (FileMonitorFlags.NONE, null); var monitor = file.monitor (FileMonitorFlags.NONE, null);
monitor.changed.connect(() => { monitor.changed.connect(() => {
file_changed (filename); file_changed (filename);
}); });
file_monitors[filename] = monitor; file_monitors[filename] = monitor;
} catch (Error e) { } catch (Error e) {
warning ("Failed to monitor %s: %s", filename, e.message); warning ("Failed to monitor %s: %s", filename, e.message);
} }
} }
public async Animation get_animation (string filename) public async Animation get_animation (string filename)
{ {
if (animation_filename == filename) { if (animation_filename == filename) {
Idle.add (() => { Idle.add (() => {
get_animation.callback (); get_animation.callback ();
return false; return false;
}); });
yield; yield;
return animation; return animation;
} }
var animation = new Animation (filename); var animation = new Animation (filename);
yield animation.load (); yield animation.load ();
Idle.add (() => { Idle.add (() => {
get_animation.callback (); get_animation.callback ();
return false; return false;
}); });
yield; yield;
return animation; return animation;
} }
#if HAS_MUTTER330 #if HAS_MUTTER330
public BackgroundSource get_background_source (Meta.Display display, string settings_schema) public BackgroundSource get_background_source (Meta.Display display, string settings_schema)
#else #else
public BackgroundSource get_background_source (Meta.Screen screen, string settings_schema) public BackgroundSource get_background_source (Meta.Screen screen, string settings_schema)
#endif #endif
{ {
var background_source = background_sources[settings_schema]; var background_source = background_sources[settings_schema];
if (background_source == null) { if (background_source == null) {
#if HAS_MUTTER330 #if HAS_MUTTER330
background_source = new BackgroundSource (display, settings_schema); background_source = new BackgroundSource (display, settings_schema);
#else #else
background_source = new BackgroundSource (screen, settings_schema); background_source = new BackgroundSource (screen, settings_schema);
#endif #endif
background_source.use_count = 1; background_source.use_count = 1;
background_sources[settings_schema] = background_source; background_sources[settings_schema] = background_source;
} else } else
background_source.use_count++; background_source.use_count++;
return background_source; return background_source;
} }
public void release_background_source (string settings_schema) public void release_background_source (string settings_schema)
{ {
if (background_sources.has_key (settings_schema)) { if (background_sources.has_key (settings_schema)) {
var source = background_sources[settings_schema]; var source = background_sources[settings_schema];
if (--source.use_count == 0) { if (--source.use_count == 0) {
background_sources.unset (settings_schema); background_sources.unset (settings_schema);
source.destroy (); source.destroy ();
} }
} }
} }
} }
} }

View File

@ -17,78 +17,78 @@
namespace Gala namespace Gala
{ {
public class BackgroundContainer : Meta.BackgroundGroup public class BackgroundContainer : Meta.BackgroundGroup
{ {
public signal void changed (); public signal void changed ();
#if HAS_MUTTER330 #if HAS_MUTTER330
public Meta.Display display { get; construct; } public Meta.Display display { get; construct; }
public BackgroundContainer (Meta.Display display) public BackgroundContainer (Meta.Display display)
{ {
Object (display: display); Object (display: display);
} }
construct construct
{ {
Meta.MonitorManager.@get ().monitors_changed.connect (update); Meta.MonitorManager.@get ().monitors_changed.connect (update);
update (); update ();
} }
~BackgroundContainer () ~BackgroundContainer ()
{ {
Meta.MonitorManager.@get ().monitors_changed.disconnect (update); Meta.MonitorManager.@get ().monitors_changed.disconnect (update);
} }
#else #else
public Meta.Screen screen { get; construct; } public Meta.Screen screen { get; construct; }
public BackgroundContainer (Meta.Screen screen) public BackgroundContainer (Meta.Screen screen)
{ {
Object (screen: screen); Object (screen: screen);
} }
construct construct
{ {
screen.monitors_changed.connect (update); screen.monitors_changed.connect (update);
update (); update ();
} }
~BackgroundContainer () ~BackgroundContainer ()
{ {
screen.monitors_changed.disconnect (update); screen.monitors_changed.disconnect (update);
} }
#endif #endif
void update () void update ()
{ {
var reference_child = (get_child_at_index (0) as BackgroundManager); var reference_child = (get_child_at_index (0) as BackgroundManager);
if (reference_child != null) if (reference_child != null)
reference_child.changed.disconnect (background_changed); reference_child.changed.disconnect (background_changed);
destroy_all_children (); destroy_all_children ();
#if HAS_MUTTER330 #if HAS_MUTTER330
for (var i = 0; i < display.get_n_monitors (); i++) { for (var i = 0; i < display.get_n_monitors (); i++) {
var background = new BackgroundManager (display, i); var background = new BackgroundManager (display, i);
#else #else
for (var i = 0; i < screen.get_n_monitors (); i++) { for (var i = 0; i < screen.get_n_monitors (); i++) {
var background = new BackgroundManager (screen, i); var background = new BackgroundManager (screen, i);
#endif #endif
add_child (background); add_child (background);
if (i == 0) if (i == 0)
background.changed.connect (background_changed); background.changed.connect (background_changed);
} }
} }
void background_changed () void background_changed ()
{ {
changed (); changed ();
} }
} }
} }

View File

@ -17,173 +17,173 @@
namespace Gala namespace Gala
{ {
public class BackgroundManager : Meta.BackgroundGroup public class BackgroundManager : Meta.BackgroundGroup
{ {
const string BACKGROUND_SCHEMA = "org.gnome.desktop.background"; const string BACKGROUND_SCHEMA = "org.gnome.desktop.background";
const int FADE_ANIMATION_TIME = 1000; const int FADE_ANIMATION_TIME = 1000;
public signal void changed (); public signal void changed ();
#if HAS_MUTTER330 #if HAS_MUTTER330
public Meta.Display display { get; construct; } public Meta.Display display { get; construct; }
#else #else
public Meta.Screen screen { get; construct; } public Meta.Screen screen { get; construct; }
#endif #endif
public int monitor_index { get; construct; } public int monitor_index { get; construct; }
public bool control_position { get; construct; } public bool control_position { get; construct; }
BackgroundSource background_source; BackgroundSource background_source;
Meta.BackgroundActor background_actor; Meta.BackgroundActor background_actor;
Meta.BackgroundActor? new_background_actor = null; Meta.BackgroundActor? new_background_actor = null;
#if HAS_MUTTER330 #if HAS_MUTTER330
public BackgroundManager (Meta.Display display, int monitor_index, bool control_position = true) public BackgroundManager (Meta.Display display, int monitor_index, bool control_position = true)
{ {
Object (display: display, monitor_index: monitor_index, control_position: control_position); Object (display: display, monitor_index: monitor_index, control_position: control_position);
} }
#else #else
public BackgroundManager (Meta.Screen screen, int monitor_index, bool control_position = true) public BackgroundManager (Meta.Screen screen, int monitor_index, bool control_position = true)
{ {
Object (screen: screen, monitor_index: monitor_index, control_position: control_position); Object (screen: screen, monitor_index: monitor_index, control_position: control_position);
} }
#endif #endif
construct construct
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
background_source = BackgroundCache.get_default ().get_background_source (display, BACKGROUND_SCHEMA); background_source = BackgroundCache.get_default ().get_background_source (display, BACKGROUND_SCHEMA);
#else #else
background_source = BackgroundCache.get_default ().get_background_source (screen, BACKGROUND_SCHEMA); background_source = BackgroundCache.get_default ().get_background_source (screen, BACKGROUND_SCHEMA);
#endif #endif
background_actor = create_background_actor (); background_actor = create_background_actor ();
destroy.connect (on_destroy); destroy.connect (on_destroy);
} }
void on_destroy () void on_destroy ()
{ {
BackgroundCache.get_default ().release_background_source (BACKGROUND_SCHEMA); BackgroundCache.get_default ().release_background_source (BACKGROUND_SCHEMA);
background_source = null; background_source = null;
if (new_background_actor != null) { if (new_background_actor != null) {
new_background_actor.destroy (); new_background_actor.destroy ();
new_background_actor = null; new_background_actor = null;
} }
if (background_actor != null) { if (background_actor != null) {
background_actor.destroy (); background_actor.destroy ();
background_actor = null; background_actor = null;
} }
} }
void swap_background_actor () void swap_background_actor ()
{ {
return_if_fail (new_background_actor != null); return_if_fail (new_background_actor != null);
var old_background_actor = background_actor; var old_background_actor = background_actor;
background_actor = new_background_actor; background_actor = new_background_actor;
new_background_actor = null; new_background_actor = null;
if (old_background_actor == null) if (old_background_actor == null)
return; return;
var transition = new Clutter.PropertyTransition ("opacity"); var transition = new Clutter.PropertyTransition ("opacity");
transition.set_from_value (255); transition.set_from_value (255);
transition.set_to_value (0); transition.set_to_value (0);
transition.duration = FADE_ANIMATION_TIME; transition.duration = FADE_ANIMATION_TIME;
transition.progress_mode = Clutter.AnimationMode.EASE_OUT_QUAD; transition.progress_mode = Clutter.AnimationMode.EASE_OUT_QUAD;
transition.remove_on_complete = true; transition.remove_on_complete = true;
transition.completed.connect (() => { transition.completed.connect (() => {
old_background_actor.destroy (); old_background_actor.destroy ();
changed (); changed ();
}); });
old_background_actor.add_transition ("fade-out", transition); old_background_actor.add_transition ("fade-out", transition);
} }
void update_background_actor () void update_background_actor ()
{ {
if (new_background_actor != null) { if (new_background_actor != null) {
// Skip displaying existing background queued for load // Skip displaying existing background queued for load
new_background_actor.destroy (); new_background_actor.destroy ();
new_background_actor = null; new_background_actor = null;
} }
new_background_actor = create_background_actor (); new_background_actor = create_background_actor ();
new_background_actor.vignette_sharpness = background_actor.vignette_sharpness; new_background_actor.vignette_sharpness = background_actor.vignette_sharpness;
new_background_actor.brightness = background_actor.brightness; new_background_actor.brightness = background_actor.brightness;
new_background_actor.visible = background_actor.visible; new_background_actor.visible = background_actor.visible;
var background = new_background_actor.background.get_data<unowned Background> ("delegate"); var background = new_background_actor.background.get_data<unowned Background> ("delegate");
if (background.is_loaded) { if (background.is_loaded) {
swap_background_actor (); swap_background_actor ();
return; return;
} }
ulong handler = 0; ulong handler = 0;
handler = background.loaded.connect (() => { handler = background.loaded.connect (() => {
SignalHandler.disconnect (background, handler); SignalHandler.disconnect (background, handler);
background.set_data<ulong> ("background-loaded-handler", 0); background.set_data<ulong> ("background-loaded-handler", 0);
swap_background_actor (); swap_background_actor ();
}); });
background.set_data<ulong> ("background-loaded-handler", handler); background.set_data<ulong> ("background-loaded-handler", handler);
} }
public void set_size (float width, float height) { public void set_size (float width, float height) {
background_actor.set_size (width, height); background_actor.set_size (width, height);
} }
Meta.BackgroundActor create_background_actor () Meta.BackgroundActor create_background_actor ()
{ {
var background = background_source.get_background (monitor_index); var background = background_source.get_background (monitor_index);
#if HAS_MUTTER330 #if HAS_MUTTER330
var background_actor = new Meta.BackgroundActor (display, monitor_index); var background_actor = new Meta.BackgroundActor (display, monitor_index);
#else #else
var background_actor = new Meta.BackgroundActor (screen, monitor_index); var background_actor = new Meta.BackgroundActor (screen, monitor_index);
#endif #endif
background_actor.background = background.background; background_actor.background = background.background;
insert_child_below (background_actor, null); insert_child_below (background_actor, null);
#if HAS_MUTTER330 #if HAS_MUTTER330
var monitor = display.get_monitor_geometry (monitor_index); var monitor = display.get_monitor_geometry (monitor_index);
#else #else
var monitor = screen.get_monitor_geometry (monitor_index); var monitor = screen.get_monitor_geometry (monitor_index);
#endif #endif
background_actor.set_size (monitor.width, monitor.height); background_actor.set_size (monitor.width, monitor.height);
if (control_position) { if (control_position) {
background_actor.set_position (monitor.x, monitor.y); background_actor.set_position (monitor.x, monitor.y);
} }
ulong changed_handler = 0; ulong changed_handler = 0;
changed_handler = background.changed.connect (() => { changed_handler = background.changed.connect (() => {
SignalHandler.disconnect (background, changed_handler); SignalHandler.disconnect (background, changed_handler);
changed_handler = 0; changed_handler = 0;
update_background_actor (); update_background_actor ();
}); });
background_actor.destroy.connect (() => { background_actor.destroy.connect (() => {
if (changed_handler != 0) { if (changed_handler != 0) {
SignalHandler.disconnect (background, changed_handler); SignalHandler.disconnect (background, changed_handler);
changed_handler = 0; changed_handler = 0;
} }
var loaded_handler = background.get_data<ulong> ("background-loaded-handler"); var loaded_handler = background.get_data<ulong> ("background-loaded-handler");
if (loaded_handler != 0) { if (loaded_handler != 0) {
SignalHandler.disconnect (background, loaded_handler); SignalHandler.disconnect (background, loaded_handler);
background.set_data<ulong> ("background-loaded-handler", 0); background.set_data<ulong> ("background-loaded-handler", 0);
} }
}); });
return background_actor; return background_actor;
} }
} }
} }

View File

@ -17,171 +17,171 @@
namespace Gala namespace Gala
{ {
public class BackgroundSource : Object public class BackgroundSource : Object
{ {
public signal void changed (); public signal void changed ();
#if HAS_MUTTER330 #if HAS_MUTTER330
public Meta.Display display { get; construct; } public Meta.Display display { get; construct; }
#else #else
public Meta.Screen screen { get; construct; } public Meta.Screen screen { get; construct; }
#endif #endif
public Settings settings { get; construct; } public Settings settings { get; construct; }
internal int use_count { get; set; default = 0; } internal int use_count { get; set; default = 0; }
Gee.HashMap<int,Background> backgrounds; Gee.HashMap<int,Background> backgrounds;
#if HAS_MUTTER330 #if HAS_MUTTER330
public BackgroundSource (Meta.Display display, string settings_schema) public BackgroundSource (Meta.Display display, string settings_schema)
{ {
Object (display: display, settings: new Settings (settings_schema)); Object (display: display, settings: new Settings (settings_schema));
} }
#else #else
public BackgroundSource (Meta.Screen screen, string settings_schema) public BackgroundSource (Meta.Screen screen, string settings_schema)
{ {
Object (screen: screen, settings: new Settings (settings_schema)); Object (screen: screen, settings: new Settings (settings_schema));
} }
#endif #endif
construct construct
{ {
backgrounds = new Gee.HashMap<int,Background> (); backgrounds = new Gee.HashMap<int,Background> ();
#if HAS_MUTTER330 #if HAS_MUTTER330
Meta.MonitorManager.@get ().monitors_changed.connect (monitors_changed); Meta.MonitorManager.@get ().monitors_changed.connect (monitors_changed);
#else #else
screen.monitors_changed.connect (monitors_changed); screen.monitors_changed.connect (monitors_changed);
#endif #endif
settings_hash_cache = get_current_settings_hash_cache (); settings_hash_cache = get_current_settings_hash_cache ();
settings.changed.connect (settings_changed); settings.changed.connect (settings_changed);
} }
void monitors_changed () void monitors_changed ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
var n = display.get_n_monitors (); var n = display.get_n_monitors ();
#else #else
var n = screen.get_n_monitors (); var n = screen.get_n_monitors ();
#endif #endif
var i = 0; var i = 0;
foreach (var background in backgrounds.values) { foreach (var background in backgrounds.values) {
if (i++ < n) { if (i++ < n) {
background.update_resolution (); background.update_resolution ();
continue; continue;
} }
background.changed.disconnect (background_changed); background.changed.disconnect (background_changed);
background.destroy (); background.destroy ();
// TODO can we remove from a list while iterating? // TODO can we remove from a list while iterating?
backgrounds.unset (i); backgrounds.unset (i);
} }
} }
public Background get_background (int monitor_index) public Background get_background (int monitor_index)
{ {
string? filename = null; string? filename = null;
var style = settings.get_enum ("picture-options"); var style = settings.get_enum ("picture-options");
if (style != GDesktop.BackgroundStyle.NONE) { if (style != GDesktop.BackgroundStyle.NONE) {
var uri = settings.get_string ("picture-uri"); var uri = settings.get_string ("picture-uri");
if (Uri.parse_scheme (uri) != null) if (Uri.parse_scheme (uri) != null)
filename = File.new_for_uri (uri).get_path (); filename = File.new_for_uri (uri).get_path ();
else else
filename = uri; filename = uri;
} }
// Animated backgrounds are (potentially) per-monitor, since // Animated backgrounds are (potentially) per-monitor, since
// they can have variants that depend on the aspect ratio and // they can have variants that depend on the aspect ratio and
// size of the monitor; for other backgrounds we can use the // size of the monitor; for other backgrounds we can use the
// same background object for all monitors. // same background object for all monitors.
if (filename == null || !filename.has_suffix (".xml")) if (filename == null || !filename.has_suffix (".xml"))
monitor_index = 0; monitor_index = 0;
if (!backgrounds.has_key (monitor_index)) { if (!backgrounds.has_key (monitor_index)) {
#if HAS_MUTTER330 #if HAS_MUTTER330
var background = new Background (display, monitor_index, filename, this, (GDesktop.BackgroundStyle) style); var background = new Background (display, monitor_index, filename, this, (GDesktop.BackgroundStyle) style);
#else #else
var background = new Background (screen, monitor_index, filename, this, (GDesktop.BackgroundStyle) style); var background = new Background (screen, monitor_index, filename, this, (GDesktop.BackgroundStyle) style);
#endif #endif
background.changed.connect (background_changed); background.changed.connect (background_changed);
backgrounds[monitor_index] = background; backgrounds[monitor_index] = background;
} }
return backgrounds[monitor_index]; return backgrounds[monitor_index];
} }
void background_changed (Background background) void background_changed (Background background)
{ {
background.changed.disconnect (background_changed); background.changed.disconnect (background_changed);
background.destroy (); background.destroy ();
backgrounds.unset (background.monitor_index); backgrounds.unset (background.monitor_index);
} }
public void destroy () public void destroy ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
Meta.MonitorManager.@get ().monitors_changed.disconnect (monitors_changed); Meta.MonitorManager.@get ().monitors_changed.disconnect (monitors_changed);
#else #else
screen.monitors_changed.disconnect (monitors_changed); screen.monitors_changed.disconnect (monitors_changed);
#endif #endif
foreach (var background in backgrounds) { foreach (var background in backgrounds) {
background.changed.disconnect (background_changed); background.changed.disconnect (background_changed);
background.destroy (); background.destroy ();
} }
} }
// unfortunately the settings sometimes tend to fire random changes even though // unfortunately the settings sometimes tend to fire random changes even though
// nothing actually happend. The code below is used to prevent us from spamming // nothing actually happend. The code below is used to prevent us from spamming
// new actors all the time, which lead to some problems in other areas of the code // new actors all the time, which lead to some problems in other areas of the code
// helper struct which stores the hash values generated by g_variant_hash // helper struct which stores the hash values generated by g_variant_hash
struct SettingsHashCache struct SettingsHashCache
{ {
uint color_shading_type; uint color_shading_type;
uint picture_opacity; uint picture_opacity;
uint picture_options; uint picture_options;
uint picture_uri; uint picture_uri;
uint primar_color; uint primar_color;
uint secondary_color; uint secondary_color;
} }
SettingsHashCache settings_hash_cache; SettingsHashCache settings_hash_cache;
// list of keys that are actually relevant for us // list of keys that are actually relevant for us
const string[] options = { "color-shading-type", "picture-opacity", const string[] options = { "color-shading-type", "picture-opacity",
"picture-options", "picture-uri", "primary-color", "secondary-color" }; "picture-options", "picture-uri", "primary-color", "secondary-color" };
void settings_changed (string key) void settings_changed (string key)
{ {
if (!(key in options)) if (!(key in options))
return; return;
var current = get_current_settings_hash_cache (); var current = get_current_settings_hash_cache ();
if (Memory.cmp (&settings_hash_cache, &current, sizeof (SettingsHashCache)) == 0) { if (Memory.cmp (&settings_hash_cache, &current, sizeof (SettingsHashCache)) == 0) {
return; return;
} }
Memory.copy (&settings_hash_cache, &current, sizeof (SettingsHashCache)); Memory.copy (&settings_hash_cache, &current, sizeof (SettingsHashCache));
changed (); changed ();
} }
SettingsHashCache get_current_settings_hash_cache () SettingsHashCache get_current_settings_hash_cache ()
{ {
return { return {
settings.get_value ("color-shading-type").hash (), settings.get_value ("color-shading-type").hash (),
settings.get_value ("picture-opacity").hash (), settings.get_value ("picture-opacity").hash (),
settings.get_value ("picture-options").hash (), settings.get_value ("picture-options").hash (),
settings.get_value ("picture-uri").hash (), settings.get_value ("picture-uri").hash (),
settings.get_value ("primary-color").hash (), settings.get_value ("primary-color").hash (),
settings.get_value ("secondary-color").hash () settings.get_value ("secondary-color").hash ()
}; };
} }
} }
} }

View File

@ -18,89 +18,89 @@
namespace Gala namespace Gala
{ {
#if HAS_MUTTER332 #if HAS_MUTTER332
public class SystemBackground : GLib.Object public class SystemBackground : GLib.Object
#else #else
public class SystemBackground : Meta.BackgroundActor public class SystemBackground : Meta.BackgroundActor
#endif #endif
{ {
const Clutter.Color DEFAULT_BACKGROUND_COLOR = { 0x2e, 0x34, 0x36, 0xff }; const Clutter.Color DEFAULT_BACKGROUND_COLOR = { 0x2e, 0x34, 0x36, 0xff };
static Meta.Background? system_background = null; static Meta.Background? system_background = null;
#if HAS_MUTTER332 #if HAS_MUTTER332
public Meta.BackgroundActor background_actor { get; construct; } public Meta.BackgroundActor background_actor { get; construct; }
#endif #endif
public signal void loaded (); public signal void loaded ();
#if HAS_MUTTER330 #if HAS_MUTTER330
public SystemBackground (Meta.Display display) public SystemBackground (Meta.Display display)
{ {
#if HAS_MUTTER332 #if HAS_MUTTER332
Object (background_actor: new Meta.BackgroundActor (display, 0)); Object (background_actor: new Meta.BackgroundActor (display, 0));
#else #else
Object (meta_display: display, monitor: 0); Object (meta_display: display, monitor: 0);
#endif #endif
} }
#else #else
public SystemBackground (Meta.Screen screen) public SystemBackground (Meta.Screen screen)
{ {
Object (meta_screen: screen, monitor: 0); Object (meta_screen: screen, monitor: 0);
} }
#endif #endif
construct construct
{ {
var background_file = GLib.File.new_for_uri ("resource:///io/elementary/desktop/gala/texture.png"); var background_file = GLib.File.new_for_uri ("resource:///io/elementary/desktop/gala/texture.png");
unowned string custom_path = AppearanceSettings.get_default ().workspace_switcher_background; unowned string custom_path = AppearanceSettings.get_default ().workspace_switcher_background;
if (custom_path != "" && FileUtils.test (custom_path, FileTest.IS_REGULAR)) { if (custom_path != "" && FileUtils.test (custom_path, FileTest.IS_REGULAR)) {
background_file = GLib.File.new_for_path (custom_path); background_file = GLib.File.new_for_path (custom_path);
} }
if (system_background == null) { if (system_background == null) {
#if HAS_MUTTER332 #if HAS_MUTTER332
system_background = new Meta.Background (background_actor.meta_display); system_background = new Meta.Background (background_actor.meta_display);
#elif HAS_MUTTER330 #elif HAS_MUTTER330
system_background = new Meta.Background (meta_display); system_background = new Meta.Background (meta_display);
#else #else
system_background = new Meta.Background (meta_screen); system_background = new Meta.Background (meta_screen);
#endif #endif
system_background.set_color (DEFAULT_BACKGROUND_COLOR); system_background.set_color (DEFAULT_BACKGROUND_COLOR);
system_background.set_file (background_file, GDesktop.BackgroundStyle.WALLPAPER); system_background.set_file (background_file, GDesktop.BackgroundStyle.WALLPAPER);
} }
#if HAS_MUTTER332 #if HAS_MUTTER332
background_actor.background = system_background; background_actor.background = system_background;
#else #else
background = system_background; background = system_background;
#endif #endif
var cache = Meta.BackgroundImageCache.get_default (); var cache = Meta.BackgroundImageCache.get_default ();
var image = cache.load (background_file); var image = cache.load (background_file);
if (image.is_loaded ()) { if (image.is_loaded ()) {
image = null; image = null;
Idle.add(() => { Idle.add(() => {
loaded (); loaded ();
return false; return false;
}); });
} else { } else {
ulong handler = 0; ulong handler = 0;
handler = image.loaded.connect (() => { handler = image.loaded.connect (() => {
loaded (); loaded ();
SignalHandler.disconnect (image, handler); SignalHandler.disconnect (image, handler);
image = null; image = null;
}); });
} }
} }
public static void refresh () public static void refresh ()
{ {
// Meta.Background.refresh_all does not refresh backgrounds with the WALLPAPER style. // Meta.Background.refresh_all does not refresh backgrounds with the WALLPAPER style.
// (Last tested with mutter 3.28) // (Last tested with mutter 3.28)
// As a workaround, re-apply the current color again to force the wallpaper texture // As a workaround, re-apply the current color again to force the wallpaper texture
// to be rendered from scratch. // to be rendered from scratch.
if (system_background != null) if (system_background != null)
system_background.set_color (DEFAULT_BACKGROUND_COLOR); system_background.set_color (DEFAULT_BACKGROUND_COLOR);
} }
} }
} }

View File

@ -17,233 +17,233 @@
namespace Gala namespace Gala
{ {
[DBus (name="org.pantheon.gala")] [DBus (name="org.pantheon.gala")]
public class DBus public class DBus
{ {
static DBus? instance; static DBus? instance;
static WindowManager wm; static WindowManager wm;
[DBus (visible = false)] [DBus (visible = false)]
public static void init (WindowManager _wm) public static void init (WindowManager _wm)
{ {
wm = _wm; wm = _wm;
Bus.own_name (BusType.SESSION, "org.pantheon.gala", BusNameOwnerFlags.NONE, Bus.own_name (BusType.SESSION, "org.pantheon.gala", BusNameOwnerFlags.NONE,
(connection) => { (connection) => {
if (instance == null) if (instance == null)
instance = new DBus (); instance = new DBus ();
try { try {
connection.register_object ("/org/pantheon/gala", instance); connection.register_object ("/org/pantheon/gala", instance);
} catch (Error e) { warning (e.message); } } catch (Error e) { warning (e.message); }
}, },
() => {}, () => {},
() => warning ("Could not acquire name\n") ); () => warning ("Could not acquire name\n") );
Bus.own_name (BusType.SESSION, "org.gnome.Shell", BusNameOwnerFlags.NONE, Bus.own_name (BusType.SESSION, "org.gnome.Shell", BusNameOwnerFlags.NONE,
(connection) => { (connection) => {
try { try {
connection.register_object ("/org/gnome/Shell", DBusAccelerator.init (wm)); connection.register_object ("/org/gnome/Shell", DBusAccelerator.init (wm));
connection.register_object ("/org/gnome/Shell/Screenshot", ScreenshotManager.init (wm)); connection.register_object ("/org/gnome/Shell/Screenshot", ScreenshotManager.init (wm));
} catch (Error e) { warning (e.message); } } catch (Error e) { warning (e.message); }
}, },
() => {}, () => {},
() => critical ("Could not acquire name") ); () => critical ("Could not acquire name") );
Bus.own_name (BusType.SESSION, "org.gnome.Shell.Screenshot", BusNameOwnerFlags.REPLACE, Bus.own_name (BusType.SESSION, "org.gnome.Shell.Screenshot", BusNameOwnerFlags.REPLACE,
() => {}, () => {},
() => {}, () => {},
() => critical ("Could not acquire name") ); () => critical ("Could not acquire name") );
Bus.own_name (BusType.SESSION, "org.gnome.SessionManager.EndSessionDialog", BusNameOwnerFlags.NONE, Bus.own_name (BusType.SESSION, "org.gnome.SessionManager.EndSessionDialog", BusNameOwnerFlags.NONE,
(connection) => { (connection) => {
try { try {
connection.register_object ("/org/gnome/SessionManager/EndSessionDialog", SessionManager.init ()); connection.register_object ("/org/gnome/SessionManager/EndSessionDialog", SessionManager.init ());
} catch (Error e) { warning (e.message); } } catch (Error e) { warning (e.message); }
}, },
() => {}, () => {},
() => critical ("Could not acquire name") ); () => critical ("Could not acquire name") );
} }
private DBus () private DBus ()
{ {
if (wm.background_group != null) if (wm.background_group != null)
(wm.background_group as BackgroundContainer).changed.connect (() => background_changed ()); (wm.background_group as BackgroundContainer).changed.connect (() => background_changed ());
else else
assert_not_reached (); assert_not_reached ();
} }
public void perform_action (ActionType type) throws DBusError, IOError public void perform_action (ActionType type) throws DBusError, IOError
{ {
wm.perform_action (type); wm.perform_action (type);
} }
const double SATURATION_WEIGHT = 1.5; const double SATURATION_WEIGHT = 1.5;
const double WEIGHT_THRESHOLD = 1.0; const double WEIGHT_THRESHOLD = 1.0;
class DummyOffscreenEffect : Clutter.OffscreenEffect { class DummyOffscreenEffect : Clutter.OffscreenEffect {
public signal void done_painting (); public signal void done_painting ();
public override void post_paint () public override void post_paint ()
{ {
base.post_paint (); base.post_paint ();
done_painting (); done_painting ();
} }
} }
public struct ColorInformation public struct ColorInformation
{ {
double average_red; double average_red;
double average_green; double average_green;
double average_blue; double average_blue;
double mean; double mean;
double variance; double variance;
} }
/** /**
* Emitted when the background change occured and the transition ended. * Emitted when the background change occured and the transition ended.
* You can safely call get_optimal_panel_alpha then. It is not guaranteed * You can safely call get_optimal_panel_alpha then. It is not guaranteed
* that this signal will be emitted only once per group of changes as often * that this signal will be emitted only once per group of changes as often
* done by GUIs. The change may not be visible to the user. * done by GUIs. The change may not be visible to the user.
*/ */
public signal void background_changed (); public signal void background_changed ();
/** /**
* Attaches a dummy offscreen effect to the background at monitor to get its * Attaches a dummy offscreen effect to the background at monitor to get its
* isolated color data. Then calculate the red, green and blue components of * isolated color data. Then calculate the red, green and blue components of
* the average color in that area and the mean color value and variance. All * the average color in that area and the mean color value and variance. All
* variables are returned as a tuple in that order. * variables are returned as a tuple in that order.
* *
* @param monitor The monitor where the panel will be placed * @param monitor The monitor where the panel will be placed
* @param reference_x X coordinate of the rectangle used to gather color data * @param reference_x X coordinate of the rectangle used to gather color data
* relative to the monitor you picked. Values will be clamped * relative to the monitor you picked. Values will be clamped
* to its dimensions * to its dimensions
* @param reference_y Y coordinate * @param reference_y Y coordinate
* @param reference_width Width of the rectangle * @param reference_width Width of the rectangle
* @param reference_height Height of the rectangle * @param reference_height Height of the rectangle
*/ */
public async ColorInformation get_background_color_information (int monitor, public async ColorInformation get_background_color_information (int monitor,
int reference_x, int reference_y, int reference_width, int reference_height) int reference_x, int reference_y, int reference_width, int reference_height)
throws DBusError, IOError throws DBusError, IOError
{ {
var background = wm.background_group.get_child_at_index (monitor); var background = wm.background_group.get_child_at_index (monitor);
if (background == null) if (background == null)
throw new DBusError.INVALID_ARGS ("Invalid monitor requested"); throw new DBusError.INVALID_ARGS ("Invalid monitor requested");
var effect = new DummyOffscreenEffect (); var effect = new DummyOffscreenEffect ();
background.add_effect (effect); background.add_effect (effect);
var tex_width = (int)background.width; var tex_width = (int)background.width;
var tex_height = (int)background.height; var tex_height = (int)background.height;
int x_start = reference_x; int x_start = reference_x;
int y_start = reference_y; int y_start = reference_y;
int width = int.min (tex_width - reference_x, reference_width); int width = int.min (tex_width - reference_x, reference_width);
int height = int.min (tex_height - reference_y, reference_height); int height = int.min (tex_height - reference_y, reference_height);
if (x_start > tex_width || x_start > tex_height || width <= 0 || height <= 0) if (x_start > tex_width || x_start > tex_height || width <= 0 || height <= 0)
throw new DBusError.INVALID_ARGS ("Invalid rectangle specified"); throw new DBusError.INVALID_ARGS ("Invalid rectangle specified");
double variance = 0, mean = 0, double variance = 0, mean = 0,
rTotal = 0, gTotal = 0, bTotal = 0; rTotal = 0, gTotal = 0, bTotal = 0;
ulong paint_signal_handler = 0; ulong paint_signal_handler = 0;
paint_signal_handler = effect.done_painting.connect (() => { paint_signal_handler = effect.done_painting.connect (() => {
SignalHandler.disconnect (effect, paint_signal_handler); SignalHandler.disconnect (effect, paint_signal_handler);
background.remove_effect (effect); background.remove_effect (effect);
var texture = (Cogl.Texture)effect.get_texture (); var texture = (Cogl.Texture)effect.get_texture ();
var pixels = new uint8[texture.get_width () * texture.get_height () * 4]; var pixels = new uint8[texture.get_width () * texture.get_height () * 4];
CoglFixes.texture_get_data (texture, Cogl.PixelFormat.BGRA_8888_PRE, 0, pixels); CoglFixes.texture_get_data (texture, Cogl.PixelFormat.BGRA_8888_PRE, 0, pixels);
int size = width * height; int size = width * height;
double mean_squares = 0; double mean_squares = 0;
double pixel = 0; double pixel = 0;
double max, min, score, delta, scoreTotal = 0, double max, min, score, delta, scoreTotal = 0,
rTotal2 = 0, gTotal2 = 0, bTotal2 = 0; rTotal2 = 0, gTotal2 = 0, bTotal2 = 0;
// code to calculate weighted average color is copied from // code to calculate weighted average color is copied from
// plank's lib/Drawing/DrawingService.vala average_color() // plank's lib/Drawing/DrawingService.vala average_color()
// http://bazaar.launchpad.net/~docky-core/plank/trunk/view/head:/lib/Drawing/DrawingService.vala // http://bazaar.launchpad.net/~docky-core/plank/trunk/view/head:/lib/Drawing/DrawingService.vala
for (int y = y_start; y < height; y++) { for (int y = y_start; y < height; y++) {
for (int x = x_start; x < width; x++) { for (int x = x_start; x < width; x++) {
int i = y * width * 4 + x * 4; int i = y * width * 4 + x * 4;
uint8 r = pixels[i]; uint8 r = pixels[i];
uint8 g = pixels[i + 1]; uint8 g = pixels[i + 1];
uint8 b = pixels[i + 2]; uint8 b = pixels[i + 2];
pixel = (0.3 * r + 0.6 * g + 0.11 * b) - 128f; pixel = (0.3 * r + 0.6 * g + 0.11 * b) - 128f;
min = uint8.min (r, uint8.min (g, b)); min = uint8.min (r, uint8.min (g, b));
max = uint8.max (r, uint8.max (g, b)); max = uint8.max (r, uint8.max (g, b));
delta = max - min; delta = max - min;
// prefer colored pixels over shades of grey // prefer colored pixels over shades of grey
score = SATURATION_WEIGHT * (delta == 0 ? 0.0 : delta / max); score = SATURATION_WEIGHT * (delta == 0 ? 0.0 : delta / max);
rTotal += score * r; rTotal += score * r;
gTotal += score * g; gTotal += score * g;
bTotal += score * b; bTotal += score * b;
scoreTotal += score; scoreTotal += score;
rTotal += r; rTotal += r;
gTotal += g; gTotal += g;
bTotal += b; bTotal += b;
mean += pixel; mean += pixel;
mean_squares += pixel * pixel; mean_squares += pixel * pixel;
} }
} }
scoreTotal /= size; scoreTotal /= size;
bTotal /= size; bTotal /= size;
gTotal /= size; gTotal /= size;
rTotal /= size; rTotal /= size;
if (scoreTotal > 0.0) { if (scoreTotal > 0.0) {
bTotal /= scoreTotal; bTotal /= scoreTotal;
gTotal /= scoreTotal; gTotal /= scoreTotal;
rTotal /= scoreTotal; rTotal /= scoreTotal;
} }
bTotal2 /= size * uint8.MAX; bTotal2 /= size * uint8.MAX;
gTotal2 /= size * uint8.MAX; gTotal2 /= size * uint8.MAX;
rTotal2 /= size * uint8.MAX; rTotal2 /= size * uint8.MAX;
// combine weighted and not weighted sum depending on the average "saturation" // combine weighted and not weighted sum depending on the average "saturation"
// if saturation isn't reasonable enough // if saturation isn't reasonable enough
// s = 0.0 -> f = 0.0 ; s = WEIGHT_THRESHOLD -> f = 1.0 // s = 0.0 -> f = 0.0 ; s = WEIGHT_THRESHOLD -> f = 1.0
if (scoreTotal <= WEIGHT_THRESHOLD) { if (scoreTotal <= WEIGHT_THRESHOLD) {
var f = 1.0 / WEIGHT_THRESHOLD * scoreTotal; var f = 1.0 / WEIGHT_THRESHOLD * scoreTotal;
var rf = 1.0 - f; var rf = 1.0 - f;
bTotal = bTotal * f + bTotal2 * rf; bTotal = bTotal * f + bTotal2 * rf;
gTotal = gTotal * f + gTotal2 * rf; gTotal = gTotal * f + gTotal2 * rf;
rTotal = rTotal * f + rTotal2 * rf; rTotal = rTotal * f + rTotal2 * rf;
} }
// there shouldn't be values larger then 1.0 // there shouldn't be values larger then 1.0
var max_val = double.max (rTotal, double.max (gTotal, bTotal)); var max_val = double.max (rTotal, double.max (gTotal, bTotal));
if (max_val > 1.0) { if (max_val > 1.0) {
bTotal /= max_val; bTotal /= max_val;
gTotal /= max_val; gTotal /= max_val;
rTotal /= max_val; rTotal /= max_val;
} }
mean /= size; mean /= size;
mean_squares *= mean_squares / size; mean_squares *= mean_squares / size;
variance = Math.sqrt (mean_squares - mean * mean) / (double) size; variance = Math.sqrt (mean_squares - mean * mean) / (double) size;
get_background_color_information.callback (); get_background_color_information.callback ();
}); });
background.queue_redraw (); background.queue_redraw ();
yield; yield;
return { rTotal, gTotal, bTotal, mean, variance }; return { rTotal, gTotal, bTotal, mean, variance };
} }
} }
} }

View File

@ -17,134 +17,134 @@
namespace Gala namespace Gala
{ {
public struct Accelerator public struct Accelerator
{ {
public string name; public string name;
public Meta.KeyBindingFlags flags; public Meta.KeyBindingFlags flags;
} }
[DBus (name="org.gnome.Shell")] [DBus (name="org.gnome.Shell")]
public class DBusAccelerator public class DBusAccelerator
{ {
static DBusAccelerator? instance; static DBusAccelerator? instance;
[DBus (visible = false)] [DBus (visible = false)]
public static unowned DBusAccelerator init (WindowManager wm) public static unowned DBusAccelerator init (WindowManager wm)
{ {
if (instance == null) if (instance == null)
instance = new DBusAccelerator (wm); instance = new DBusAccelerator (wm);
return instance; return instance;
} }
public signal void accelerator_activated (uint action, GLib.HashTable<string, Variant> parameters); public signal void accelerator_activated (uint action, GLib.HashTable<string, Variant> parameters);
WindowManager wm; WindowManager wm;
HashTable<string, uint?> grabbed_accelerators; HashTable<string, uint?> grabbed_accelerators;
DBusAccelerator (WindowManager _wm) DBusAccelerator (WindowManager _wm)
{ {
wm = _wm; wm = _wm;
grabbed_accelerators = new HashTable<string, uint?> (str_hash, str_equal); grabbed_accelerators = new HashTable<string, uint?> (str_hash, str_equal);
#if HAS_MUTTER330 #if HAS_MUTTER330
wm.get_display ().accelerator_activated.connect (on_accelerator_activated); wm.get_display ().accelerator_activated.connect (on_accelerator_activated);
#else #else
wm.get_screen ().get_display ().accelerator_activated.connect (on_accelerator_activated); wm.get_screen ().get_display ().accelerator_activated.connect (on_accelerator_activated);
#endif #endif
} }
#if HAS_MUTTER334 #if HAS_MUTTER334
void on_accelerator_activated (uint action, Clutter.InputDevice device, uint timestamp) void on_accelerator_activated (uint action, Clutter.InputDevice device, uint timestamp)
#else #else
void on_accelerator_activated (uint action, uint device_id, uint timestamp) void on_accelerator_activated (uint action, uint device_id, uint timestamp)
#endif #endif
{ {
foreach (string accelerator in grabbed_accelerators.get_keys ()) { foreach (string accelerator in grabbed_accelerators.get_keys ()) {
if (grabbed_accelerators[accelerator] == action) { if (grabbed_accelerators[accelerator] == action) {
var parameters = new GLib.HashTable<string, Variant> (null, null); var parameters = new GLib.HashTable<string, Variant> (null, null);
#if HAS_MUTTER334 #if HAS_MUTTER334
parameters.set ("device-id", new Variant.uint32 (device.id)); parameters.set ("device-id", new Variant.uint32 (device.id));
#else #else
parameters.set ("device-id", new Variant.uint32 (device_id)); parameters.set ("device-id", new Variant.uint32 (device_id));
#endif #endif
parameters.set ("timestamp", new Variant.uint32 (timestamp)); parameters.set ("timestamp", new Variant.uint32 (timestamp));
accelerator_activated (action, parameters); accelerator_activated (action, parameters);
} }
} }
} }
public uint grab_accelerator (string accelerator, uint flags) throws DBusError, IOError public uint grab_accelerator (string accelerator, uint flags) throws DBusError, IOError
{ {
uint? action = grabbed_accelerators[accelerator]; uint? action = grabbed_accelerators[accelerator];
if (action == null) { if (action == null) {
#if HAS_MUTTER332 #if HAS_MUTTER332
action = wm.get_display ().grab_accelerator (accelerator, (Meta.KeyBindingFlags)flags); action = wm.get_display ().grab_accelerator (accelerator, (Meta.KeyBindingFlags)flags);
#elif HAS_MUTTER330 #elif HAS_MUTTER330
action = wm.get_display ().grab_accelerator (accelerator); action = wm.get_display ().grab_accelerator (accelerator);
#else #else
action = wm.get_screen ().get_display ().grab_accelerator (accelerator); action = wm.get_screen ().get_display ().grab_accelerator (accelerator);
#endif #endif
if (action > 0) { if (action > 0) {
grabbed_accelerators[accelerator] = action; grabbed_accelerators[accelerator] = action;
} }
} }
return action; return action;
} }
public uint[] grab_accelerators (Accelerator[] accelerators) throws DBusError, IOError public uint[] grab_accelerators (Accelerator[] accelerators) throws DBusError, IOError
{ {
uint[] actions = {}; uint[] actions = {};
foreach (unowned Accelerator? accelerator in accelerators) { foreach (unowned Accelerator? accelerator in accelerators) {
actions += grab_accelerator (accelerator.name, accelerator.flags); actions += grab_accelerator (accelerator.name, accelerator.flags);
} }
return actions; return actions;
} }
public bool ungrab_accelerator (uint action) throws DBusError, IOError public bool ungrab_accelerator (uint action) throws DBusError, IOError
{ {
bool ret = false; bool ret = false;
foreach (unowned string accelerator in grabbed_accelerators.get_keys ()) { foreach (unowned string accelerator in grabbed_accelerators.get_keys ()) {
if (grabbed_accelerators[accelerator] == action) { if (grabbed_accelerators[accelerator] == action) {
#if HAS_MUTTER330 #if HAS_MUTTER330
ret = wm.get_display ().ungrab_accelerator (action); ret = wm.get_display ().ungrab_accelerator (action);
#else #else
ret = wm.get_screen ().get_display ().ungrab_accelerator (action); ret = wm.get_screen ().get_display ().ungrab_accelerator (action);
#endif #endif
grabbed_accelerators.remove (accelerator); grabbed_accelerators.remove (accelerator);
break; break;
} }
} }
return ret; return ret;
} }
[DBus (name = "ShowOSD")] [DBus (name = "ShowOSD")]
public void show_osd (GLib.HashTable<string, Variant> parameters) throws DBusError, IOError public void show_osd (GLib.HashTable<string, Variant> parameters) throws DBusError, IOError
{ {
int32 monitor_index = -1; int32 monitor_index = -1;
if (parameters.contains ("monitor")) if (parameters.contains ("monitor"))
monitor_index = parameters["monitor"].get_int32 (); monitor_index = parameters["monitor"].get_int32 ();
string icon = ""; string icon = "";
if (parameters.contains ("icon")) if (parameters.contains ("icon"))
icon = parameters["icon"].get_string (); icon = parameters["icon"].get_string ();
string label = ""; string label = "";
if (parameters.contains ("label")) if (parameters.contains ("label"))
label = parameters["label"].get_string (); label = parameters["label"].get_string ();
int32 level = 0; int32 level = 0;
if (parameters.contains ("level")) if (parameters.contains ("level"))
level = parameters["level"].get_int32 (); level = parameters["level"].get_int32 ();
//if (monitor_index > -1) //if (monitor_index > -1)
// message ("MediaFeedback requested for specific monitor %i which is not supported", monitor_index); // message ("MediaFeedback requested for specific monitor %i which is not supported", monitor_index);
MediaFeedback.send (icon, level); MediaFeedback.send (icon, level);
} }
} }
} }

View File

@ -17,52 +17,52 @@
namespace Gala namespace Gala
{ {
/** /**
* Provides access to a PlankDrawingDockTheme and PlankDockPrefereces * Provides access to a PlankDrawingDockTheme and PlankDockPrefereces
*/ */
public class DockThemeManager : Object public class DockThemeManager : Object
{ {
static DockThemeManager? instance = null; static DockThemeManager? instance = null;
public static unowned DockThemeManager get_default () public static unowned DockThemeManager get_default ()
{ {
if (instance == null) if (instance == null)
instance = new DockThemeManager (); instance = new DockThemeManager ();
return instance; return instance;
} }
Plank.DockPreferences? dock_settings = null; Plank.DockPreferences? dock_settings = null;
Plank.DockTheme? dock_theme = null; Plank.DockTheme? dock_theme = null;
public signal void dock_theme_changed (Plank.DockTheme? old_theme, public signal void dock_theme_changed (Plank.DockTheme? old_theme,
Plank.DockTheme new_theme); Plank.DockTheme new_theme);
DockThemeManager () DockThemeManager ()
{ {
dock_settings = new Plank.DockPreferences ("dock1"); dock_settings = new Plank.DockPreferences ("dock1");
dock_settings.notify["Theme"].connect (load_dock_theme); dock_settings.notify["Theme"].connect (load_dock_theme);
} }
public Plank.DockTheme get_dock_theme () public Plank.DockTheme get_dock_theme ()
{ {
if (dock_theme == null) if (dock_theme == null)
load_dock_theme (); load_dock_theme ();
return dock_theme; return dock_theme;
} }
public Plank.DockPreferences get_dock_settings () public Plank.DockPreferences get_dock_settings ()
{ {
return dock_settings; return dock_settings;
} }
void load_dock_theme () void load_dock_theme ()
{ {
var new_theme = new Plank.DockTheme (dock_settings.Theme); var new_theme = new Plank.DockTheme (dock_settings.Theme);
new_theme.load ("dock"); new_theme.load ("dock");
dock_theme_changed (dock_theme, new_theme); dock_theme_changed (dock_theme, new_theme);
dock_theme = new_theme; dock_theme = new_theme;
} }
} }
} }

View File

@ -19,389 +19,389 @@ using Clutter;
namespace Gala namespace Gala
{ {
[Flags] [Flags]
public enum DragDropActionType public enum DragDropActionType
{ {
SOURCE, SOURCE,
DESTINATION DESTINATION
} }
public class DragDropAction : Clutter.Action public class DragDropAction : Clutter.Action
{ {
static Gee.HashMap<string,Gee.LinkedList<Actor>>? sources = null; static Gee.HashMap<string,Gee.LinkedList<Actor>>? sources = null;
static Gee.HashMap<string,Gee.LinkedList<Actor>>? destinations = null; static Gee.HashMap<string,Gee.LinkedList<Actor>>? destinations = null;
/** /**
* A drag has been started. You have to connect to this signal and * A drag has been started. You have to connect to this signal and
* return an actor that is transformed during the drag operation. * return an actor that is transformed during the drag operation.
* *
* @param x The global x coordinate where the action was activated * @param x The global x coordinate where the action was activated
* @param y The global y coordinate where the action was activated * @param y The global y coordinate where the action was activated
* @return A ClutterActor that serves as handle * @return A ClutterActor that serves as handle
*/ */
public signal Actor drag_begin (float x, float y); public signal Actor drag_begin (float x, float y);
/** /**
* A drag has been canceled. You may want to consider cleaning up * A drag has been canceled. You may want to consider cleaning up
* your handle. * your handle.
*/ */
public signal void drag_canceled (); public signal void drag_canceled ();
/** /**
* A drag action has successfully been finished. * A drag action has successfully been finished.
* *
* @param actor The actor on which the drag finished * @param actor The actor on which the drag finished
*/ */
public signal void drag_end (Actor actor); public signal void drag_end (Actor actor);
/** /**
* The destination has been crossed * The destination has been crossed
* *
* @param target the target actor that is crossing the destination * @param target the target actor that is crossing the destination
* @param hovered indicates whether the actor is now hovered or not * @param hovered indicates whether the actor is now hovered or not
*/ */
public signal void crossed (Actor? target, bool hovered); public signal void crossed (Actor? target, bool hovered);
/** /**
* Emitted on the source when a destination is crossed. * Emitted on the source when a destination is crossed.
* *
* @param destination The destination actor that has been crossed * @param destination The destination actor that has been crossed
* @param hovered Whether the actor is now hovered or has just been left * @param hovered Whether the actor is now hovered or has just been left
*/ */
public signal void destination_crossed (Actor destination, bool hovered); public signal void destination_crossed (Actor destination, bool hovered);
/** /**
* The source has been clicked, but the movement was not larger than * The source has been clicked, but the movement was not larger than
* the drag threshold. Useful if the source is also activable. * the drag threshold. Useful if the source is also activable.
* *
* @param button The button which was pressed * @param button The button which was pressed
*/ */
public signal void actor_clicked (uint32 button); public signal void actor_clicked (uint32 button);
/** /**
* The type of the action * The type of the action
*/ */
public DragDropActionType drag_type { get; construct; } public DragDropActionType drag_type { get; construct; }
/** /**
* The unique id given to this drag-drop-group * The unique id given to this drag-drop-group
*/ */
public string drag_id { get; construct; } public string drag_id { get; construct; }
public Actor handle { get; private set; } public Actor handle { get; private set; }
/** /**
* Indicates whether a drag action is currently active * Indicates whether a drag action is currently active
*/ */
public bool dragging { get; private set; default = false; } public bool dragging { get; private set; default = false; }
/** /**
* Allow checking the parents of reactive children if they are valid destinations * Allow checking the parents of reactive children if they are valid destinations
* if the child is none * if the child is none
*/ */
public bool allow_bubbling { get; set; default = true; } public bool allow_bubbling { get; set; default = true; }
public Actor? hovered { private get; set; default = null; } public Actor? hovered { private get; set; default = null; }
bool clicked = false; bool clicked = false;
float last_x; float last_x;
float last_y; float last_y;
/** /**
* Create a new DragDropAction * Create a new DragDropAction
* *
* @param type The type of this actor * @param type The type of this actor
* @param id An ID that marks which sources can be dragged on * @param id An ID that marks which sources can be dragged on
* which destinations. It has to be the same for all actors that * which destinations. It has to be the same for all actors that
* should be compatible with each other. * should be compatible with each other.
*/ */
public DragDropAction (DragDropActionType type, string id) public DragDropAction (DragDropActionType type, string id)
{ {
Object (drag_type : type, drag_id : id); Object (drag_type : type, drag_id : id);
if (sources == null) if (sources == null)
sources = new Gee.HashMap<string,Gee.LinkedList<Actor>> (); sources = new Gee.HashMap<string,Gee.LinkedList<Actor>> ();
if (destinations == null) if (destinations == null)
destinations = new Gee.HashMap<string,Gee.LinkedList<Actor>> (); destinations = new Gee.HashMap<string,Gee.LinkedList<Actor>> ();
} }
~DragDropAction () ~DragDropAction ()
{ {
if (actor != null) if (actor != null)
release_actor (actor); release_actor (actor);
} }
public override void set_actor (Actor? new_actor) public override void set_actor (Actor? new_actor)
{ {
if (actor != null) { if (actor != null) {
release_actor (actor); release_actor (actor);
} }
if (new_actor != null) { if (new_actor != null) {
connect_actor (new_actor); connect_actor (new_actor);
} }
base.set_actor (new_actor); base.set_actor (new_actor);
} }
void release_actor (Actor actor) void release_actor (Actor actor)
{ {
if (DragDropActionType.SOURCE in drag_type) { if (DragDropActionType.SOURCE in drag_type) {
actor.button_press_event.disconnect (source_clicked); actor.button_press_event.disconnect (source_clicked);
var source_list = sources.@get (drag_id); var source_list = sources.@get (drag_id);
source_list.remove (actor); source_list.remove (actor);
} }
if (DragDropActionType.DESTINATION in drag_type) { if (DragDropActionType.DESTINATION in drag_type) {
var dest_list = destinations[drag_id]; var dest_list = destinations[drag_id];
dest_list.remove (actor); dest_list.remove (actor);
} }
} }
void connect_actor (Actor actor) void connect_actor (Actor actor)
{ {
if (DragDropActionType.SOURCE in drag_type) { if (DragDropActionType.SOURCE in drag_type) {
actor.button_press_event.connect (source_clicked); actor.button_press_event.connect (source_clicked);
var source_list = sources.@get (drag_id); var source_list = sources.@get (drag_id);
if (source_list == null) { if (source_list == null) {
source_list = new Gee.LinkedList<Actor> (); source_list = new Gee.LinkedList<Actor> ();
sources.@set (drag_id, source_list); sources.@set (drag_id, source_list);
} }
source_list.add (actor); source_list.add (actor);
} }
if (DragDropActionType.DESTINATION in drag_type) { if (DragDropActionType.DESTINATION in drag_type) {
var dest_list = destinations[drag_id]; var dest_list = destinations[drag_id];
if (dest_list == null) { if (dest_list == null) {
dest_list = new Gee.LinkedList<Actor> (); dest_list = new Gee.LinkedList<Actor> ();
destinations[drag_id] = dest_list; destinations[drag_id] = dest_list;
} }
dest_list.add (actor); dest_list.add (actor);
} }
} }
void emit_crossed (Actor destination, bool is_hovered) void emit_crossed (Actor destination, bool is_hovered)
{ {
get_drag_drop_action (destination).crossed (actor, is_hovered); get_drag_drop_action (destination).crossed (actor, is_hovered);
destination_crossed (destination, is_hovered); destination_crossed (destination, is_hovered);
} }
bool source_clicked (ButtonEvent event) bool source_clicked (ButtonEvent event)
{ {
if (event.button != 1) { if (event.button != 1) {
actor_clicked (event.button); actor_clicked (event.button);
return false; return false;
} }
actor.get_stage ().captured_event.connect (follow_move); actor.get_stage ().captured_event.connect (follow_move);
clicked = true; clicked = true;
last_x = event.x; last_x = event.x;
last_y = event.y; last_y = event.y;
return true; return true;
} }
bool follow_move (Event event) bool follow_move (Event event)
{ {
// still determining if we actually want to start a drag action // still determining if we actually want to start a drag action
if (!dragging) { if (!dragging) {
switch (event.get_type ()) { switch (event.get_type ()) {
case EventType.MOTION: case EventType.MOTION:
float x, y; float x, y;
event.get_coords (out x, out y); event.get_coords (out x, out y);
var drag_threshold = Clutter.Settings.get_default ().dnd_drag_threshold; var drag_threshold = Clutter.Settings.get_default ().dnd_drag_threshold;
if (Math.fabsf (last_x - x) > drag_threshold || Math.fabsf (last_y - y) > drag_threshold) { if (Math.fabsf (last_x - x) > drag_threshold || Math.fabsf (last_y - y) > drag_threshold) {
handle = drag_begin (x, y); handle = drag_begin (x, y);
if (handle == null) { if (handle == null) {
actor.get_stage ().captured_event.disconnect (follow_move); actor.get_stage ().captured_event.disconnect (follow_move);
critical ("No handle has been returned by the started signal, aborting drag."); critical ("No handle has been returned by the started signal, aborting drag.");
return false; return false;
} }
handle.reactive = false; handle.reactive = false;
clicked = false; clicked = false;
dragging = true; dragging = true;
var source_list = sources.@get (drag_id); var source_list = sources.@get (drag_id);
if (source_list != null) { if (source_list != null) {
var dest_list = destinations[drag_id]; var dest_list = destinations[drag_id];
foreach (var actor in source_list) { foreach (var actor in source_list) {
// Do not unset reactivity on destinations // Do not unset reactivity on destinations
if (actor in dest_list) { if (actor in dest_list) {
continue; continue;
} }
actor.reactive = false; actor.reactive = false;
} }
} }
} }
return true; return true;
case EventType.BUTTON_RELEASE: case EventType.BUTTON_RELEASE:
float x, y, ex, ey; float x, y, ex, ey;
event.get_coords (out ex, out ey); event.get_coords (out ex, out ey);
actor.get_transformed_position (out x, out y); actor.get_transformed_position (out x, out y);
// release has happened within bounds of actor // release has happened within bounds of actor
if (x < ex && x + actor.width > ex && y < ey && y + actor.height > ey) { if (x < ex && x + actor.width > ex && y < ey && y + actor.height > ey) {
actor_clicked (event.get_button ()); actor_clicked (event.get_button ());
} }
actor.get_stage ().captured_event.disconnect (follow_move); actor.get_stage ().captured_event.disconnect (follow_move);
clicked = false; clicked = false;
dragging = false; dragging = false;
return true; return true;
default: default:
return true; return true;
} }
} }
switch (event.get_type ()) { switch (event.get_type ()) {
case EventType.KEY_PRESS: case EventType.KEY_PRESS:
if (event.get_key_code () == Key.Escape) { if (event.get_key_code () == Key.Escape) {
cancel (); cancel ();
} }
return true; return true;
case EventType.MOTION: case EventType.MOTION:
float x, y; float x, y;
event.get_coords (out x, out y); event.get_coords (out x, out y);
handle.x -= last_x - x; handle.x -= last_x - x;
handle.y -= last_y - y; handle.y -= last_y - y;
last_x = x; last_x = x;
last_y = y; last_y = y;
var stage = actor.get_stage (); var stage = actor.get_stage ();
var actor = stage.get_actor_at_pos (PickMode.REACTIVE, (int) x, (int) y); var actor = stage.get_actor_at_pos (PickMode.REACTIVE, (int) x, (int) y);
DragDropAction action = null; DragDropAction action = null;
// if we're allowed to bubble and this actor is not a destination, check its parents // if we're allowed to bubble and this actor is not a destination, check its parents
if (actor != null && (action = get_drag_drop_action (actor)) == null && allow_bubbling) { if (actor != null && (action = get_drag_drop_action (actor)) == null && allow_bubbling) {
while ((actor = actor.get_parent ()) != stage) { while ((actor = actor.get_parent ()) != stage) {
if ((action = get_drag_drop_action (actor)) != null) if ((action = get_drag_drop_action (actor)) != null)
break; break;
} }
} }
// didn't change, no need to do anything // didn't change, no need to do anything
if (actor == hovered) if (actor == hovered)
return true; return true;
if (action == null) { if (action == null) {
// apparently we left ours if we had one before // apparently we left ours if we had one before
if (hovered != null) { if (hovered != null) {
emit_crossed (hovered, false); emit_crossed (hovered, false);
hovered = null; hovered = null;
} }
return true; return true;
} }
// signal the previous one that we left it // signal the previous one that we left it
if (hovered != null) { if (hovered != null) {
emit_crossed (hovered, false); emit_crossed (hovered, false);
} }
// tell the new one that it is hovered // tell the new one that it is hovered
hovered = actor; hovered = actor;
emit_crossed (hovered, true); emit_crossed (hovered, true);
return true; return true;
case EventType.BUTTON_RELEASE: case EventType.BUTTON_RELEASE:
if (hovered != null) { if (hovered != null) {
finish (); finish ();
} else { } else {
cancel (); cancel ();
} }
return true; return true;
case EventType.ENTER: case EventType.ENTER:
case EventType.LEAVE: case EventType.LEAVE:
return true; return true;
} }
return false; return false;
} }
/** /**
* Looks for a DragDropAction instance if this actor has one or NULL. * Looks for a DragDropAction instance if this actor has one or NULL.
* It also checks if it is a DESTINATION and if the id matches * It also checks if it is a DESTINATION and if the id matches
* *
* @return the DragDropAction instance on this actor or NULL * @return the DragDropAction instance on this actor or NULL
*/ */
DragDropAction? get_drag_drop_action (Actor actor) DragDropAction? get_drag_drop_action (Actor actor)
{ {
DragDropAction? drop_action = null; DragDropAction? drop_action = null;
foreach (var action in actor.get_actions ()) { foreach (var action in actor.get_actions ()) {
drop_action = action as DragDropAction; drop_action = action as DragDropAction;
if (drop_action == null if (drop_action == null
|| !(DragDropActionType.DESTINATION in drop_action.drag_type) || !(DragDropActionType.DESTINATION in drop_action.drag_type)
|| drop_action.drag_id != drag_id) || drop_action.drag_id != drag_id)
continue; continue;
return drop_action; return drop_action;
} }
return null; return null;
} }
/** /**
* Abort the drag * Abort the drag
*/ */
public void cancel () public void cancel ()
{ {
cleanup (); cleanup ();
drag_canceled (); drag_canceled ();
} }
/** /**
* Allows you to abort all drags currently running for a given drag-id * Allows you to abort all drags currently running for a given drag-id
*/ */
public static void cancel_all_by_id (string id) public static void cancel_all_by_id (string id)
{ {
var actors = sources.@get (id); var actors = sources.@get (id);
if (actors == null) if (actors == null)
return; return;
foreach (var actor in actors) { foreach (var actor in actors) {
foreach (var action in actor.get_actions ()) { foreach (var action in actor.get_actions ()) {
var drag_action = action as DragDropAction; var drag_action = action as DragDropAction;
if (drag_action != null && drag_action.dragging) { if (drag_action != null && drag_action.dragging) {
drag_action.cancel (); drag_action.cancel ();
break; break;
} }
} }
} }
} }
void finish () void finish ()
{ {
// make sure they reset the style or whatever they changed when hovered // make sure they reset the style or whatever they changed when hovered
emit_crossed (hovered, false); emit_crossed (hovered, false);
cleanup (); cleanup ();
drag_end (hovered); drag_end (hovered);
} }
void cleanup () void cleanup ()
{ {
var source_list = sources.@get (drag_id); var source_list = sources.@get (drag_id);
if (source_list != null) { if (source_list != null) {
foreach (var actor in source_list) { foreach (var actor in source_list) {
actor.reactive = true; actor.reactive = true;
} }
} }
if (dragging) if (dragging)
actor.get_stage ().captured_event.disconnect (follow_move); actor.get_stage ().captured_event.disconnect (follow_move);
dragging = false; dragging = false;
} }
} }
} }

View File

@ -19,368 +19,368 @@ using Meta;
namespace Gala namespace Gala
{ {
public enum InputArea public enum InputArea
{ {
NONE, NONE,
FULLSCREEN, FULLSCREEN,
DEFAULT DEFAULT
} }
public class InternalUtils public class InternalUtils
{ {
public static bool workspaces_only_on_primary () public static bool workspaces_only_on_primary ()
{ {
return Prefs.get_dynamic_workspaces () return Prefs.get_dynamic_workspaces ()
&& Prefs.get_workspaces_only_on_primary (); && Prefs.get_workspaces_only_on_primary ();
} }
/* /*
* Reload shadow settings * Reload shadow settings
*/ */
public static void reload_shadow () public static void reload_shadow ()
{ {
var factory = ShadowFactory.get_default (); var factory = ShadowFactory.get_default ();
var settings = ShadowSettings.get_default (); var settings = ShadowSettings.get_default ();
Meta.ShadowParams shadow; Meta.ShadowParams shadow;
//normal focused //normal focused
shadow = settings.get_shadowparams ("normal_focused"); shadow = settings.get_shadowparams ("normal_focused");
factory.set_params ("normal", true, shadow); factory.set_params ("normal", true, shadow);
//normal unfocused //normal unfocused
shadow = settings.get_shadowparams ("normal_unfocused"); shadow = settings.get_shadowparams ("normal_unfocused");
factory.set_params ("normal", false, shadow); factory.set_params ("normal", false, shadow);
//menus //menus
shadow = settings.get_shadowparams ("menu"); shadow = settings.get_shadowparams ("menu");
factory.set_params ("menu", false, shadow); factory.set_params ("menu", false, shadow);
factory.set_params ("dropdown-menu", false, shadow); factory.set_params ("dropdown-menu", false, shadow);
factory.set_params ("popup-menu", false, shadow); factory.set_params ("popup-menu", false, shadow);
//dialog focused //dialog focused
shadow = settings.get_shadowparams ("dialog_focused"); shadow = settings.get_shadowparams ("dialog_focused");
factory.set_params ("dialog", true, shadow); factory.set_params ("dialog", true, shadow);
factory.set_params ("modal_dialog", false, shadow); factory.set_params ("modal_dialog", false, shadow);
//dialog unfocused //dialog unfocused
shadow = settings.get_shadowparams ("dialog_unfocused"); shadow = settings.get_shadowparams ("dialog_unfocused");
factory.set_params ("dialog", false, shadow); factory.set_params ("dialog", false, shadow);
factory.set_params ("modal_dialog", false, shadow); factory.set_params ("modal_dialog", false, shadow);
} }
/** /**
* set the area where clutter can receive events * set the area where clutter can receive events
**/ **/
#if HAS_MUTTER330 #if HAS_MUTTER330
public static void set_input_area (Display display, InputArea area) public static void set_input_area (Display display, InputArea area)
{ {
X.Xrectangle[] rects = {}; X.Xrectangle[] rects = {};
int width, height; int width, height;
display.get_size (out width, out height); display.get_size (out width, out height);
var geometry = display.get_monitor_geometry (display.get_primary_monitor ()); var geometry = display.get_monitor_geometry (display.get_primary_monitor ());
switch (area) { switch (area) {
case InputArea.FULLSCREEN: case InputArea.FULLSCREEN:
X.Xrectangle rect = {0, 0, (ushort)width, (ushort)height}; X.Xrectangle rect = {0, 0, (ushort)width, (ushort)height};
rects = {rect}; rects = {rect};
break; break;
case InputArea.DEFAULT: case InputArea.DEFAULT:
var schema = BehaviorSettings.get_default ().schema; var schema = BehaviorSettings.get_default ().schema;
// if ActionType is NONE make it 0 sized // if ActionType is NONE make it 0 sized
ushort tl_size = (schema.get_enum ("hotcorner-topleft") != ActionType.NONE ? 1 : 0); ushort tl_size = (schema.get_enum ("hotcorner-topleft") != ActionType.NONE ? 1 : 0);
ushort tr_size = (schema.get_enum ("hotcorner-topright") != ActionType.NONE ? 1 : 0); ushort tr_size = (schema.get_enum ("hotcorner-topright") != ActionType.NONE ? 1 : 0);
ushort bl_size = (schema.get_enum ("hotcorner-bottomleft") != ActionType.NONE ? 1 : 0); ushort bl_size = (schema.get_enum ("hotcorner-bottomleft") != ActionType.NONE ? 1 : 0);
ushort br_size = (schema.get_enum ("hotcorner-bottomright") != ActionType.NONE ? 1 : 0); ushort br_size = (schema.get_enum ("hotcorner-bottomright") != ActionType.NONE ? 1 : 0);
X.Xrectangle topleft = {(short)geometry.x, (short)geometry.y, tl_size, tl_size}; X.Xrectangle topleft = {(short)geometry.x, (short)geometry.y, tl_size, tl_size};
X.Xrectangle topright = {(short)(geometry.x + geometry.width - 1), (short)geometry.y, tr_size, tr_size}; X.Xrectangle topright = {(short)(geometry.x + geometry.width - 1), (short)geometry.y, tr_size, tr_size};
X.Xrectangle bottomleft = {(short)geometry.x, (short)(geometry.y + geometry.height - 1), bl_size, bl_size}; X.Xrectangle bottomleft = {(short)geometry.x, (short)(geometry.y + geometry.height - 1), bl_size, bl_size};
X.Xrectangle bottomright = {(short)(geometry.x + geometry.width - 1), (short)(geometry.y + geometry.height - 1), br_size, br_size}; X.Xrectangle bottomright = {(short)(geometry.x + geometry.width - 1), (short)(geometry.y + geometry.height - 1), br_size, br_size};
rects = {topleft, topright, bottomleft, bottomright}; rects = {topleft, topright, bottomleft, bottomright};
// add plugin's requested areas // add plugin's requested areas
if (area == InputArea.FULLSCREEN || area == InputArea.DEFAULT) { if (area == InputArea.FULLSCREEN || area == InputArea.DEFAULT) {
foreach (var rect in PluginManager.get_default ().regions) { foreach (var rect in PluginManager.get_default ().regions) {
rects += rect; rects += rect;
} }
} }
break; break;
case InputArea.NONE: case InputArea.NONE:
default: default:
#if HAS_MUTTER334 #if HAS_MUTTER334
unowned Meta.X11Display x11display = display.get_x11_display (); unowned Meta.X11Display x11display = display.get_x11_display ();
x11display.clear_stage_input_region (); x11display.clear_stage_input_region ();
#else #else
display.empty_stage_input_region (); display.empty_stage_input_region ();
#endif #endif
return; return;
} }
#if HAS_MUTTER334 #if HAS_MUTTER334
unowned Meta.X11Display x11display = display.get_x11_display (); unowned Meta.X11Display x11display = display.get_x11_display ();
var xregion = X.Fixes.create_region (x11display.get_xdisplay (), rects); var xregion = X.Fixes.create_region (x11display.get_xdisplay (), rects);
x11display.set_stage_input_region (xregion); x11display.set_stage_input_region (xregion);
#else #else
var xregion = X.Fixes.create_region (display.get_x11_display ().get_xdisplay (), rects); var xregion = X.Fixes.create_region (display.get_x11_display ().get_xdisplay (), rects);
Util.set_stage_input_region (display, xregion); Util.set_stage_input_region (display, xregion);
#endif #endif
} }
#else #else
public static void set_input_area (Screen screen, InputArea area) public static void set_input_area (Screen screen, InputArea area)
{ {
var display = screen.get_display (); var display = screen.get_display ();
X.Xrectangle[] rects = {}; X.Xrectangle[] rects = {};
int width, height; int width, height;
screen.get_size (out width, out height); screen.get_size (out width, out height);
var geometry = screen.get_monitor_geometry (screen.get_primary_monitor ()); var geometry = screen.get_monitor_geometry (screen.get_primary_monitor ());
switch (area) { switch (area) {
case InputArea.FULLSCREEN: case InputArea.FULLSCREEN:
X.Xrectangle rect = {0, 0, (ushort)width, (ushort)height}; X.Xrectangle rect = {0, 0, (ushort)width, (ushort)height};
rects = {rect}; rects = {rect};
break; break;
case InputArea.DEFAULT: case InputArea.DEFAULT:
var schema = BehaviorSettings.get_default ().schema; var schema = BehaviorSettings.get_default ().schema;
// if ActionType is NONE make it 0 sized // if ActionType is NONE make it 0 sized
ushort tl_size = (schema.get_enum ("hotcorner-topleft") != ActionType.NONE ? 1 : 0); ushort tl_size = (schema.get_enum ("hotcorner-topleft") != ActionType.NONE ? 1 : 0);
ushort tr_size = (schema.get_enum ("hotcorner-topright") != ActionType.NONE ? 1 : 0); ushort tr_size = (schema.get_enum ("hotcorner-topright") != ActionType.NONE ? 1 : 0);
ushort bl_size = (schema.get_enum ("hotcorner-bottomleft") != ActionType.NONE ? 1 : 0); ushort bl_size = (schema.get_enum ("hotcorner-bottomleft") != ActionType.NONE ? 1 : 0);
ushort br_size = (schema.get_enum ("hotcorner-bottomright") != ActionType.NONE ? 1 : 0); ushort br_size = (schema.get_enum ("hotcorner-bottomright") != ActionType.NONE ? 1 : 0);
X.Xrectangle topleft = {(short)geometry.x, (short)geometry.y, tl_size, tl_size}; X.Xrectangle topleft = {(short)geometry.x, (short)geometry.y, tl_size, tl_size};
X.Xrectangle topright = {(short)(geometry.x + geometry.width - 1), (short)geometry.y, tr_size, tr_size}; X.Xrectangle topright = {(short)(geometry.x + geometry.width - 1), (short)geometry.y, tr_size, tr_size};
X.Xrectangle bottomleft = {(short)geometry.x, (short)(geometry.y + geometry.height - 1), bl_size, bl_size}; X.Xrectangle bottomleft = {(short)geometry.x, (short)(geometry.y + geometry.height - 1), bl_size, bl_size};
X.Xrectangle bottomright = {(short)(geometry.x + geometry.width - 1), (short)(geometry.y + geometry.height - 1), br_size, br_size}; X.Xrectangle bottomright = {(short)(geometry.x + geometry.width - 1), (short)(geometry.y + geometry.height - 1), br_size, br_size};
rects = {topleft, topright, bottomleft, bottomright}; rects = {topleft, topright, bottomleft, bottomright};
// add plugin's requested areas // add plugin's requested areas
if (area == InputArea.FULLSCREEN || area == InputArea.DEFAULT) { if (area == InputArea.FULLSCREEN || area == InputArea.DEFAULT) {
foreach (var rect in PluginManager.get_default ().regions) { foreach (var rect in PluginManager.get_default ().regions) {
rects += rect; rects += rect;
} }
} }
break; break;
case InputArea.NONE: case InputArea.NONE:
default: default:
screen.empty_stage_input_region (); screen.empty_stage_input_region ();
return; return;
} }
var xregion = X.Fixes.create_region (display.get_xdisplay (), rects); var xregion = X.Fixes.create_region (display.get_xdisplay (), rects);
screen.set_stage_input_region (xregion); screen.set_stage_input_region (xregion);
} }
#endif #endif
/** /**
* Inserts a workspace at the given index. To ensure the workspace is not immediately * Inserts a workspace at the given index. To ensure the workspace is not immediately
* removed again when in dynamic workspaces, the window is first placed on it. * removed again when in dynamic workspaces, the window is first placed on it.
* *
* @param index The index at which to insert the workspace * @param index The index at which to insert the workspace
* @param new_window A window that should be moved to the new workspace * @param new_window A window that should be moved to the new workspace
*/ */
public static void insert_workspace_with_window (int index, Window new_window) public static void insert_workspace_with_window (int index, Window new_window)
{ {
unowned WorkspaceManager workspace_manager = WorkspaceManager.get_default (); unowned WorkspaceManager workspace_manager = WorkspaceManager.get_default ();
workspace_manager.freeze_remove (); workspace_manager.freeze_remove ();
new_window.change_workspace_by_index (index, false); new_window.change_workspace_by_index (index, false);
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned List<WindowActor> actors = new_window.get_display ().get_window_actors (); unowned List<WindowActor> actors = new_window.get_display ().get_window_actors ();
#else #else
unowned List<WindowActor> actors = new_window.get_screen ().get_window_actors (); unowned List<WindowActor> actors = new_window.get_screen ().get_window_actors ();
#endif #endif
foreach (unowned Meta.WindowActor actor in actors) { foreach (unowned Meta.WindowActor actor in actors) {
if (actor.is_destroyed ()) if (actor.is_destroyed ())
continue; continue;
unowned Meta.Window window = actor.get_meta_window (); unowned Meta.Window window = actor.get_meta_window ();
if (window == new_window) if (window == new_window)
continue; continue;
var current_index = window.get_workspace ().index (); var current_index = window.get_workspace ().index ();
if (current_index >= index if (current_index >= index
&& !window.on_all_workspaces) { && !window.on_all_workspaces) {
window.change_workspace_by_index (current_index + 1, true); window.change_workspace_by_index (current_index + 1, true);
} }
} }
workspace_manager.thaw_remove (); workspace_manager.thaw_remove ();
workspace_manager.cleanup (); workspace_manager.cleanup ();
} }
// Code ported from KWin present windows effect // Code ported from KWin present windows effect
// https://projects.kde.org/projects/kde/kde-workspace/repository/revisions/master/entry/kwin/effects/presentwindows/presentwindows.cpp // https://projects.kde.org/projects/kde/kde-workspace/repository/revisions/master/entry/kwin/effects/presentwindows/presentwindows.cpp
// constants, mainly for natural expo // constants, mainly for natural expo
const int GAPS = 10; const int GAPS = 10;
const int MAX_TRANSLATIONS = 100000; const int MAX_TRANSLATIONS = 100000;
const int ACCURACY = 20; const int ACCURACY = 20;
// some math utilities // some math utilities
static int squared_distance (Gdk.Point a, Gdk.Point b) static int squared_distance (Gdk.Point a, Gdk.Point b)
{ {
var k1 = b.x - a.x; var k1 = b.x - a.x;
var k2 = b.y - a.y; var k2 = b.y - a.y;
return k1*k1 + k2*k2; return k1*k1 + k2*k2;
} }
static Meta.Rectangle rect_adjusted (Meta.Rectangle rect, int dx1, int dy1, int dx2, int dy2) static Meta.Rectangle rect_adjusted (Meta.Rectangle rect, int dx1, int dy1, int dx2, int dy2)
{ {
return {rect.x + dx1, rect.y + dy1, rect.width + (-dx1 + dx2), rect.height + (-dy1 + dy2)}; return {rect.x + dx1, rect.y + dy1, rect.width + (-dx1 + dx2), rect.height + (-dy1 + dy2)};
} }
static Gdk.Point rect_center (Meta.Rectangle rect) static Gdk.Point rect_center (Meta.Rectangle rect)
{ {
return {rect.x + rect.width / 2, rect.y + rect.height / 2}; return {rect.x + rect.width / 2, rect.y + rect.height / 2};
} }
public struct TilableWindow public struct TilableWindow
{ {
Meta.Rectangle rect; Meta.Rectangle rect;
void *id; void *id;
} }
public static List<TilableWindow?> calculate_grid_placement (Meta.Rectangle area, public static List<TilableWindow?> calculate_grid_placement (Meta.Rectangle area,
List<TilableWindow?> windows) List<TilableWindow?> windows)
{ {
uint window_count = windows.length (); uint window_count = windows.length ();
int columns = (int)Math.ceil (Math.sqrt (window_count)); int columns = (int)Math.ceil (Math.sqrt (window_count));
int rows = (int)Math.ceil (window_count / (double)columns); int rows = (int)Math.ceil (window_count / (double)columns);
// Assign slots // Assign slots
int slot_width = area.width / columns; int slot_width = area.width / columns;
int slot_height = area.height / rows; int slot_height = area.height / rows;
TilableWindow?[] taken_slots = {}; TilableWindow?[] taken_slots = {};
taken_slots.resize (rows * columns); taken_slots.resize (rows * columns);
// precalculate all slot centers // precalculate all slot centers
Gdk.Point[] slot_centers = {}; Gdk.Point[] slot_centers = {};
slot_centers.resize (rows * columns); slot_centers.resize (rows * columns);
for (int x = 0; x < columns; x++) { for (int x = 0; x < columns; x++) {
for (int y = 0; y < rows; y++) { for (int y = 0; y < rows; y++) {
slot_centers[x + y * columns] = {area.x + slot_width * x + slot_width / 2, slot_centers[x + y * columns] = {area.x + slot_width * x + slot_width / 2,
area.y + slot_height * y + slot_height / 2}; area.y + slot_height * y + slot_height / 2};
} }
} }
// Assign each window to the closest available slot // Assign each window to the closest available slot
var tmplist = windows.copy (); var tmplist = windows.copy ();
while (tmplist.length () > 0) { while (tmplist.length () > 0) {
unowned List<unowned TilableWindow?> link = tmplist.nth (0); unowned List<unowned TilableWindow?> link = tmplist.nth (0);
var window = link.data; var window = link.data;
var rect = window.rect; var rect = window.rect;
var slot_candidate = -1; var slot_candidate = -1;
var slot_candidate_distance = int.MAX; var slot_candidate_distance = int.MAX;
var pos = rect_center (rect); var pos = rect_center (rect);
// all slots // all slots
for (int i = 0; i < columns * rows; i++) { for (int i = 0; i < columns * rows; i++) {
if (i > window_count - 1) if (i > window_count - 1)
break; break;
var dist = squared_distance (pos, slot_centers[i]); var dist = squared_distance (pos, slot_centers[i]);
if (dist < slot_candidate_distance) { if (dist < slot_candidate_distance) {
// window is interested in this slot // window is interested in this slot
var occupier = taken_slots[i]; var occupier = taken_slots[i];
if (occupier == window) if (occupier == window)
continue; continue;
if (occupier == null || dist < squared_distance (rect_center (occupier.rect), slot_centers[i])) { if (occupier == null || dist < squared_distance (rect_center (occupier.rect), slot_centers[i])) {
// either nobody lives here, or we're better - takeover the slot if it's our best // either nobody lives here, or we're better - takeover the slot if it's our best
slot_candidate = i; slot_candidate = i;
slot_candidate_distance = dist; slot_candidate_distance = dist;
} }
} }
} }
if (slot_candidate == -1) if (slot_candidate == -1)
continue; continue;
if (taken_slots[slot_candidate] != null) if (taken_slots[slot_candidate] != null)
tmplist.prepend (taken_slots[slot_candidate]); tmplist.prepend (taken_slots[slot_candidate]);
tmplist.remove_link (link); tmplist.remove_link (link);
taken_slots[slot_candidate] = window; taken_slots[slot_candidate] = window;
} }
var result = new List<TilableWindow?> (); var result = new List<TilableWindow?> ();
// see how many windows we have on the last row // see how many windows we have on the last row
int left_over = (int)window_count - columns * (rows - 1); int left_over = (int)window_count - columns * (rows - 1);
for (int slot = 0; slot < columns * rows; slot++) { for (int slot = 0; slot < columns * rows; slot++) {
var window = taken_slots[slot]; var window = taken_slots[slot];
// some slots might be empty // some slots might be empty
if (window == null) if (window == null)
continue; continue;
var rect = window.rect; var rect = window.rect;
// Work out where the slot is // Work out where the slot is
Meta.Rectangle target = {area.x + (slot % columns) * slot_width, Meta.Rectangle target = {area.x + (slot % columns) * slot_width,
area.y + (slot / columns) * slot_height, area.y + (slot / columns) * slot_height,
slot_width, slot_width,
slot_height}; slot_height};
target = rect_adjusted (target, 10, 10, -10, -10); target = rect_adjusted (target, 10, 10, -10, -10);
float scale; float scale;
if (target.width / (double)rect.width < target.height / (double)rect.height) { if (target.width / (double)rect.width < target.height / (double)rect.height) {
// Center vertically // Center vertically
scale = target.width / (float)rect.width; scale = target.width / (float)rect.width;
target.y += (target.height - (int)(rect.height * scale)) / 2; target.y += (target.height - (int)(rect.height * scale)) / 2;
target.height = (int)Math.floorf (rect.height * scale); target.height = (int)Math.floorf (rect.height * scale);
} else { } else {
// Center horizontally // Center horizontally
scale = target.height / (float)rect.height; scale = target.height / (float)rect.height;
target.x += (target.width - (int)(rect.width * scale)) / 2; target.x += (target.width - (int)(rect.width * scale)) / 2;
target.width = (int)Math.floorf (rect.width * scale); target.width = (int)Math.floorf (rect.width * scale);
} }
// Don't scale the windows too much // Don't scale the windows too much
if (scale > 1.0) { if (scale > 1.0) {
scale = 1.0f; scale = 1.0f;
target = {rect_center (target).x - (int)Math.floorf (rect.width * scale) / 2, target = {rect_center (target).x - (int)Math.floorf (rect.width * scale) / 2,
rect_center (target).y - (int)Math.floorf (rect.height * scale) / 2, rect_center (target).y - (int)Math.floorf (rect.height * scale) / 2,
(int)Math.floorf (scale * rect.width), (int)Math.floorf (scale * rect.width),
(int)Math.floorf (scale * rect.height)}; (int)Math.floorf (scale * rect.height)};
} }
// put the last row in the center, if necessary // put the last row in the center, if necessary
if (left_over != columns && slot >= columns * (rows - 1)) if (left_over != columns && slot >= columns * (rows - 1))
target.x += (columns - left_over) * slot_width / 2; target.x += (columns - left_over) * slot_width / 2;
result.prepend ({ target, window.id }); result.prepend ({ target, window.id });
} }
result.reverse (); result.reverse ();
return result; return result;
} }
public static inline bool get_window_is_normal (Meta.Window window) public static inline bool get_window_is_normal (Meta.Window window)
{ {
switch (window.get_window_type ()) { switch (window.get_window_type ()) {
case Meta.WindowType.NORMAL: case Meta.WindowType.NORMAL:
case Meta.WindowType.DIALOG: case Meta.WindowType.DIALOG:
case Meta.WindowType.MODAL_DIALOG: case Meta.WindowType.MODAL_DIALOG:
return true; return true;
default: default:
return false; return false;
} }
} }
public static int get_ui_scaling_factor () public static int get_ui_scaling_factor ()
{ {
return Meta.Backend.get_backend ().get_settings ().get_ui_scaling_factor (); return Meta.Backend.get_backend ().get_settings ().get_ui_scaling_factor ();
} }
} }
} }

View File

@ -17,97 +17,97 @@
namespace Gala namespace Gala
{ {
public class KeyboardManager : Object public class KeyboardManager : Object
{ {
static KeyboardManager? instance; static KeyboardManager? instance;
static VariantType sources_variant_type; static VariantType sources_variant_type;
public static void init (Meta.Display display) public static void init (Meta.Display display)
{ {
if (instance != null) if (instance != null)
return; return;
instance = new KeyboardManager (); instance = new KeyboardManager ();
display.modifiers_accelerator_activated.connect (instance.handle_modifiers_accelerator_activated); display.modifiers_accelerator_activated.connect (instance.handle_modifiers_accelerator_activated);
} }
static construct static construct
{ {
sources_variant_type = new VariantType ("a(ss)"); sources_variant_type = new VariantType ("a(ss)");
} }
GLib.Settings settings; GLib.Settings settings;
KeyboardManager () KeyboardManager ()
{ {
Object (); Object ();
} }
construct construct
{ {
var schema = GLib.SettingsSchemaSource.get_default ().lookup ("org.gnome.desktop.input-sources", true); var schema = GLib.SettingsSchemaSource.get_default ().lookup ("org.gnome.desktop.input-sources", true);
if (schema == null) if (schema == null)
return; return;
settings = new GLib.Settings.full (schema, null, null); settings = new GLib.Settings.full (schema, null, null);
Signal.connect (settings, "changed", (Callback) set_keyboard_layout, this); Signal.connect (settings, "changed", (Callback) set_keyboard_layout, this);
set_keyboard_layout (settings, "current"); set_keyboard_layout (settings, "current");
} }
[CCode (instance_pos = -1)] [CCode (instance_pos = -1)]
bool handle_modifiers_accelerator_activated (Meta.Display display) bool handle_modifiers_accelerator_activated (Meta.Display display)
{ {
display.ungrab_keyboard (display.get_current_time ()); display.ungrab_keyboard (display.get_current_time ());
var sources = settings.get_value ("sources"); var sources = settings.get_value ("sources");
if (!sources.is_of_type (sources_variant_type)) if (!sources.is_of_type (sources_variant_type))
return true; return true;
var n_sources = (uint) sources.n_children (); var n_sources = (uint) sources.n_children ();
if (n_sources < 2) if (n_sources < 2)
return true; return true;
var current = settings.get_uint ("current"); var current = settings.get_uint ("current");
settings.set_uint ("current", (current + 1) % n_sources); settings.set_uint ("current", (current + 1) % n_sources);
return true; return true;
} }
[CCode (instance_pos = -1)] [CCode (instance_pos = -1)]
void set_keyboard_layout (GLib.Settings settings, string key) void set_keyboard_layout (GLib.Settings settings, string key)
{ {
if (!(key == "current" || key == "source" || key == "xkb-options")) if (!(key == "current" || key == "source" || key == "xkb-options"))
return; return;
string layout = "us", variant = "", options = ""; string layout = "us", variant = "", options = "";
var sources = settings.get_value ("sources"); var sources = settings.get_value ("sources");
if (!sources.is_of_type (sources_variant_type)) if (!sources.is_of_type (sources_variant_type))
return; return;
var current = settings.get_uint ("current"); var current = settings.get_uint ("current");
unowned string? type = null, name = null; unowned string? type = null, name = null;
if (sources.n_children () > current) if (sources.n_children () > current)
sources.get_child (current, "(&s&s)", out type, out name); sources.get_child (current, "(&s&s)", out type, out name);
if (type == "xkb") { if (type == "xkb") {
string[] arr = name.split ("+", 2); string[] arr = name.split ("+", 2);
layout = arr[0]; layout = arr[0];
variant = arr[1] ?? ""; variant = arr[1] ?? "";
} }
var xkb_options = settings.get_strv ("xkb-options"); var xkb_options = settings.get_strv ("xkb-options");
if (xkb_options.length > 0) if (xkb_options.length > 0)
options = string.joinv (",", xkb_options); options = string.joinv (",", xkb_options);
// Needed to make common keybindings work on non-latin layouts // Needed to make common keybindings work on non-latin layouts
if (layout != "us" || variant != "") { if (layout != "us" || variant != "") {
layout = layout + ",us"; layout = layout + ",us";
variant = variant + ","; variant = variant + ",";
} }
Meta.Backend.get_backend ().set_keymap (layout, variant, options); Meta.Backend.get_backend ().set_keymap (layout, variant, options);
} }
} }
} }

View File

@ -17,47 +17,47 @@
namespace Gala namespace Gala
{ {
const OptionEntry[] OPTIONS = { const OptionEntry[] OPTIONS = {
{ "version", 0, OptionFlags.NO_ARG, OptionArg.CALLBACK, (void*) print_version, "Print version", null }, { "version", 0, OptionFlags.NO_ARG, OptionArg.CALLBACK, (void*) print_version, "Print version", null },
{ null } { null }
}; };
void print_version () { void print_version () {
stdout.printf ("Gala %s\n", Config.VERSION); stdout.printf ("Gala %s\n", Config.VERSION);
Meta.exit (Meta.ExitCode.SUCCESS); Meta.exit (Meta.ExitCode.SUCCESS);
} }
public static int main (string[] args) public static int main (string[] args)
{ {
unowned OptionContext ctx = Meta.get_option_context (); unowned OptionContext ctx = Meta.get_option_context ();
ctx.add_main_entries (Gala.OPTIONS, null); ctx.add_main_entries (Gala.OPTIONS, null);
try { try {
ctx.parse (ref args); ctx.parse (ref args);
} catch (Error e) { } catch (Error e) {
stderr.printf ("Error initializing: %s\n", e.message); stderr.printf ("Error initializing: %s\n", e.message);
Meta.exit (Meta.ExitCode.ERROR); Meta.exit (Meta.ExitCode.ERROR);
} }
Meta.Plugin.manager_set_plugin_type (typeof (WindowManagerGala)); Meta.Plugin.manager_set_plugin_type (typeof (WindowManagerGala));
Meta.Util.set_wm_name ("Mutter(Gala)"); Meta.Util.set_wm_name ("Mutter(Gala)");
/** /**
* Prevent Meta.init () from causing gtk to load gail and at-bridge * Prevent Meta.init () from causing gtk to load gail and at-bridge
* Taken from Gnome-Shell main.c * Taken from Gnome-Shell main.c
*/ */
GLib.Environment.set_variable ("NO_GAIL", "1", true); GLib.Environment.set_variable ("NO_GAIL", "1", true);
GLib.Environment.set_variable ("NO_AT_BRIDGE", "1", true); GLib.Environment.set_variable ("NO_AT_BRIDGE", "1", true);
Meta.init (); Meta.init ();
GLib.Environment.unset_variable ("NO_GAIL"); GLib.Environment.unset_variable ("NO_GAIL");
GLib.Environment.unset_variable ("NO_AT_BRIDGE"); GLib.Environment.unset_variable ("NO_AT_BRIDGE");
Plank.Paths.initialize ("plank", Config.DATADIR + "/plank"); Plank.Paths.initialize ("plank", Config.DATADIR + "/plank");
// Force initialization of static fields in Utils class // Force initialization of static fields in Utils class
// https://bugzilla.gnome.org/show_bug.cgi?id=543189 // https://bugzilla.gnome.org/show_bug.cgi?id=543189
typeof (Gala.Utils).class_ref (); typeof (Gala.Utils).class_ref ();
return Meta.run (); return Meta.run ();
} }
} }

View File

@ -17,113 +17,113 @@
namespace Gala namespace Gala
{ {
[DBus (name = "org.freedesktop.Notifications")] [DBus (name = "org.freedesktop.Notifications")]
interface DBusNotifications : GLib.Object interface DBusNotifications : GLib.Object
{ {
public abstract uint32 notify (string app_name, uint32 replaces_id, string app_icon, string summary, public abstract uint32 notify (string app_name, uint32 replaces_id, string app_icon, string summary,
string body, string[] actions, HashTable<string, Variant> hints, int32 expire_timeout) throws DBusError, IOError; string body, string[] actions, HashTable<string, Variant> hints, int32 expire_timeout) throws DBusError, IOError;
} }
public class MediaFeedback : GLib.Object public class MediaFeedback : GLib.Object
{ {
[Compact] [Compact]
class Feedback class Feedback
{ {
public string icon; public string icon;
public int32 level; public int32 level;
public Feedback (string _icon, int32 _level) public Feedback (string _icon, int32 _level)
{ {
icon = _icon; icon = _icon;
level = _level; level = _level;
} }
} }
static MediaFeedback? instance = null; static MediaFeedback? instance = null;
static ThreadPool<Feedback>? pool = null; static ThreadPool<Feedback>? pool = null;
public static void init () public static void init ()
{ {
if (instance == null) if (instance == null)
instance = new MediaFeedback (); instance = new MediaFeedback ();
} }
public static void send (string icon, int val) public static void send (string icon, int val)
requires (instance != null && pool != null) requires (instance != null && pool != null)
{ {
try { try {
pool.add (new Feedback (icon, val)); pool.add (new Feedback (icon, val));
} catch (ThreadError e) { } catch (ThreadError e) {
} }
} }
DBusConnection? connection = null; DBusConnection? connection = null;
DBusNotifications? notifications = null; DBusNotifications? notifications = null;
uint dbus_name_owner_changed_signal_id = 0; uint dbus_name_owner_changed_signal_id = 0;
uint32 notification_id = 0; uint32 notification_id = 0;
MediaFeedback () MediaFeedback ()
{ {
Object (); Object ();
} }
construct construct
{ {
try { try {
pool = new ThreadPool<Feedback>.with_owned_data ((ThreadPoolFunc<Feedback>) send_feedback, 1, false); pool = new ThreadPool<Feedback>.with_owned_data ((ThreadPoolFunc<Feedback>) send_feedback, 1, false);
} catch (ThreadError e) { } catch (ThreadError e) {
critical ("%s", e.message); critical ("%s", e.message);
pool = null; pool = null;
} }
try { try {
connection = Bus.get_sync (BusType.SESSION); connection = Bus.get_sync (BusType.SESSION);
dbus_name_owner_changed_signal_id = connection.signal_subscribe ("org.freedesktop.DBus", "org.freedesktop.DBus", dbus_name_owner_changed_signal_id = connection.signal_subscribe ("org.freedesktop.DBus", "org.freedesktop.DBus",
"NameOwnerChanged", "/org/freedesktop/DBus", null, DBusSignalFlags.NONE, (DBusSignalCallback) handle_name_owner_changed); "NameOwnerChanged", "/org/freedesktop/DBus", null, DBusSignalFlags.NONE, (DBusSignalCallback) handle_name_owner_changed);
} catch (IOError e) { } catch (IOError e) {
} }
} }
[CCode (instance_pos = -1)] [CCode (instance_pos = -1)]
void handle_name_owner_changed (DBusConnection connection, string sender_name, string object_path, void handle_name_owner_changed (DBusConnection connection, string sender_name, string object_path,
string interface_name, string signal_name, Variant parameters) string interface_name, string signal_name, Variant parameters)
{ {
string name, before, after; string name, before, after;
parameters.get ("(sss)", out name, out before, out after); parameters.get ("(sss)", out name, out before, out after);
if (name != "org.freedesktop.Notifications") if (name != "org.freedesktop.Notifications")
return; return;
if (after != "" && before == "") if (after != "" && before == "")
new Thread<void*> (null, () => { new Thread<void*> (null, () => {
lock (notifications) { lock (notifications) {
try { try {
notifications = connection.get_proxy_sync<DBusNotifications> ("org.freedesktop.Notifications", notifications = connection.get_proxy_sync<DBusNotifications> ("org.freedesktop.Notifications",
"/org/freedesktop/Notifications", DBusProxyFlags.NONE); "/org/freedesktop/Notifications", DBusProxyFlags.NONE);
} catch (Error e) { } catch (Error e) {
notifications = null; notifications = null;
} }
} }
return null; return null;
}); });
else if (before != "" && after == "") else if (before != "" && after == "")
lock (notifications) { lock (notifications) {
notifications = null; notifications = null;
} }
} }
[CCode (instance_pos = -1)] [CCode (instance_pos = -1)]
void send_feedback (owned Feedback feedback) void send_feedback (owned Feedback feedback)
{ {
var hints = new GLib.HashTable<string, Variant> (null, null); var hints = new GLib.HashTable<string, Variant> (null, null);
hints.set ("x-canonical-private-synchronous", new Variant.string ("gala-feedback")); hints.set ("x-canonical-private-synchronous", new Variant.string ("gala-feedback"));
hints.set ("value", new Variant.int32 (feedback.level)); hints.set ("value", new Variant.int32 (feedback.level));
try { try {
notification_id = notifications.notify ("gala-feedback", notification_id, feedback.icon, "", "", {}, hints, 2000); notification_id = notifications.notify ("gala-feedback", notification_id, feedback.icon, "", "", {}, hints, 2000);
} catch (Error e) { } catch (Error e) {
critical ("%s", e.message); critical ("%s", e.message);
} }
} }
} }
} }

View File

@ -17,217 +17,217 @@
namespace Gala namespace Gala
{ {
delegate PluginInfo RegisterPluginFunction (); delegate PluginInfo RegisterPluginFunction ();
public class PluginManager : Object public class PluginManager : Object
{ {
static PluginManager? instance = null; static PluginManager? instance = null;
public static unowned PluginManager get_default () public static unowned PluginManager get_default ()
{ {
if (instance == null) if (instance == null)
instance = new PluginManager (); instance = new PluginManager ();
return instance; return instance;
} }
public signal void regions_changed (); public signal void regions_changed ();
public bool initialized { get; private set; default = false; } public bool initialized { get; private set; default = false; }
public X.Xrectangle[] regions { get; private set; } public X.Xrectangle[] regions { get; private set; }
public string? window_switcher_provider { get; private set; default = null; } public string? window_switcher_provider { get; private set; default = null; }
public string? desktop_provider { get; private set; default = null; } public string? desktop_provider { get; private set; default = null; }
public string? window_overview_provider { get; private set; default = null; } public string? window_overview_provider { get; private set; default = null; }
public string? workspace_view_provider { get; private set; default = null; } public string? workspace_view_provider { get; private set; default = null; }
HashTable<string,Plugin> plugins; HashTable<string,Plugin> plugins;
File plugin_dir; File plugin_dir;
WindowManager? wm = null; WindowManager? wm = null;
Gee.LinkedList<PluginInfo?> load_later_plugins; Gee.LinkedList<PluginInfo?> load_later_plugins;
PluginManager () PluginManager ()
{ {
plugins = new HashTable<string,Plugin> (str_hash, str_equal); plugins = new HashTable<string,Plugin> (str_hash, str_equal);
load_later_plugins = new Gee.LinkedList<PluginInfo?> (); load_later_plugins = new Gee.LinkedList<PluginInfo?> ();
if (!Module.supported ()) { if (!Module.supported ()) {
warning ("Modules are not supported on this platform"); warning ("Modules are not supported on this platform");
return; return;
} }
plugin_dir = File.new_for_path (Config.PLUGINDIR); plugin_dir = File.new_for_path (Config.PLUGINDIR);
if (!plugin_dir.query_exists ()) if (!plugin_dir.query_exists ())
return; return;
try { try {
var enumerator = plugin_dir.enumerate_children (FileAttribute.STANDARD_NAME + var enumerator = plugin_dir.enumerate_children (FileAttribute.STANDARD_NAME +
"," + FileAttribute.STANDARD_CONTENT_TYPE, 0); "," + FileAttribute.STANDARD_CONTENT_TYPE, 0);
FileInfo info; FileInfo info;
while ((info = enumerator.next_file ()) != null) { while ((info = enumerator.next_file ()) != null) {
if (info.get_content_type () == "application/x-sharedlib") if (info.get_content_type () == "application/x-sharedlib")
load_module (info.get_name ()); load_module (info.get_name ());
} }
} catch (Error e) { } catch (Error e) {
warning (e.message); warning (e.message);
} }
try { try {
plugin_dir.monitor_directory (FileMonitorFlags.NONE, null).changed.connect ((file, other_file, type) => { plugin_dir.monitor_directory (FileMonitorFlags.NONE, null).changed.connect ((file, other_file, type) => {
if (type == FileMonitorEvent.CREATED) { if (type == FileMonitorEvent.CREATED) {
load_module (file.get_basename ()); load_module (file.get_basename ());
} }
}); });
} catch (Error e) { } catch (Error e) {
warning (e.message); warning (e.message);
} }
} }
bool load_module (string plugin_name) bool load_module (string plugin_name)
{ {
var path = Module.build_path (plugin_dir.get_path (), plugin_name); var path = Module.build_path (plugin_dir.get_path (), plugin_name);
var module = Module.open (path, ModuleFlags.BIND_LOCAL); var module = Module.open (path, ModuleFlags.BIND_LOCAL);
if (module == null) { if (module == null) {
warning (Module.error ()); warning (Module.error ());
return false; return false;
} }
void* function; void* function;
module.symbol ("register_plugin", out function); module.symbol ("register_plugin", out function);
if (function == null) { if (function == null) {
warning ("%s failed to register: register_plugin() function not found", plugin_name); warning ("%s failed to register: register_plugin() function not found", plugin_name);
return false; return false;
} }
unowned RegisterPluginFunction register = (RegisterPluginFunction)function; unowned RegisterPluginFunction register = (RegisterPluginFunction)function;
var info = register (); var info = register ();
if (info.plugin_type.is_a (typeof (Plugin)) == false) { if (info.plugin_type.is_a (typeof (Plugin)) == false) {
warning ("%s does not return a class of type Plugin", plugin_name); warning ("%s does not return a class of type Plugin", plugin_name);
return false; return false;
} }
if (!check_provides (info.name, info.provides)) { if (!check_provides (info.name, info.provides)) {
return false; return false;
} }
info.module_name = plugin_name; info.module_name = plugin_name;
module.make_resident (); module.make_resident ();
if (info.load_priority == LoadPriority.DEFERRED && !initialized) { if (info.load_priority == LoadPriority.DEFERRED && !initialized) {
load_later_plugins.add (info); load_later_plugins.add (info);
} else { } else {
load_plugin_class (info); load_plugin_class (info);
} }
return true; return true;
} }
void load_plugin_class (PluginInfo info) void load_plugin_class (PluginInfo info)
{ {
var plugin = (Plugin)Object.@new (info.plugin_type); var plugin = (Plugin)Object.@new (info.plugin_type);
plugins.set (info.module_name, plugin); plugins.set (info.module_name, plugin);
debug ("Loaded plugin %s (%s)", info.name, info.module_name); debug ("Loaded plugin %s (%s)", info.name, info.module_name);
if (initialized) { if (initialized) {
initialize_plugin (info.module_name, plugin); initialize_plugin (info.module_name, plugin);
recalculate_regions (); recalculate_regions ();
} }
} }
void initialize_plugin (string plugin_name, Plugin plugin) void initialize_plugin (string plugin_name, Plugin plugin)
{ {
plugin.initialize (wm); plugin.initialize (wm);
plugin.region_changed.connect (recalculate_regions); plugin.region_changed.connect (recalculate_regions);
} }
bool check_provides (string name, PluginFunction provides) bool check_provides (string name, PluginFunction provides)
{ {
var message = "Plugins %s and %s both provide %s functionality, using first one only"; var message = "Plugins %s and %s both provide %s functionality, using first one only";
switch (provides) { switch (provides) {
case PluginFunction.WORKSPACE_VIEW: case PluginFunction.WORKSPACE_VIEW:
if (workspace_view_provider != null) { if (workspace_view_provider != null) {
warning (message, workspace_view_provider, name, "workspace view"); warning (message, workspace_view_provider, name, "workspace view");
return false; return false;
} }
workspace_view_provider = name; workspace_view_provider = name;
return true; return true;
case PluginFunction.WINDOW_OVERVIEW: case PluginFunction.WINDOW_OVERVIEW:
if (window_overview_provider != null) { if (window_overview_provider != null) {
warning (message, window_overview_provider, name, "window overview"); warning (message, window_overview_provider, name, "window overview");
return false; return false;
} }
window_overview_provider = name; window_overview_provider = name;
return true; return true;
case PluginFunction.DESKTOP: case PluginFunction.DESKTOP:
if (desktop_provider != null) { if (desktop_provider != null) {
warning (message, desktop_provider, name, "desktop"); warning (message, desktop_provider, name, "desktop");
return false; return false;
} }
desktop_provider = name; desktop_provider = name;
return true; return true;
case PluginFunction.WINDOW_SWITCHER: case PluginFunction.WINDOW_SWITCHER:
if (window_switcher_provider != null) { if (window_switcher_provider != null) {
warning (message, window_switcher_provider, name, "window switcher"); warning (message, window_switcher_provider, name, "window switcher");
return false; return false;
} }
window_switcher_provider = name; window_switcher_provider = name;
return true; return true;
} }
return true; return true;
} }
public void initialize (WindowManager _wm) public void initialize (WindowManager _wm)
{ {
wm = _wm; wm = _wm;
plugins.@foreach (initialize_plugin); plugins.@foreach (initialize_plugin);
recalculate_regions (); recalculate_regions ();
initialized = true; initialized = true;
} }
public void load_waiting_plugins () public void load_waiting_plugins ()
{ {
foreach (var info in load_later_plugins) { foreach (var info in load_later_plugins) {
load_plugin_class (info); load_plugin_class (info);
} }
load_later_plugins.clear (); load_later_plugins.clear ();
} }
public Plugin? get_plugin (string id) public Plugin? get_plugin (string id)
{ {
return plugins.lookup (id); return plugins.lookup (id);
} }
/** /**
* Iterate over all plugins and grab their regions, update the regions * Iterate over all plugins and grab their regions, update the regions
* array accordingly and emit the regions_changed signal. * array accordingly and emit the regions_changed signal.
*/ */
void recalculate_regions () void recalculate_regions ()
{ {
X.Xrectangle[] regions = {}; X.Xrectangle[] regions = {};
plugins.@foreach ((name, plugin) => { plugins.@foreach ((name, plugin) => {
foreach (var region in plugin.region) { foreach (var region in plugin.region) {
X.Xrectangle rect = { X.Xrectangle rect = {
(short) region.x, (short) region.x,
(short) region.y, (short) region.y,
(ushort) region.width, (ushort) region.width,
(ushort) region.height (ushort) region.height
}; };
regions += rect; regions += rect;
} }
}); });
this.regions = regions; this.regions = regions;
regions_changed (); regions_changed ();
} }
} }
} }

View File

@ -17,11 +17,11 @@
namespace Gala namespace Gala
{ {
[DBus (name = "org.gnome.ScreenSaver")] [DBus (name = "org.gnome.ScreenSaver")]
public interface ScreenSaver : GLib.Object public interface ScreenSaver : GLib.Object
{ {
public abstract bool get_active () throws DBusError, IOError; public abstract bool get_active () throws DBusError, IOError;
public signal void active_changed (bool active); public signal void active_changed (bool active);
} }
} }

View File

@ -17,357 +17,357 @@
namespace Gala namespace Gala
{ {
const string EXTENSION = ".png"; const string EXTENSION = ".png";
const int UNCONCEAL_TEXT_TIMEOUT = 2000; const int UNCONCEAL_TEXT_TIMEOUT = 2000;
[DBus (name="org.gnome.Shell.Screenshot")] [DBus (name="org.gnome.Shell.Screenshot")]
public class ScreenshotManager : Object public class ScreenshotManager : Object
{ {
static ScreenshotManager? instance; static ScreenshotManager? instance;
[DBus (visible = false)] [DBus (visible = false)]
public static unowned ScreenshotManager init (WindowManager wm) public static unowned ScreenshotManager init (WindowManager wm)
{ {
if (instance == null) if (instance == null)
instance = new ScreenshotManager (wm); instance = new ScreenshotManager (wm);
return instance; return instance;
} }
WindowManager wm; WindowManager wm;
Settings desktop_settings; Settings desktop_settings;
string prev_font_regular; string prev_font_regular;
string prev_font_document; string prev_font_document;
string prev_font_mono; string prev_font_mono;
uint conceal_timeout; uint conceal_timeout;
construct { construct {
desktop_settings = new Settings ("org.gnome.desktop.interface"); desktop_settings = new Settings ("org.gnome.desktop.interface");
} }
ScreenshotManager (WindowManager _wm) ScreenshotManager (WindowManager _wm)
{ {
wm = _wm; wm = _wm;
} }
public void flash_area (int x, int y, int width, int height) throws DBusError, IOError public void flash_area (int x, int y, int width, int height) throws DBusError, IOError
{ {
debug ("Flashing area"); debug ("Flashing area");
double[] keyframes = { 0.3f, 0.8f }; double[] keyframes = { 0.3f, 0.8f };
GLib.Value[] values = { 180U, 0U }; GLib.Value[] values = { 180U, 0U };
var transition = new Clutter.KeyframeTransition ("opacity"); var transition = new Clutter.KeyframeTransition ("opacity");
transition.duration = 200; transition.duration = 200;
transition.remove_on_complete = true; transition.remove_on_complete = true;
transition.progress_mode = Clutter.AnimationMode.LINEAR; transition.progress_mode = Clutter.AnimationMode.LINEAR;
transition.set_key_frames (keyframes); transition.set_key_frames (keyframes);
transition.set_values (values); transition.set_values (values);
transition.set_to_value (0.0f); transition.set_to_value (0.0f);
var flash_actor = new Clutter.Actor (); var flash_actor = new Clutter.Actor ();
flash_actor.set_size (width, height); flash_actor.set_size (width, height);
flash_actor.set_position (x, y); flash_actor.set_position (x, y);
flash_actor.set_background_color (Clutter.Color.get_static (Clutter.StaticColor.WHITE)); flash_actor.set_background_color (Clutter.Color.get_static (Clutter.StaticColor.WHITE));
flash_actor.set_opacity (0); flash_actor.set_opacity (0);
flash_actor.transitions_completed.connect ((actor) => { flash_actor.transitions_completed.connect ((actor) => {
wm.top_window_group.remove_child (actor); wm.top_window_group.remove_child (actor);
actor.destroy (); actor.destroy ();
}); });
wm.top_window_group.add_child (flash_actor); wm.top_window_group.add_child (flash_actor);
flash_actor.add_transition ("flash", transition); flash_actor.add_transition ("flash", transition);
} }
public async void screenshot (bool include_cursor, bool flash, string filename, out bool success, out string filename_used) throws DBusError, IOError public async void screenshot (bool include_cursor, bool flash, string filename, out bool success, out string filename_used) throws DBusError, IOError
{ {
debug ("Taking screenshot"); debug ("Taking screenshot");
int width, height; int width, height;
#if HAS_MUTTER330 #if HAS_MUTTER330
wm.get_display ().get_size (out width, out height); wm.get_display ().get_size (out width, out height);
#else #else
wm.get_screen ().get_size (out width, out height); wm.get_screen ().get_size (out width, out height);
#endif #endif
var image = take_screenshot (0, 0, width, height, include_cursor); var image = take_screenshot (0, 0, width, height, include_cursor);
unconceal_text (); unconceal_text ();
if (flash) { if (flash) {
flash_area (0, 0, width, height); flash_area (0, 0, width, height);
} }
success = yield save_image (image, filename, out filename_used); success = yield save_image (image, filename, out filename_used);
} }
public async void screenshot_area (int x, int y, int width, int height, bool flash, string filename, out bool success, out string filename_used) throws DBusError, IOError public async void screenshot_area (int x, int y, int width, int height, bool flash, string filename, out bool success, out string filename_used) throws DBusError, IOError
{ {
yield screenshot_area_with_cursor (x, y, width, height, false, flash, filename, out success, out filename_used); yield screenshot_area_with_cursor (x, y, width, height, false, flash, filename, out success, out filename_used);
} }
public async void screenshot_area_with_cursor (int x, int y, int width, int height, bool include_cursor, bool flash, string filename, out bool success, out string filename_used) throws DBusError, IOError public async void screenshot_area_with_cursor (int x, int y, int width, int height, bool include_cursor, bool flash, string filename, out bool success, out string filename_used) throws DBusError, IOError
{ {
debug ("Taking area screenshot"); debug ("Taking area screenshot");
yield wait_stage_repaint (); yield wait_stage_repaint ();
var image = take_screenshot (x, y, width, height, include_cursor); var image = take_screenshot (x, y, width, height, include_cursor);
unconceal_text (); unconceal_text ();
if (flash) { if (flash) {
flash_area (x, y, width, height); flash_area (x, y, width, height);
} }
success = yield save_image (image, filename, out filename_used); success = yield save_image (image, filename, out filename_used);
if (!success) if (!success)
throw new DBusError.FAILED ("Failed to save image"); throw new DBusError.FAILED ("Failed to save image");
} }
public async void screenshot_window (bool include_frame, bool include_cursor, bool flash, string filename, out bool success, out string filename_used) throws DBusError, IOError public async void screenshot_window (bool include_frame, bool include_cursor, bool flash, string filename, out bool success, out string filename_used) throws DBusError, IOError
{ {
debug ("Taking window screenshot"); debug ("Taking window screenshot");
#if HAS_MUTTER330 #if HAS_MUTTER330
var window = wm.get_display ().get_focus_window (); var window = wm.get_display ().get_focus_window ();
#else #else
var window = wm.get_screen ().get_display ().get_focus_window (); var window = wm.get_screen ().get_display ().get_focus_window ();
#endif #endif
if (window == null) { if (window == null) {
unconceal_text (); unconceal_text ();
throw new DBusError.FAILED ("Cannot find active window"); throw new DBusError.FAILED ("Cannot find active window");
} }
var window_actor = (Meta.WindowActor) window.get_compositor_private (); var window_actor = (Meta.WindowActor) window.get_compositor_private ();
unowned Meta.ShapedTexture window_texture = (Meta.ShapedTexture) window_actor.get_texture (); unowned Meta.ShapedTexture window_texture = (Meta.ShapedTexture) window_actor.get_texture ();
float actor_x, actor_y; float actor_x, actor_y;
window_actor.get_position (out actor_x, out actor_y); window_actor.get_position (out actor_x, out actor_y);
var rect = window.get_frame_rect (); var rect = window.get_frame_rect ();
if (include_frame) { if (include_frame) {
rect = window.frame_rect_to_client_rect (rect); rect = window.frame_rect_to_client_rect (rect);
} }
Cairo.RectangleInt clip = { rect.x - (int) actor_x, rect.y - (int) actor_y, rect.width, rect.height }; Cairo.RectangleInt clip = { rect.x - (int) actor_x, rect.y - (int) actor_y, rect.width, rect.height };
var image = (Cairo.ImageSurface) window_texture.get_image (clip); var image = (Cairo.ImageSurface) window_texture.get_image (clip);
if (include_cursor) { if (include_cursor) {
image = composite_stage_cursor (image, { rect.x, rect.y, rect.width, rect.height }); image = composite_stage_cursor (image, { rect.x, rect.y, rect.width, rect.height });
} }
unconceal_text (); unconceal_text ();
if (flash) { if (flash) {
flash_area (rect.x, rect.y, rect.width, rect.height); flash_area (rect.x, rect.y, rect.width, rect.height);
} }
success = yield save_image (image, filename, out filename_used); success = yield save_image (image, filename, out filename_used);
} }
public async void select_area (out int x, out int y, out int width, out int height) throws DBusError, IOError public async void select_area (out int x, out int y, out int width, out int height) throws DBusError, IOError
{ {
var selection_area = new SelectionArea (wm); var selection_area = new SelectionArea (wm);
selection_area.closed.connect (() => Idle.add (select_area.callback)); selection_area.closed.connect (() => Idle.add (select_area.callback));
wm.ui_group.add (selection_area); wm.ui_group.add (selection_area);
selection_area.start_selection (); selection_area.start_selection ();
yield; yield;
selection_area.destroy (); selection_area.destroy ();
if (selection_area.cancelled) { if (selection_area.cancelled) {
throw new GLib.IOError.CANCELLED ("Operation was cancelled"); throw new GLib.IOError.CANCELLED ("Operation was cancelled");
} }
yield wait_stage_repaint (); yield wait_stage_repaint ();
selection_area.get_selection_rectangle (out x, out y, out width, out height); selection_area.get_selection_rectangle (out x, out y, out width, out height);
} }
private void unconceal_text () private void unconceal_text ()
{ {
if (conceal_timeout == 0) { if (conceal_timeout == 0) {
return; return;
} }
desktop_settings.set_string ("font-name", prev_font_regular); desktop_settings.set_string ("font-name", prev_font_regular);
desktop_settings.set_string ("monospace-font-name", prev_font_mono); desktop_settings.set_string ("monospace-font-name", prev_font_mono);
desktop_settings.set_string ("document-font-name", prev_font_document); desktop_settings.set_string ("document-font-name", prev_font_document);
Source.remove (conceal_timeout); Source.remove (conceal_timeout);
conceal_timeout = 0; conceal_timeout = 0;
} }
public async void conceal_text () throws DBusError, IOError public async void conceal_text () throws DBusError, IOError
{ {
if (conceal_timeout > 0) { if (conceal_timeout > 0) {
Source.remove (conceal_timeout); Source.remove (conceal_timeout);
} else { } else {
prev_font_regular = desktop_settings.get_string ("font-name"); prev_font_regular = desktop_settings.get_string ("font-name");
prev_font_mono = desktop_settings.get_string ("monospace-font-name"); prev_font_mono = desktop_settings.get_string ("monospace-font-name");
prev_font_document = desktop_settings.get_string ("document-font-name"); prev_font_document = desktop_settings.get_string ("document-font-name");
desktop_settings.set_string ("font-name", "Redacted Script Regular 9"); desktop_settings.set_string ("font-name", "Redacted Script Regular 9");
desktop_settings.set_string ("monospace-font-name", "Redacted Script Light 10"); desktop_settings.set_string ("monospace-font-name", "Redacted Script Light 10");
desktop_settings.set_string ("document-font-name", "Redacted Script Regular 10"); desktop_settings.set_string ("document-font-name", "Redacted Script Regular 10");
} }
conceal_timeout = Timeout.add (UNCONCEAL_TEXT_TIMEOUT, () => { conceal_timeout = Timeout.add (UNCONCEAL_TEXT_TIMEOUT, () => {
unconceal_text (); unconceal_text ();
return Source.REMOVE; return Source.REMOVE;
}); });
} }
static string find_target_path () static string find_target_path ()
{ {
// Try to create dedicated "Screenshots" subfolder in PICTURES xdg-dir // Try to create dedicated "Screenshots" subfolder in PICTURES xdg-dir
unowned string? base_path = Environment.get_user_special_dir (UserDirectory.PICTURES); unowned string? base_path = Environment.get_user_special_dir (UserDirectory.PICTURES);
if (base_path != null && FileUtils.test (base_path, FileTest.EXISTS)) { if (base_path != null && FileUtils.test (base_path, FileTest.EXISTS)) {
var path = Path.build_path (Path.DIR_SEPARATOR_S, base_path, _("Screenshots")); var path = Path.build_path (Path.DIR_SEPARATOR_S, base_path, _("Screenshots"));
if (FileUtils.test (path, FileTest.EXISTS)) { if (FileUtils.test (path, FileTest.EXISTS)) {
return path; return path;
} else if (DirUtils.create (path, 0755) == 0) { } else if (DirUtils.create (path, 0755) == 0) {
return path; return path;
} else { } else {
return base_path; return base_path;
} }
} }
return Environment.get_home_dir (); return Environment.get_home_dir ();
} }
static async bool save_image (Cairo.ImageSurface image, string filename, out string used_filename) static async bool save_image (Cairo.ImageSurface image, string filename, out string used_filename)
{ {
used_filename = filename; used_filename = filename;
// We only alter non absolute filename because absolute // We only alter non absolute filename because absolute
// filename is used for temp clipboard file and shouldn't be changed // filename is used for temp clipboard file and shouldn't be changed
if (!Path.is_absolute (used_filename)) { if (!Path.is_absolute (used_filename)) {
if (!used_filename.has_suffix (EXTENSION)) { if (!used_filename.has_suffix (EXTENSION)) {
used_filename = used_filename.concat (EXTENSION); used_filename = used_filename.concat (EXTENSION);
} }
var scale_factor = InternalUtils.get_ui_scaling_factor (); var scale_factor = InternalUtils.get_ui_scaling_factor ();
if (scale_factor > 1) { if (scale_factor > 1) {
var scale_pos = -EXTENSION.length; var scale_pos = -EXTENSION.length;
used_filename = used_filename.splice (scale_pos, scale_pos, "@%ix".printf (scale_factor)); used_filename = used_filename.splice (scale_pos, scale_pos, "@%ix".printf (scale_factor));
} }
var path = find_target_path (); var path = find_target_path ();
used_filename = Path.build_filename (path, used_filename, null); used_filename = Path.build_filename (path, used_filename, null);
} }
try { try {
var screenshot = Gdk.pixbuf_get_from_surface (image, 0, 0, image.get_width (), image.get_height ()); var screenshot = Gdk.pixbuf_get_from_surface (image, 0, 0, image.get_width (), image.get_height ());
var file = File.new_for_path (used_filename); var file = File.new_for_path (used_filename);
FileIOStream stream; FileIOStream stream;
if (file.query_exists ()) { if (file.query_exists ()) {
stream = yield file.open_readwrite_async (FileCreateFlags.NONE); stream = yield file.open_readwrite_async (FileCreateFlags.NONE);
} else { } else {
stream = yield file.create_readwrite_async (FileCreateFlags.NONE); stream = yield file.create_readwrite_async (FileCreateFlags.NONE);
} }
yield screenshot.save_to_stream_async (stream.output_stream, "png"); yield screenshot.save_to_stream_async (stream.output_stream, "png");
return true; return true;
} catch (GLib.Error e) { } catch (GLib.Error e) {
warning ("could not save file: %s", e.message); warning ("could not save file: %s", e.message);
return false; return false;
} }
} }
Cairo.ImageSurface take_screenshot (int x, int y, int width, int height, bool include_cursor) Cairo.ImageSurface take_screenshot (int x, int y, int width, int height, bool include_cursor)
{ {
Cairo.ImageSurface image; Cairo.ImageSurface image;
Clutter.Capture[] captures; Clutter.Capture[] captures;
wm.stage.capture (false, {x, y, width, height}, out captures); wm.stage.capture (false, {x, y, width, height}, out captures);
if (captures.length == 0) if (captures.length == 0)
image = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height); image = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
else if (captures.length == 1) else if (captures.length == 1)
image = captures[0].image; image = captures[0].image;
else else
image = composite_capture_images (captures, x, y, width, height); image = composite_capture_images (captures, x, y, width, height);
if (include_cursor) { if (include_cursor) {
image = composite_stage_cursor (image, { x, y, width, height}); image = composite_stage_cursor (image, { x, y, width, height});
} }
image.mark_dirty (); image.mark_dirty ();
return image; return image;
} }
Cairo.ImageSurface composite_capture_images (Clutter.Capture[] captures, int x, int y, int width, int height) Cairo.ImageSurface composite_capture_images (Clutter.Capture[] captures, int x, int y, int width, int height)
{ {
var image = new Cairo.ImageSurface (captures[0].image.get_format (), width, height); var image = new Cairo.ImageSurface (captures[0].image.get_format (), width, height);
var cr = new Cairo.Context (image); var cr = new Cairo.Context (image);
foreach (unowned Clutter.Capture capture in captures) { foreach (unowned Clutter.Capture capture in captures) {
// Ignore capture regions with scale other than 1 for now; mutter can't // Ignore capture regions with scale other than 1 for now; mutter can't
// produce them yet, so there is no way to test them. // produce them yet, so there is no way to test them.
double capture_scale = 1.0; double capture_scale = 1.0;
capture.image.get_device_scale (out capture_scale, null); capture.image.get_device_scale (out capture_scale, null);
if (capture_scale != 1.0) if (capture_scale != 1.0)
continue; continue;
cr.save (); cr.save ();
cr.translate (capture.rect.x - x, capture.rect.y - y); cr.translate (capture.rect.x - x, capture.rect.y - y);
cr.set_source_surface (capture.image, 0, 0); cr.set_source_surface (capture.image, 0, 0);
cr.restore (); cr.restore ();
} }
return image; return image;
} }
Cairo.ImageSurface composite_stage_cursor (Cairo.ImageSurface image, Cairo.RectangleInt image_rect) Cairo.ImageSurface composite_stage_cursor (Cairo.ImageSurface image, Cairo.RectangleInt image_rect)
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.CursorTracker cursor_tracker = wm.get_display ().get_cursor_tracker (); unowned Meta.CursorTracker cursor_tracker = wm.get_display ().get_cursor_tracker ();
#else #else
unowned Meta.CursorTracker cursor_tracker = wm.get_screen ().get_cursor_tracker (); unowned Meta.CursorTracker cursor_tracker = wm.get_screen ().get_cursor_tracker ();
#endif #endif
int x, y; int x, y;
cursor_tracker.get_pointer (out x, out y, null); cursor_tracker.get_pointer (out x, out y, null);
var region = new Cairo.Region.rectangle (image_rect); var region = new Cairo.Region.rectangle (image_rect);
if (!region.contains_point (x, y)) { if (!region.contains_point (x, y)) {
return image; return image;
} }
unowned Cogl.Texture texture = cursor_tracker.get_sprite (); unowned Cogl.Texture texture = cursor_tracker.get_sprite ();
if (texture == null) { if (texture == null) {
return image; return image;
} }
int width = (int)texture.get_width (); int width = (int)texture.get_width ();
int height = (int)texture.get_height (); int height = (int)texture.get_height ();
uint8[] data = new uint8[width * height * 4]; uint8[] data = new uint8[width * height * 4];
CoglFixes.texture_get_data (texture, Cogl.PixelFormat.RGBA_8888, 0, data); CoglFixes.texture_get_data (texture, Cogl.PixelFormat.RGBA_8888, 0, data);
var cursor_image = new Cairo.ImageSurface.for_data (data, Cairo.Format.ARGB32, width, height, width * 4); var cursor_image = new Cairo.ImageSurface.for_data (data, Cairo.Format.ARGB32, width, height, width * 4);
var target = new Cairo.ImageSurface (Cairo.Format.ARGB32, image_rect.width, image_rect.height); var target = new Cairo.ImageSurface (Cairo.Format.ARGB32, image_rect.width, image_rect.height);
var cr = new Cairo.Context (target); var cr = new Cairo.Context (target);
cr.set_operator (Cairo.Operator.OVER); cr.set_operator (Cairo.Operator.OVER);
cr.set_source_surface (image, 0, 0); cr.set_source_surface (image, 0, 0);
cr.paint (); cr.paint ();
cr.set_operator (Cairo.Operator.OVER); cr.set_operator (Cairo.Operator.OVER);
cr.set_source_surface (cursor_image, x - image_rect.x, y - image_rect.y); cr.set_source_surface (cursor_image, x - image_rect.x, y - image_rect.y);
cr.paint (); cr.paint ();
return (Cairo.ImageSurface)cr.get_target (); return (Cairo.ImageSurface)cr.get_target ();
} }
async void wait_stage_repaint () async void wait_stage_repaint ()
{ {
ulong signal_id = 0UL; ulong signal_id = 0UL;
signal_id = wm.stage.paint.connect_after (() => { signal_id = wm.stage.paint.connect_after (() => {
wm.stage.disconnect (signal_id); wm.stage.disconnect (signal_id);
Idle.add (wait_stage_repaint.callback); Idle.add (wait_stage_repaint.callback);
}); });
wm.stage.queue_redraw (); wm.stage.queue_redraw ();
yield; yield;
} }
} }
} }

View File

@ -20,82 +20,82 @@
namespace Gala namespace Gala
{ {
[DBus (name = "io.elementary.wingpanel.session.EndSessionDialog")] [DBus (name = "io.elementary.wingpanel.session.EndSessionDialog")]
public interface WingpanelEndSessionDialog : Object public interface WingpanelEndSessionDialog : Object
{ {
public signal void confirmed_logout (); public signal void confirmed_logout ();
public signal void confirmed_reboot (); public signal void confirmed_reboot ();
public signal void confirmed_shutdown (); public signal void confirmed_shutdown ();
public signal void canceled (); public signal void canceled ();
public signal void closed (); public signal void closed ();
public abstract void open (uint type, uint timestamp, uint open_length, ObjectPath[] inhibiters) throws DBusError, IOError; public abstract void open (uint type, uint timestamp, uint open_length, ObjectPath[] inhibiters) throws DBusError, IOError;
} }
[DBus (name = "org.gnome.SessionManager.EndSessionDialog")] [DBus (name = "org.gnome.SessionManager.EndSessionDialog")]
public class SessionManager : Object public class SessionManager : Object
{ {
static SessionManager? instance; static SessionManager? instance;
[DBus (visible = false)] [DBus (visible = false)]
public static unowned SessionManager init () public static unowned SessionManager init ()
{ {
if (instance == null) { if (instance == null) {
instance = new SessionManager (); instance = new SessionManager ();
} }
return instance; return instance;
} }
public signal void confirmed_logout (); public signal void confirmed_logout ();
public signal void confirmed_reboot (); public signal void confirmed_reboot ();
public signal void confirmed_shutdown (); public signal void confirmed_shutdown ();
public signal void canceled (); public signal void canceled ();
public signal void closed (); public signal void closed ();
WingpanelEndSessionDialog? proxy = null; WingpanelEndSessionDialog? proxy = null;
SessionManager () SessionManager ()
{ {
Bus.watch_name (BusType.SESSION, "io.elementary.wingpanel.session.EndSessionDialog", Bus.watch_name (BusType.SESSION, "io.elementary.wingpanel.session.EndSessionDialog",
BusNameWatcherFlags.NONE, proxy_appeared, proxy_vanished); BusNameWatcherFlags.NONE, proxy_appeared, proxy_vanished);
} }
void get_proxy_cb (Object? o, AsyncResult? res) void get_proxy_cb (Object? o, AsyncResult? res)
{ {
try { try {
proxy = Bus.get_proxy.end (res); proxy = Bus.get_proxy.end (res);
} catch (Error e) { } catch (Error e) {
warning ("Could not connect to io.elementary.wingpanel.session.EndSessionDialog proxy: %s", e.message); warning ("Could not connect to io.elementary.wingpanel.session.EndSessionDialog proxy: %s", e.message);
return; return;
} }
proxy.confirmed_logout.connect (() => confirmed_logout ()); proxy.confirmed_logout.connect (() => confirmed_logout ());
proxy.confirmed_reboot.connect (() => confirmed_reboot ()); proxy.confirmed_reboot.connect (() => confirmed_reboot ());
proxy.confirmed_shutdown.connect (() => confirmed_shutdown ()); proxy.confirmed_shutdown.connect (() => confirmed_shutdown ());
proxy.canceled.connect (() => canceled ()); proxy.canceled.connect (() => canceled ());
proxy.closed.connect (() => closed ()); proxy.closed.connect (() => closed ());
} }
void proxy_appeared () void proxy_appeared ()
{ {
Bus.get_proxy.begin<WingpanelEndSessionDialog> (BusType.SESSION, Bus.get_proxy.begin<WingpanelEndSessionDialog> (BusType.SESSION,
"io.elementary.wingpanel.session.EndSessionDialog", "/io/elementary/wingpanel/session/EndSessionDialog", "io.elementary.wingpanel.session.EndSessionDialog", "/io/elementary/wingpanel/session/EndSessionDialog",
0, null, get_proxy_cb); 0, null, get_proxy_cb);
} }
void proxy_vanished () void proxy_vanished ()
{ {
proxy = null; proxy = null;
} }
public void open (uint type, uint timestamp, uint open_length, ObjectPath[] inhibiters) throws DBusError, IOError public void open (uint type, uint timestamp, uint open_length, ObjectPath[] inhibiters) throws DBusError, IOError
{ {
if (proxy == null) { if (proxy == null) {
throw new DBusError.FAILED ("io.elementary.wingpanel.session.EndSessionDialog DBus interface is not registered."); throw new DBusError.FAILED ("io.elementary.wingpanel.session.EndSessionDialog DBus interface is not registered.");
} }
proxy.open (type, timestamp, open_length, inhibiters); proxy.open (type, timestamp, open_length, inhibiters);
} }
} }
} }

View File

@ -17,139 +17,139 @@
namespace Gala namespace Gala
{ {
public class BehaviorSettings : Granite.Services.Settings public class BehaviorSettings : Granite.Services.Settings
{ {
public bool dynamic_workspaces { get; set; } public bool dynamic_workspaces { get; set; }
public bool edge_tiling { get; set; } public bool edge_tiling { get; set; }
public string panel_main_menu_action { get; set; } public string panel_main_menu_action { get; set; }
public string toggle_recording_action { get; set; } public string toggle_recording_action { get; set; }
public string overlay_action { get; set; } public string overlay_action { get; set; }
public string hotcorner_custom_command { get; set; } public string hotcorner_custom_command { get; set; }
public string[] dock_names { get; set; } public string[] dock_names { get; set; }
public bool move_maximized_workspace { get; set; } public bool move_maximized_workspace { get; set; }
public WindowOverviewType window_overview_type { get; set; } public WindowOverviewType window_overview_type { get; set; }
public ActionType hotcorner_topleft { get; set; } public ActionType hotcorner_topleft { get; set; }
public ActionType hotcorner_topright { get; set; } public ActionType hotcorner_topright { get; set; }
public ActionType hotcorner_bottomleft { get; set; } public ActionType hotcorner_bottomleft { get; set; }
public ActionType hotcorner_bottomright { get; set; } public ActionType hotcorner_bottomright { get; set; }
static BehaviorSettings? instance = null; static BehaviorSettings? instance = null;
private BehaviorSettings () private BehaviorSettings ()
{ {
base (Config.SCHEMA + ".behavior"); base (Config.SCHEMA + ".behavior");
} }
public static unowned BehaviorSettings get_default () public static unowned BehaviorSettings get_default ()
{ {
if (instance == null) if (instance == null)
instance = new BehaviorSettings (); instance = new BehaviorSettings ();
return instance; return instance;
} }
} }
public class KeybindingSettings : Granite.Services.Settings public class KeybindingSettings : Granite.Services.Settings
{ {
static KeybindingSettings? instance = null; static KeybindingSettings? instance = null;
private KeybindingSettings () private KeybindingSettings ()
{ {
base (Config.SCHEMA + ".keybindings"); base (Config.SCHEMA + ".keybindings");
} }
public static unowned KeybindingSettings get_default () public static unowned KeybindingSettings get_default ()
{ {
if (instance == null) if (instance == null)
instance = new KeybindingSettings (); instance = new KeybindingSettings ();
return instance; return instance;
} }
} }
public class AppearanceSettings : Granite.Services.Settings public class AppearanceSettings : Granite.Services.Settings
{ {
public string button_layout { get; set; } public string button_layout { get; set; }
public bool attach_modal_dialogs { get; set; } public bool attach_modal_dialogs { get; set; }
public bool dim_parents { get; set; } public bool dim_parents { get; set; }
public string workspace_switcher_background { get; set; } public string workspace_switcher_background { get; set; }
static AppearanceSettings? instance = null; static AppearanceSettings? instance = null;
private AppearanceSettings () private AppearanceSettings ()
{ {
base (Config.SCHEMA + ".appearance"); base (Config.SCHEMA + ".appearance");
} }
public static unowned AppearanceSettings get_default () public static unowned AppearanceSettings get_default ()
{ {
if (instance == null) if (instance == null)
instance = new AppearanceSettings (); instance = new AppearanceSettings ();
return instance; return instance;
} }
} }
public class ShadowSettings : Granite.Services.Settings public class ShadowSettings : Granite.Services.Settings
{ {
public string[] menu { get; set; } public string[] menu { get; set; }
public string[] normal_focused { get; set; } public string[] normal_focused { get; set; }
public string[] normal_unfocused { get; set; } public string[] normal_unfocused { get; set; }
public string[] dialog_focused { get; set; } public string[] dialog_focused { get; set; }
public string[] dialog_unfocused { get; set; } public string[] dialog_unfocused { get; set; }
static ShadowSettings? instance = null; static ShadowSettings? instance = null;
private ShadowSettings () private ShadowSettings ()
{ {
base (Config.SCHEMA + ".shadows"); base (Config.SCHEMA + ".shadows");
} }
public static unowned ShadowSettings get_default () public static unowned ShadowSettings get_default ()
{ {
if (instance == null) if (instance == null)
instance = new ShadowSettings (); instance = new ShadowSettings ();
return instance; return instance;
} }
public Meta.ShadowParams get_shadowparams (string class_name) public Meta.ShadowParams get_shadowparams (string class_name)
{ {
string[] val; string[] val;
get (class_name, out val); get (class_name, out val);
if (val == null || int.parse (val[0]) < 1) if (val == null || int.parse (val[0]) < 1)
return Meta.ShadowParams () {radius = 1, top_fade = 0, x_offset = 0, y_offset = 0, opacity = 0}; return Meta.ShadowParams () {radius = 1, top_fade = 0, x_offset = 0, y_offset = 0, opacity = 0};
return Meta.ShadowParams () {radius = int.parse (val[0]), top_fade = int.parse (val[1]), return Meta.ShadowParams () {radius = int.parse (val[0]), top_fade = int.parse (val[1]),
x_offset = int.parse (val[2]), y_offset = int.parse (val[3]), opacity = (uint8)int.parse (val[4])}; x_offset = int.parse (val[2]), y_offset = int.parse (val[3]), opacity = (uint8)int.parse (val[4])};
} }
} }
public class BackgroundSettings : Granite.Services.Settings public class BackgroundSettings : Granite.Services.Settings
{ {
public string picture_options { get; set; } public string picture_options { get; set; }
public string picture_uri { get; set; } public string picture_uri { get; set; }
public int picture_opacity { get; set; } public int picture_opacity { get; set; }
public string primary_color { get; set; } public string primary_color { get; set; }
public string secondary_color { get; set; } public string secondary_color { get; set; }
public string color_shading_type { get; set; } public string color_shading_type { get; set; }
static BackgroundSettings? instance = null; static BackgroundSettings? instance = null;
private BackgroundSettings () private BackgroundSettings ()
{ {
base ("org.gnome.desktop.background"); base ("org.gnome.desktop.background");
} }
public static unowned BackgroundSettings get_default () public static unowned BackgroundSettings get_default ()
{ {
if (instance == null) if (instance == null)
instance = new BackgroundSettings (); instance = new BackgroundSettings ();
return instance; return instance;
} }
} }
} }

View File

@ -19,150 +19,150 @@ using Clutter;
namespace Gala namespace Gala
{ {
public class ShadowEffect : Effect public class ShadowEffect : Effect
{ {
private class Shadow private class Shadow
{ {
public int users; public int users;
public Cogl.Texture texture; public Cogl.Texture texture;
public Shadow (Cogl.Texture _texture) public Shadow (Cogl.Texture _texture)
{ {
texture = _texture; texture = _texture;
users = 1; users = 1;
} }
} }
// the sizes of the textures often repeat, especially for the background actor // the sizes of the textures often repeat, especially for the background actor
// so we keep a cache to avoid creating the same texture all over again. // so we keep a cache to avoid creating the same texture all over again.
static Gee.HashMap<string,Shadow> shadow_cache; static Gee.HashMap<string,Shadow> shadow_cache;
static Gtk.StyleContext style_context; static Gtk.StyleContext style_context;
class construct class construct
{ {
shadow_cache = new Gee.HashMap<string,Shadow> (); shadow_cache = new Gee.HashMap<string,Shadow> ();
var style_path = new Gtk.WidgetPath (); var style_path = new Gtk.WidgetPath ();
var id = style_path.append_type (typeof (Gtk.Window)); var id = style_path.append_type (typeof (Gtk.Window));
style_context = new Gtk.StyleContext (); style_context = new Gtk.StyleContext ();
style_context.add_provider (Gala.Utils.get_gala_css (), Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK); style_context.add_provider (Gala.Utils.get_gala_css (), Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK);
style_context.add_class ("decoration"); style_context.add_class ("decoration");
style_context.set_path (style_path); style_context.set_path (style_path);
} }
public int shadow_size { get; construct; } public int shadow_size { get; construct; }
public int shadow_spread { get; construct; } public int shadow_spread { get; construct; }
public float scale_factor { get; set; default = 1; } public float scale_factor { get; set; default = 1; }
public uint8 shadow_opacity { get; set; default = 255; } public uint8 shadow_opacity { get; set; default = 255; }
public string? css_class { get; set; default = null; } public string? css_class { get; set; default = null; }
Cogl.Material material; Cogl.Material material;
string? current_key = null; string? current_key = null;
public ShadowEffect (int shadow_size, int shadow_spread) public ShadowEffect (int shadow_size, int shadow_spread)
{ {
Object (shadow_size: shadow_size, shadow_spread: shadow_spread); Object (shadow_size: shadow_size, shadow_spread: shadow_spread);
} }
construct construct
{ {
material = new Cogl.Material (); material = new Cogl.Material ();
} }
~ShadowEffect () ~ShadowEffect ()
{ {
if (current_key != null) if (current_key != null)
decrement_shadow_users (current_key); decrement_shadow_users (current_key);
} }
Cogl.Texture? get_shadow (int width, int height, int shadow_size, int shadow_spread) Cogl.Texture? get_shadow (int width, int height, int shadow_size, int shadow_spread)
{ {
var old_key = current_key; var old_key = current_key;
current_key = "%ix%i:%i:%i".printf (width, height, shadow_size, shadow_spread); current_key = "%ix%i:%i:%i".printf (width, height, shadow_size, shadow_spread);
if (old_key == current_key) if (old_key == current_key)
return null; return null;
if (old_key != null) if (old_key != null)
decrement_shadow_users (old_key); decrement_shadow_users (old_key);
Shadow? shadow = null; Shadow? shadow = null;
if ((shadow = shadow_cache.@get (current_key)) != null) { if ((shadow = shadow_cache.@get (current_key)) != null) {
shadow.users++; shadow.users++;
return shadow.texture; return shadow.texture;
} }
var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height); var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
var cr = new Cairo.Context (surface); var cr = new Cairo.Context (surface);
cr.set_source_rgba (0, 0, 0, 0); cr.set_source_rgba (0, 0, 0, 0);
cr.fill (); cr.fill ();
cr.set_operator (Cairo.Operator.OVER); cr.set_operator (Cairo.Operator.OVER);
cr.save (); cr.save ();
cr.scale (scale_factor, scale_factor); cr.scale (scale_factor, scale_factor);
style_context.save (); style_context.save ();
if (css_class != null) { if (css_class != null) {
style_context.add_class (css_class); style_context.add_class (css_class);
} }
style_context.set_scale ((int)scale_factor); style_context.set_scale ((int)scale_factor);
style_context.render_background (cr, shadow_size, shadow_size, width - shadow_size * 2, height - shadow_size * 2); style_context.render_background (cr, shadow_size, shadow_size, width - shadow_size * 2, height - shadow_size * 2);
style_context.restore (); style_context.restore ();
cr.restore (); cr.restore ();
cr.paint (); cr.paint ();
var texture = new Cogl.Texture.from_data (width, height, 0, Cogl.PixelFormat.BGRA_8888_PRE, var texture = new Cogl.Texture.from_data (width, height, 0, Cogl.PixelFormat.BGRA_8888_PRE,
Cogl.PixelFormat.ANY, surface.get_stride (), surface.get_data ()); Cogl.PixelFormat.ANY, surface.get_stride (), surface.get_data ());
shadow_cache.@set (current_key, new Shadow (texture)); shadow_cache.@set (current_key, new Shadow (texture));
return texture; return texture;
} }
void decrement_shadow_users (string key) void decrement_shadow_users (string key)
{ {
var shadow = shadow_cache.@get (key); var shadow = shadow_cache.@get (key);
if (shadow == null) if (shadow == null)
return; return;
if (--shadow.users == 0) if (--shadow.users == 0)
shadow_cache.unset (key); shadow_cache.unset (key);
} }
public override void paint (EffectPaintFlags flags) public override void paint (EffectPaintFlags flags)
{ {
var bounding_box = get_bounding_box (); var bounding_box = get_bounding_box ();
var width = (int) (bounding_box.x2 - bounding_box.x1); var width = (int) (bounding_box.x2 - bounding_box.x1);
var height = (int) (bounding_box.y2 - bounding_box.y1); var height = (int) (bounding_box.y2 - bounding_box.y1);
var shadow = get_shadow (width, height, shadow_size, shadow_spread); var shadow = get_shadow (width, height, shadow_size, shadow_spread);
if (shadow != null) if (shadow != null)
material.set_layer (0, shadow); material.set_layer (0, shadow);
var opacity = actor.get_paint_opacity () * shadow_opacity / 255; var opacity = actor.get_paint_opacity () * shadow_opacity / 255;
var alpha = Cogl.Color.from_4ub (255, 255, 255, opacity); var alpha = Cogl.Color.from_4ub (255, 255, 255, opacity);
alpha.premultiply (); alpha.premultiply ();
material.set_color (alpha); material.set_color (alpha);
Cogl.set_source (material); Cogl.set_source (material);
Cogl.rectangle (bounding_box.x1, bounding_box.y1, bounding_box.x2, bounding_box.y2); Cogl.rectangle (bounding_box.x1, bounding_box.y1, bounding_box.x2, bounding_box.y2);
actor.continue_paint (); actor.continue_paint ();
} }
public virtual ActorBox get_bounding_box () public virtual ActorBox get_bounding_box ()
{ {
var size = shadow_size * scale_factor; var size = shadow_size * scale_factor;
var bounding_box = ActorBox (); var bounding_box = ActorBox ();
bounding_box.set_origin (-size, -size); bounding_box.set_origin (-size, -size);
bounding_box.set_size (actor.width + size * 2, actor.height + size * 2); bounding_box.set_size (actor.width + size * 2, actor.height + size * 2);
return bounding_box; return bounding_box;
} }
} }
} }

View File

@ -17,46 +17,46 @@
namespace Gala namespace Gala
{ {
public class TextShadowEffect : Clutter.Effect public class TextShadowEffect : Clutter.Effect
{ {
int _offset_y; int _offset_y;
public int offset_y { public int offset_y {
get { return _offset_y; } get { return _offset_y; }
set { _offset_y = value; update (); } set { _offset_y = value; update (); }
} }
int _offset_x; int _offset_x;
public int offset_x { public int offset_x {
get { return _offset_x; } get { return _offset_x; }
set { _offset_x = value; update (); } set { _offset_x = value; update (); }
} }
uint8 _opacity; uint8 _opacity;
public uint8 opacity { public uint8 opacity {
get { return _opacity; } get { return _opacity; }
set { _opacity = value; update (); } set { _opacity = value; update (); }
} }
public TextShadowEffect (int offset_x, int offset_y, uint8 opacity) public TextShadowEffect (int offset_x, int offset_y, uint8 opacity)
{ {
_offset_x = offset_x; _offset_x = offset_x;
_offset_y = offset_y; _offset_y = offset_y;
_opacity = opacity; _opacity = opacity;
} }
public override bool pre_paint () public override bool pre_paint ()
{ {
var layout = ((Clutter.Text)get_actor ()).get_layout (); var layout = ((Clutter.Text)get_actor ()).get_layout ();
Cogl.pango_render_layout (layout, offset_x, offset_y, Cogl.Color.from_4ub (0, 0, 0, opacity), 0); Cogl.pango_render_layout (layout, offset_x, offset_y, Cogl.Color.from_4ub (0, 0, 0, opacity), 0);
return true; return true;
} }
public void update () public void update ()
{ {
if (get_actor () != null) if (get_actor () != null)
get_actor ().queue_redraw (); get_actor ().queue_redraw ();
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -20,146 +20,146 @@ using Meta;
namespace Gala namespace Gala
{ {
/** /**
* This class contains the icon groups at the bottom and will take * This class contains the icon groups at the bottom and will take
* care of displaying actors for inserting windows between the groups * care of displaying actors for inserting windows between the groups
* once implemented * once implemented
*/ */
public class IconGroupContainer : Actor public class IconGroupContainer : Actor
{ {
public const int SPACING = 48; public const int SPACING = 48;
public const int GROUP_WIDTH = 64; public const int GROUP_WIDTH = 64;
public signal void request_reposition (bool animate); public signal void request_reposition (bool animate);
#if HAS_MUTTER330 #if HAS_MUTTER330
public Meta.Display display { get; construct; } public Meta.Display display { get; construct; }
#else #else
public Screen screen { get; construct; } public Screen screen { get; construct; }
#endif #endif
#if HAS_MUTTER330 #if HAS_MUTTER330
public IconGroupContainer (Meta.Display display) public IconGroupContainer (Meta.Display display)
{ {
Object (display: display); Object (display: display);
layout_manager = new BoxLayout (); layout_manager = new BoxLayout ();
} }
#else #else
public IconGroupContainer (Screen screen) public IconGroupContainer (Screen screen)
{ {
Object (screen: screen); Object (screen: screen);
layout_manager = new BoxLayout (); layout_manager = new BoxLayout ();
} }
#endif #endif
public void add_group (IconGroup group) public void add_group (IconGroup group)
{ {
var index = group.workspace.index (); var index = group.workspace.index ();
insert_child_at_index (group, index * 2); insert_child_at_index (group, index * 2);
var thumb = new WorkspaceInsertThumb (index); var thumb = new WorkspaceInsertThumb (index);
thumb.notify["expanded"].connect_after (expanded_changed); thumb.notify["expanded"].connect_after (expanded_changed);
insert_child_at_index (thumb, index * 2); insert_child_at_index (thumb, index * 2);
update_inserter_indices (); update_inserter_indices ();
} }
public void remove_group (IconGroup group) public void remove_group (IconGroup group)
{ {
var thumb = (WorkspaceInsertThumb) group.get_previous_sibling (); var thumb = (WorkspaceInsertThumb) group.get_previous_sibling ();
thumb.notify["expanded"].disconnect (expanded_changed); thumb.notify["expanded"].disconnect (expanded_changed);
remove_child (thumb); remove_child (thumb);
remove_child (group); remove_child (group);
update_inserter_indices (); update_inserter_indices ();
} }
/** /**
* Removes an icon group "in place". * Removes an icon group "in place".
* When initially dragging an icon group we remove * When initially dragging an icon group we remove
* it and it's previous WorkspaceInsertThumb. This would make * it and it's previous WorkspaceInsertThumb. This would make
* the container immediately reallocate and fill the empty space * the container immediately reallocate and fill the empty space
* with right-most IconGroups. * with right-most IconGroups.
* *
* We don't want that until the IconGroup * We don't want that until the IconGroup
* leaves the expanded WorkspaceInsertThumb. * leaves the expanded WorkspaceInsertThumb.
*/ */
public void remove_group_in_place (IconGroup group) public void remove_group_in_place (IconGroup group)
{ {
var deleted_thumb = (WorkspaceInsertThumb) group.get_previous_sibling (); var deleted_thumb = (WorkspaceInsertThumb) group.get_previous_sibling ();
var deleted_placeholder_thumb = (WorkspaceInsertThumb) group.get_next_sibling (); var deleted_placeholder_thumb = (WorkspaceInsertThumb) group.get_next_sibling ();
remove_group (group); remove_group (group);
/** /**
* We will account for that empty space * We will account for that empty space
* by manually expanding the next WorkspaceInsertThumb with the * by manually expanding the next WorkspaceInsertThumb with the
* width we deleted. Because the IconGroup is still hovering over * width we deleted. Because the IconGroup is still hovering over
* the expanded thumb, we will also update the drag & drop action * the expanded thumb, we will also update the drag & drop action
* of IconGroup on that. * of IconGroup on that.
*/ */
float deleted_width = deleted_thumb.get_width () + group.get_width (); float deleted_width = deleted_thumb.get_width () + group.get_width ();
deleted_placeholder_thumb.expanded = true; deleted_placeholder_thumb.expanded = true;
deleted_placeholder_thumb.width += deleted_width; deleted_placeholder_thumb.width += deleted_width;
group.set_hovered_actor (deleted_placeholder_thumb); group.set_hovered_actor (deleted_placeholder_thumb);
} }
public void reset_thumbs (int delay) public void reset_thumbs (int delay)
{ {
foreach (var child in get_children ()) { foreach (var child in get_children ()) {
unowned WorkspaceInsertThumb thumb = child as WorkspaceInsertThumb; unowned WorkspaceInsertThumb thumb = child as WorkspaceInsertThumb;
if (thumb != null) { if (thumb != null) {
thumb.delay = delay; thumb.delay = delay;
thumb.destroy_all_children (); thumb.destroy_all_children ();
} }
} }
} }
void expanded_changed (ParamSpec param) void expanded_changed (ParamSpec param)
{ {
request_reposition (true); request_reposition (true);
} }
/** /**
* Calculates the width that will be occupied taking currently running animations * Calculates the width that will be occupied taking currently running animations
* end states into account * end states into account
*/ */
public float calculate_total_width () public float calculate_total_width ()
{ {
var scale = InternalUtils.get_ui_scaling_factor (); var scale = InternalUtils.get_ui_scaling_factor ();
var spacing = SPACING * scale; var spacing = SPACING * scale;
var group_width = GROUP_WIDTH * scale; var group_width = GROUP_WIDTH * scale;
var width = 0.0f; var width = 0.0f;
foreach (var child in get_children ()) { foreach (var child in get_children ()) {
if (child is WorkspaceInsertThumb) { if (child is WorkspaceInsertThumb) {
if (((WorkspaceInsertThumb) child).expanded) if (((WorkspaceInsertThumb) child).expanded)
width += group_width + spacing * 2; width += group_width + spacing * 2;
else else
width += spacing; width += spacing;
} else } else
width += group_width; width += group_width;
} }
width += spacing; width += spacing;
return width; return width;
} }
void update_inserter_indices () void update_inserter_indices ()
{ {
var current_index = 0; var current_index = 0;
foreach (var child in get_children ()) { foreach (var child in get_children ()) {
unowned WorkspaceInsertThumb thumb = child as WorkspaceInsertThumb; unowned WorkspaceInsertThumb thumb = child as WorkspaceInsertThumb;
if (thumb != null) { if (thumb != null) {
thumb.workspace_index = current_index++; thumb.workspace_index = current_index++;
} }
} }
} }
} }
} }

View File

@ -20,150 +20,150 @@ using Meta;
namespace Gala namespace Gala
{ {
/** /**
* More or less utility class to contain a WindowCloneContainer for each * More or less utility class to contain a WindowCloneContainer for each
* non-primary monitor. It's the pendant to the WorkspaceClone which is * non-primary monitor. It's the pendant to the WorkspaceClone which is
* only placed on the primary monitor. It also draws a wallpaper behind itself * only placed on the primary monitor. It also draws a wallpaper behind itself
* as the WindowGroup is hidden while the view is active. Only used when * as the WindowGroup is hidden while the view is active. Only used when
* workspaces-only-on-primary is set to true. * workspaces-only-on-primary is set to true.
*/ */
public class MonitorClone : Actor public class MonitorClone : Actor
{ {
public signal void window_selected (Window window); public signal void window_selected (Window window);
#if HAS_MUTTER330 #if HAS_MUTTER330
public Meta.Display display { get; construct; } public Meta.Display display { get; construct; }
#else #else
public Screen screen { get; construct; } public Screen screen { get; construct; }
#endif #endif
public int monitor { get; construct; } public int monitor { get; construct; }
WindowCloneContainer window_container; WindowCloneContainer window_container;
BackgroundManager background; BackgroundManager background;
#if HAS_MUTTER330 #if HAS_MUTTER330
public MonitorClone (Meta.Display display, int monitor) public MonitorClone (Meta.Display display, int monitor)
{ {
Object (display: display, monitor: monitor); Object (display: display, monitor: monitor);
} }
#else #else
public MonitorClone (Screen screen, int monitor) public MonitorClone (Screen screen, int monitor)
{ {
Object (screen: screen, monitor: monitor); Object (screen: screen, monitor: monitor);
} }
#endif #endif
construct construct
{ {
reactive = true; reactive = true;
#if HAS_MUTTER330 #if HAS_MUTTER330
background = new BackgroundManager (display, monitor, false); background = new BackgroundManager (display, monitor, false);
#else #else
background = new BackgroundManager (screen, monitor, false); background = new BackgroundManager (screen, monitor, false);
#endif #endif
background.set_easing_duration (MultitaskingView.ANIMATION_DURATION); background.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
window_container = new WindowCloneContainer (); window_container = new WindowCloneContainer ();
window_container.window_selected.connect ((w) => { window_selected (w); }); window_container.window_selected.connect ((w) => { window_selected (w); });
#if HAS_MUTTER330 #if HAS_MUTTER330
display.restacked.connect (window_container.restack_windows); display.restacked.connect (window_container.restack_windows);
display.window_entered_monitor.connect (window_entered); display.window_entered_monitor.connect (window_entered);
display.window_left_monitor.connect (window_left); display.window_left_monitor.connect (window_left);
#else #else
screen.restacked.connect (window_container.restack_windows); screen.restacked.connect (window_container.restack_windows);
screen.window_entered_monitor.connect (window_entered); screen.window_entered_monitor.connect (window_entered);
screen.window_left_monitor.connect (window_left); screen.window_left_monitor.connect (window_left);
#endif #endif
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned GLib.List<Meta.WindowActor> window_actors = display.get_window_actors (); unowned GLib.List<Meta.WindowActor> window_actors = display.get_window_actors ();
#else #else
unowned GLib.List<Meta.WindowActor> window_actors = screen.get_window_actors (); unowned GLib.List<Meta.WindowActor> window_actors = screen.get_window_actors ();
#endif #endif
foreach (unowned Meta.WindowActor window_actor in window_actors) { foreach (unowned Meta.WindowActor window_actor in window_actors) {
if (window_actor.is_destroyed ()) if (window_actor.is_destroyed ())
continue; continue;
unowned Meta.Window window = window_actor.get_meta_window (); unowned Meta.Window window = window_actor.get_meta_window ();
if (window.get_monitor () == monitor) { if (window.get_monitor () == monitor) {
window_entered (monitor, window); window_entered (monitor, window);
} }
} }
add_child (background); add_child (background);
add_child (window_container); add_child (window_container);
var drop = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window"); var drop = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
add_action (drop); add_action (drop);
update_allocation (); update_allocation ();
} }
~MonitorClone () ~MonitorClone ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
display.window_entered_monitor.disconnect (window_entered); display.window_entered_monitor.disconnect (window_entered);
display.window_left_monitor.disconnect (window_left); display.window_left_monitor.disconnect (window_left);
display.restacked.disconnect (window_container.restack_windows); display.restacked.disconnect (window_container.restack_windows);
#else #else
screen.window_entered_monitor.disconnect (window_entered); screen.window_entered_monitor.disconnect (window_entered);
screen.window_left_monitor.disconnect (window_left); screen.window_left_monitor.disconnect (window_left);
screen.restacked.disconnect (window_container.restack_windows); screen.restacked.disconnect (window_container.restack_windows);
#endif #endif
} }
/** /**
* Make sure the MonitorClone is at the location of the monitor on the stage * Make sure the MonitorClone is at the location of the monitor on the stage
*/ */
public void update_allocation () public void update_allocation ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
var monitor_geometry = display.get_monitor_geometry (monitor); var monitor_geometry = display.get_monitor_geometry (monitor);
#else #else
var monitor_geometry = screen.get_monitor_geometry (monitor); var monitor_geometry = screen.get_monitor_geometry (monitor);
#endif #endif
set_position (monitor_geometry.x, monitor_geometry.y); set_position (monitor_geometry.x, monitor_geometry.y);
set_size (monitor_geometry.width, monitor_geometry.height); set_size (monitor_geometry.width, monitor_geometry.height);
window_container.set_size (monitor_geometry.width, monitor_geometry.height); window_container.set_size (monitor_geometry.width, monitor_geometry.height);
} }
/** /**
* Animate the windows from their old location to a tiled layout * Animate the windows from their old location to a tiled layout
*/ */
public void open () public void open ()
{ {
window_container.open (); window_container.open ();
// background.opacity = 0; TODO consider this option // background.opacity = 0; TODO consider this option
} }
/** /**
* Animate the windows back to their old location * Animate the windows back to their old location
*/ */
public void close () public void close ()
{ {
window_container.close (); window_container.close ();
background.opacity = 255; background.opacity = 255;
} }
void window_left (int window_monitor, Window window) void window_left (int window_monitor, Window window)
{ {
if (window_monitor != monitor) if (window_monitor != monitor)
return; return;
window_container.remove_window (window); window_container.remove_window (window);
} }
void window_entered (int window_monitor, Window window) void window_entered (int window_monitor, Window window)
{ {
if (window_monitor != monitor || window.window_type != WindowType.NORMAL) if (window_monitor != monitor || window.window_type != WindowType.NORMAL)
return; return;
window_container.add_window (window); window_container.add_window (window);
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -19,57 +19,57 @@ using Meta;
namespace Gala namespace Gala
{ {
/** /**
* A clone for a MetaWindowActor that will guard against the * A clone for a MetaWindowActor that will guard against the
* meta_window_appears_focused crash by disabling painting the clone * meta_window_appears_focused crash by disabling painting the clone
* as soon as it gets unavailable. * as soon as it gets unavailable.
*/ */
public class SafeWindowClone : Clutter.Clone public class SafeWindowClone : Clutter.Clone
{ {
public Window window { get; construct; } public Window window { get; construct; }
/** /**
* If set to true, the SafeWindowClone will destroy itself when the connected * If set to true, the SafeWindowClone will destroy itself when the connected
* window is unmanaged * window is unmanaged
*/ */
public bool destroy_on_unmanaged { get; construct set; default = false; } public bool destroy_on_unmanaged { get; construct set; default = false; }
/** /**
* Creates a new SafeWindowClone * Creates a new SafeWindowClone
* *
* @param window The window to clone from * @param window The window to clone from
* @param destroy_on_unmanaged see destroy_on_unmanaged property * @param destroy_on_unmanaged see destroy_on_unmanaged property
*/ */
public SafeWindowClone (Window window, bool destroy_on_unmanaged = false) public SafeWindowClone (Window window, bool destroy_on_unmanaged = false)
{ {
var actor = (WindowActor) window.get_compositor_private (); var actor = (WindowActor) window.get_compositor_private ();
Object (window: window, Object (window: window,
source: actor, source: actor,
destroy_on_unmanaged: destroy_on_unmanaged); destroy_on_unmanaged: destroy_on_unmanaged);
} }
construct construct
{ {
if (source != null) if (source != null)
window.unmanaged.connect (reset_source); window.unmanaged.connect (reset_source);
} }
~SafeWindowClone () ~SafeWindowClone ()
{ {
window.unmanaged.disconnect (reset_source); window.unmanaged.disconnect (reset_source);
} }
void reset_source () void reset_source ()
{ {
// actually destroying the clone will be handled somewhere else (unless we were // actually destroying the clone will be handled somewhere else (unless we were
// requested to destroy it), we just need to make sure the clone doesn't attempt // requested to destroy it), we just need to make sure the clone doesn't attempt
// to draw a clone of a window that has been destroyed // to draw a clone of a window that has been destroyed
source = null; source = null;
if (destroy_on_unmanaged) if (destroy_on_unmanaged)
destroy (); destroy ();
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -20,381 +20,381 @@ using Meta;
namespace Gala namespace Gala
{ {
/** /**
* Container which controls the layout of a set of WindowClones. * Container which controls the layout of a set of WindowClones.
*/ */
public class WindowCloneContainer : Actor public class WindowCloneContainer : Actor
{ {
public signal void window_selected (Window window); public signal void window_selected (Window window);
public int padding_top { get; set; default = 12; } public int padding_top { get; set; default = 12; }
public int padding_left { get; set; default = 12; } public int padding_left { get; set; default = 12; }
public int padding_right { get; set; default = 12; } public int padding_right { get; set; default = 12; }
public int padding_bottom { get; set; default = 12; } public int padding_bottom { get; set; default = 12; }
public bool overview_mode { get; construct; } public bool overview_mode { get; construct; }
bool opened; bool opened;
/** /**
* The window that is currently selected via keyboard shortcuts. It is not * The window that is currently selected via keyboard shortcuts. It is not
* necessarily the same as the active window. * necessarily the same as the active window.
*/ */
WindowClone? current_window; WindowClone? current_window;
public WindowCloneContainer (bool overview_mode = false) public WindowCloneContainer (bool overview_mode = false)
{ {
Object (overview_mode: overview_mode); Object (overview_mode: overview_mode);
} }
construct construct
{ {
opened = false; opened = false;
current_window = null; current_window = null;
} }
/** /**
* Create a WindowClone for a MetaWindow and add it to the group * Create a WindowClone for a MetaWindow and add it to the group
* *
* @param window The window for which to create the WindowClone for * @param window The window for which to create the WindowClone for
*/ */
public void add_window (Window window) public void add_window (Window window)
{ {
unowned Meta.Display display = window.get_display (); unowned Meta.Display display = window.get_display ();
var children = get_children (); var children = get_children ();
GLib.SList<Meta.Window> windows = new GLib.SList<Meta.Window> (); GLib.SList<Meta.Window> windows = new GLib.SList<Meta.Window> ();
foreach (unowned Actor child in children) { foreach (unowned Actor child in children) {
unowned WindowClone tw = (WindowClone) child; unowned WindowClone tw = (WindowClone) child;
windows.prepend (tw.window); windows.prepend (tw.window);
} }
windows.prepend (window); windows.prepend (window);
windows.reverse (); windows.reverse ();
var windows_ordered = display.sort_windows_by_stacking (windows); var windows_ordered = display.sort_windows_by_stacking (windows);
var new_window = new WindowClone (window, overview_mode); var new_window = new WindowClone (window, overview_mode);
new_window.selected.connect (window_selected_cb); new_window.selected.connect (window_selected_cb);
new_window.destroy.connect (window_destroyed); new_window.destroy.connect (window_destroyed);
new_window.request_reposition.connect (reflow); new_window.request_reposition.connect (reflow);
var added = false; var added = false;
unowned Meta.Window? target = null; unowned Meta.Window? target = null;
foreach (unowned Meta.Window w in windows_ordered) { foreach (unowned Meta.Window w in windows_ordered) {
if (w != window) { if (w != window) {
target = w; target = w;
continue; continue;
} }
break; break;
} }
foreach (unowned Actor child in children) { foreach (unowned Actor child in children) {
unowned WindowClone tw = (WindowClone) child; unowned WindowClone tw = (WindowClone) child;
if (target == tw.window) { if (target == tw.window) {
insert_child_above (new_window, tw); insert_child_above (new_window, tw);
added = true; added = true;
break; break;
} }
} }
// top most or no other children // top most or no other children
if (!added) if (!added)
add_child (new_window); add_child (new_window);
reflow (); reflow ();
} }
/** /**
* Find and remove the WindowClone for a MetaWindow * Find and remove the WindowClone for a MetaWindow
*/ */
public void remove_window (Window window) public void remove_window (Window window)
{ {
foreach (var child in get_children ()) { foreach (var child in get_children ()) {
if (((WindowClone) child).window == window) { if (((WindowClone) child).window == window) {
remove_child (child); remove_child (child);
break; break;
} }
} }
reflow (); reflow ();
} }
void window_selected_cb (WindowClone tiled) void window_selected_cb (WindowClone tiled)
{ {
window_selected (tiled.window); window_selected (tiled.window);
} }
void window_destroyed (Actor actor) void window_destroyed (Actor actor)
{ {
var window = actor as WindowClone; var window = actor as WindowClone;
if (window == null) if (window == null)
return; return;
window.destroy.disconnect (window_destroyed); window.destroy.disconnect (window_destroyed);
window.selected.disconnect (window_selected_cb); window.selected.disconnect (window_selected_cb);
Idle.add (() => { Idle.add (() => {
reflow (); reflow ();
return false; return false;
}); });
} }
/** /**
* Sort the windows z-order by their actual stacking to make intersections * Sort the windows z-order by their actual stacking to make intersections
* during animations correct. * during animations correct.
*/ */
#if HAS_MUTTER330 #if HAS_MUTTER330
public void restack_windows (Meta.Display display) public void restack_windows (Meta.Display display)
{ {
var children = get_children (); var children = get_children ();
GLib.SList<Meta.Window> windows = new GLib.SList<Meta.Window> (); GLib.SList<Meta.Window> windows = new GLib.SList<Meta.Window> ();
foreach (unowned Actor child in children) { foreach (unowned Actor child in children) {
unowned WindowClone tw = (WindowClone) child; unowned WindowClone tw = (WindowClone) child;
windows.prepend (tw.window); windows.prepend (tw.window);
} }
var windows_ordered = display.sort_windows_by_stacking (windows); var windows_ordered = display.sort_windows_by_stacking (windows);
windows_ordered.reverse (); windows_ordered.reverse ();
foreach (unowned Meta.Window window in windows_ordered) { foreach (unowned Meta.Window window in windows_ordered) {
var i = 0; var i = 0;
foreach (unowned Actor child in children) { foreach (unowned Actor child in children) {
if (((WindowClone) child).window == window) { if (((WindowClone) child).window == window) {
set_child_at_index (child, i); set_child_at_index (child, i);
children.remove (child); children.remove (child);
i++; i++;
break; break;
} }
} }
} }
} }
#else #else
public void restack_windows (Screen screen) public void restack_windows (Screen screen)
{ {
unowned Meta.Display display = screen.get_display (); unowned Meta.Display display = screen.get_display ();
var children = get_children (); var children = get_children ();
GLib.SList<Meta.Window> windows = new GLib.SList<Meta.Window> (); GLib.SList<Meta.Window> windows = new GLib.SList<Meta.Window> ();
foreach (unowned Actor child in children) { foreach (unowned Actor child in children) {
unowned WindowClone tw = (WindowClone) child; unowned WindowClone tw = (WindowClone) child;
windows.prepend (tw.window); windows.prepend (tw.window);
} }
var windows_ordered = display.sort_windows_by_stacking (windows); var windows_ordered = display.sort_windows_by_stacking (windows);
windows_ordered.reverse (); windows_ordered.reverse ();
foreach (unowned Meta.Window window in windows_ordered) { foreach (unowned Meta.Window window in windows_ordered) {
var i = 0; var i = 0;
foreach (unowned Actor child in children) { foreach (unowned Actor child in children) {
if (((WindowClone) child).window == window) { if (((WindowClone) child).window == window) {
set_child_at_index (child, i); set_child_at_index (child, i);
children.remove (child); children.remove (child);
i++; i++;
break; break;
} }
} }
} }
} }
#endif #endif
/** /**
* Recalculate the tiling positions of the windows and animate them to * Recalculate the tiling positions of the windows and animate them to
* the resulting spots. * the resulting spots.
*/ */
public void reflow () public void reflow ()
{ {
if (!opened) if (!opened)
return; return;
var windows = new List<InternalUtils.TilableWindow?> (); var windows = new List<InternalUtils.TilableWindow?> ();
foreach (var child in get_children ()) { foreach (var child in get_children ()) {
unowned WindowClone window = (WindowClone) child; unowned WindowClone window = (WindowClone) child;
windows.prepend ({ window.window.get_frame_rect (), window }); windows.prepend ({ window.window.get_frame_rect (), window });
} }
if (windows.length () < 1) if (windows.length () < 1)
return; return;
// make sure the windows are always in the same order so the algorithm // make sure the windows are always in the same order so the algorithm
// doesn't give us different slots based on stacking order, which can lead // doesn't give us different slots based on stacking order, which can lead
// to windows flying around weirdly // to windows flying around weirdly
windows.sort ((a, b) => { windows.sort ((a, b) => {
var seq_a = ((WindowClone) a.id).window.get_stable_sequence (); var seq_a = ((WindowClone) a.id).window.get_stable_sequence ();
var seq_b = ((WindowClone) b.id).window.get_stable_sequence (); var seq_b = ((WindowClone) b.id).window.get_stable_sequence ();
return (int) (seq_b - seq_a); return (int) (seq_b - seq_a);
}); });
Meta.Rectangle area = { Meta.Rectangle area = {
padding_left, padding_left,
padding_top, padding_top,
(int)width - padding_left - padding_right, (int)width - padding_left - padding_right,
(int)height - padding_top - padding_bottom (int)height - padding_top - padding_bottom
}; };
var window_positions = InternalUtils.calculate_grid_placement (area, windows); var window_positions = InternalUtils.calculate_grid_placement (area, windows);
foreach (var tilable in window_positions) { foreach (var tilable in window_positions) {
unowned WindowClone window = (WindowClone) tilable.id; unowned WindowClone window = (WindowClone) tilable.id;
window.take_slot (tilable.rect); window.take_slot (tilable.rect);
window.place_widgets (tilable.rect.width, tilable.rect.height); window.place_widgets (tilable.rect.width, tilable.rect.height);
} }
} }
/** /**
* Look for the next window in a direction and make this window the * Look for the next window in a direction and make this window the
* new current_window. Used for keyboard navigation. * new current_window. Used for keyboard navigation.
* *
* @param direction The MetaMotionDirection in which to search for windows for. * @param direction The MetaMotionDirection in which to search for windows for.
*/ */
public void select_next_window (MotionDirection direction) public void select_next_window (MotionDirection direction)
{ {
if (get_n_children () < 1) if (get_n_children () < 1)
return; return;
if (current_window == null) { if (current_window == null) {
current_window = (WindowClone) get_child_at_index (0); current_window = (WindowClone) get_child_at_index (0);
return; return;
} }
var current_rect = current_window.slot; var current_rect = current_window.slot;
WindowClone? closest = null; WindowClone? closest = null;
foreach (var window in get_children ()) { foreach (var window in get_children ()) {
if (window == current_window) if (window == current_window)
continue; continue;
var window_rect = ((WindowClone) window).slot; var window_rect = ((WindowClone) window).slot;
switch (direction) { switch (direction) {
case MotionDirection.LEFT: case MotionDirection.LEFT:
if (window_rect.x > current_rect.x) if (window_rect.x > current_rect.x)
continue; continue;
// test for vertical intersection // test for vertical intersection
if (window_rect.y + window_rect.height > current_rect.y if (window_rect.y + window_rect.height > current_rect.y
&& window_rect.y < current_rect.y + current_rect.height) { && window_rect.y < current_rect.y + current_rect.height) {
if (closest == null if (closest == null
|| closest.slot.x < window_rect.x) || closest.slot.x < window_rect.x)
closest = (WindowClone) window; closest = (WindowClone) window;
} }
break; break;
case MotionDirection.RIGHT: case MotionDirection.RIGHT:
if (window_rect.x < current_rect.x) if (window_rect.x < current_rect.x)
continue; continue;
// test for vertical intersection // test for vertical intersection
if (window_rect.y + window_rect.height > current_rect.y if (window_rect.y + window_rect.height > current_rect.y
&& window_rect.y < current_rect.y + current_rect.height) { && window_rect.y < current_rect.y + current_rect.height) {
if (closest == null if (closest == null
|| closest.slot.x > window_rect.x) || closest.slot.x > window_rect.x)
closest = (WindowClone) window; closest = (WindowClone) window;
} }
break; break;
case MotionDirection.UP: case MotionDirection.UP:
if (window_rect.y > current_rect.y) if (window_rect.y > current_rect.y)
continue; continue;
// test for horizontal intersection // test for horizontal intersection
if (window_rect.x + window_rect.width > current_rect.x if (window_rect.x + window_rect.width > current_rect.x
&& window_rect.x < current_rect.x + current_rect.width) { && window_rect.x < current_rect.x + current_rect.width) {
if (closest == null if (closest == null
|| closest.slot.y < window_rect.y) || closest.slot.y < window_rect.y)
closest = (WindowClone) window; closest = (WindowClone) window;
} }
break; break;
case MotionDirection.DOWN: case MotionDirection.DOWN:
if (window_rect.y < current_rect.y) if (window_rect.y < current_rect.y)
continue; continue;
// test for horizontal intersection // test for horizontal intersection
if (window_rect.x + window_rect.width > current_rect.x if (window_rect.x + window_rect.width > current_rect.x
&& window_rect.x < current_rect.x + current_rect.width) { && window_rect.x < current_rect.x + current_rect.width) {
if (closest == null if (closest == null
|| closest.slot.y > window_rect.y) || closest.slot.y > window_rect.y)
closest = (WindowClone) window; closest = (WindowClone) window;
} }
break; break;
} }
} }
if (closest == null) if (closest == null)
return; return;
if (current_window != null) if (current_window != null)
current_window.active = false; current_window.active = false;
closest.active = true; closest.active = true;
current_window = closest; current_window = closest;
} }
/** /**
* Emit the selected signal for the current_window. * Emit the selected signal for the current_window.
*/ */
public bool activate_selected_window () public bool activate_selected_window ()
{ {
if (current_window != null) { if (current_window != null) {
current_window.selected (); current_window.selected ();
return true; return true;
} }
return false; return false;
} }
/** /**
* When opened the WindowClones are animated to a tiled layout * When opened the WindowClones are animated to a tiled layout
*/ */
public void open (Window? selected_window = null) public void open (Window? selected_window = null)
{ {
if (opened) if (opened)
return; return;
opened = true; opened = true;
// hide the highlight when opened // hide the highlight when opened
if (selected_window != null) { if (selected_window != null) {
foreach (var child in get_children ()) { foreach (var child in get_children ()) {
unowned WindowClone tiled_window = (WindowClone) child; unowned WindowClone tiled_window = (WindowClone) child;
if (tiled_window.window == selected_window) { if (tiled_window.window == selected_window) {
current_window = tiled_window; current_window = tiled_window;
break; break;
} }
} }
if (current_window != null) { if (current_window != null) {
current_window.active = false; current_window.active = false;
} }
} else { } else {
current_window = null; current_window = null;
} }
// make sure our windows are where they belong in case they were moved // make sure our windows are where they belong in case they were moved
// while were closed. // while were closed.
foreach (var window in get_children ()) foreach (var window in get_children ())
((WindowClone) window).transition_to_original_state (false); ((WindowClone) window).transition_to_original_state (false);
reflow (); reflow ();
} }
/** /**
* Calls the transition_to_original_state() function on each child * Calls the transition_to_original_state() function on each child
* to make them take their original locations again. * to make them take their original locations again.
*/ */
public void close () public void close ()
{ {
if (!opened) if (!opened)
return; return;
opened = false; opened = false;
foreach (var window in get_children ()) foreach (var window in get_children ())
((WindowClone) window).transition_to_original_state (true); ((WindowClone) window).transition_to_original_state (true);
} }
} }
} }

View File

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

View File

@ -21,368 +21,368 @@ using Clutter;
namespace Gala namespace Gala
{ {
public enum WindowOverviewType public enum WindowOverviewType
{ {
GRID = 0, GRID = 0,
NATURAL NATURAL
} }
public delegate void WindowPlacer (Actor window, Meta.Rectangle rect); public delegate void WindowPlacer (Actor window, Meta.Rectangle rect);
public class WindowOverview : Actor, ActivatableComponent public class WindowOverview : Actor, ActivatableComponent
{ {
const int BORDER = 10; const int BORDER = 10;
const int TOP_GAP = 30; const int TOP_GAP = 30;
const int BOTTOM_GAP = 100; const int BOTTOM_GAP = 100;
public WindowManager wm { get; construct; } public WindowManager wm { get; construct; }
#if HAS_MUTTER330 #if HAS_MUTTER330
Meta.Display display; Meta.Display display;
#else #else
Meta.Screen screen; Meta.Screen screen;
#endif #endif
ModalProxy modal_proxy; ModalProxy modal_proxy;
bool ready; bool ready;
// the workspaces which we expose right now // the workspaces which we expose right now
List<Workspace> workspaces; List<Workspace> workspaces;
public WindowOverview (WindowManager wm) public WindowOverview (WindowManager wm)
{ {
Object (wm : wm); Object (wm : wm);
} }
construct construct
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
display = wm.get_display (); display = wm.get_display ();
display.get_workspace_manager ().workspace_switched.connect (close); display.get_workspace_manager ().workspace_switched.connect (close);
display.restacked.connect (restack_windows); display.restacked.connect (restack_windows);
#else #else
screen = wm.get_screen (); screen = wm.get_screen ();
screen.workspace_switched.connect (close); screen.workspace_switched.connect (close);
screen.restacked.connect (restack_windows); screen.restacked.connect (restack_windows);
#endif #endif
visible = false; visible = false;
ready = true; ready = true;
reactive = true; reactive = true;
} }
~WindowOverview () ~WindowOverview ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
display.restacked.disconnect (restack_windows); display.restacked.disconnect (restack_windows);
#else #else
screen.restacked.disconnect (restack_windows); screen.restacked.disconnect (restack_windows);
#endif #endif
} }
public override bool key_press_event (Clutter.KeyEvent event) public override bool key_press_event (Clutter.KeyEvent event)
{ {
if (event.keyval == Clutter.Key.Escape) { if (event.keyval == Clutter.Key.Escape) {
close (); close ();
return true; return true;
} }
return false; return false;
} }
public override void key_focus_out () public override void key_focus_out ()
{ {
if (!contains (get_stage ().key_focus)) if (!contains (get_stage ().key_focus))
close (); close ();
} }
public override bool button_press_event (Clutter.ButtonEvent event) public override bool button_press_event (Clutter.ButtonEvent event)
{ {
if (event.button == 1) if (event.button == 1)
close (); close ();
return true; return true;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public bool is_opened () public bool is_opened ()
{ {
return visible; return visible;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
* You may specify 'all-windows' in hints to expose all windows * You may specify 'all-windows' in hints to expose all windows
*/ */
public void open (HashTable<string,Variant>? hints = null) public void open (HashTable<string,Variant>? hints = null)
{ {
if (!ready) if (!ready)
return; return;
if (visible) { if (visible) {
close (); close ();
return; return;
} }
var all_windows = hints != null && "all-windows" in hints; var all_windows = hints != null && "all-windows" in hints;
var used_windows = new SList<Window> (); var used_windows = new SList<Window> ();
workspaces = new List<Workspace> (); workspaces = new List<Workspace> ();
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.WorkspaceManager manager = display.get_workspace_manager (); unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
if (all_windows) { if (all_windows) {
for (int i = 0; i < manager.get_n_workspaces (); i++) { for (int i = 0; i < manager.get_n_workspaces (); i++) {
workspaces.append (manager.get_workspace_by_index (i)); workspaces.append (manager.get_workspace_by_index (i));
} }
} else { } else {
workspaces.append (manager.get_active_workspace ()); workspaces.append (manager.get_active_workspace ());
} }
#else #else
if (all_windows) { if (all_windows) {
foreach (var workspace in screen.get_workspaces ()) foreach (var workspace in screen.get_workspaces ())
workspaces.append (workspace); workspaces.append (workspace);
} else { } else {
workspaces.append (screen.get_active_workspace ()); workspaces.append (screen.get_active_workspace ());
} }
#endif #endif
foreach (var workspace in workspaces) { foreach (var workspace in workspaces) {
foreach (var window in workspace.list_windows ()) { foreach (var window in workspace.list_windows ()) {
if (window.window_type != WindowType.NORMAL && if (window.window_type != WindowType.NORMAL &&
window.window_type != WindowType.DOCK && window.window_type != WindowType.DOCK &&
window.window_type != WindowType.DIALOG || window.window_type != WindowType.DIALOG ||
window.is_attached_dialog ()) { window.is_attached_dialog ()) {
var actor = window.get_compositor_private () as WindowActor; var actor = window.get_compositor_private () as WindowActor;
if (actor != null) if (actor != null)
actor.hide (); actor.hide ();
continue; continue;
} }
if (window.window_type == WindowType.DOCK) if (window.window_type == WindowType.DOCK)
continue; continue;
// skip windows that are on all workspace except we're currently // skip windows that are on all workspace except we're currently
// processing the workspace it actually belongs to // processing the workspace it actually belongs to
if (window.is_on_all_workspaces () && window.get_workspace () != workspace) if (window.is_on_all_workspaces () && window.get_workspace () != workspace)
continue; continue;
used_windows.append (window); used_windows.append (window);
} }
} }
var n_windows = used_windows.length (); var n_windows = used_windows.length ();
if (n_windows == 0) if (n_windows == 0)
return; return;
ready = false; ready = false;
foreach (var workspace in workspaces) { foreach (var workspace in workspaces) {
workspace.window_added.connect (add_window); workspace.window_added.connect (add_window);
workspace.window_removed.connect (remove_window); workspace.window_removed.connect (remove_window);
} }
#if HAS_MUTTER330 #if HAS_MUTTER330
display.window_left_monitor.connect (window_left_monitor); display.window_left_monitor.connect (window_left_monitor);
// sort windows by stacking order // sort windows by stacking order
var windows = display.sort_windows_by_stacking (used_windows); var windows = display.sort_windows_by_stacking (used_windows);
#else #else
screen.window_left_monitor.connect (window_left_monitor); screen.window_left_monitor.connect (window_left_monitor);
// sort windows by stacking order // sort windows by stacking order
var windows = screen.get_display ().sort_windows_by_stacking (used_windows); var windows = screen.get_display ().sort_windows_by_stacking (used_windows);
#endif #endif
grab_key_focus (); grab_key_focus ();
modal_proxy = wm.push_modal (); modal_proxy = wm.push_modal ();
modal_proxy.keybinding_filter = keybinding_filter; modal_proxy.keybinding_filter = keybinding_filter;
visible = true; visible = true;
#if HAS_MUTTER330 #if HAS_MUTTER330
for (var i = 0; i < display.get_n_monitors (); i++) { for (var i = 0; i < display.get_n_monitors (); i++) {
var geometry = display.get_monitor_geometry (i); var geometry = display.get_monitor_geometry (i);
#else #else
for (var i = 0; i < screen.get_n_monitors (); i++) { for (var i = 0; i < screen.get_n_monitors (); i++) {
var geometry = screen.get_monitor_geometry (i); var geometry = screen.get_monitor_geometry (i);
#endif #endif
var container = new WindowCloneContainer (true); var container = new WindowCloneContainer (true);
container.padding_top = TOP_GAP; container.padding_top = TOP_GAP;
container.padding_left = container.padding_right = BORDER; container.padding_left = container.padding_right = BORDER;
container.padding_bottom = BOTTOM_GAP; container.padding_bottom = BOTTOM_GAP;
container.set_position (geometry.x, geometry.y); container.set_position (geometry.x, geometry.y);
container.set_size (geometry.width, geometry.height); container.set_size (geometry.width, geometry.height);
container.window_selected.connect (thumb_selected); container.window_selected.connect (thumb_selected);
add_child (container); add_child (container);
} }
foreach (var window in windows) { foreach (var window in windows) {
unowned WindowActor actor = window.get_compositor_private () as WindowActor; unowned WindowActor actor = window.get_compositor_private () as WindowActor;
if (actor != null) if (actor != null)
actor.hide (); actor.hide ();
unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer; unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer;
if (container == null) if (container == null)
continue; continue;
container.add_window (window); container.add_window (window);
} }
foreach (var child in get_children ()) foreach (var child in get_children ())
((WindowCloneContainer) child).open (); ((WindowCloneContainer) child).open ();
ready = true; ready = true;
} }
bool keybinding_filter (KeyBinding binding) bool keybinding_filter (KeyBinding binding)
{ {
var name = binding.get_name (); var name = binding.get_name ();
return (name != "expose-windows" && name != "expose-all-windows"); return (name != "expose-windows" && name != "expose-all-windows");
} }
#if HAS_MUTTER330 #if HAS_MUTTER330
void restack_windows (Display display) void restack_windows (Display display)
{ {
foreach (var child in get_children ()) foreach (var child in get_children ())
((WindowCloneContainer) child).restack_windows (display); ((WindowCloneContainer) child).restack_windows (display);
} }
#else #else
void restack_windows (Screen screen) void restack_windows (Screen screen)
{ {
foreach (var child in get_children ()) foreach (var child in get_children ())
((WindowCloneContainer) child).restack_windows (screen); ((WindowCloneContainer) child).restack_windows (screen);
} }
#endif #endif
void window_left_monitor (int num, Window window) void window_left_monitor (int num, Window window)
{ {
unowned WindowCloneContainer container = get_child_at_index (num) as WindowCloneContainer; unowned WindowCloneContainer container = get_child_at_index (num) as WindowCloneContainer;
if (container == null) if (container == null)
return; return;
// make sure the window belongs to one of our workspaces // make sure the window belongs to one of our workspaces
foreach (var workspace in workspaces) foreach (var workspace in workspaces)
if (window.located_on_workspace (workspace)) { if (window.located_on_workspace (workspace)) {
container.remove_window (window); container.remove_window (window);
break; break;
} }
} }
void add_window (Window window) void add_window (Window window)
{ {
if (!visible if (!visible
|| (window.window_type != WindowType.NORMAL && window.window_type != WindowType.DIALOG)) || (window.window_type != WindowType.NORMAL && window.window_type != WindowType.DIALOG))
return; return;
unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer; unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer;
if (container == null) if (container == null)
return; return;
// make sure the window belongs to one of our workspaces // make sure the window belongs to one of our workspaces
foreach (var workspace in workspaces) foreach (var workspace in workspaces)
if (window.located_on_workspace (workspace)) { if (window.located_on_workspace (workspace)) {
container.add_window (window); container.add_window (window);
break; break;
} }
} }
void remove_window (Window window) void remove_window (Window window)
{ {
unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer; unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer;
if (container == null) if (container == null)
return; return;
container.remove_window (window); container.remove_window (window);
} }
#if HAS_MUTTER330 #if HAS_MUTTER330
void thumb_selected (Window window) void thumb_selected (Window window)
{ {
if (window.get_workspace () == display.get_workspace_manager ().get_active_workspace ()) { if (window.get_workspace () == display.get_workspace_manager ().get_active_workspace ()) {
window.activate (display.get_current_time ()); window.activate (display.get_current_time ());
close (); close ();
} else { } else {
close (); close ();
//wait for the animation to finish before switching //wait for the animation to finish before switching
Timeout.add (400, () => { Timeout.add (400, () => {
window.get_workspace ().activate_with_focus (window, display.get_current_time ()); window.get_workspace ().activate_with_focus (window, display.get_current_time ());
return false; return false;
}); });
} }
} }
#else #else
void thumb_selected (Window window) void thumb_selected (Window window)
{ {
if (window.get_workspace () == screen.get_active_workspace ()) { if (window.get_workspace () == screen.get_active_workspace ()) {
window.activate (screen.get_display ().get_current_time ()); window.activate (screen.get_display ().get_current_time ());
close (); close ();
} else { } else {
close (); close ();
//wait for the animation to finish before switching //wait for the animation to finish before switching
Timeout.add (400, () => { Timeout.add (400, () => {
window.get_workspace ().activate_with_focus (window, screen.get_display ().get_current_time ()); window.get_workspace ().activate_with_focus (window, screen.get_display ().get_current_time ());
return false; return false;
}); });
} }
} }
#endif #endif
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public void close () public void close ()
{ {
if (!visible || !ready) if (!visible || !ready)
return; return;
foreach (var workspace in workspaces) { foreach (var workspace in workspaces) {
workspace.window_added.disconnect (add_window); workspace.window_added.disconnect (add_window);
workspace.window_removed.disconnect (remove_window); workspace.window_removed.disconnect (remove_window);
} }
#if HAS_MUTTER330 #if HAS_MUTTER330
display.window_left_monitor.disconnect (window_left_monitor); display.window_left_monitor.disconnect (window_left_monitor);
#else #else
screen.window_left_monitor.disconnect (window_left_monitor); screen.window_left_monitor.disconnect (window_left_monitor);
#endif #endif
ready = false; ready = false;
wm.pop_modal (modal_proxy); wm.pop_modal (modal_proxy);
foreach (var child in get_children ()) { foreach (var child in get_children ()) {
((WindowCloneContainer) child).close (); ((WindowCloneContainer) child).close ();
} }
Clutter.Threads.Timeout.add (300, () => { Clutter.Threads.Timeout.add (300, () => {
cleanup (); cleanup ();
return false; return false;
}); });
} }
void cleanup () void cleanup ()
{ {
ready = true; ready = true;
visible = false; visible = false;
#if HAS_MUTTER330 #if HAS_MUTTER330
foreach (var window in display.get_workspace_manager ().get_active_workspace ().list_windows ()) foreach (var window in display.get_workspace_manager ().get_active_workspace ().list_windows ())
#else #else
foreach (var window in screen.get_active_workspace ().list_windows ()) foreach (var window in screen.get_active_workspace ().list_windows ())
#endif #endif
if (window.showing_on_its_workspace ()) if (window.showing_on_its_workspace ())
((Actor) window.get_compositor_private ()).show (); ((Actor) window.get_compositor_private ()).show ();
destroy_all_children (); destroy_all_children ();
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -20,413 +20,413 @@ using Meta;
namespace Gala namespace Gala
{ {
/** /**
* Utility class which adds a border and a shadow to a Background * Utility class which adds a border and a shadow to a Background
*/ */
class FramedBackground : BackgroundManager class FramedBackground : BackgroundManager
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
public FramedBackground (Display display) public FramedBackground (Display display)
{ {
Object (display: display, monitor_index: display.get_primary_monitor (), control_position: false); Object (display: display, monitor_index: display.get_primary_monitor (), control_position: false);
} }
#else #else
public FramedBackground (Screen screen) public FramedBackground (Screen screen)
{ {
Object (screen: screen, monitor_index: screen.get_primary_monitor (), control_position: false); Object (screen: screen, monitor_index: screen.get_primary_monitor (), control_position: false);
} }
#endif #endif
construct construct
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
var primary = display.get_primary_monitor (); var primary = display.get_primary_monitor ();
var monitor_geom = display.get_monitor_geometry (primary); var monitor_geom = display.get_monitor_geometry (primary);
#else #else
var primary = screen.get_primary_monitor (); var primary = screen.get_primary_monitor ();
var monitor_geom = screen.get_monitor_geometry (primary); var monitor_geom = screen.get_monitor_geometry (primary);
#endif #endif
var effect = new ShadowEffect (40, 5); var effect = new ShadowEffect (40, 5);
effect.css_class = "workspace"; effect.css_class = "workspace";
add_effect (effect); add_effect (effect);
} }
public override void paint () public override void paint ()
{ {
base.paint (); base.paint ();
Cogl.set_source_color4ub (0, 0, 0, 100); Cogl.set_source_color4ub (0, 0, 0, 100);
var path = new Cogl.Path (); var path = new Cogl.Path ();
path.rectangle (0, 0, width, height); path.rectangle (0, 0, width, height);
path.stroke (); path.stroke ();
Cogl.set_source_color4ub (255, 255, 255, 25); Cogl.set_source_color4ub (255, 255, 255, 25);
path.rectangle (0.5f, 0.5f, width - 1, height - 1); path.rectangle (0.5f, 0.5f, width - 1, height - 1);
path.stroke (); path.stroke ();
} }
} }
/** /**
* This is the container which manages a clone of the background which will * This is the container which manages a clone of the background which will
* be scaled and animated inwards, a WindowCloneContainer for the windows on * be scaled and animated inwards, a WindowCloneContainer for the windows on
* this workspace and also holds the instance for this workspace's IconGroup. * this workspace and also holds the instance for this workspace's IconGroup.
* The latter is not added to the WorkspaceClone itself though but to a container * The latter is not added to the WorkspaceClone itself though but to a container
* of the MultitaskingView. * of the MultitaskingView.
*/ */
public class WorkspaceClone : Actor public class WorkspaceClone : Actor
{ {
/** /**
* The offset of the scaled background to the bottom of the monitor bounds * The offset of the scaled background to the bottom of the monitor bounds
*/ */
public const int BOTTOM_OFFSET = 100; public const int BOTTOM_OFFSET = 100;
/** /**
* The offset of the scaled background to the top of the monitor bounds * The offset of the scaled background to the top of the monitor bounds
*/ */
const int TOP_OFFSET = 20; const int TOP_OFFSET = 20;
/** /**
* The amount of time a window has to be over the WorkspaceClone while in drag * The amount of time a window has to be over the WorkspaceClone while in drag
* before we activate the workspace. * before we activate the workspace.
*/ */
const int HOVER_ACTIVATE_DELAY = 400; const int HOVER_ACTIVATE_DELAY = 400;
/** /**
* A window has been selected, the MultitaskingView should consider activating * A window has been selected, the MultitaskingView should consider activating
* and closing the view. * and closing the view.
*/ */
public signal void window_selected (Window window); public signal void window_selected (Window window);
/** /**
* The background has been selected. Switch to that workspace. * The background has been selected. Switch to that workspace.
* *
* @param close_view If the MultitaskingView should also consider closing itself * @param close_view If the MultitaskingView should also consider closing itself
* after switching. * after switching.
*/ */
public signal void selected (bool close_view); public signal void selected (bool close_view);
public Workspace workspace { get; construct; } public Workspace workspace { get; construct; }
public IconGroup icon_group { get; private set; } public IconGroup icon_group { get; private set; }
public WindowCloneContainer window_container { get; private set; } public WindowCloneContainer window_container { get; private set; }
bool _active = false; bool _active = false;
/** /**
* If this WorkspaceClone is currently the active one. Also sets the active * If this WorkspaceClone is currently the active one. Also sets the active
* state on its IconGroup. * state on its IconGroup.
*/ */
public bool active { public bool active {
get { get {
return _active; return _active;
} }
set { set {
_active = value; _active = value;
icon_group.active = value; icon_group.active = value;
} }
} }
BackgroundManager background; BackgroundManager background;
bool opened; bool opened;
uint hover_activate_timeout = 0; uint hover_activate_timeout = 0;
public WorkspaceClone (Workspace workspace) public WorkspaceClone (Workspace workspace)
{ {
Object (workspace: workspace); Object (workspace: workspace);
} }
construct construct
{ {
opened = false; opened = false;
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Display display = workspace.get_display (); unowned Display display = workspace.get_display ();
var monitor_geometry = display.get_monitor_geometry (display.get_primary_monitor ()); var monitor_geometry = display.get_monitor_geometry (display.get_primary_monitor ());
#else #else
unowned Screen screen = workspace.get_screen (); unowned Screen screen = workspace.get_screen ();
var monitor_geometry = screen.get_monitor_geometry (screen.get_primary_monitor ()); var monitor_geometry = screen.get_monitor_geometry (screen.get_primary_monitor ());
#endif #endif
#if HAS_MUTTER330 #if HAS_MUTTER330
background = new FramedBackground (display); background = new FramedBackground (display);
#else #else
background = new FramedBackground (screen); background = new FramedBackground (screen);
#endif #endif
background.reactive = true; background.reactive = true;
background.button_press_event.connect (() => { background.button_press_event.connect (() => {
selected (true); selected (true);
return false; return false;
}); });
window_container = new WindowCloneContainer (); window_container = new WindowCloneContainer ();
window_container.window_selected.connect ((w) => { window_selected (w); }); window_container.window_selected.connect ((w) => { window_selected (w); });
window_container.set_size (monitor_geometry.width, monitor_geometry.height); window_container.set_size (monitor_geometry.width, monitor_geometry.height);
#if HAS_MUTTER330 #if HAS_MUTTER330
display.restacked.connect (window_container.restack_windows); display.restacked.connect (window_container.restack_windows);
#else #else
screen.restacked.connect (window_container.restack_windows); screen.restacked.connect (window_container.restack_windows);
#endif #endif
icon_group = new IconGroup (workspace); icon_group = new IconGroup (workspace);
icon_group.selected.connect (() => { icon_group.selected.connect (() => {
#if HAS_MUTTER330 #if HAS_MUTTER330
if (workspace == display.get_workspace_manager ().get_active_workspace ()) if (workspace == display.get_workspace_manager ().get_active_workspace ())
Utils.bell (display); Utils.bell (display);
else else
selected (false); selected (false);
#else #else
if (workspace == screen.get_active_workspace ()) if (workspace == screen.get_active_workspace ())
Utils.bell (screen); Utils.bell (screen);
else else
selected (false); selected (false);
#endif #endif
}); });
var icons_drop_action = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window"); var icons_drop_action = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
icon_group.add_action (icons_drop_action); icon_group.add_action (icons_drop_action);
var background_drop_action = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window"); var background_drop_action = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
background.add_action (background_drop_action); background.add_action (background_drop_action);
background_drop_action.crossed.connect ((target, hovered) => { background_drop_action.crossed.connect ((target, hovered) => {
if (!hovered && hover_activate_timeout != 0) { if (!hovered && hover_activate_timeout != 0) {
Source.remove (hover_activate_timeout); Source.remove (hover_activate_timeout);
hover_activate_timeout = 0; hover_activate_timeout = 0;
return; return;
} }
if (hovered && hover_activate_timeout == 0) { if (hovered && hover_activate_timeout == 0) {
hover_activate_timeout = Timeout.add (HOVER_ACTIVATE_DELAY, () => { hover_activate_timeout = Timeout.add (HOVER_ACTIVATE_DELAY, () => {
selected (false); selected (false);
hover_activate_timeout = 0; hover_activate_timeout = 0;
return false; return false;
}); });
} }
}); });
#if HAS_MUTTER330 #if HAS_MUTTER330
display.window_entered_monitor.connect (window_entered_monitor); display.window_entered_monitor.connect (window_entered_monitor);
display.window_left_monitor.connect (window_left_monitor); display.window_left_monitor.connect (window_left_monitor);
#else #else
screen.window_entered_monitor.connect (window_entered_monitor); screen.window_entered_monitor.connect (window_entered_monitor);
screen.window_left_monitor.connect (window_left_monitor); screen.window_left_monitor.connect (window_left_monitor);
#endif #endif
workspace.window_added.connect (add_window); workspace.window_added.connect (add_window);
workspace.window_removed.connect (remove_window); workspace.window_removed.connect (remove_window);
add_child (background); add_child (background);
add_child (window_container); add_child (window_container);
// add existing windows // add existing windows
var windows = workspace.list_windows (); var windows = workspace.list_windows ();
foreach (var window in windows) { foreach (var window in windows) {
#if HAS_MUTTER330 #if HAS_MUTTER330
if (window.window_type == WindowType.NORMAL if (window.window_type == WindowType.NORMAL
&& !window.on_all_workspaces && !window.on_all_workspaces
&& window.get_monitor () == display.get_primary_monitor ()) { && window.get_monitor () == display.get_primary_monitor ()) {
window_container.add_window (window); window_container.add_window (window);
icon_group.add_window (window, true); icon_group.add_window (window, true);
} }
#else #else
if (window.window_type == WindowType.NORMAL if (window.window_type == WindowType.NORMAL
&& !window.on_all_workspaces && !window.on_all_workspaces
&& window.get_monitor () == screen.get_primary_monitor ()) { && window.get_monitor () == screen.get_primary_monitor ()) {
window_container.add_window (window); window_container.add_window (window);
icon_group.add_window (window, true); icon_group.add_window (window, true);
} }
#endif #endif
} }
var listener = WindowListener.get_default (); var listener = WindowListener.get_default ();
listener.window_no_longer_on_all_workspaces.connect (add_window); listener.window_no_longer_on_all_workspaces.connect (add_window);
} }
~WorkspaceClone () ~WorkspaceClone ()
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.Display display = workspace.get_display (); unowned Meta.Display display = workspace.get_display ();
display.restacked.disconnect (window_container.restack_windows); display.restacked.disconnect (window_container.restack_windows);
display.window_entered_monitor.disconnect (window_entered_monitor); display.window_entered_monitor.disconnect (window_entered_monitor);
display.window_left_monitor.disconnect (window_left_monitor); display.window_left_monitor.disconnect (window_left_monitor);
#else #else
unowned Screen screen = workspace.get_screen (); unowned Screen screen = workspace.get_screen ();
screen.restacked.disconnect (window_container.restack_windows); screen.restacked.disconnect (window_container.restack_windows);
screen.window_entered_monitor.disconnect (window_entered_monitor); screen.window_entered_monitor.disconnect (window_entered_monitor);
screen.window_left_monitor.disconnect (window_left_monitor); screen.window_left_monitor.disconnect (window_left_monitor);
#endif #endif
workspace.window_added.disconnect (add_window); workspace.window_added.disconnect (add_window);
workspace.window_removed.disconnect (remove_window); workspace.window_removed.disconnect (remove_window);
var listener = WindowListener.get_default (); var listener = WindowListener.get_default ();
listener.window_no_longer_on_all_workspaces.disconnect (add_window); listener.window_no_longer_on_all_workspaces.disconnect (add_window);
background.destroy (); background.destroy ();
} }
/** /**
* Add a window to the WindowCloneContainer and the IconGroup if it really * Add a window to the WindowCloneContainer and the IconGroup if it really
* belongs to this workspace and this monitor. * belongs to this workspace and this monitor.
*/ */
void add_window (Window window) void add_window (Window window)
{ {
#if HAS_MUTTER330 #if HAS_MUTTER330
if (window.window_type != WindowType.NORMAL if (window.window_type != WindowType.NORMAL
|| window.get_workspace () != workspace || window.get_workspace () != workspace
|| window.on_all_workspaces || window.on_all_workspaces
|| window.get_monitor () != window.get_display ().get_primary_monitor ()) || window.get_monitor () != window.get_display ().get_primary_monitor ())
return; return;
#else #else
if (window.window_type != WindowType.NORMAL if (window.window_type != WindowType.NORMAL
|| window.get_workspace () != workspace || window.get_workspace () != workspace
|| window.on_all_workspaces || window.on_all_workspaces
|| window.get_monitor () != window.get_screen ().get_primary_monitor ()) || window.get_monitor () != window.get_screen ().get_primary_monitor ())
return; return;
#endif #endif
foreach (var child in window_container.get_children ()) foreach (var child in window_container.get_children ())
if (((WindowClone) child).window == window) if (((WindowClone) child).window == window)
return; return;
window_container.add_window (window); window_container.add_window (window);
icon_group.add_window (window); icon_group.add_window (window);
} }
/** /**
* Remove a window from the WindowCloneContainer and the IconGroup * Remove a window from the WindowCloneContainer and the IconGroup
*/ */
void remove_window (Window window) void remove_window (Window window)
{ {
window_container.remove_window (window); window_container.remove_window (window);
icon_group.remove_window (window, opened); icon_group.remove_window (window, opened);
} }
#if HAS_MUTTER330 #if HAS_MUTTER330
void window_entered_monitor (Display display, int monitor, Window window) void window_entered_monitor (Display display, int monitor, Window window)
{ {
add_window (window); add_window (window);
} }
void window_left_monitor (Display display, int monitor, Window window) void window_left_monitor (Display display, int monitor, Window window)
{ {
if (monitor == display.get_primary_monitor ()) if (monitor == display.get_primary_monitor ())
remove_window (window); remove_window (window);
} }
#else #else
void window_entered_monitor (Screen screen, int monitor, Window window) void window_entered_monitor (Screen screen, int monitor, Window window)
{ {
add_window (window); add_window (window);
} }
void window_left_monitor (Screen screen, int monitor, Window window) void window_left_monitor (Screen screen, int monitor, Window window)
{ {
if (monitor == screen.get_primary_monitor ()) if (monitor == screen.get_primary_monitor ())
remove_window (window); remove_window (window);
} }
#endif #endif
void update_size (Meta.Rectangle monitor_geometry) void update_size (Meta.Rectangle monitor_geometry)
{ {
if (window_container.width != monitor_geometry.width || window_container.height != monitor_geometry.height) { if (window_container.width != monitor_geometry.width || window_container.height != monitor_geometry.height) {
window_container.set_size (monitor_geometry.width, monitor_geometry.height); window_container.set_size (monitor_geometry.width, monitor_geometry.height);
background.set_size (window_container.width, window_container.height); background.set_size (window_container.width, window_container.height);
} }
} }
/** /**
* Utility function to shrink a MetaRectangle on all sides for the given amount. * Utility function to shrink a MetaRectangle on all sides for the given amount.
* Negative amounts will scale it instead. * Negative amounts will scale it instead.
* *
* @param amount The amount in px to shrink. * @param amount The amount in px to shrink.
*/ */
static inline void shrink_rectangle (ref Meta.Rectangle rect, int amount) static inline void shrink_rectangle (ref Meta.Rectangle rect, int amount)
{ {
rect.x += amount; rect.x += amount;
rect.y += amount; rect.y += amount;
rect.width -= amount * 2; rect.width -= amount * 2;
rect.height -= amount * 2; rect.height -= amount * 2;
} }
/** /**
* Animates the background to its scale, causes a redraw on the IconGroup and * Animates the background to its scale, causes a redraw on the IconGroup and
* makes sure the WindowCloneContainer animates its windows to their tiled layout. * makes sure the WindowCloneContainer animates its windows to their tiled layout.
* Also sets the current_window of the WindowCloneContainer to the active window * Also sets the current_window of the WindowCloneContainer to the active window
* if it belongs to this workspace. * if it belongs to this workspace.
*/ */
public void open () public void open ()
{ {
if (opened) if (opened)
return; return;
opened = true; opened = true;
var scale_factor = InternalUtils.get_ui_scaling_factor (); var scale_factor = InternalUtils.get_ui_scaling_factor ();
#if HAS_MUTTER330 #if HAS_MUTTER330
var display = workspace.get_display (); var display = workspace.get_display ();
var monitor = display.get_monitor_geometry (display.get_primary_monitor ()); var monitor = display.get_monitor_geometry (display.get_primary_monitor ());
#else #else
var screen = workspace.get_screen (); var screen = workspace.get_screen ();
var display = screen.get_display (); var display = screen.get_display ();
var monitor = screen.get_monitor_geometry (screen.get_primary_monitor ()); var monitor = screen.get_monitor_geometry (screen.get_primary_monitor ());
#endif #endif
var scale = (float)(monitor.height - TOP_OFFSET * scale_factor - BOTTOM_OFFSET * scale_factor) / monitor.height; var scale = (float)(monitor.height - TOP_OFFSET * scale_factor - BOTTOM_OFFSET * scale_factor) / monitor.height;
var pivotY = TOP_OFFSET * scale_factor / (monitor.height - monitor.height * scale); var pivotY = TOP_OFFSET * scale_factor / (monitor.height - monitor.height * scale);
update_size (monitor); update_size (monitor);
background.set_pivot_point (0.5f, pivotY); background.set_pivot_point (0.5f, pivotY);
background.save_easing_state (); background.save_easing_state ();
background.set_easing_duration (MultitaskingView.ANIMATION_DURATION); background.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
background.set_easing_mode (MultitaskingView.ANIMATION_MODE); background.set_easing_mode (MultitaskingView.ANIMATION_MODE);
background.set_scale (scale, scale); background.set_scale (scale, scale);
background.restore_easing_state (); background.restore_easing_state ();
Meta.Rectangle area = { Meta.Rectangle area = {
(int)Math.floorf (monitor.x + monitor.width - monitor.width * scale) / 2, (int)Math.floorf (monitor.x + monitor.width - monitor.width * scale) / 2,
(int)Math.floorf (monitor.y + TOP_OFFSET * scale_factor), (int)Math.floorf (monitor.y + TOP_OFFSET * scale_factor),
(int)Math.floorf (monitor.width * scale), (int)Math.floorf (monitor.width * scale),
(int)Math.floorf (monitor.height * scale) (int)Math.floorf (monitor.height * scale)
}; };
shrink_rectangle (ref area, 32); shrink_rectangle (ref area, 32);
window_container.padding_top = TOP_OFFSET * scale_factor; window_container.padding_top = TOP_OFFSET * scale_factor;
window_container.padding_left = window_container.padding_left =
window_container.padding_right = (int)(monitor.width - monitor.width * scale) / 2; window_container.padding_right = (int)(monitor.width - monitor.width * scale) / 2;
window_container.padding_bottom = BOTTOM_OFFSET * scale_factor; window_container.padding_bottom = BOTTOM_OFFSET * scale_factor;
icon_group.redraw (); icon_group.redraw ();
#if HAS_MUTTER330 #if HAS_MUTTER330
window_container.open (display.get_workspace_manager ().get_active_workspace () == workspace ? display.get_focus_window () : null); window_container.open (display.get_workspace_manager ().get_active_workspace () == workspace ? display.get_focus_window () : null);
#else #else
window_container.open (screen.get_active_workspace () == workspace ? display.get_focus_window () : null); window_container.open (screen.get_active_workspace () == workspace ? display.get_focus_window () : null);
#endif #endif
} }
/** /**
* Close the view again by animating the background back to its scale and * Close the view again by animating the background back to its scale and
* the windows back to their old locations. * the windows back to their old locations.
*/ */
public void close () public void close ()
{ {
if (!opened) if (!opened)
return; return;
opened = false; opened = false;
background.save_easing_state (); background.save_easing_state ();
background.set_easing_duration (MultitaskingView.ANIMATION_DURATION); background.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
background.set_easing_mode (MultitaskingView.ANIMATION_MODE); background.set_easing_mode (MultitaskingView.ANIMATION_MODE);
background.set_scale (1, 1); background.set_scale (1, 1);
background.restore_easing_state (); background.restore_easing_state ();
window_container.close (); window_container.close ();
} }
} }
} }

View File

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

View File

@ -20,126 +20,126 @@ using Meta;
namespace Gala namespace Gala
{ {
public struct WindowGeometry { public struct WindowGeometry {
Meta.Rectangle inner; Meta.Rectangle inner;
Meta.Rectangle outer; Meta.Rectangle outer;
} }
public class WindowListener : Object public class WindowListener : Object
{ {
static WindowListener? instance = null; static WindowListener? instance = null;
#if HAS_MUTTER330 #if HAS_MUTTER330
public static void init (Meta.Display display) public static void init (Meta.Display display)
{ {
if (instance != null) if (instance != null)
return; return;
instance = new WindowListener (); instance = new WindowListener ();
foreach (unowned Meta.WindowActor actor in display.get_window_actors ()) { foreach (unowned Meta.WindowActor actor in display.get_window_actors ()) {
if (actor.is_destroyed ()) if (actor.is_destroyed ())
continue; continue;
unowned Meta.Window window = actor.get_meta_window (); unowned Meta.Window window = actor.get_meta_window ();
if (window.window_type == WindowType.NORMAL) if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window); instance.monitor_window (window);
} }
display.window_created.connect ((window) => { display.window_created.connect ((window) => {
if (window.window_type == WindowType.NORMAL) if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window); instance.monitor_window (window);
}); });
} }
#else #else
public static void init (Screen screen) public static void init (Screen screen)
{ {
if (instance != null) if (instance != null)
return; return;
instance = new WindowListener (); instance = new WindowListener ();
foreach (unowned Meta.WindowActor actor in screen.get_window_actors ()) { foreach (unowned Meta.WindowActor actor in screen.get_window_actors ()) {
if (actor.is_destroyed ()) if (actor.is_destroyed ())
continue; continue;
unowned Meta.Window window = actor.get_meta_window (); unowned Meta.Window window = actor.get_meta_window ();
if (window.window_type == WindowType.NORMAL) if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window); instance.monitor_window (window);
} }
screen.get_display ().window_created.connect ((window) => { screen.get_display ().window_created.connect ((window) => {
if (window.window_type == WindowType.NORMAL) if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window); instance.monitor_window (window);
}); });
} }
#endif #endif
public static unowned WindowListener get_default () public static unowned WindowListener get_default ()
requires (instance != null) requires (instance != null)
{ {
return instance; return instance;
} }
public signal void window_no_longer_on_all_workspaces (Window window); public signal void window_no_longer_on_all_workspaces (Window window);
Gee.HashMap<Meta.Window, WindowGeometry?> unmaximized_state_geometry; Gee.HashMap<Meta.Window, WindowGeometry?> unmaximized_state_geometry;
WindowListener () WindowListener ()
{ {
unmaximized_state_geometry = new Gee.HashMap<Meta.Window, WindowGeometry?> (); unmaximized_state_geometry = new Gee.HashMap<Meta.Window, WindowGeometry?> ();
} }
void monitor_window (Window window) void monitor_window (Window window)
{ {
window.notify.connect (window_notify); window.notify.connect (window_notify);
window.unmanaged.connect (window_removed); window.unmanaged.connect (window_removed);
window_maximized_changed (window); window_maximized_changed (window);
} }
void window_notify (Object object, ParamSpec pspec) void window_notify (Object object, ParamSpec pspec)
{ {
var window = (Window) object; var window = (Window) object;
switch (pspec.name) { switch (pspec.name) {
case "maximized-horizontally": case "maximized-horizontally":
case "maximized-vertically": case "maximized-vertically":
window_maximized_changed (window); window_maximized_changed (window);
break; break;
case "on-all-workspaces": case "on-all-workspaces":
window_on_all_workspaces_changed (window); window_on_all_workspaces_changed (window);
break; break;
} }
} }
void window_on_all_workspaces_changed (Window window) void window_on_all_workspaces_changed (Window window)
{ {
if (window.on_all_workspaces) if (window.on_all_workspaces)
return; return;
window_no_longer_on_all_workspaces (window); window_no_longer_on_all_workspaces (window);
} }
void window_maximized_changed (Window window) void window_maximized_changed (Window window)
{ {
WindowGeometry window_geometry = {}; WindowGeometry window_geometry = {};
window_geometry.inner = window.get_frame_rect (); window_geometry.inner = window.get_frame_rect ();
window_geometry.outer = window.get_buffer_rect (); window_geometry.outer = window.get_buffer_rect ();
unmaximized_state_geometry.@set (window, window_geometry); unmaximized_state_geometry.@set (window, window_geometry);
} }
public WindowGeometry? get_unmaximized_state_geometry (Window window) public WindowGeometry? get_unmaximized_state_geometry (Window window)
{ {
return unmaximized_state_geometry.@get (window); return unmaximized_state_geometry.@get (window);
} }
void window_removed (Window window) void window_removed (Window window)
{ {
window.notify.disconnect (window_notify); window.notify.disconnect (window_notify);
window.unmanaged.disconnect (window_removed); window.unmanaged.disconnect (window_removed);
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -19,407 +19,407 @@ using Meta;
namespace Gala namespace Gala
{ {
public class WorkspaceManager : Object public class WorkspaceManager : Object
{ {
public static void init (WindowManager wm) public static void init (WindowManager wm)
requires (instance == null) requires (instance == null)
{ {
instance = new WorkspaceManager (wm); instance = new WorkspaceManager (wm);
} }
public static unowned WorkspaceManager get_default () public static unowned WorkspaceManager get_default ()
requires (instance != null) requires (instance != null)
{ {
return instance; return instance;
} }
static WorkspaceManager? instance = null; static WorkspaceManager? instance = null;
public WindowManager wm { get; construct; } public WindowManager wm { get; construct; }
Gee.LinkedList<Workspace> workspaces_marked_removed; Gee.LinkedList<Workspace> workspaces_marked_removed;
int remove_freeze_count = 0; int remove_freeze_count = 0;
WorkspaceManager (WindowManager wm) WorkspaceManager (WindowManager wm)
{ {
Object (wm: wm); Object (wm: wm);
} }
construct construct
{ {
workspaces_marked_removed = new Gee.LinkedList<Workspace> (); workspaces_marked_removed = new Gee.LinkedList<Workspace> ();
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.Display display = wm.get_display (); unowned Meta.Display display = wm.get_display ();
unowned Meta.WorkspaceManager manager = display.get_workspace_manager (); unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
if (Prefs.get_dynamic_workspaces ()) if (Prefs.get_dynamic_workspaces ())
manager.override_workspace_layout (DisplayCorner.TOPLEFT, false, 1, -1); manager.override_workspace_layout (DisplayCorner.TOPLEFT, false, 1, -1);
for (var i = 0; i < manager.get_n_workspaces (); i++) for (var i = 0; i < manager.get_n_workspaces (); i++)
workspace_added (manager, i); workspace_added (manager, i);
Prefs.add_listener (prefs_listener); Prefs.add_listener (prefs_listener);
manager.workspace_switched.connect_after (workspace_switched); manager.workspace_switched.connect_after (workspace_switched);
manager.workspace_added.connect (workspace_added); manager.workspace_added.connect (workspace_added);
manager.workspace_removed.connect_after (workspace_removed); manager.workspace_removed.connect_after (workspace_removed);
display.window_entered_monitor.connect (window_entered_monitor); display.window_entered_monitor.connect (window_entered_monitor);
display.window_left_monitor.connect (window_left_monitor); display.window_left_monitor.connect (window_left_monitor);
// make sure the last workspace has no windows on it // make sure the last workspace has no windows on it
if (Prefs.get_dynamic_workspaces () if (Prefs.get_dynamic_workspaces ()
&& Utils.get_n_windows (manager.get_workspace_by_index (manager.get_n_workspaces () - 1)) > 0) && Utils.get_n_windows (manager.get_workspace_by_index (manager.get_n_workspaces () - 1)) > 0)
append_workspace (); append_workspace ();
#else #else
unowned Screen screen = wm.get_screen (); unowned Screen screen = wm.get_screen ();
if (Prefs.get_dynamic_workspaces ()) if (Prefs.get_dynamic_workspaces ())
screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, 1, -1); screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, 1, -1);
for (var i = 0; i < screen.get_n_workspaces (); i++) for (var i = 0; i < screen.get_n_workspaces (); i++)
workspace_added (screen, i); workspace_added (screen, i);
Prefs.add_listener (prefs_listener); Prefs.add_listener (prefs_listener);
screen.workspace_switched.connect_after (workspace_switched); screen.workspace_switched.connect_after (workspace_switched);
screen.workspace_added.connect (workspace_added); screen.workspace_added.connect (workspace_added);
screen.workspace_removed.connect_after (workspace_removed); screen.workspace_removed.connect_after (workspace_removed);
screen.window_entered_monitor.connect (window_entered_monitor); screen.window_entered_monitor.connect (window_entered_monitor);
screen.window_left_monitor.connect (window_left_monitor); screen.window_left_monitor.connect (window_left_monitor);
// make sure the last workspace has no windows on it // make sure the last workspace has no windows on it
if (Prefs.get_dynamic_workspaces () if (Prefs.get_dynamic_workspaces ()
&& Utils.get_n_windows (screen.get_workspace_by_index (screen.get_n_workspaces () - 1)) > 0) && Utils.get_n_windows (screen.get_workspace_by_index (screen.get_n_workspaces () - 1)) > 0)
append_workspace (); append_workspace ();
#endif #endif
// There are some empty workspace at startup // There are some empty workspace at startup
cleanup (); cleanup ();
} }
~WorkspaceManager () ~WorkspaceManager ()
{ {
Prefs.remove_listener (prefs_listener); Prefs.remove_listener (prefs_listener);
#if HAS_MUTTER330
unowned Meta.Display display = wm.get_display ();
unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
manager.workspace_added.disconnect (workspace_added);
manager.workspace_switched.disconnect (workspace_switched);
manager.workspace_removed.disconnect (workspace_removed);
display.window_entered_monitor.disconnect (window_entered_monitor);
display.window_left_monitor.disconnect (window_left_monitor);
#else
unowned Screen screen = wm.get_screen ();
screen.workspace_added.disconnect (workspace_added);
screen.workspace_switched.disconnect (workspace_switched);
screen.workspace_removed.disconnect (workspace_removed);
screen.window_entered_monitor.disconnect (window_entered_monitor);
screen.window_left_monitor.disconnect (window_left_monitor);
#endif
}
#if HAS_MUTTER330
void workspace_added (Meta.WorkspaceManager manager, int index)
{
var workspace = manager.get_workspace_by_index (index);
if (workspace == null)
return;
workspace.window_added.connect (window_added);
workspace.window_removed.connect (window_removed);
}
void workspace_removed (Meta.WorkspaceManager manager, int index)
{
List<Workspace> existing_workspaces = null;
for (int i = 0; i < manager.get_n_workspaces (); i++) {
existing_workspaces.append (manager.get_workspace_by_index (i));
}
var it = workspaces_marked_removed.iterator ();
while (it.next ()) {
var workspace = it.@get ();
if (existing_workspaces.index (workspace) < 0)
it.remove ();
}
}
void workspace_switched (Meta.WorkspaceManager manager, 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 = manager.get_workspace_by_index (from);
if (Utils.get_n_windows (prev_workspace) < 1
&& from != manager.get_n_workspaces () - 1) {
remove_workspace (prev_workspace);
}
}
#else
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_removed (Screen screen, int index)
{
unowned List<Workspace> existing_workspaces = screen.get_workspaces ();
var it = workspaces_marked_removed.iterator ();
while (it.next ()) {
if (existing_workspaces.index (it.@get ()) < 0)
it.remove ();
}
}
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) {
remove_workspace (prev_workspace);
}
}
#endif
void window_added (Workspace? workspace, Window window)
{
if (workspace == null || !Prefs.get_dynamic_workspaces ()
|| window.on_all_workspaces)
return;
#if HAS_MUTTER330
unowned Meta.WorkspaceManager manager = workspace.get_display ().get_workspace_manager ();
int last_workspace = manager.get_n_workspaces () - 1;
#else
unowned Screen screen = workspace.get_screen ();
int last_workspace = screen.get_n_workspaces () - 1;
#endif
if ((window.window_type == WindowType.NORMAL
|| window.window_type == WindowType.DIALOG
|| window.window_type == WindowType.MODAL_DIALOG)
&& workspace.index () == last_workspace)
append_workspace ();
}
void window_removed (Workspace? workspace, Window window)
{
if (workspace == null || !Prefs.get_dynamic_workspaces () || window.on_all_workspaces)
return;
#if HAS_MUTTER330
unowned Meta.WorkspaceManager manager = workspace.get_display ().get_workspace_manager ();
var index = workspace.index ();
bool is_active_workspace = workspace == manager.get_active_workspace ();
int last_workspace = manager.get_n_workspaces () - 1;
#else
unowned Screen screen = workspace.get_screen ();
var index = screen.get_workspaces ().index (workspace);
bool is_active_workspace = workspace == screen.get_active_workspace ();
int last_workspace = screen.get_n_workspaces () - 1;
#endif
if (window.window_type != WindowType.NORMAL
&& window.window_type != WindowType.DIALOG
&& window.window_type != WindowType.MODAL_DIALOG)
return;
// 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
// or we are in modal-mode
if ((!is_active_workspace || wm.is_modal ())
&& remove_freeze_count < 1
&& Utils.get_n_windows (workspace) < 1
&& index != last_workspace) {
remove_workspace (workspace);
}
}
#if HAS_MUTTER330
void window_entered_monitor (Meta.Display display, int monitor, Window window)
{
if (InternalUtils.workspaces_only_on_primary ()
&& monitor == display.get_primary_monitor ())
window_added (window.get_workspace (), window);
}
void window_left_monitor (Meta.Display display, int monitor, Window window)
{
if (InternalUtils.workspaces_only_on_primary ()
&& monitor == display.get_primary_monitor ())
window_removed (window.get_workspace (), window);
}
#else
void window_entered_monitor (Screen screen, int monitor, Window window)
{
if (InternalUtils.workspaces_only_on_primary ()
&& monitor == screen.get_primary_monitor ())
window_added (window.get_workspace (), window);
}
void window_left_monitor (Screen screen, int monitor, Window window)
{
if (InternalUtils.workspaces_only_on_primary ()
&& monitor == screen.get_primary_monitor ())
window_removed (window.get_workspace (), window);
}
#endif
void prefs_listener (Meta.Preference pref)
{
#if HAS_MUTTER330
unowned Meta.WorkspaceManager manager = wm.get_display ().get_workspace_manager ();
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 (manager.get_workspace_by_index (manager.get_n_workspaces () - 1)) > 0)
append_workspace ();
}
#else
unowned Screen screen = wm.get_screen ();
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 ();
}
#endif
}
void append_workspace ()
{
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.Display display = wm.get_display (); unowned Meta.Display display = wm.get_display ();
unowned Meta.WorkspaceManager manager = display.get_workspace_manager (); unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
manager.workspace_added.disconnect (workspace_added);
manager.append_new_workspace (false, display.get_current_time ()); manager.workspace_switched.disconnect (workspace_switched);
manager.workspace_removed.disconnect (workspace_removed);
display.window_entered_monitor.disconnect (window_entered_monitor);
display.window_left_monitor.disconnect (window_left_monitor);
#else #else
unowned Screen screen = wm.get_screen (); unowned Screen screen = wm.get_screen ();
screen.workspace_added.disconnect (workspace_added);
screen.append_new_workspace (false, screen.get_display ().get_current_time ()); screen.workspace_switched.disconnect (workspace_switched);
screen.workspace_removed.disconnect (workspace_removed);
screen.window_entered_monitor.disconnect (window_entered_monitor);
screen.window_left_monitor.disconnect (window_left_monitor);
#endif #endif
} }
/** #if HAS_MUTTER330
* Make sure we switch to a different workspace and remove the given one void workspace_added (Meta.WorkspaceManager manager, int index)
* {
* @param workspace The workspace to remove var workspace = manager.get_workspace_by_index (index);
*/ if (workspace == null)
void remove_workspace (Workspace workspace) return;
{
workspace.window_added.connect (window_added);
workspace.window_removed.connect (window_removed);
}
void workspace_removed (Meta.WorkspaceManager manager, int index)
{
List<Workspace> existing_workspaces = null;
for (int i = 0; i < manager.get_n_workspaces (); i++) {
existing_workspaces.append (manager.get_workspace_by_index (i));
}
var it = workspaces_marked_removed.iterator ();
while (it.next ()) {
var workspace = it.@get ();
if (existing_workspaces.index (workspace) < 0)
it.remove ();
}
}
void workspace_switched (Meta.WorkspaceManager manager, 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 = manager.get_workspace_by_index (from);
if (Utils.get_n_windows (prev_workspace) < 1
&& from != manager.get_n_workspaces () - 1) {
remove_workspace (prev_workspace);
}
}
#else
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_removed (Screen screen, int index)
{
unowned List<Workspace> existing_workspaces = screen.get_workspaces ();
var it = workspaces_marked_removed.iterator ();
while (it.next ()) {
if (existing_workspaces.index (it.@get ()) < 0)
it.remove ();
}
}
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) {
remove_workspace (prev_workspace);
}
}
#endif
void window_added (Workspace? workspace, Window window)
{
if (workspace == null || !Prefs.get_dynamic_workspaces ()
|| window.on_all_workspaces)
return;
#if HAS_MUTTER330
unowned Meta.WorkspaceManager manager = workspace.get_display ().get_workspace_manager ();
int last_workspace = manager.get_n_workspaces () - 1;
#else
unowned Screen screen = workspace.get_screen ();
int last_workspace = screen.get_n_workspaces () - 1;
#endif
if ((window.window_type == WindowType.NORMAL
|| window.window_type == WindowType.DIALOG
|| window.window_type == WindowType.MODAL_DIALOG)
&& workspace.index () == last_workspace)
append_workspace ();
}
void window_removed (Workspace? workspace, Window window)
{
if (workspace == null || !Prefs.get_dynamic_workspaces () || window.on_all_workspaces)
return;
#if HAS_MUTTER330
unowned Meta.WorkspaceManager manager = workspace.get_display ().get_workspace_manager ();
var index = workspace.index ();
bool is_active_workspace = workspace == manager.get_active_workspace ();
int last_workspace = manager.get_n_workspaces () - 1;
#else
unowned Screen screen = workspace.get_screen ();
var index = screen.get_workspaces ().index (workspace);
bool is_active_workspace = workspace == screen.get_active_workspace ();
int last_workspace = screen.get_n_workspaces () - 1;
#endif
if (window.window_type != WindowType.NORMAL
&& window.window_type != WindowType.DIALOG
&& window.window_type != WindowType.MODAL_DIALOG)
return;
// 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
// or we are in modal-mode
if ((!is_active_workspace || wm.is_modal ())
&& remove_freeze_count < 1
&& Utils.get_n_windows (workspace) < 1
&& index != last_workspace) {
remove_workspace (workspace);
}
}
#if HAS_MUTTER330
void window_entered_monitor (Meta.Display display, int monitor, Window window)
{
if (InternalUtils.workspaces_only_on_primary ()
&& monitor == display.get_primary_monitor ())
window_added (window.get_workspace (), window);
}
void window_left_monitor (Meta.Display display, int monitor, Window window)
{
if (InternalUtils.workspaces_only_on_primary ()
&& monitor == display.get_primary_monitor ())
window_removed (window.get_workspace (), window);
}
#else
void window_entered_monitor (Screen screen, int monitor, Window window)
{
if (InternalUtils.workspaces_only_on_primary ()
&& monitor == screen.get_primary_monitor ())
window_added (window.get_workspace (), window);
}
void window_left_monitor (Screen screen, int monitor, Window window)
{
if (InternalUtils.workspaces_only_on_primary ()
&& monitor == screen.get_primary_monitor ())
window_removed (window.get_workspace (), window);
}
#endif
void prefs_listener (Meta.Preference pref)
{
#if HAS_MUTTER330
unowned Meta.WorkspaceManager manager = wm.get_display ().get_workspace_manager ();
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 (manager.get_workspace_by_index (manager.get_n_workspaces () - 1)) > 0)
append_workspace ();
}
#else
unowned Screen screen = wm.get_screen ();
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 ();
}
#endif
}
void append_workspace ()
{
#if HAS_MUTTER330
unowned Meta.Display display = wm.get_display ();
unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
manager.append_new_workspace (false, display.get_current_time ());
#else
unowned Screen screen = wm.get_screen ();
screen.append_new_workspace (false, screen.get_display ().get_current_time ());
#endif
}
/**
* Make sure we switch to a different workspace and remove the given one
*
* @param workspace The workspace to remove
*/
void remove_workspace (Workspace workspace)
{
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.Display display = workspace.get_display (); unowned Meta.Display display = workspace.get_display ();
unowned Meta.WorkspaceManager manager = display.get_workspace_manager (); unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
var time = display.get_current_time (); var time = display.get_current_time ();
unowned Meta.Workspace active_workspace = manager.get_active_workspace (); unowned Meta.Workspace active_workspace = manager.get_active_workspace ();
#else #else
unowned Screen screen = workspace.get_screen (); unowned Screen screen = workspace.get_screen ();
var time = screen.get_display ().get_current_time (); var time = screen.get_display ().get_current_time ();
unowned Meta.Workspace active_workspace = screen.get_active_workspace (); unowned Meta.Workspace active_workspace = screen.get_active_workspace ();
#endif #endif
if (workspace == active_workspace) { if (workspace == active_workspace) {
Workspace? next = null; Workspace? next = null;
next = workspace.get_neighbor (MotionDirection.LEFT); next = workspace.get_neighbor (MotionDirection.LEFT);
// if it's the first one we may have another one to the right // if it's the first one we may have another one to the right
if (next == workspace || next == null) if (next == workspace || next == null)
next = workspace.get_neighbor (MotionDirection.RIGHT); next = workspace.get_neighbor (MotionDirection.RIGHT);
if (next != null) if (next != null)
next.activate (time); next.activate (time);
} }
// workspace has already been removed // workspace has already been removed
if (workspace in workspaces_marked_removed) { if (workspace in workspaces_marked_removed) {
return; return;
} }
workspace.window_added.disconnect (window_added); workspace.window_added.disconnect (window_added);
workspace.window_removed.disconnect (window_removed); workspace.window_removed.disconnect (window_removed);
workspaces_marked_removed.add (workspace); workspaces_marked_removed.add (workspace);
#if HAS_MUTTER330 #if HAS_MUTTER330
manager.remove_workspace (workspace, time); manager.remove_workspace (workspace, time);
#else #else
screen.remove_workspace (workspace, time); screen.remove_workspace (workspace, time);
#endif #endif
} }
/** /**
* Temporarily disables removing workspaces when they are empty * Temporarily disables removing workspaces when they are empty
*/ */
public void freeze_remove () public void freeze_remove ()
{ {
remove_freeze_count++; remove_freeze_count++;
} }
/** /**
* Undo the effect of freeze_remove() * Undo the effect of freeze_remove()
*/ */
public void thaw_remove () public void thaw_remove ()
{ {
remove_freeze_count--; remove_freeze_count--;
assert (remove_freeze_count >= 0); assert (remove_freeze_count >= 0);
} }
/** /**
* If workspaces are dynamic, checks if there are empty workspaces that should * If workspaces are dynamic, checks if there are empty workspaces that should
* be removed. Particularily useful in conjunction with freeze/thaw_remove to * be removed. Particularily useful in conjunction with freeze/thaw_remove to
* cleanup after an operation that required stable workspace/window indices * cleanup after an operation that required stable workspace/window indices
*/ */
public void cleanup () public void cleanup ()
{ {
if (!Prefs.get_dynamic_workspaces ()) if (!Prefs.get_dynamic_workspaces ())
return; return;
#if HAS_MUTTER330 #if HAS_MUTTER330
unowned Meta.Display display = wm.get_display (); unowned Meta.Display display = wm.get_display ();
unowned Meta.WorkspaceManager manager = display.get_workspace_manager (); unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
List<Meta.Workspace> workspaces = null; List<Meta.Workspace> workspaces = null;
for (int i = 0; i < manager.get_n_workspaces (); i++) { for (int i = 0; i < manager.get_n_workspaces (); i++) {
workspaces.append (manager.get_workspace_by_index (i)); workspaces.append (manager.get_workspace_by_index (i));
} }
foreach (var workspace in workspaces) { foreach (var workspace in workspaces) {
var last_index = manager.get_n_workspaces () - 1; var last_index = manager.get_n_workspaces () - 1;
if (Utils.get_n_windows (workspace) < 1 if (Utils.get_n_windows (workspace) < 1
&& workspace.index () != last_index) { && workspace.index () != last_index) {
remove_workspace (workspace); remove_workspace (workspace);
} }
} }
#else #else
var screen = wm.get_screen (); var screen = wm.get_screen ();
var last_index = screen.get_n_workspaces () - 1; var last_index = screen.get_n_workspaces () - 1;
unowned GLib.List<Meta.Workspace> workspaces = screen.get_workspaces (); unowned GLib.List<Meta.Workspace> workspaces = screen.get_workspaces ();
foreach (var workspace in workspaces) { foreach (var workspace in workspaces) {
if (Utils.get_n_windows (workspace) < 1 if (Utils.get_n_windows (workspace) < 1
&& workspace.index () != last_index) { && workspace.index () != last_index) {
remove_workspace (workspace); remove_workspace (workspace);
} }
} }
#endif #endif
} }
} }
} }