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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -20,99 +20,99 @@ using Meta;
namespace Gala.Plugins.Notify
{
public class NotificationStack : Actor
{
// 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
const int TOP_OFFSET = 2;
const int ADDITIONAL_MARGIN = 12;
public class NotificationStack : Actor
{
// 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
const int TOP_OFFSET = 2;
const int ADDITIONAL_MARGIN = 12;
public signal void animations_changed (bool running);
public signal void animations_changed (bool running);
#if HAS_MUTTER330
public Meta.Display display { get; construct; }
public Meta.Display display { get; construct; }
public NotificationStack (Meta.Display display)
{
Object (display: display);
}
public NotificationStack (Meta.Display display)
{
Object (display: display);
}
#else
public Screen screen { get; construct; }
public Screen screen { get; construct; }
public new float width
{
get
{
var scale = Utils.get_ui_scaling_factor ();
return (Notification.WIDTH + 2 * Notification.MARGIN + ADDITIONAL_MARGIN) * scale;
}
}
public new float width
{
get
{
var scale = Utils.get_ui_scaling_factor ();
return (Notification.WIDTH + 2 * Notification.MARGIN + ADDITIONAL_MARGIN) * scale;
}
}
public NotificationStack (Screen screen)
{
Object (screen: screen);
}
public NotificationStack (Screen screen)
{
Object (screen: screen);
}
#endif
construct
{
clip_to_allocation = true;
}
construct
{
clip_to_allocation = true;
}
public void show_notification (Notification notification)
{
animations_changed (true);
var scale = Utils.get_ui_scaling_factor ();
public void show_notification (Notification notification)
{
animations_changed (true);
var scale = Utils.get_ui_scaling_factor ();
// raise ourselves when we got something to show
get_parent ().set_child_above_sibling (this, null);
// raise ourselves when we got something to show
get_parent ().set_child_above_sibling (this, null);
// 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
notification.margin_left = ADDITIONAL_MARGIN * scale;
// 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
notification.margin_left = ADDITIONAL_MARGIN * scale;
notification.notify["being-destroyed"].connect (() => {
animations_changed (true);
});
notification.notify["being-destroyed"].connect (() => {
animations_changed (true);
});
notification.destroy.connect (() => {
animations_changed (false);
update_positions ();
});
notification.destroy.connect (() => {
animations_changed (false);
update_positions ();
});
notification.get_transition ("entry").completed.connect (() => {
animations_changed (false);
});
notification.get_transition ("entry").completed.connect (() => {
animations_changed (false);
});
float height;
notification.get_preferred_height (Notification.WIDTH * scale, out height, null);
update_positions (height);
float height;
notification.get_preferred_height (Notification.WIDTH * scale, out height, null);
update_positions (height);
notification.y = TOP_OFFSET * scale;
insert_child_at_index (notification, 0);
}
notification.y = TOP_OFFSET * scale;
insert_child_at_index (notification, 0);
}
void update_positions (float add_y = 0.0f)
{
var scale = Utils.get_ui_scaling_factor ();
var y = add_y + TOP_OFFSET * scale;
var i = get_n_children ();
var delay_step = i > 0 ? 150 / i : 0;
foreach (var child in get_children ()) {
if (((Notification) child).being_destroyed)
continue;
void update_positions (float add_y = 0.0f)
{
var scale = Utils.get_ui_scaling_factor ();
var y = add_y + TOP_OFFSET * scale;
var i = get_n_children ();
var delay_step = i > 0 ? 150 / i : 0;
foreach (var child in get_children ()) {
if (((Notification) child).being_destroyed)
continue;
child.save_easing_state ();
child.set_easing_mode (AnimationMode.EASE_OUT_BACK);
child.set_easing_duration (200);
child.set_easing_delay ((i--) * delay_step);
child.save_easing_state ();
child.set_easing_mode (AnimationMode.EASE_OUT_BACK);
child.set_easing_duration (200);
child.set_easing_delay ((i--) * delay_step);
child.y = y;
child.restore_easing_state ();
child.y = y;
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
{
public class NotifySettings : Granite.Services.Settings
{
public bool do_not_disturb { get; set; }
public class NotifySettings : Granite.Services.Settings
{
public bool do_not_disturb { get; set; }
static NotifySettings? instance = null;
static NotifySettings? instance = null;
private NotifySettings ()
{
base (Config.SCHEMA + ".notifications");
}
private NotifySettings ()
{
base (Config.SCHEMA + ".notifications");
}
public static unowned NotifySettings get_default ()
{
if (instance == null)
instance = new NotifySettings ();
public static unowned NotifySettings get_default ()
{
if (instance == null)
instance = new NotifySettings ();
return instance;
}
}
return instance;
}
}
}

View File

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

View File

@ -17,11 +17,11 @@
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)
{
move ();
return false;
}
public override bool drag_progress (Clutter.Actor actor, float delta_x, float delta_y)
{
move ();
return false;
}
}

View File

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

View File

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

View File

@ -19,135 +19,135 @@ using Clutter;
namespace Gala.Plugins.PIP
{
public class ShadowEffect : Effect
{
private class Shadow
{
public int users;
public Cogl.Texture texture;
public class ShadowEffect : Effect
{
private class Shadow
{
public int users;
public Cogl.Texture texture;
public Shadow (Cogl.Texture _texture)
{
texture = _texture;
users = 1;
}
}
public Shadow (Cogl.Texture _texture)
{
texture = _texture;
users = 1;
}
}
// 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.
static Gee.HashMap<string,Shadow> shadow_cache;
// 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.
static Gee.HashMap<string,Shadow> shadow_cache;
static construct
{
shadow_cache = new Gee.HashMap<string,Shadow> ();
}
static construct
{
shadow_cache = new Gee.HashMap<string,Shadow> ();
}
public int shadow_size { get; construct; }
public int shadow_spread { get; construct; }
public int shadow_size { get; construct; }
public int shadow_spread { get; construct; }
public float scale_factor { get; set; default = 1; }
public uint8 shadow_opacity { get; set; default = 255; }
public float scale_factor { get; set; default = 1; }
public uint8 shadow_opacity { get; set; default = 255; }
Cogl.Material material;
string? current_key = null;
Cogl.Material material;
string? current_key = null;
public ShadowEffect (int shadow_size, int shadow_spread)
{
Object (shadow_size: shadow_size, shadow_spread: shadow_spread);
}
public ShadowEffect (int shadow_size, int shadow_spread)
{
Object (shadow_size: shadow_size, shadow_spread: shadow_spread);
}
construct
{
material = new Cogl.Material ();
}
construct
{
material = new Cogl.Material ();
}
~ShadowEffect ()
{
if (current_key != null)
decrement_shadow_users (current_key);
}
~ShadowEffect ()
{
if (current_key != null)
decrement_shadow_users (current_key);
}
Cogl.Texture? get_shadow (int width, int height, int shadow_size, int shadow_spread)
{
var old_key = current_key;
Cogl.Texture? get_shadow (int width, int height, int shadow_size, int shadow_spread)
{
var old_key = current_key;
current_key = "%ix%i:%i:%i".printf (width, height, shadow_size, shadow_spread);
if (old_key == current_key)
return null;
current_key = "%ix%i:%i:%i".printf (width, height, shadow_size, shadow_spread);
if (old_key == current_key)
return null;
if (old_key != null)
decrement_shadow_users (old_key);
if (old_key != null)
decrement_shadow_users (old_key);
Shadow? shadow = null;
if ((shadow = shadow_cache.@get (current_key)) != null) {
shadow.users++;
return shadow.texture;
}
Shadow? shadow = null;
if ((shadow = shadow_cache.@get (current_key)) != null) {
shadow.users++;
return shadow.texture;
}
// fill a new texture for this size
var buffer = new Granite.Drawing.BufferSurface (width, height);
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);
buffer.context.set_source_rgba (0, 0, 0, 0.7);
buffer.context.fill ();
// fill a new texture for this size
var buffer = new Granite.Drawing.BufferSurface (width, height);
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);
buffer.context.set_source_rgba (0, 0, 0, 0.7);
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 cr = new Cairo.Context (surface);
var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
var cr = new Cairo.Context (surface);
cr.set_source_surface (buffer.surface, 0, 0);
cr.paint ();
cr.set_source_surface (buffer.surface, 0, 0);
cr.paint ();
var texture = new Cogl.Texture.from_data (width, height, 0, Cogl.PixelFormat.BGRA_8888_PRE,
Cogl.PixelFormat.ANY, surface.get_stride (), surface.get_data ());
var texture = new Cogl.Texture.from_data (width, height, 0, Cogl.PixelFormat.BGRA_8888_PRE,
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)
{
var shadow = shadow_cache.@get (key);
void decrement_shadow_users (string key)
{
var shadow = shadow_cache.@get (key);
if (shadow == null)
return;
if (shadow == null)
return;
if (--shadow.users == 0)
shadow_cache.unset (key);
}
if (--shadow.users == 0)
shadow_cache.unset (key);
}
public override void paint (EffectPaintFlags flags)
{
var bounding_box = get_bounding_box ();
var shadow = get_shadow ((int) (bounding_box.x2 - bounding_box.x1), (int) (bounding_box.y2 - bounding_box.y1),
shadow_size, shadow_spread);
public override void paint (EffectPaintFlags flags)
{
var bounding_box = get_bounding_box ();
var shadow = get_shadow ((int) (bounding_box.x2 - bounding_box.x1), (int) (bounding_box.y2 - bounding_box.y1),
shadow_size, shadow_spread);
if (shadow != null)
material.set_layer (0, shadow);
if (shadow != null)
material.set_layer (0, shadow);
var opacity = actor.get_paint_opacity () * shadow_opacity / 255;
var alpha = Cogl.Color.from_4ub (255, 255, 255, opacity);
alpha.premultiply ();
var opacity = actor.get_paint_opacity () * shadow_opacity / 255;
var alpha = Cogl.Color.from_4ub (255, 255, 255, opacity);
alpha.premultiply ();
material.set_color (alpha);
material.set_color (alpha);
Cogl.set_source (material);
Cogl.rectangle (bounding_box.x1, bounding_box.y1, bounding_box.x2, bounding_box.y2);
Cogl.set_source (material);
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 ()
{
var size = shadow_size * scale_factor;
var bounding_box = ActorBox ();
public virtual ActorBox get_bounding_box ()
{
var size = shadow_size * scale_factor;
var bounding_box = ActorBox ();
bounding_box.set_origin (-size, -size);
bounding_box.set_size (actor.width + size * 2, actor.height + size * 2);
bounding_box.set_origin (-size, -size);
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
{
public class Main : Gala.Plugin
{
const int PADDING = 50;
public class Main : Gala.Plugin
{
const int PADDING = 50;
Gala.WindowManager? wm = null;
Clutter.Actor red_box;
Gala.WindowManager? wm = null;
Clutter.Actor red_box;
// This function is called as soon as Gala has started and gives you
// an instance of the GalaWindowManager class.
public override void initialize (Gala.WindowManager wm)
{
// 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,
// we won't need it here
this.wm = wm;
// This function is called as soon as Gala has started and gives you
// an instance of the GalaWindowManager class.
public override void initialize (Gala.WindowManager wm)
{
// 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,
// we won't need it here
this.wm = wm;
// for demonstration purposes we'll add a red quad to the stage which will
// turn green when clicked
red_box = new Clutter.Actor ();
red_box.set_size (100, 100);
red_box.background_color = { 255, 0, 0, 255 };
red_box.reactive = true;
red_box.button_press_event.connect (turn_green);
// for demonstration purposes we'll add a red quad to the stage which will
// turn green when clicked
red_box = new Clutter.Actor ();
red_box.set_size (100, 100);
red_box.background_color = { 255, 0, 0, 255 };
red_box.reactive = true;
red_box.button_press_event.connect (turn_green);
// 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
// remotely similar to a documentation
// 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
// remotely similar to a documentation
#if HAS_MUTTER330
var display = wm.get_display ();
var rect = display.get_monitor_geometry (display.get_primary_monitor ());
var display = wm.get_display ();
var rect = display.get_monitor_geometry (display.get_primary_monitor ());
#else
var screen = wm.get_screen ();
var rect = screen.get_monitor_geometry (screen.get_primary_monitor ());
var screen = wm.get_screen ();
var rect = screen.get_monitor_geometry (screen.get_primary_monitor ());
#endif
red_box.x = rect.x + rect.width - red_box.width - PADDING;
red_box.y = rect.y + rect.height - red_box.height - PADDING;
red_box.x = rect.x + rect.width - red_box.width - 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
// 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
// function. It will update the region with the allocation of the actor
// whenever its allocation changes. Make sure to set freeze_track to
// true while animating the actor to not make gala update the region
// every single frame.
// You can also handle the region manually by setting the custom_region
// property. The tracked actors and custom regions will be merged by
// the plugin.
track_actor (red_box);
// 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.
// 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
// whenever its allocation changes. Make sure to set freeze_track to
// true while animating the actor to not make gala update the region
// every single frame.
// You can also handle the region manually by setting the custom_region
// property. The tracked actors and custom regions will be merged by
// the plugin.
track_actor (red_box);
// 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.
wm.ui_group.add_child (red_box);
}
// 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.
wm.ui_group.add_child (red_box);
}
bool turn_green (Clutter.ButtonEvent event)
{
red_box.background_color = { 0, 255, 0, 255 };
return true;
}
bool turn_green (Clutter.ButtonEvent event)
{
red_box.background_color = { 0, 255, 0, 255 };
return true;
}
// 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
// your plugin is compatible in case we'd add disabling specific plugins
// in the future
public override void destroy ()
{
// here you would destroy actors you added to the stage or remove
// keybindings
// 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
// your plugin is compatible in case we'd add disabling specific plugins
// in the future
public override void destroy ()
{
// here you would destroy actors you added to the stage or remove
// keybindings
red_box.destroy ();
}
}
red_box.destroy ();
}
}
}
// 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.
public Gala.PluginInfo register_plugin ()
{
return {
"template-plugin", // the plugin's name
"Tom Beckmann <tomjonabc@gmail.com>", // you, the author
typeof (Gala.Plugins.Template.Main), // the type of your plugin class
return {
"template-plugin", // the plugin's name
"Tom Beckmann <tomjonabc@gmail.com>", // you, the author
typeof (Gala.Plugins.Template.Main), // the type of your plugin class
Gala.PluginFunction.ADDITION, // the function which your plugin
// fulfils, ADDITION means nothing
// specific
Gala.PluginFunction.ADDITION, // the function which your plugin
// fulfils, ADDITION means nothing
// specific
Gala.LoadPriority.IMMEDIATE // indicates whether your plugin's
// start can be delayed until gala
// has loaded the important stuff or
// if you want your plugin to start
// right away. False means wait.
};
Gala.LoadPriority.IMMEDIATE // indicates whether your plugin's
// start can be delayed until gala
// has loaded the important stuff or
// if you want your plugin to start
// right away. False means wait.
};
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,233 +17,233 @@
namespace Gala
{
[DBus (name="org.pantheon.gala")]
public class DBus
{
static DBus? instance;
static WindowManager wm;
[DBus (name="org.pantheon.gala")]
public class DBus
{
static DBus? instance;
static WindowManager wm;
[DBus (visible = false)]
public static void init (WindowManager _wm)
{
wm = _wm;
[DBus (visible = false)]
public static void init (WindowManager _wm)
{
wm = _wm;
Bus.own_name (BusType.SESSION, "org.pantheon.gala", BusNameOwnerFlags.NONE,
(connection) => {
if (instance == null)
instance = new DBus ();
Bus.own_name (BusType.SESSION, "org.pantheon.gala", BusNameOwnerFlags.NONE,
(connection) => {
if (instance == null)
instance = new DBus ();
try {
connection.register_object ("/org/pantheon/gala", instance);
} catch (Error e) { warning (e.message); }
},
() => {},
() => warning ("Could not acquire name\n") );
try {
connection.register_object ("/org/pantheon/gala", instance);
} catch (Error e) { warning (e.message); }
},
() => {},
() => warning ("Could not acquire name\n") );
Bus.own_name (BusType.SESSION, "org.gnome.Shell", BusNameOwnerFlags.NONE,
(connection) => {
try {
connection.register_object ("/org/gnome/Shell", DBusAccelerator.init (wm));
connection.register_object ("/org/gnome/Shell/Screenshot", ScreenshotManager.init (wm));
} catch (Error e) { warning (e.message); }
},
() => {},
() => critical ("Could not acquire name") );
Bus.own_name (BusType.SESSION, "org.gnome.Shell", BusNameOwnerFlags.NONE,
(connection) => {
try {
connection.register_object ("/org/gnome/Shell", DBusAccelerator.init (wm));
connection.register_object ("/org/gnome/Shell/Screenshot", ScreenshotManager.init (wm));
} catch (Error e) { warning (e.message); }
},
() => {},
() => critical ("Could not acquire name") );
Bus.own_name (BusType.SESSION, "org.gnome.Shell.Screenshot", BusNameOwnerFlags.REPLACE,
() => {},
() => {},
() => critical ("Could not acquire name") );
Bus.own_name (BusType.SESSION, "org.gnome.Shell.Screenshot", BusNameOwnerFlags.REPLACE,
() => {},
() => {},
() => critical ("Could not acquire name") );
Bus.own_name (BusType.SESSION, "org.gnome.SessionManager.EndSessionDialog", BusNameOwnerFlags.NONE,
(connection) => {
try {
connection.register_object ("/org/gnome/SessionManager/EndSessionDialog", SessionManager.init ());
} catch (Error e) { warning (e.message); }
},
() => {},
() => critical ("Could not acquire name") );
}
Bus.own_name (BusType.SESSION, "org.gnome.SessionManager.EndSessionDialog", BusNameOwnerFlags.NONE,
(connection) => {
try {
connection.register_object ("/org/gnome/SessionManager/EndSessionDialog", SessionManager.init ());
} catch (Error e) { warning (e.message); }
},
() => {},
() => critical ("Could not acquire name") );
}
private DBus ()
{
if (wm.background_group != null)
(wm.background_group as BackgroundContainer).changed.connect (() => background_changed ());
else
assert_not_reached ();
}
private DBus ()
{
if (wm.background_group != null)
(wm.background_group as BackgroundContainer).changed.connect (() => background_changed ());
else
assert_not_reached ();
}
public void perform_action (ActionType type) throws DBusError, IOError
{
wm.perform_action (type);
}
public void perform_action (ActionType type) throws DBusError, IOError
{
wm.perform_action (type);
}
const double SATURATION_WEIGHT = 1.5;
const double WEIGHT_THRESHOLD = 1.0;
const double SATURATION_WEIGHT = 1.5;
const double WEIGHT_THRESHOLD = 1.0;
class DummyOffscreenEffect : Clutter.OffscreenEffect {
public signal void done_painting ();
public override void post_paint ()
{
base.post_paint ();
done_painting ();
}
}
class DummyOffscreenEffect : Clutter.OffscreenEffect {
public signal void done_painting ();
public override void post_paint ()
{
base.post_paint ();
done_painting ();
}
}
public struct ColorInformation
{
double average_red;
double average_green;
double average_blue;
double mean;
double variance;
}
public struct ColorInformation
{
double average_red;
double average_green;
double average_blue;
double mean;
double variance;
}
/**
* Emitted when the background change occured and the transition ended.
* 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
* done by GUIs. The change may not be visible to the user.
*/
public signal void background_changed ();
/**
* Emitted when the background change occured and the transition ended.
* 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
* done by GUIs. The change may not be visible to the user.
*/
public signal void background_changed ();
/**
* 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
* the average color in that area and the mean color value and variance. All
* variables are returned as a tuple in that order.
*
* @param monitor The monitor where the panel will be placed
* @param reference_x X coordinate of the rectangle used to gather color data
* relative to the monitor you picked. Values will be clamped
* to its dimensions
* @param reference_y Y coordinate
* @param reference_width Width of the rectangle
* @param reference_height Height of the rectangle
*/
public async ColorInformation get_background_color_information (int monitor,
int reference_x, int reference_y, int reference_width, int reference_height)
throws DBusError, IOError
{
var background = wm.background_group.get_child_at_index (monitor);
if (background == null)
throw new DBusError.INVALID_ARGS ("Invalid monitor requested");
/**
* 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
* the average color in that area and the mean color value and variance. All
* variables are returned as a tuple in that order.
*
* @param monitor The monitor where the panel will be placed
* @param reference_x X coordinate of the rectangle used to gather color data
* relative to the monitor you picked. Values will be clamped
* to its dimensions
* @param reference_y Y coordinate
* @param reference_width Width of the rectangle
* @param reference_height Height of the rectangle
*/
public async ColorInformation get_background_color_information (int monitor,
int reference_x, int reference_y, int reference_width, int reference_height)
throws DBusError, IOError
{
var background = wm.background_group.get_child_at_index (monitor);
if (background == null)
throw new DBusError.INVALID_ARGS ("Invalid monitor requested");
var effect = new DummyOffscreenEffect ();
background.add_effect (effect);
var effect = new DummyOffscreenEffect ();
background.add_effect (effect);
var tex_width = (int)background.width;
var tex_height = (int)background.height;
var tex_width = (int)background.width;
var tex_height = (int)background.height;
int x_start = reference_x;
int y_start = reference_y;
int width = int.min (tex_width - reference_x, reference_width);
int height = int.min (tex_height - reference_y, reference_height);
int x_start = reference_x;
int y_start = reference_y;
int width = int.min (tex_width - reference_x, reference_width);
int height = int.min (tex_height - reference_y, reference_height);
if (x_start > tex_width || x_start > tex_height || width <= 0 || height <= 0)
throw new DBusError.INVALID_ARGS ("Invalid rectangle specified");
if (x_start > tex_width || x_start > tex_height || width <= 0 || height <= 0)
throw new DBusError.INVALID_ARGS ("Invalid rectangle specified");
double variance = 0, mean = 0,
rTotal = 0, gTotal = 0, bTotal = 0;
double variance = 0, mean = 0,
rTotal = 0, gTotal = 0, bTotal = 0;
ulong paint_signal_handler = 0;
paint_signal_handler = effect.done_painting.connect (() => {
SignalHandler.disconnect (effect, paint_signal_handler);
background.remove_effect (effect);
ulong paint_signal_handler = 0;
paint_signal_handler = effect.done_painting.connect (() => {
SignalHandler.disconnect (effect, paint_signal_handler);
background.remove_effect (effect);
var texture = (Cogl.Texture)effect.get_texture ();
var pixels = new uint8[texture.get_width () * texture.get_height () * 4];
CoglFixes.texture_get_data (texture, Cogl.PixelFormat.BGRA_8888_PRE, 0, pixels);
var texture = (Cogl.Texture)effect.get_texture ();
var pixels = new uint8[texture.get_width () * texture.get_height () * 4];
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 pixel = 0;
double mean_squares = 0;
double pixel = 0;
double max, min, score, delta, scoreTotal = 0,
rTotal2 = 0, gTotal2 = 0, bTotal2 = 0;
double max, min, score, delta, scoreTotal = 0,
rTotal2 = 0, gTotal2 = 0, bTotal2 = 0;
// code to calculate weighted average color is copied from
// plank's lib/Drawing/DrawingService.vala average_color()
// http://bazaar.launchpad.net/~docky-core/plank/trunk/view/head:/lib/Drawing/DrawingService.vala
for (int y = y_start; y < height; y++) {
for (int x = x_start; x < width; x++) {
int i = y * width * 4 + x * 4;
// code to calculate weighted average color is copied from
// plank's lib/Drawing/DrawingService.vala average_color()
// http://bazaar.launchpad.net/~docky-core/plank/trunk/view/head:/lib/Drawing/DrawingService.vala
for (int y = y_start; y < height; y++) {
for (int x = x_start; x < width; x++) {
int i = y * width * 4 + x * 4;
uint8 r = pixels[i];
uint8 g = pixels[i + 1];
uint8 b = pixels[i + 2];
uint8 r = pixels[i];
uint8 g = pixels[i + 1];
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));
max = uint8.max (r, uint8.max (g, b));
delta = max - min;
min = uint8.min (r, uint8.min (g, b));
max = uint8.max (r, uint8.max (g, b));
delta = max - min;
// prefer colored pixels over shades of grey
score = SATURATION_WEIGHT * (delta == 0 ? 0.0 : delta / max);
// prefer colored pixels over shades of grey
score = SATURATION_WEIGHT * (delta == 0 ? 0.0 : delta / max);
rTotal += score * r;
gTotal += score * g;
bTotal += score * b;
scoreTotal += score;
rTotal += score * r;
gTotal += score * g;
bTotal += score * b;
scoreTotal += score;
rTotal += r;
gTotal += g;
bTotal += b;
rTotal += r;
gTotal += g;
bTotal += b;
mean += pixel;
mean_squares += pixel * pixel;
}
}
mean += pixel;
mean_squares += pixel * pixel;
}
}
scoreTotal /= size;
bTotal /= size;
gTotal /= size;
rTotal /= size;
scoreTotal /= size;
bTotal /= size;
gTotal /= size;
rTotal /= size;
if (scoreTotal > 0.0) {
bTotal /= scoreTotal;
gTotal /= scoreTotal;
rTotal /= scoreTotal;
}
if (scoreTotal > 0.0) {
bTotal /= scoreTotal;
gTotal /= scoreTotal;
rTotal /= scoreTotal;
}
bTotal2 /= size * uint8.MAX;
gTotal2 /= size * uint8.MAX;
rTotal2 /= size * uint8.MAX;
bTotal2 /= size * uint8.MAX;
gTotal2 /= size * uint8.MAX;
rTotal2 /= size * uint8.MAX;
// combine weighted and not weighted sum depending on the average "saturation"
// if saturation isn't reasonable enough
// s = 0.0 -> f = 0.0 ; s = WEIGHT_THRESHOLD -> f = 1.0
if (scoreTotal <= WEIGHT_THRESHOLD) {
var f = 1.0 / WEIGHT_THRESHOLD * scoreTotal;
var rf = 1.0 - f;
bTotal = bTotal * f + bTotal2 * rf;
gTotal = gTotal * f + gTotal2 * rf;
rTotal = rTotal * f + rTotal2 * rf;
}
// combine weighted and not weighted sum depending on the average "saturation"
// if saturation isn't reasonable enough
// s = 0.0 -> f = 0.0 ; s = WEIGHT_THRESHOLD -> f = 1.0
if (scoreTotal <= WEIGHT_THRESHOLD) {
var f = 1.0 / WEIGHT_THRESHOLD * scoreTotal;
var rf = 1.0 - f;
bTotal = bTotal * f + bTotal2 * rf;
gTotal = gTotal * f + gTotal2 * rf;
rTotal = rTotal * f + rTotal2 * rf;
}
// there shouldn't be values larger then 1.0
var max_val = double.max (rTotal, double.max (gTotal, bTotal));
if (max_val > 1.0) {
bTotal /= max_val;
gTotal /= max_val;
rTotal /= max_val;
}
// there shouldn't be values larger then 1.0
var max_val = double.max (rTotal, double.max (gTotal, bTotal));
if (max_val > 1.0) {
bTotal /= max_val;
gTotal /= max_val;
rTotal /= max_val;
}
mean /= size;
mean_squares *= mean_squares / size;
mean /= 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
{
public struct Accelerator
{
public string name;
public Meta.KeyBindingFlags flags;
}
public struct Accelerator
{
public string name;
public Meta.KeyBindingFlags flags;
}
[DBus (name="org.gnome.Shell")]
public class DBusAccelerator
{
static DBusAccelerator? instance;
[DBus (visible = false)]
public static unowned DBusAccelerator init (WindowManager wm)
{
if (instance == null)
instance = new DBusAccelerator (wm);
[DBus (name="org.gnome.Shell")]
public class DBusAccelerator
{
static DBusAccelerator? instance;
[DBus (visible = false)]
public static unowned DBusAccelerator init (WindowManager wm)
{
if (instance == null)
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;
HashTable<string, uint?> grabbed_accelerators;
WindowManager wm;
HashTable<string, uint?> grabbed_accelerators;
DBusAccelerator (WindowManager _wm)
{
wm = _wm;
grabbed_accelerators = new HashTable<string, uint?> (str_hash, str_equal);
DBusAccelerator (WindowManager _wm)
{
wm = _wm;
grabbed_accelerators = new HashTable<string, uint?> (str_hash, str_equal);
#if HAS_MUTTER330
wm.get_display ().accelerator_activated.connect (on_accelerator_activated);
wm.get_display ().accelerator_activated.connect (on_accelerator_activated);
#else
wm.get_screen ().get_display ().accelerator_activated.connect (on_accelerator_activated);
wm.get_screen ().get_display ().accelerator_activated.connect (on_accelerator_activated);
#endif
}
}
#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
void on_accelerator_activated (uint action, uint device_id, uint timestamp)
void on_accelerator_activated (uint action, uint device_id, uint timestamp)
#endif
{
foreach (string accelerator in grabbed_accelerators.get_keys ()) {
if (grabbed_accelerators[accelerator] == action) {
var parameters = new GLib.HashTable<string, Variant> (null, null);
{
foreach (string accelerator in grabbed_accelerators.get_keys ()) {
if (grabbed_accelerators[accelerator] == action) {
var parameters = new GLib.HashTable<string, Variant> (null, null);
#if HAS_MUTTER334
parameters.set ("device-id", new Variant.uint32 (device.id));
parameters.set ("device-id", new Variant.uint32 (device.id));
#else
parameters.set ("device-id", new Variant.uint32 (device_id));
parameters.set ("device-id", new Variant.uint32 (device_id));
#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
{
uint? action = grabbed_accelerators[accelerator];
public uint grab_accelerator (string accelerator, uint flags) throws DBusError, IOError
{
uint? action = grabbed_accelerators[accelerator];
if (action == null) {
if (action == null) {
#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
action = wm.get_display ().grab_accelerator (accelerator);
action = wm.get_display ().grab_accelerator (accelerator);
#else
action = wm.get_screen ().get_display ().grab_accelerator (accelerator);
action = wm.get_screen ().get_display ().grab_accelerator (accelerator);
#endif
if (action > 0) {
grabbed_accelerators[accelerator] = action;
}
}
if (action > 0) {
grabbed_accelerators[accelerator] = action;
}
}
return action;
}
return action;
}
public uint[] grab_accelerators (Accelerator[] accelerators) throws DBusError, IOError
{
uint[] actions = {};
public uint[] grab_accelerators (Accelerator[] accelerators) throws DBusError, IOError
{
uint[] actions = {};
foreach (unowned Accelerator? accelerator in accelerators) {
actions += grab_accelerator (accelerator.name, accelerator.flags);
}
foreach (unowned Accelerator? accelerator in accelerators) {
actions += grab_accelerator (accelerator.name, accelerator.flags);
}
return actions;
}
return actions;
}
public bool ungrab_accelerator (uint action) throws DBusError, IOError
{
bool ret = false;
public bool ungrab_accelerator (uint action) throws DBusError, IOError
{
bool ret = false;
foreach (unowned string accelerator in grabbed_accelerators.get_keys ()) {
if (grabbed_accelerators[accelerator] == action) {
foreach (unowned string accelerator in grabbed_accelerators.get_keys ()) {
if (grabbed_accelerators[accelerator] == action) {
#if HAS_MUTTER330
ret = wm.get_display ().ungrab_accelerator (action);
ret = wm.get_display ().ungrab_accelerator (action);
#else
ret = wm.get_screen ().get_display ().ungrab_accelerator (action);
ret = wm.get_screen ().get_display ().ungrab_accelerator (action);
#endif
grabbed_accelerators.remove (accelerator);
break;
}
}
grabbed_accelerators.remove (accelerator);
break;
}
}
return ret;
}
return ret;
}
[DBus (name = "ShowOSD")]
public void show_osd (GLib.HashTable<string, Variant> parameters) throws DBusError, IOError
{
int32 monitor_index = -1;
if (parameters.contains ("monitor"))
monitor_index = parameters["monitor"].get_int32 ();
string icon = "";
if (parameters.contains ("icon"))
icon = parameters["icon"].get_string ();
string label = "";
if (parameters.contains ("label"))
label = parameters["label"].get_string ();
int32 level = 0;
if (parameters.contains ("level"))
level = parameters["level"].get_int32 ();
//if (monitor_index > -1)
// message ("MediaFeedback requested for specific monitor %i which is not supported", monitor_index);
MediaFeedback.send (icon, level);
}
}
[DBus (name = "ShowOSD")]
public void show_osd (GLib.HashTable<string, Variant> parameters) throws DBusError, IOError
{
int32 monitor_index = -1;
if (parameters.contains ("monitor"))
monitor_index = parameters["monitor"].get_int32 ();
string icon = "";
if (parameters.contains ("icon"))
icon = parameters["icon"].get_string ();
string label = "";
if (parameters.contains ("label"))
label = parameters["label"].get_string ();
int32 level = 0;
if (parameters.contains ("level"))
level = parameters["level"].get_int32 ();
//if (monitor_index > -1)
// message ("MediaFeedback requested for specific monitor %i which is not supported", monitor_index);
MediaFeedback.send (icon, level);
}
}
}

View File

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

View File

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

View File

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

View File

@ -17,97 +17,97 @@
namespace Gala
{
public class KeyboardManager : Object
{
static KeyboardManager? instance;
static VariantType sources_variant_type;
public class KeyboardManager : Object
{
static KeyboardManager? instance;
static VariantType sources_variant_type;
public static void init (Meta.Display display)
{
if (instance != null)
return;
public static void init (Meta.Display display)
{
if (instance != null)
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
{
sources_variant_type = new VariantType ("a(ss)");
}
static construct
{
sources_variant_type = new VariantType ("a(ss)");
}
GLib.Settings settings;
GLib.Settings settings;
KeyboardManager ()
{
Object ();
}
construct
{
var schema = GLib.SettingsSchemaSource.get_default ().lookup ("org.gnome.desktop.input-sources", true);
if (schema == null)
return;
KeyboardManager ()
{
Object ();
}
construct
{
var schema = GLib.SettingsSchemaSource.get_default ().lookup ("org.gnome.desktop.input-sources", true);
if (schema == null)
return;
settings = new GLib.Settings.full (schema, null, null);
Signal.connect (settings, "changed", (Callback) set_keyboard_layout, this);
settings = new GLib.Settings.full (schema, null, null);
Signal.connect (settings, "changed", (Callback) set_keyboard_layout, this);
set_keyboard_layout (settings, "current");
}
set_keyboard_layout (settings, "current");
}
[CCode (instance_pos = -1)]
bool handle_modifiers_accelerator_activated (Meta.Display display)
{
display.ungrab_keyboard (display.get_current_time ());
[CCode (instance_pos = -1)]
bool handle_modifiers_accelerator_activated (Meta.Display display)
{
display.ungrab_keyboard (display.get_current_time ());
var sources = settings.get_value ("sources");
if (!sources.is_of_type (sources_variant_type))
return true;
var sources = settings.get_value ("sources");
if (!sources.is_of_type (sources_variant_type))
return true;
var n_sources = (uint) sources.n_children ();
if (n_sources < 2)
return true;
var n_sources = (uint) sources.n_children ();
if (n_sources < 2)
return true;
var current = settings.get_uint ("current");
settings.set_uint ("current", (current + 1) % n_sources);
var current = settings.get_uint ("current");
settings.set_uint ("current", (current + 1) % n_sources);
return true;
}
return true;
}
[CCode (instance_pos = -1)]
void set_keyboard_layout (GLib.Settings settings, string key)
{
if (!(key == "current" || key == "source" || key == "xkb-options"))
return;
[CCode (instance_pos = -1)]
void set_keyboard_layout (GLib.Settings settings, string key)
{
if (!(key == "current" || key == "source" || key == "xkb-options"))
return;
string layout = "us", variant = "", options = "";
string layout = "us", variant = "", options = "";
var sources = settings.get_value ("sources");
if (!sources.is_of_type (sources_variant_type))
return;
var sources = settings.get_value ("sources");
if (!sources.is_of_type (sources_variant_type))
return;
var current = settings.get_uint ("current");
unowned string? type = null, name = null;
if (sources.n_children () > current)
sources.get_child (current, "(&s&s)", out type, out name);
if (type == "xkb") {
string[] arr = name.split ("+", 2);
layout = arr[0];
variant = arr[1] ?? "";
}
var current = settings.get_uint ("current");
unowned string? type = null, name = null;
if (sources.n_children () > current)
sources.get_child (current, "(&s&s)", out type, out name);
if (type == "xkb") {
string[] arr = name.split ("+", 2);
layout = arr[0];
variant = arr[1] ?? "";
}
var xkb_options = settings.get_strv ("xkb-options");
if (xkb_options.length > 0)
options = string.joinv (",", xkb_options);
var xkb_options = settings.get_strv ("xkb-options");
if (xkb_options.length > 0)
options = string.joinv (",", xkb_options);
// Needed to make common keybindings work on non-latin layouts
if (layout != "us" || variant != "") {
layout = layout + ",us";
variant = variant + ",";
}
// Needed to make common keybindings work on non-latin layouts
if (layout != "us" || variant != "") {
layout = layout + ",us";
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
{
const OptionEntry[] OPTIONS = {
{ "version", 0, OptionFlags.NO_ARG, OptionArg.CALLBACK, (void*) print_version, "Print version", null },
{ null }
};
const OptionEntry[] OPTIONS = {
{ "version", 0, OptionFlags.NO_ARG, OptionArg.CALLBACK, (void*) print_version, "Print version", null },
{ null }
};
void print_version () {
stdout.printf ("Gala %s\n", Config.VERSION);
Meta.exit (Meta.ExitCode.SUCCESS);
}
void print_version () {
stdout.printf ("Gala %s\n", Config.VERSION);
Meta.exit (Meta.ExitCode.SUCCESS);
}
public static int main (string[] args)
{
unowned OptionContext ctx = Meta.get_option_context ();
ctx.add_main_entries (Gala.OPTIONS, null);
try {
ctx.parse (ref args);
} catch (Error e) {
stderr.printf ("Error initializing: %s\n", e.message);
Meta.exit (Meta.ExitCode.ERROR);
}
public static int main (string[] args)
{
unowned OptionContext ctx = Meta.get_option_context ();
ctx.add_main_entries (Gala.OPTIONS, null);
try {
ctx.parse (ref args);
} catch (Error e) {
stderr.printf ("Error initializing: %s\n", e.message);
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
* Taken from Gnome-Shell main.c
*/
GLib.Environment.set_variable ("NO_GAIL", "1", true);
GLib.Environment.set_variable ("NO_AT_BRIDGE", "1", true);
Meta.init ();
GLib.Environment.unset_variable ("NO_GAIL");
GLib.Environment.unset_variable ("NO_AT_BRIDGE");
/**
* Prevent Meta.init () from causing gtk to load gail and at-bridge
* Taken from Gnome-Shell main.c
*/
GLib.Environment.set_variable ("NO_GAIL", "1", true);
GLib.Environment.set_variable ("NO_AT_BRIDGE", "1", true);
Meta.init ();
GLib.Environment.unset_variable ("NO_GAIL");
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
// https://bugzilla.gnome.org/show_bug.cgi?id=543189
typeof (Gala.Utils).class_ref ();
// Force initialization of static fields in Utils class
// https://bugzilla.gnome.org/show_bug.cgi?id=543189
typeof (Gala.Utils).class_ref ();
return Meta.run ();
}
return Meta.run ();
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -20,82 +20,82 @@
namespace Gala
{
[DBus (name = "io.elementary.wingpanel.session.EndSessionDialog")]
public interface WingpanelEndSessionDialog : Object
{
public signal void confirmed_logout ();
public signal void confirmed_reboot ();
public signal void confirmed_shutdown ();
public signal void canceled ();
public signal void closed ();
[DBus (name = "io.elementary.wingpanel.session.EndSessionDialog")]
public interface WingpanelEndSessionDialog : Object
{
public signal void confirmed_logout ();
public signal void confirmed_reboot ();
public signal void confirmed_shutdown ();
public signal void canceled ();
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")]
public class SessionManager : Object
{
static SessionManager? instance;
[DBus (name = "org.gnome.SessionManager.EndSessionDialog")]
public class SessionManager : Object
{
static SessionManager? instance;
[DBus (visible = false)]
public static unowned SessionManager init ()
{
if (instance == null) {
instance = new SessionManager ();
}
[DBus (visible = false)]
public static unowned SessionManager init ()
{
if (instance == null) {
instance = new SessionManager ();
}
return instance;
}
return instance;
}
public signal void confirmed_logout ();
public signal void confirmed_reboot ();
public signal void confirmed_shutdown ();
public signal void canceled ();
public signal void closed ();
public signal void confirmed_logout ();
public signal void confirmed_reboot ();
public signal void confirmed_shutdown ();
public signal void canceled ();
public signal void closed ();
WingpanelEndSessionDialog? proxy = null;
WingpanelEndSessionDialog? proxy = null;
SessionManager ()
{
Bus.watch_name (BusType.SESSION, "io.elementary.wingpanel.session.EndSessionDialog",
BusNameWatcherFlags.NONE, proxy_appeared, proxy_vanished);
}
SessionManager ()
{
Bus.watch_name (BusType.SESSION, "io.elementary.wingpanel.session.EndSessionDialog",
BusNameWatcherFlags.NONE, proxy_appeared, proxy_vanished);
}
void get_proxy_cb (Object? o, AsyncResult? res)
{
try {
proxy = Bus.get_proxy.end (res);
} catch (Error e) {
warning ("Could not connect to io.elementary.wingpanel.session.EndSessionDialog proxy: %s", e.message);
return;
}
void get_proxy_cb (Object? o, AsyncResult? res)
{
try {
proxy = Bus.get_proxy.end (res);
} catch (Error e) {
warning ("Could not connect to io.elementary.wingpanel.session.EndSessionDialog proxy: %s", e.message);
return;
}
proxy.confirmed_logout.connect (() => confirmed_logout ());
proxy.confirmed_reboot.connect (() => confirmed_reboot ());
proxy.confirmed_shutdown.connect (() => confirmed_shutdown ());
proxy.canceled.connect (() => canceled ());
proxy.closed.connect (() => closed ());
}
proxy.confirmed_logout.connect (() => confirmed_logout ());
proxy.confirmed_reboot.connect (() => confirmed_reboot ());
proxy.confirmed_shutdown.connect (() => confirmed_shutdown ());
proxy.canceled.connect (() => canceled ());
proxy.closed.connect (() => closed ());
}
void proxy_appeared ()
{
Bus.get_proxy.begin<WingpanelEndSessionDialog> (BusType.SESSION,
"io.elementary.wingpanel.session.EndSessionDialog", "/io/elementary/wingpanel/session/EndSessionDialog",
0, null, get_proxy_cb);
}
void proxy_appeared ()
{
Bus.get_proxy.begin<WingpanelEndSessionDialog> (BusType.SESSION,
"io.elementary.wingpanel.session.EndSessionDialog", "/io/elementary/wingpanel/session/EndSessionDialog",
0, null, get_proxy_cb);
}
void proxy_vanished ()
{
proxy = null;
}
void proxy_vanished ()
{
proxy = null;
}
public void open (uint type, uint timestamp, uint open_length, ObjectPath[] inhibiters) throws DBusError, IOError
{
if (proxy == null) {
throw new DBusError.FAILED ("io.elementary.wingpanel.session.EndSessionDialog DBus interface is not registered.");
}
public void open (uint type, uint timestamp, uint open_length, ObjectPath[] inhibiters) throws DBusError, IOError
{
if (proxy == null) {
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
{
public class BehaviorSettings : Granite.Services.Settings
{
public bool dynamic_workspaces { get; set; }
public bool edge_tiling { get; set; }
public string panel_main_menu_action { get; set; }
public string toggle_recording_action { get; set; }
public string overlay_action { get; set; }
public string hotcorner_custom_command { get; set; }
public string[] dock_names { get; set; }
public bool move_maximized_workspace { get; set; }
public class BehaviorSettings : Granite.Services.Settings
{
public bool dynamic_workspaces { get; set; }
public bool edge_tiling { get; set; }
public string panel_main_menu_action { get; set; }
public string toggle_recording_action { get; set; }
public string overlay_action { get; set; }
public string hotcorner_custom_command { get; set; }
public string[] dock_names { 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_topright { get; set; }
public ActionType hotcorner_bottomleft { get; set; }
public ActionType hotcorner_bottomright { get; set; }
public ActionType hotcorner_topleft { get; set; }
public ActionType hotcorner_topright { get; set; }
public ActionType hotcorner_bottomleft { get; set; }
public ActionType hotcorner_bottomright { get; set; }
static BehaviorSettings? instance = null;
static BehaviorSettings? instance = null;
private BehaviorSettings ()
{
base (Config.SCHEMA + ".behavior");
}
private BehaviorSettings ()
{
base (Config.SCHEMA + ".behavior");
}
public static unowned BehaviorSettings get_default ()
{
if (instance == null)
instance = new BehaviorSettings ();
public static unowned BehaviorSettings get_default ()
{
if (instance == null)
instance = new BehaviorSettings ();
return instance;
}
}
return instance;
}
}
public class KeybindingSettings : Granite.Services.Settings
{
static KeybindingSettings? instance = null;
public class KeybindingSettings : Granite.Services.Settings
{
static KeybindingSettings? instance = null;
private KeybindingSettings ()
{
base (Config.SCHEMA + ".keybindings");
}
private KeybindingSettings ()
{
base (Config.SCHEMA + ".keybindings");
}
public static unowned KeybindingSettings get_default ()
{
if (instance == null)
instance = new KeybindingSettings ();
public static unowned KeybindingSettings get_default ()
{
if (instance == null)
instance = new KeybindingSettings ();
return instance;
}
}
return instance;
}
}
public class AppearanceSettings : Granite.Services.Settings
{
public string button_layout { get; set; }
public bool attach_modal_dialogs { get; set; }
public bool dim_parents { get; set; }
public string workspace_switcher_background { get; set; }
public class AppearanceSettings : Granite.Services.Settings
{
public string button_layout { get; set; }
public bool attach_modal_dialogs { get; set; }
public bool dim_parents { get; set; }
public string workspace_switcher_background { get; set; }
static AppearanceSettings? instance = null;
static AppearanceSettings? instance = null;
private AppearanceSettings ()
{
base (Config.SCHEMA + ".appearance");
}
private AppearanceSettings ()
{
base (Config.SCHEMA + ".appearance");
}
public static unowned AppearanceSettings get_default ()
{
if (instance == null)
instance = new AppearanceSettings ();
public static unowned AppearanceSettings get_default ()
{
if (instance == null)
instance = new AppearanceSettings ();
return instance;
}
}
return instance;
}
}
public class ShadowSettings : Granite.Services.Settings
{
public string[] menu { get; set; }
public string[] normal_focused { get; set; }
public string[] normal_unfocused { get; set; }
public string[] dialog_focused { get; set; }
public string[] dialog_unfocused { get; set; }
public class ShadowSettings : Granite.Services.Settings
{
public string[] menu { get; set; }
public string[] normal_focused { get; set; }
public string[] normal_unfocused { get; set; }
public string[] dialog_focused { get; set; }
public string[] dialog_unfocused { get; set; }
static ShadowSettings? instance = null;
static ShadowSettings? instance = null;
private ShadowSettings ()
{
base (Config.SCHEMA + ".shadows");
}
private ShadowSettings ()
{
base (Config.SCHEMA + ".shadows");
}
public static unowned ShadowSettings get_default ()
{
if (instance == null)
instance = new ShadowSettings ();
public static unowned ShadowSettings get_default ()
{
if (instance == null)
instance = new ShadowSettings ();
return instance;
}
return instance;
}
public Meta.ShadowParams get_shadowparams (string class_name)
{
string[] val;
get (class_name, out val);
public Meta.ShadowParams get_shadowparams (string class_name)
{
string[] val;
get (class_name, out val);
if (val == null || int.parse (val[0]) < 1)
return Meta.ShadowParams () {radius = 1, top_fade = 0, x_offset = 0, y_offset = 0, opacity = 0};
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 = 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])};
}
}
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])};
}
}
public class BackgroundSettings : Granite.Services.Settings
{
public string picture_options { get; set; }
public string picture_uri { get; set; }
public int picture_opacity { get; set; }
public string primary_color { get; set; }
public string secondary_color { get; set; }
public string color_shading_type { get; set; }
public class BackgroundSettings : Granite.Services.Settings
{
public string picture_options { get; set; }
public string picture_uri { get; set; }
public int picture_opacity { get; set; }
public string primary_color { get; set; }
public string secondary_color { get; set; }
public string color_shading_type { get; set; }
static BackgroundSettings? instance = null;
static BackgroundSettings? instance = null;
private BackgroundSettings ()
{
base ("org.gnome.desktop.background");
}
private BackgroundSettings ()
{
base ("org.gnome.desktop.background");
}
public static unowned BackgroundSettings get_default ()
{
if (instance == null)
instance = new BackgroundSettings ();
public static unowned BackgroundSettings get_default ()
{
if (instance == null)
instance = new BackgroundSettings ();
return instance;
}
}
return instance;
}
}
}

View File

@ -19,150 +19,150 @@ using Clutter;
namespace Gala
{
public class ShadowEffect : Effect
{
private class Shadow
{
public int users;
public Cogl.Texture texture;
public class ShadowEffect : Effect
{
private class Shadow
{
public int users;
public Cogl.Texture texture;
public Shadow (Cogl.Texture _texture)
{
texture = _texture;
users = 1;
}
}
public Shadow (Cogl.Texture _texture)
{
texture = _texture;
users = 1;
}
}
// 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.
static Gee.HashMap<string,Shadow> shadow_cache;
static Gtk.StyleContext style_context;
// 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.
static Gee.HashMap<string,Shadow> shadow_cache;
static Gtk.StyleContext style_context;
class construct
{
shadow_cache = new Gee.HashMap<string,Shadow> ();
class construct
{
shadow_cache = new Gee.HashMap<string,Shadow> ();
var style_path = new Gtk.WidgetPath ();
var id = style_path.append_type (typeof (Gtk.Window));
var style_path = new Gtk.WidgetPath ();
var id = style_path.append_type (typeof (Gtk.Window));
style_context = new Gtk.StyleContext ();
style_context.add_provider (Gala.Utils.get_gala_css (), Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK);
style_context.add_class ("decoration");
style_context.set_path (style_path);
}
style_context = new Gtk.StyleContext ();
style_context.add_provider (Gala.Utils.get_gala_css (), Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK);
style_context.add_class ("decoration");
style_context.set_path (style_path);
}
public int shadow_size { get; construct; }
public int shadow_spread { get; construct; }
public int shadow_size { get; construct; }
public int shadow_spread { get; construct; }
public float scale_factor { get; set; default = 1; }
public uint8 shadow_opacity { get; set; default = 255; }
public string? css_class { get; set; default = null; }
public float scale_factor { get; set; default = 1; }
public uint8 shadow_opacity { get; set; default = 255; }
public string? css_class { get; set; default = null; }
Cogl.Material material;
string? current_key = null;
Cogl.Material material;
string? current_key = null;
public ShadowEffect (int shadow_size, int shadow_spread)
{
Object (shadow_size: shadow_size, shadow_spread: shadow_spread);
}
public ShadowEffect (int shadow_size, int shadow_spread)
{
Object (shadow_size: shadow_size, shadow_spread: shadow_spread);
}
construct
{
material = new Cogl.Material ();
}
construct
{
material = new Cogl.Material ();
}
~ShadowEffect ()
{
if (current_key != null)
decrement_shadow_users (current_key);
}
~ShadowEffect ()
{
if (current_key != null)
decrement_shadow_users (current_key);
}
Cogl.Texture? get_shadow (int width, int height, int shadow_size, int shadow_spread)
{
var old_key = current_key;
current_key = "%ix%i:%i:%i".printf (width, height, shadow_size, shadow_spread);
if (old_key == current_key)
return null;
Cogl.Texture? get_shadow (int width, int height, int shadow_size, int shadow_spread)
{
var old_key = current_key;
current_key = "%ix%i:%i:%i".printf (width, height, shadow_size, shadow_spread);
if (old_key == current_key)
return null;
if (old_key != null)
decrement_shadow_users (old_key);
if (old_key != null)
decrement_shadow_users (old_key);
Shadow? shadow = null;
if ((shadow = shadow_cache.@get (current_key)) != null) {
shadow.users++;
return shadow.texture;
}
Shadow? shadow = null;
if ((shadow = shadow_cache.@get (current_key)) != null) {
shadow.users++;
return shadow.texture;
}
var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
var cr = new Cairo.Context (surface);
cr.set_source_rgba (0, 0, 0, 0);
cr.fill ();
var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
var cr = new Cairo.Context (surface);
cr.set_source_rgba (0, 0, 0, 0);
cr.fill ();
cr.set_operator (Cairo.Operator.OVER);
cr.save ();
cr.scale (scale_factor, scale_factor);
style_context.save ();
if (css_class != null) {
style_context.add_class (css_class);
}
cr.set_operator (Cairo.Operator.OVER);
cr.save ();
cr.scale (scale_factor, scale_factor);
style_context.save ();
if (css_class != null) {
style_context.add_class (css_class);
}
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.restore ();
cr.restore ();
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.restore ();
cr.restore ();
cr.paint ();
cr.paint ();
var texture = new Cogl.Texture.from_data (width, height, 0, Cogl.PixelFormat.BGRA_8888_PRE,
Cogl.PixelFormat.ANY, surface.get_stride (), surface.get_data ());
var texture = new Cogl.Texture.from_data (width, height, 0, Cogl.PixelFormat.BGRA_8888_PRE,
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)
{
var shadow = shadow_cache.@get (key);
void decrement_shadow_users (string key)
{
var shadow = shadow_cache.@get (key);
if (shadow == null)
return;
if (shadow == null)
return;
if (--shadow.users == 0)
shadow_cache.unset (key);
}
if (--shadow.users == 0)
shadow_cache.unset (key);
}
public override void paint (EffectPaintFlags flags)
{
var bounding_box = get_bounding_box ();
var width = (int) (bounding_box.x2 - bounding_box.x1);
var height = (int) (bounding_box.y2 - bounding_box.y1);
public override void paint (EffectPaintFlags flags)
{
var bounding_box = get_bounding_box ();
var width = (int) (bounding_box.x2 - bounding_box.x1);
var height = (int) (bounding_box.y2 - bounding_box.y1);
var shadow = get_shadow (width, height, shadow_size, shadow_spread);
if (shadow != null)
material.set_layer (0, shadow);
var shadow = get_shadow (width, height, shadow_size, shadow_spread);
if (shadow != null)
material.set_layer (0, shadow);
var opacity = actor.get_paint_opacity () * shadow_opacity / 255;
var alpha = Cogl.Color.from_4ub (255, 255, 255, opacity);
alpha.premultiply ();
var opacity = actor.get_paint_opacity () * shadow_opacity / 255;
var alpha = Cogl.Color.from_4ub (255, 255, 255, opacity);
alpha.premultiply ();
material.set_color (alpha);
material.set_color (alpha);
Cogl.set_source (material);
Cogl.rectangle (bounding_box.x1, bounding_box.y1, bounding_box.x2, bounding_box.y2);
Cogl.set_source (material);
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 ()
{
var size = shadow_size * scale_factor;
var bounding_box = ActorBox ();
public virtual ActorBox get_bounding_box ()
{
var size = shadow_size * scale_factor;
var bounding_box = ActorBox ();
bounding_box.set_origin (-size, -size);
bounding_box.set_size (actor.width + size * 2, actor.height + size * 2);
bounding_box.set_origin (-size, -size);
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
{
public class TextShadowEffect : Clutter.Effect
{
int _offset_y;
public int offset_y {
get { return _offset_y; }
set { _offset_y = value; update (); }
}
public class TextShadowEffect : Clutter.Effect
{
int _offset_y;
public int offset_y {
get { return _offset_y; }
set { _offset_y = value; update (); }
}
int _offset_x;
public int offset_x {
get { return _offset_x; }
set { _offset_x = value; update (); }
}
int _offset_x;
public int offset_x {
get { return _offset_x; }
set { _offset_x = value; update (); }
}
uint8 _opacity;
public uint8 opacity {
get { return _opacity; }
set { _opacity = value; update (); }
}
uint8 _opacity;
public uint8 opacity {
get { return _opacity; }
set { _opacity = value; update (); }
}
public TextShadowEffect (int offset_x, int offset_y, uint8 opacity)
{
_offset_x = offset_x;
_offset_y = offset_y;
_opacity = opacity;
}
public TextShadowEffect (int offset_x, int offset_y, uint8 opacity)
{
_offset_x = offset_x;
_offset_y = offset_y;
_opacity = opacity;
}
public override bool pre_paint ()
{
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);
public override bool pre_paint ()
{
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);
return true;
}
return true;
}
public void update ()
{
if (get_actor () != null)
get_actor ().queue_redraw ();
}
}
public void update ()
{
if (get_actor () != null)
get_actor ().queue_redraw ();
}
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -20,150 +20,150 @@ using Meta;
namespace Gala
{
/**
* More or less utility class to contain a WindowCloneContainer for each
* 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
* as the WindowGroup is hidden while the view is active. Only used when
* workspaces-only-on-primary is set to true.
*/
public class MonitorClone : Actor
{
public signal void window_selected (Window window);
/**
* More or less utility class to contain a WindowCloneContainer for each
* 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
* as the WindowGroup is hidden while the view is active. Only used when
* workspaces-only-on-primary is set to true.
*/
public class MonitorClone : Actor
{
public signal void window_selected (Window window);
#if HAS_MUTTER330
public Meta.Display display { get; construct; }
public Meta.Display display { get; construct; }
#else
public Screen screen { get; construct; }
public Screen screen { get; construct; }
#endif
public int monitor { get; construct; }
public int monitor { get; construct; }
WindowCloneContainer window_container;
BackgroundManager background;
WindowCloneContainer window_container;
BackgroundManager background;
#if HAS_MUTTER330
public MonitorClone (Meta.Display display, int monitor)
{
Object (display: display, monitor: monitor);
}
public MonitorClone (Meta.Display display, int monitor)
{
Object (display: display, monitor: monitor);
}
#else
public MonitorClone (Screen screen, int monitor)
{
Object (screen: screen, monitor: monitor);
}
public MonitorClone (Screen screen, int monitor)
{
Object (screen: screen, monitor: monitor);
}
#endif
construct
{
reactive = true;
construct
{
reactive = true;
#if HAS_MUTTER330
background = new BackgroundManager (display, monitor, false);
background = new BackgroundManager (display, monitor, false);
#else
background = new BackgroundManager (screen, monitor, false);
background = new BackgroundManager (screen, monitor, false);
#endif
background.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
background.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
window_container = new WindowCloneContainer ();
window_container.window_selected.connect ((w) => { window_selected (w); });
window_container = new WindowCloneContainer ();
window_container.window_selected.connect ((w) => { window_selected (w); });
#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_left_monitor.connect (window_left);
display.window_entered_monitor.connect (window_entered);
display.window_left_monitor.connect (window_left);
#else
screen.restacked.connect (window_container.restack_windows);
screen.restacked.connect (window_container.restack_windows);
screen.window_entered_monitor.connect (window_entered);
screen.window_left_monitor.connect (window_left);
screen.window_entered_monitor.connect (window_entered);
screen.window_left_monitor.connect (window_left);
#endif
#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
unowned GLib.List<Meta.WindowActor> window_actors = screen.get_window_actors ();
unowned GLib.List<Meta.WindowActor> window_actors = screen.get_window_actors ();
#endif
foreach (unowned Meta.WindowActor window_actor in window_actors) {
if (window_actor.is_destroyed ())
continue;
foreach (unowned Meta.WindowActor window_actor in window_actors) {
if (window_actor.is_destroyed ())
continue;
unowned Meta.Window window = window_actor.get_meta_window ();
if (window.get_monitor () == monitor) {
window_entered (monitor, window);
}
}
unowned Meta.Window window = window_actor.get_meta_window ();
if (window.get_monitor () == monitor) {
window_entered (monitor, window);
}
}
add_child (background);
add_child (window_container);
add_child (background);
add_child (window_container);
var drop = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
add_action (drop);
var drop = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
add_action (drop);
update_allocation ();
}
update_allocation ();
}
~MonitorClone ()
{
~MonitorClone ()
{
#if HAS_MUTTER330
display.window_entered_monitor.disconnect (window_entered);
display.window_left_monitor.disconnect (window_left);
display.restacked.disconnect (window_container.restack_windows);
display.window_entered_monitor.disconnect (window_entered);
display.window_left_monitor.disconnect (window_left);
display.restacked.disconnect (window_container.restack_windows);
#else
screen.window_entered_monitor.disconnect (window_entered);
screen.window_left_monitor.disconnect (window_left);
screen.restacked.disconnect (window_container.restack_windows);
screen.window_entered_monitor.disconnect (window_entered);
screen.window_left_monitor.disconnect (window_left);
screen.restacked.disconnect (window_container.restack_windows);
#endif
}
}
/**
* Make sure the MonitorClone is at the location of the monitor on the stage
*/
public void update_allocation ()
{
/**
* Make sure the MonitorClone is at the location of the monitor on the stage
*/
public void update_allocation ()
{
#if HAS_MUTTER330
var monitor_geometry = display.get_monitor_geometry (monitor);
var monitor_geometry = display.get_monitor_geometry (monitor);
#else
var monitor_geometry = screen.get_monitor_geometry (monitor);
var monitor_geometry = screen.get_monitor_geometry (monitor);
#endif
set_position (monitor_geometry.x, monitor_geometry.y);
set_size (monitor_geometry.width, monitor_geometry.height);
window_container.set_size (monitor_geometry.width, monitor_geometry.height);
}
set_position (monitor_geometry.x, monitor_geometry.y);
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
*/
public void open ()
{
window_container.open ();
// background.opacity = 0; TODO consider this option
}
/**
* Animate the windows from their old location to a tiled layout
*/
public void open ()
{
window_container.open ();
// background.opacity = 0; TODO consider this option
}
/**
* Animate the windows back to their old location
*/
public void close ()
{
window_container.close ();
background.opacity = 255;
}
/**
* Animate the windows back to their old location
*/
public void close ()
{
window_container.close ();
background.opacity = 255;
}
void window_left (int window_monitor, Window window)
{
if (window_monitor != monitor)
return;
void window_left (int window_monitor, Window window)
{
if (window_monitor != monitor)
return;
window_container.remove_window (window);
}
window_container.remove_window (window);
}
void window_entered (int window_monitor, Window window)
{
if (window_monitor != monitor || window.window_type != WindowType.NORMAL)
return;
void window_entered (int window_monitor, Window window)
{
if (window_monitor != monitor || window.window_type != WindowType.NORMAL)
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
{
/**
* A clone for a MetaWindowActor that will guard against the
* meta_window_appears_focused crash by disabling painting the clone
* as soon as it gets unavailable.
*/
public class SafeWindowClone : Clutter.Clone
{
public Window window { get; construct; }
/**
* A clone for a MetaWindowActor that will guard against the
* meta_window_appears_focused crash by disabling painting the clone
* as soon as it gets unavailable.
*/
public class SafeWindowClone : Clutter.Clone
{
public Window window { get; construct; }
/**
* If set to true, the SafeWindowClone will destroy itself when the connected
* window is unmanaged
*/
public bool destroy_on_unmanaged { get; construct set; default = false; }
/**
* If set to true, the SafeWindowClone will destroy itself when the connected
* window is unmanaged
*/
public bool destroy_on_unmanaged { get; construct set; default = false; }
/**
* Creates a new SafeWindowClone
*
* @param window The window to clone from
* @param destroy_on_unmanaged see destroy_on_unmanaged property
*/
public SafeWindowClone (Window window, bool destroy_on_unmanaged = false)
{
var actor = (WindowActor) window.get_compositor_private ();
/**
* Creates a new SafeWindowClone
*
* @param window The window to clone from
* @param destroy_on_unmanaged see destroy_on_unmanaged property
*/
public SafeWindowClone (Window window, bool destroy_on_unmanaged = false)
{
var actor = (WindowActor) window.get_compositor_private ();
Object (window: window,
source: actor,
destroy_on_unmanaged: destroy_on_unmanaged);
}
Object (window: window,
source: actor,
destroy_on_unmanaged: destroy_on_unmanaged);
}
construct
{
if (source != null)
window.unmanaged.connect (reset_source);
}
construct
{
if (source != null)
window.unmanaged.connect (reset_source);
}
~SafeWindowClone ()
{
window.unmanaged.disconnect (reset_source);
}
~SafeWindowClone ()
{
window.unmanaged.disconnect (reset_source);
}
void reset_source ()
{
// 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
// to draw a clone of a window that has been destroyed
source = null;
void reset_source ()
{
// 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
// to draw a clone of a window that has been destroyed
source = null;
if (destroy_on_unmanaged)
destroy ();
}
}
if (destroy_on_unmanaged)
destroy ();
}
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -21,368 +21,368 @@ using Clutter;
namespace Gala
{
public enum WindowOverviewType
{
GRID = 0,
NATURAL
}
public enum WindowOverviewType
{
GRID = 0,
NATURAL
}
public delegate void WindowPlacer (Actor window, Meta.Rectangle rect);
public delegate void WindowPlacer (Actor window, Meta.Rectangle rect);
public class WindowOverview : Actor, ActivatableComponent
{
const int BORDER = 10;
const int TOP_GAP = 30;
const int BOTTOM_GAP = 100;
public class WindowOverview : Actor, ActivatableComponent
{
const int BORDER = 10;
const int TOP_GAP = 30;
const int BOTTOM_GAP = 100;
public WindowManager wm { get; construct; }
public WindowManager wm { get; construct; }
#if HAS_MUTTER330
Meta.Display display;
Meta.Display display;
#else
Meta.Screen screen;
Meta.Screen screen;
#endif
ModalProxy modal_proxy;
bool ready;
ModalProxy modal_proxy;
bool ready;
// the workspaces which we expose right now
List<Workspace> workspaces;
// the workspaces which we expose right now
List<Workspace> workspaces;
public WindowOverview (WindowManager wm)
{
Object (wm : wm);
}
public WindowOverview (WindowManager wm)
{
Object (wm : wm);
}
construct
{
construct
{
#if HAS_MUTTER330
display = wm.get_display ();
display = wm.get_display ();
display.get_workspace_manager ().workspace_switched.connect (close);
display.restacked.connect (restack_windows);
display.get_workspace_manager ().workspace_switched.connect (close);
display.restacked.connect (restack_windows);
#else
screen = wm.get_screen ();
screen = wm.get_screen ();
screen.workspace_switched.connect (close);
screen.restacked.connect (restack_windows);
screen.workspace_switched.connect (close);
screen.restacked.connect (restack_windows);
#endif
visible = false;
ready = true;
reactive = true;
}
visible = false;
ready = true;
reactive = true;
}
~WindowOverview ()
{
~WindowOverview ()
{
#if HAS_MUTTER330
display.restacked.disconnect (restack_windows);
display.restacked.disconnect (restack_windows);
#else
screen.restacked.disconnect (restack_windows);
screen.restacked.disconnect (restack_windows);
#endif
}
}
public override bool key_press_event (Clutter.KeyEvent event)
{
if (event.keyval == Clutter.Key.Escape) {
close ();
public override bool key_press_event (Clutter.KeyEvent event)
{
if (event.keyval == Clutter.Key.Escape) {
close ();
return true;
}
return true;
}
return false;
}
return false;
}
public override void key_focus_out ()
{
if (!contains (get_stage ().key_focus))
close ();
}
public override void key_focus_out ()
{
if (!contains (get_stage ().key_focus))
close ();
}
public override bool button_press_event (Clutter.ButtonEvent event)
{
if (event.button == 1)
close ();
public override bool button_press_event (Clutter.ButtonEvent event)
{
if (event.button == 1)
close ();
return true;
}
return true;
}
/**
* {@inheritDoc}
*/
public bool is_opened ()
{
return visible;
}
/**
* {@inheritDoc}
*/
public bool is_opened ()
{
return visible;
}
/**
* {@inheritDoc}
* You may specify 'all-windows' in hints to expose all windows
*/
public void open (HashTable<string,Variant>? hints = null)
{
if (!ready)
return;
/**
* {@inheritDoc}
* You may specify 'all-windows' in hints to expose all windows
*/
public void open (HashTable<string,Variant>? hints = null)
{
if (!ready)
return;
if (visible) {
close ();
return;
}
if (visible) {
close ();
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
unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
if (all_windows) {
for (int i = 0; i < manager.get_n_workspaces (); i++) {
workspaces.append (manager.get_workspace_by_index (i));
}
} else {
workspaces.append (manager.get_active_workspace ());
}
if (all_windows) {
for (int i = 0; i < manager.get_n_workspaces (); i++) {
workspaces.append (manager.get_workspace_by_index (i));
}
} else {
workspaces.append (manager.get_active_workspace ());
}
#else
if (all_windows) {
foreach (var workspace in screen.get_workspaces ())
workspaces.append (workspace);
} else {
workspaces.append (screen.get_active_workspace ());
}
if (all_windows) {
foreach (var workspace in screen.get_workspaces ())
workspaces.append (workspace);
} else {
workspaces.append (screen.get_active_workspace ());
}
#endif
foreach (var workspace in workspaces) {
foreach (var window in workspace.list_windows ()) {
if (window.window_type != WindowType.NORMAL &&
window.window_type != WindowType.DOCK &&
window.window_type != WindowType.DIALOG ||
window.is_attached_dialog ()) {
var actor = window.get_compositor_private () as WindowActor;
if (actor != null)
actor.hide ();
continue;
}
if (window.window_type == WindowType.DOCK)
continue;
foreach (var workspace in workspaces) {
foreach (var window in workspace.list_windows ()) {
if (window.window_type != WindowType.NORMAL &&
window.window_type != WindowType.DOCK &&
window.window_type != WindowType.DIALOG ||
window.is_attached_dialog ()) {
var actor = window.get_compositor_private () as WindowActor;
if (actor != null)
actor.hide ();
continue;
}
if (window.window_type == WindowType.DOCK)
continue;
// skip windows that are on all workspace except we're currently
// processing the workspace it actually belongs to
if (window.is_on_all_workspaces () && window.get_workspace () != workspace)
continue;
// skip windows that are on all workspace except we're currently
// processing the workspace it actually belongs to
if (window.is_on_all_workspaces () && window.get_workspace () != workspace)
continue;
used_windows.append (window);
}
}
used_windows.append (window);
}
}
var n_windows = used_windows.length ();
if (n_windows == 0)
return;
var n_windows = used_windows.length ();
if (n_windows == 0)
return;
ready = false;
ready = false;
foreach (var workspace in workspaces) {
workspace.window_added.connect (add_window);
workspace.window_removed.connect (remove_window);
}
foreach (var workspace in workspaces) {
workspace.window_added.connect (add_window);
workspace.window_removed.connect (remove_window);
}
#if HAS_MUTTER330
display.window_left_monitor.connect (window_left_monitor);
display.window_left_monitor.connect (window_left_monitor);
// sort windows by stacking order
var windows = display.sort_windows_by_stacking (used_windows);
// sort windows by stacking order
var windows = display.sort_windows_by_stacking (used_windows);
#else
screen.window_left_monitor.connect (window_left_monitor);
screen.window_left_monitor.connect (window_left_monitor);
// sort windows by stacking order
var windows = screen.get_display ().sort_windows_by_stacking (used_windows);
// sort windows by stacking order
var windows = screen.get_display ().sort_windows_by_stacking (used_windows);
#endif
grab_key_focus ();
grab_key_focus ();
modal_proxy = wm.push_modal ();
modal_proxy.keybinding_filter = keybinding_filter;
modal_proxy = wm.push_modal ();
modal_proxy.keybinding_filter = keybinding_filter;
visible = true;
visible = true;
#if HAS_MUTTER330
for (var i = 0; i < display.get_n_monitors (); i++) {
var geometry = display.get_monitor_geometry (i);
for (var i = 0; i < display.get_n_monitors (); i++) {
var geometry = display.get_monitor_geometry (i);
#else
for (var i = 0; i < screen.get_n_monitors (); i++) {
var geometry = screen.get_monitor_geometry (i);
for (var i = 0; i < screen.get_n_monitors (); i++) {
var geometry = screen.get_monitor_geometry (i);
#endif
var container = new WindowCloneContainer (true);
container.padding_top = TOP_GAP;
container.padding_left = container.padding_right = BORDER;
container.padding_bottom = BOTTOM_GAP;
container.set_position (geometry.x, geometry.y);
container.set_size (geometry.width, geometry.height);
container.window_selected.connect (thumb_selected);
var container = new WindowCloneContainer (true);
container.padding_top = TOP_GAP;
container.padding_left = container.padding_right = BORDER;
container.padding_bottom = BOTTOM_GAP;
container.set_position (geometry.x, geometry.y);
container.set_size (geometry.width, geometry.height);
container.window_selected.connect (thumb_selected);
add_child (container);
}
add_child (container);
}
foreach (var window in windows) {
unowned WindowActor actor = window.get_compositor_private () as WindowActor;
if (actor != null)
actor.hide ();
foreach (var window in windows) {
unowned WindowActor actor = window.get_compositor_private () as WindowActor;
if (actor != null)
actor.hide ();
unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer;
if (container == null)
continue;
unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer;
if (container == null)
continue;
container.add_window (window);
}
container.add_window (window);
}
foreach (var child in get_children ())
((WindowCloneContainer) child).open ();
foreach (var child in get_children ())
((WindowCloneContainer) child).open ();
ready = true;
}
ready = true;
}
bool keybinding_filter (KeyBinding binding)
{
var name = binding.get_name ();
return (name != "expose-windows" && name != "expose-all-windows");
}
bool keybinding_filter (KeyBinding binding)
{
var name = binding.get_name ();
return (name != "expose-windows" && name != "expose-all-windows");
}
#if HAS_MUTTER330
void restack_windows (Display display)
{
foreach (var child in get_children ())
((WindowCloneContainer) child).restack_windows (display);
}
void restack_windows (Display display)
{
foreach (var child in get_children ())
((WindowCloneContainer) child).restack_windows (display);
}
#else
void restack_windows (Screen screen)
{
foreach (var child in get_children ())
((WindowCloneContainer) child).restack_windows (screen);
}
void restack_windows (Screen screen)
{
foreach (var child in get_children ())
((WindowCloneContainer) child).restack_windows (screen);
}
#endif
void window_left_monitor (int num, Window window)
{
unowned WindowCloneContainer container = get_child_at_index (num) as WindowCloneContainer;
if (container == null)
return;
void window_left_monitor (int num, Window window)
{
unowned WindowCloneContainer container = get_child_at_index (num) as WindowCloneContainer;
if (container == null)
return;
// make sure the window belongs to one of our workspaces
foreach (var workspace in workspaces)
if (window.located_on_workspace (workspace)) {
container.remove_window (window);
break;
}
}
// make sure the window belongs to one of our workspaces
foreach (var workspace in workspaces)
if (window.located_on_workspace (workspace)) {
container.remove_window (window);
break;
}
}
void add_window (Window window)
{
if (!visible
|| (window.window_type != WindowType.NORMAL && window.window_type != WindowType.DIALOG))
return;
void add_window (Window window)
{
if (!visible
|| (window.window_type != WindowType.NORMAL && window.window_type != WindowType.DIALOG))
return;
unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer;
if (container == null)
return;
unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer;
if (container == null)
return;
// make sure the window belongs to one of our workspaces
foreach (var workspace in workspaces)
if (window.located_on_workspace (workspace)) {
container.add_window (window);
break;
}
}
// make sure the window belongs to one of our workspaces
foreach (var workspace in workspaces)
if (window.located_on_workspace (workspace)) {
container.add_window (window);
break;
}
}
void remove_window (Window window)
{
unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer;
if (container == null)
return;
void remove_window (Window window)
{
unowned WindowCloneContainer container = get_child_at_index (window.get_monitor ()) as WindowCloneContainer;
if (container == null)
return;
container.remove_window (window);
}
container.remove_window (window);
}
#if HAS_MUTTER330
void thumb_selected (Window window)
{
if (window.get_workspace () == display.get_workspace_manager ().get_active_workspace ()) {
window.activate (display.get_current_time ());
close ();
} else {
close ();
//wait for the animation to finish before switching
Timeout.add (400, () => {
window.get_workspace ().activate_with_focus (window, display.get_current_time ());
return false;
});
}
}
void thumb_selected (Window window)
{
if (window.get_workspace () == display.get_workspace_manager ().get_active_workspace ()) {
window.activate (display.get_current_time ());
close ();
} else {
close ();
//wait for the animation to finish before switching
Timeout.add (400, () => {
window.get_workspace ().activate_with_focus (window, display.get_current_time ());
return false;
});
}
}
#else
void thumb_selected (Window window)
{
if (window.get_workspace () == screen.get_active_workspace ()) {
window.activate (screen.get_display ().get_current_time ());
close ();
} else {
close ();
//wait for the animation to finish before switching
Timeout.add (400, () => {
window.get_workspace ().activate_with_focus (window, screen.get_display ().get_current_time ());
return false;
});
}
}
void thumb_selected (Window window)
{
if (window.get_workspace () == screen.get_active_workspace ()) {
window.activate (screen.get_display ().get_current_time ());
close ();
} else {
close ();
//wait for the animation to finish before switching
Timeout.add (400, () => {
window.get_workspace ().activate_with_focus (window, screen.get_display ().get_current_time ());
return false;
});
}
}
#endif
/**
* {@inheritDoc}
*/
public void close ()
{
if (!visible || !ready)
return;
/**
* {@inheritDoc}
*/
public void close ()
{
if (!visible || !ready)
return;
foreach (var workspace in workspaces) {
workspace.window_added.disconnect (add_window);
workspace.window_removed.disconnect (remove_window);
}
foreach (var workspace in workspaces) {
workspace.window_added.disconnect (add_window);
workspace.window_removed.disconnect (remove_window);
}
#if HAS_MUTTER330
display.window_left_monitor.disconnect (window_left_monitor);
display.window_left_monitor.disconnect (window_left_monitor);
#else
screen.window_left_monitor.disconnect (window_left_monitor);
screen.window_left_monitor.disconnect (window_left_monitor);
#endif
ready = false;
ready = false;
wm.pop_modal (modal_proxy);
wm.pop_modal (modal_proxy);
foreach (var child in get_children ()) {
((WindowCloneContainer) child).close ();
}
foreach (var child in get_children ()) {
((WindowCloneContainer) child).close ();
}
Clutter.Threads.Timeout.add (300, () => {
cleanup ();
Clutter.Threads.Timeout.add (300, () => {
cleanup ();
return false;
});
}
return false;
});
}
void cleanup ()
{
ready = true;
visible = false;
void cleanup ()
{
ready = true;
visible = false;
#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
foreach (var window in screen.get_active_workspace ().list_windows ())
foreach (var window in screen.get_active_workspace ().list_windows ())
#endif
if (window.showing_on_its_workspace ())
((Actor) window.get_compositor_private ()).show ();
if (window.showing_on_its_workspace ())
((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
{
/**
* Utility class which adds a border and a shadow to a Background
*/
class FramedBackground : BackgroundManager
{
/**
* Utility class which adds a border and a shadow to a Background
*/
class FramedBackground : BackgroundManager
{
#if HAS_MUTTER330
public FramedBackground (Display display)
{
Object (display: display, monitor_index: display.get_primary_monitor (), control_position: false);
}
public FramedBackground (Display display)
{
Object (display: display, monitor_index: display.get_primary_monitor (), control_position: false);
}
#else
public FramedBackground (Screen screen)
{
Object (screen: screen, monitor_index: screen.get_primary_monitor (), control_position: false);
}
public FramedBackground (Screen screen)
{
Object (screen: screen, monitor_index: screen.get_primary_monitor (), control_position: false);
}
#endif
construct
{
construct
{
#if HAS_MUTTER330
var primary = display.get_primary_monitor ();
var monitor_geom = display.get_monitor_geometry (primary);
var primary = display.get_primary_monitor ();
var monitor_geom = display.get_monitor_geometry (primary);
#else
var primary = screen.get_primary_monitor ();
var monitor_geom = screen.get_monitor_geometry (primary);
var primary = screen.get_primary_monitor ();
var monitor_geom = screen.get_monitor_geometry (primary);
#endif
var effect = new ShadowEffect (40, 5);
effect.css_class = "workspace";
add_effect (effect);
}
var effect = new ShadowEffect (40, 5);
effect.css_class = "workspace";
add_effect (effect);
}
public override void paint ()
{
base.paint ();
public override void paint ()
{
base.paint ();
Cogl.set_source_color4ub (0, 0, 0, 100);
var path = new Cogl.Path ();
path.rectangle (0, 0, width, height);
path.stroke ();
Cogl.set_source_color4ub (0, 0, 0, 100);
var path = new Cogl.Path ();
path.rectangle (0, 0, width, height);
path.stroke ();
Cogl.set_source_color4ub (255, 255, 255, 25);
path.rectangle (0.5f, 0.5f, width - 1, height - 1);
path.stroke ();
}
}
Cogl.set_source_color4ub (255, 255, 255, 25);
path.rectangle (0.5f, 0.5f, width - 1, height - 1);
path.stroke ();
}
}
/**
* This is the container which manages a clone of the background which will
* be scaled and animated inwards, a WindowCloneContainer for the windows on
* 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
* of the MultitaskingView.
*/
public class WorkspaceClone : Actor
{
/**
* The offset of the scaled background to the bottom of the monitor bounds
*/
public const int BOTTOM_OFFSET = 100;
/**
* This is the container which manages a clone of the background which will
* be scaled and animated inwards, a WindowCloneContainer for the windows on
* 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
* of the MultitaskingView.
*/
public class WorkspaceClone : Actor
{
/**
* The offset of the scaled background to the bottom of the monitor bounds
*/
public const int BOTTOM_OFFSET = 100;
/**
* The offset of the scaled background to the top of the monitor bounds
*/
const int TOP_OFFSET = 20;
/**
* The offset of the scaled background to the top of the monitor bounds
*/
const int TOP_OFFSET = 20;
/**
* The amount of time a window has to be over the WorkspaceClone while in drag
* before we activate the workspace.
*/
const int HOVER_ACTIVATE_DELAY = 400;
/**
* The amount of time a window has to be over the WorkspaceClone while in drag
* before we activate the workspace.
*/
const int HOVER_ACTIVATE_DELAY = 400;
/**
* A window has been selected, the MultitaskingView should consider activating
* and closing the view.
*/
public signal void window_selected (Window window);
/**
* A window has been selected, the MultitaskingView should consider activating
* and closing the view.
*/
public signal void window_selected (Window window);
/**
* The background has been selected. Switch to that workspace.
*
* @param close_view If the MultitaskingView should also consider closing itself
* after switching.
*/
public signal void selected (bool close_view);
/**
* The background has been selected. Switch to that workspace.
*
* @param close_view If the MultitaskingView should also consider closing itself
* after switching.
*/
public signal void selected (bool close_view);
public Workspace workspace { get; construct; }
public IconGroup icon_group { get; private set; }
public WindowCloneContainer window_container { get; private set; }
public Workspace workspace { get; construct; }
public IconGroup icon_group { get; private set; }
public WindowCloneContainer window_container { get; private set; }
bool _active = false;
/**
* If this WorkspaceClone is currently the active one. Also sets the active
* state on its IconGroup.
*/
public bool active {
get {
return _active;
}
set {
_active = value;
icon_group.active = value;
}
}
bool _active = false;
/**
* If this WorkspaceClone is currently the active one. Also sets the active
* state on its IconGroup.
*/
public bool active {
get {
return _active;
}
set {
_active = value;
icon_group.active = value;
}
}
BackgroundManager background;
bool opened;
BackgroundManager background;
bool opened;
uint hover_activate_timeout = 0;
uint hover_activate_timeout = 0;
public WorkspaceClone (Workspace workspace)
{
Object (workspace: workspace);
}
public WorkspaceClone (Workspace workspace)
{
Object (workspace: workspace);
}
construct
{
opened = false;
construct
{
opened = false;
#if HAS_MUTTER330
unowned Display display = workspace.get_display ();
var monitor_geometry = display.get_monitor_geometry (display.get_primary_monitor ());
unowned Display display = workspace.get_display ();
var monitor_geometry = display.get_monitor_geometry (display.get_primary_monitor ());
#else
unowned Screen screen = workspace.get_screen ();
var monitor_geometry = screen.get_monitor_geometry (screen.get_primary_monitor ());
unowned Screen screen = workspace.get_screen ();
var monitor_geometry = screen.get_monitor_geometry (screen.get_primary_monitor ());
#endif
#if HAS_MUTTER330
background = new FramedBackground (display);
background = new FramedBackground (display);
#else
background = new FramedBackground (screen);
background = new FramedBackground (screen);
#endif
background.reactive = true;
background.button_press_event.connect (() => {
selected (true);
return false;
});
background.reactive = true;
background.button_press_event.connect (() => {
selected (true);
return false;
});
window_container = new WindowCloneContainer ();
window_container.window_selected.connect ((w) => { window_selected (w); });
window_container.set_size (monitor_geometry.width, monitor_geometry.height);
window_container = new WindowCloneContainer ();
window_container.window_selected.connect ((w) => { window_selected (w); });
window_container.set_size (monitor_geometry.width, monitor_geometry.height);
#if HAS_MUTTER330
display.restacked.connect (window_container.restack_windows);
display.restacked.connect (window_container.restack_windows);
#else
screen.restacked.connect (window_container.restack_windows);
screen.restacked.connect (window_container.restack_windows);
#endif
icon_group = new IconGroup (workspace);
icon_group.selected.connect (() => {
icon_group = new IconGroup (workspace);
icon_group.selected.connect (() => {
#if HAS_MUTTER330
if (workspace == display.get_workspace_manager ().get_active_workspace ())
Utils.bell (display);
else
selected (false);
if (workspace == display.get_workspace_manager ().get_active_workspace ())
Utils.bell (display);
else
selected (false);
#else
if (workspace == screen.get_active_workspace ())
Utils.bell (screen);
else
selected (false);
if (workspace == screen.get_active_workspace ())
Utils.bell (screen);
else
selected (false);
#endif
});
});
var icons_drop_action = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
icon_group.add_action (icons_drop_action);
var icons_drop_action = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
icon_group.add_action (icons_drop_action);
var background_drop_action = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
background.add_action (background_drop_action);
background_drop_action.crossed.connect ((target, hovered) => {
if (!hovered && hover_activate_timeout != 0) {
Source.remove (hover_activate_timeout);
hover_activate_timeout = 0;
return;
}
var background_drop_action = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
background.add_action (background_drop_action);
background_drop_action.crossed.connect ((target, hovered) => {
if (!hovered && hover_activate_timeout != 0) {
Source.remove (hover_activate_timeout);
hover_activate_timeout = 0;
return;
}
if (hovered && hover_activate_timeout == 0) {
hover_activate_timeout = Timeout.add (HOVER_ACTIVATE_DELAY, () => {
selected (false);
hover_activate_timeout = 0;
return false;
});
}
});
if (hovered && hover_activate_timeout == 0) {
hover_activate_timeout = Timeout.add (HOVER_ACTIVATE_DELAY, () => {
selected (false);
hover_activate_timeout = 0;
return false;
});
}
});
#if HAS_MUTTER330
display.window_entered_monitor.connect (window_entered_monitor);
display.window_left_monitor.connect (window_left_monitor);
display.window_entered_monitor.connect (window_entered_monitor);
display.window_left_monitor.connect (window_left_monitor);
#else
screen.window_entered_monitor.connect (window_entered_monitor);
screen.window_left_monitor.connect (window_left_monitor);
screen.window_entered_monitor.connect (window_entered_monitor);
screen.window_left_monitor.connect (window_left_monitor);
#endif
workspace.window_added.connect (add_window);
workspace.window_removed.connect (remove_window);
workspace.window_added.connect (add_window);
workspace.window_removed.connect (remove_window);
add_child (background);
add_child (window_container);
add_child (background);
add_child (window_container);
// add existing windows
var windows = workspace.list_windows ();
foreach (var window in windows) {
// add existing windows
var windows = workspace.list_windows ();
foreach (var window in windows) {
#if HAS_MUTTER330
if (window.window_type == WindowType.NORMAL
&& !window.on_all_workspaces
&& window.get_monitor () == display.get_primary_monitor ()) {
window_container.add_window (window);
icon_group.add_window (window, true);
}
if (window.window_type == WindowType.NORMAL
&& !window.on_all_workspaces
&& window.get_monitor () == display.get_primary_monitor ()) {
window_container.add_window (window);
icon_group.add_window (window, true);
}
#else
if (window.window_type == WindowType.NORMAL
&& !window.on_all_workspaces
&& window.get_monitor () == screen.get_primary_monitor ()) {
window_container.add_window (window);
icon_group.add_window (window, true);
}
if (window.window_type == WindowType.NORMAL
&& !window.on_all_workspaces
&& window.get_monitor () == screen.get_primary_monitor ()) {
window_container.add_window (window);
icon_group.add_window (window, true);
}
#endif
}
}
var listener = WindowListener.get_default ();
listener.window_no_longer_on_all_workspaces.connect (add_window);
}
var listener = WindowListener.get_default ();
listener.window_no_longer_on_all_workspaces.connect (add_window);
}
~WorkspaceClone ()
{
~WorkspaceClone ()
{
#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_left_monitor.disconnect (window_left_monitor);
display.window_entered_monitor.disconnect (window_entered_monitor);
display.window_left_monitor.disconnect (window_left_monitor);
#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_left_monitor.disconnect (window_left_monitor);
screen.window_entered_monitor.disconnect (window_entered_monitor);
screen.window_left_monitor.disconnect (window_left_monitor);
#endif
workspace.window_added.disconnect (add_window);
workspace.window_removed.disconnect (remove_window);
workspace.window_added.disconnect (add_window);
workspace.window_removed.disconnect (remove_window);
var listener = WindowListener.get_default ();
listener.window_no_longer_on_all_workspaces.disconnect (add_window);
var listener = WindowListener.get_default ();
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
* belongs to this workspace and this monitor.
*/
void add_window (Window window)
{
/**
* Add a window to the WindowCloneContainer and the IconGroup if it really
* belongs to this workspace and this monitor.
*/
void add_window (Window window)
{
#if HAS_MUTTER330
if (window.window_type != WindowType.NORMAL
|| window.get_workspace () != workspace
|| window.on_all_workspaces
|| window.get_monitor () != window.get_display ().get_primary_monitor ())
return;
if (window.window_type != WindowType.NORMAL
|| window.get_workspace () != workspace
|| window.on_all_workspaces
|| window.get_monitor () != window.get_display ().get_primary_monitor ())
return;
#else
if (window.window_type != WindowType.NORMAL
|| window.get_workspace () != workspace
|| window.on_all_workspaces
|| window.get_monitor () != window.get_screen ().get_primary_monitor ())
return;
if (window.window_type != WindowType.NORMAL
|| window.get_workspace () != workspace
|| window.on_all_workspaces
|| window.get_monitor () != window.get_screen ().get_primary_monitor ())
return;
#endif
foreach (var child in window_container.get_children ())
if (((WindowClone) child).window == window)
return;
foreach (var child in window_container.get_children ())
if (((WindowClone) child).window == window)
return;
window_container.add_window (window);
icon_group.add_window (window);
}
window_container.add_window (window);
icon_group.add_window (window);
}
/**
* Remove a window from the WindowCloneContainer and the IconGroup
*/
void remove_window (Window window)
{
window_container.remove_window (window);
icon_group.remove_window (window, opened);
}
/**
* Remove a window from the WindowCloneContainer and the IconGroup
*/
void remove_window (Window window)
{
window_container.remove_window (window);
icon_group.remove_window (window, opened);
}
#if HAS_MUTTER330
void window_entered_monitor (Display display, int monitor, Window window)
{
add_window (window);
}
void window_entered_monitor (Display display, int monitor, Window window)
{
add_window (window);
}
void window_left_monitor (Display display, int monitor, Window window)
{
if (monitor == display.get_primary_monitor ())
remove_window (window);
}
void window_left_monitor (Display display, int monitor, Window window)
{
if (monitor == display.get_primary_monitor ())
remove_window (window);
}
#else
void window_entered_monitor (Screen screen, int monitor, Window window)
{
add_window (window);
}
void window_entered_monitor (Screen screen, int monitor, Window window)
{
add_window (window);
}
void window_left_monitor (Screen screen, int monitor, Window window)
{
if (monitor == screen.get_primary_monitor ())
remove_window (window);
}
void window_left_monitor (Screen screen, int monitor, Window window)
{
if (monitor == screen.get_primary_monitor ())
remove_window (window);
}
#endif
void update_size (Meta.Rectangle monitor_geometry)
{
if (window_container.width != monitor_geometry.width || window_container.height != monitor_geometry.height) {
window_container.set_size (monitor_geometry.width, monitor_geometry.height);
background.set_size (window_container.width, window_container.height);
}
}
void update_size (Meta.Rectangle monitor_geometry)
{
if (window_container.width != monitor_geometry.width || window_container.height != monitor_geometry.height) {
window_container.set_size (monitor_geometry.width, monitor_geometry.height);
background.set_size (window_container.width, window_container.height);
}
}
/**
* Utility function to shrink a MetaRectangle on all sides for the given amount.
* Negative amounts will scale it instead.
*
* @param amount The amount in px to shrink.
*/
static inline void shrink_rectangle (ref Meta.Rectangle rect, int amount)
{
rect.x += amount;
rect.y += amount;
rect.width -= amount * 2;
rect.height -= amount * 2;
}
/**
* Utility function to shrink a MetaRectangle on all sides for the given amount.
* Negative amounts will scale it instead.
*
* @param amount The amount in px to shrink.
*/
static inline void shrink_rectangle (ref Meta.Rectangle rect, int amount)
{
rect.x += amount;
rect.y += amount;
rect.width -= amount * 2;
rect.height -= amount * 2;
}
/**
* Animates the background to its scale, causes a redraw on the IconGroup and
* makes sure the WindowCloneContainer animates its windows to their tiled layout.
* Also sets the current_window of the WindowCloneContainer to the active window
* if it belongs to this workspace.
*/
public void open ()
{
if (opened)
return;
/**
* Animates the background to its scale, causes a redraw on the IconGroup and
* makes sure the WindowCloneContainer animates its windows to their tiled layout.
* Also sets the current_window of the WindowCloneContainer to the active window
* if it belongs to this workspace.
*/
public void open ()
{
if (opened)
return;
opened = true;
opened = true;
var scale_factor = InternalUtils.get_ui_scaling_factor ();
var scale_factor = InternalUtils.get_ui_scaling_factor ();
#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
var screen = workspace.get_screen ();
var display = screen.get_display ();
var screen = workspace.get_screen ();
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
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 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);
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.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
background.set_easing_mode (MultitaskingView.ANIMATION_MODE);
background.set_scale (scale, scale);
background.restore_easing_state ();
background.save_easing_state ();
background.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
background.set_easing_mode (MultitaskingView.ANIMATION_MODE);
background.set_scale (scale, scale);
background.restore_easing_state ();
Meta.Rectangle area = {
(int)Math.floorf (monitor.x + monitor.width - monitor.width * scale) / 2,
(int)Math.floorf (monitor.y + TOP_OFFSET * scale_factor),
(int)Math.floorf (monitor.width * scale),
(int)Math.floorf (monitor.height * scale)
};
shrink_rectangle (ref area, 32);
Meta.Rectangle area = {
(int)Math.floorf (monitor.x + monitor.width - monitor.width * scale) / 2,
(int)Math.floorf (monitor.y + TOP_OFFSET * scale_factor),
(int)Math.floorf (monitor.width * scale),
(int)Math.floorf (monitor.height * scale)
};
shrink_rectangle (ref area, 32);
window_container.padding_top = TOP_OFFSET * scale_factor;
window_container.padding_left =
window_container.padding_right = (int)(monitor.width - monitor.width * scale) / 2;
window_container.padding_bottom = BOTTOM_OFFSET * scale_factor;
window_container.padding_top = TOP_OFFSET * scale_factor;
window_container.padding_left =
window_container.padding_right = (int)(monitor.width - monitor.width * scale) / 2;
window_container.padding_bottom = BOTTOM_OFFSET * scale_factor;
icon_group.redraw ();
icon_group.redraw ();
#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
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
}
}
/**
* Close the view again by animating the background back to its scale and
* the windows back to their old locations.
*/
public void close ()
{
if (!opened)
return;
/**
* Close the view again by animating the background back to its scale and
* the windows back to their old locations.
*/
public void close ()
{
if (!opened)
return;
opened = false;
opened = false;
background.save_easing_state ();
background.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
background.set_easing_mode (MultitaskingView.ANIMATION_MODE);
background.set_scale (1, 1);
background.restore_easing_state ();
background.save_easing_state ();
background.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
background.set_easing_mode (MultitaskingView.ANIMATION_MODE);
background.set_scale (1, 1);
background.restore_easing_state ();
window_container.close ();
}
}
window_container.close ();
}
}
}

View File

@ -20,112 +20,112 @@ using Meta;
namespace Gala
{
public class WorkspaceInsertThumb : Actor
{
public const int EXPAND_DELAY = 300;
public class WorkspaceInsertThumb : Actor
{
public const int EXPAND_DELAY = 300;
public int workspace_index { get; construct set; }
public bool expanded { get; set; default = false; }
public int delay { get; set; default = EXPAND_DELAY; }
public int workspace_index { get; construct set; }
public bool expanded { get; set; default = false; }
public int delay { get; set; default = EXPAND_DELAY; }
uint expand_timeout = 0;
uint expand_timeout = 0;
public WorkspaceInsertThumb (int workspace_index)
{
Object (workspace_index: workspace_index);
public WorkspaceInsertThumb (int workspace_index)
{
Object (workspace_index: workspace_index);
var scale = InternalUtils.get_ui_scaling_factor ();
width = IconGroupContainer.SPACING * scale;
height = IconGroupContainer.GROUP_WIDTH * scale;
y = (IconGroupContainer.GROUP_WIDTH * scale - IconGroupContainer.SPACING * scale) / 2;
opacity = 0;
set_pivot_point (0.5f, 0.5f);
reactive = true;
x_align = Clutter.ActorAlign.CENTER;
var scale = InternalUtils.get_ui_scaling_factor ();
width = IconGroupContainer.SPACING * scale;
height = IconGroupContainer.GROUP_WIDTH * scale;
y = (IconGroupContainer.GROUP_WIDTH * scale - IconGroupContainer.SPACING * scale) / 2;
opacity = 0;
set_pivot_point (0.5f, 0.5f);
reactive = true;
x_align = Clutter.ActorAlign.CENTER;
var drop = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
drop.crossed.connect ((target, hovered) => {
if (!Prefs.get_dynamic_workspaces () && (target != null && target is WindowClone))
return;
var drop = new DragDropAction (DragDropActionType.DESTINATION, "multitaskingview-window");
drop.crossed.connect ((target, hovered) => {
if (!Prefs.get_dynamic_workspaces () && (target != null && target is WindowClone))
return;
if (!hovered) {
if (expand_timeout != 0) {
Source.remove (expand_timeout);
expand_timeout = 0;
}
if (!hovered) {
if (expand_timeout != 0) {
Source.remove (expand_timeout);
expand_timeout = 0;
}
transform (false);
} else
expand_timeout = Timeout.add (delay, expand);
});
transform (false);
} else
expand_timeout = Timeout.add (delay, expand);
});
add_action (drop);
}
add_action (drop);
}
public void set_window_thumb (Window window)
{
destroy_all_children ();
public void set_window_thumb (Window window)
{
destroy_all_children ();
var scale = InternalUtils.get_ui_scaling_factor ();
var icon = new WindowIcon (window, IconGroupContainer.GROUP_WIDTH, scale);
icon.x = IconGroupContainer.SPACING;
icon.x_align = ActorAlign.CENTER;
add_child (icon);
}
var scale = InternalUtils.get_ui_scaling_factor ();
var icon = new WindowIcon (window, IconGroupContainer.GROUP_WIDTH, scale);
icon.x = IconGroupContainer.SPACING;
icon.x_align = ActorAlign.CENTER;
add_child (icon);
}
bool expand ()
{
expand_timeout = 0;
bool expand ()
{
expand_timeout = 0;
transform (true);
transform (true);
return false;
}
return false;
}
void transform (bool expand)
{
save_easing_state ();
set_easing_mode (AnimationMode.EASE_OUT_QUAD);
set_easing_duration (200);
void transform (bool expand)
{
save_easing_state ();
set_easing_mode (AnimationMode.EASE_OUT_QUAD);
set_easing_duration (200);
var scale = InternalUtils.get_ui_scaling_factor ();
if (!expand) {
remove_transition ("pulse");
opacity = 0;
width = IconGroupContainer.SPACING * scale;
expanded = false;
} else {
add_pulse_animation ();
opacity = 200;
width = IconGroupContainer.GROUP_WIDTH * scale + IconGroupContainer.SPACING * 2;
expanded = true;
}
var scale = InternalUtils.get_ui_scaling_factor ();
if (!expand) {
remove_transition ("pulse");
opacity = 0;
width = IconGroupContainer.SPACING * scale;
expanded = false;
} else {
add_pulse_animation ();
opacity = 200;
width = IconGroupContainer.GROUP_WIDTH * scale + IconGroupContainer.SPACING * 2;
expanded = true;
}
restore_easing_state ();
}
restore_easing_state ();
}
void add_pulse_animation ()
{
var transition = new TransitionGroup ();
transition.duration = 800;
transition.auto_reverse = true;
transition.repeat_count = -1;
transition.progress_mode = AnimationMode.LINEAR;
void add_pulse_animation ()
{
var transition = new TransitionGroup ();
transition.duration = 800;
transition.auto_reverse = true;
transition.repeat_count = -1;
transition.progress_mode = AnimationMode.LINEAR;
var scale_x_transition = new PropertyTransition ("scale-x");
scale_x_transition.set_from_value (0.8);
scale_x_transition.set_to_value (1.1);
scale_x_transition.auto_reverse = true;
var scale_x_transition = new PropertyTransition ("scale-x");
scale_x_transition.set_from_value (0.8);
scale_x_transition.set_to_value (1.1);
scale_x_transition.auto_reverse = true;
var scale_y_transition = new PropertyTransition ("scale-y");
scale_y_transition.set_from_value (0.8);
scale_y_transition.set_to_value (1.1);
scale_y_transition.auto_reverse = true;
var scale_y_transition = new PropertyTransition ("scale-y");
scale_y_transition.set_from_value (0.8);
scale_y_transition.set_to_value (1.1);
scale_y_transition.auto_reverse = true;
transition.add_transition (scale_x_transition);
transition.add_transition (scale_y_transition);
transition.add_transition (scale_x_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
{
public struct WindowGeometry {
Meta.Rectangle inner;
Meta.Rectangle outer;
}
public struct WindowGeometry {
Meta.Rectangle inner;
Meta.Rectangle outer;
}
public class WindowListener : Object
{
static WindowListener? instance = null;
public class WindowListener : Object
{
static WindowListener? instance = null;
#if HAS_MUTTER330
public static void init (Meta.Display display)
{
if (instance != null)
return;
public static void init (Meta.Display display)
{
if (instance != null)
return;
instance = new WindowListener ();
instance = new WindowListener ();
foreach (unowned Meta.WindowActor actor in display.get_window_actors ()) {
if (actor.is_destroyed ())
continue;
foreach (unowned Meta.WindowActor actor in display.get_window_actors ()) {
if (actor.is_destroyed ())
continue;
unowned Meta.Window window = actor.get_meta_window ();
if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window);
}
unowned Meta.Window window = actor.get_meta_window ();
if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window);
}
display.window_created.connect ((window) => {
if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window);
});
}
display.window_created.connect ((window) => {
if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window);
});
}
#else
public static void init (Screen screen)
{
if (instance != null)
return;
public static void init (Screen screen)
{
if (instance != null)
return;
instance = new WindowListener ();
instance = new WindowListener ();
foreach (unowned Meta.WindowActor actor in screen.get_window_actors ()) {
if (actor.is_destroyed ())
continue;
foreach (unowned Meta.WindowActor actor in screen.get_window_actors ()) {
if (actor.is_destroyed ())
continue;
unowned Meta.Window window = actor.get_meta_window ();
if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window);
}
unowned Meta.Window window = actor.get_meta_window ();
if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window);
}
screen.get_display ().window_created.connect ((window) => {
if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window);
});
}
screen.get_display ().window_created.connect ((window) => {
if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window);
});
}
#endif
public static unowned WindowListener get_default ()
requires (instance != null)
{
return instance;
}
public static unowned WindowListener get_default ()
requires (instance != null)
{
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 ()
{
unmaximized_state_geometry = new Gee.HashMap<Meta.Window, WindowGeometry?> ();
}
WindowListener ()
{
unmaximized_state_geometry = new Gee.HashMap<Meta.Window, WindowGeometry?> ();
}
void monitor_window (Window window)
{
window.notify.connect (window_notify);
window.unmanaged.connect (window_removed);
void monitor_window (Window window)
{
window.notify.connect (window_notify);
window.unmanaged.connect (window_removed);
window_maximized_changed (window);
}
window_maximized_changed (window);
}
void window_notify (Object object, ParamSpec pspec)
{
var window = (Window) object;
void window_notify (Object object, ParamSpec pspec)
{
var window = (Window) object;
switch (pspec.name) {
case "maximized-horizontally":
case "maximized-vertically":
window_maximized_changed (window);
break;
case "on-all-workspaces":
window_on_all_workspaces_changed (window);
break;
}
}
switch (pspec.name) {
case "maximized-horizontally":
case "maximized-vertically":
window_maximized_changed (window);
break;
case "on-all-workspaces":
window_on_all_workspaces_changed (window);
break;
}
}
void window_on_all_workspaces_changed (Window window)
{
if (window.on_all_workspaces)
return;
void window_on_all_workspaces_changed (Window window)
{
if (window.on_all_workspaces)
return;
window_no_longer_on_all_workspaces (window);
}
window_no_longer_on_all_workspaces (window);
}
void window_maximized_changed (Window window)
{
WindowGeometry window_geometry = {};
window_geometry.inner = window.get_frame_rect ();
window_geometry.outer = window.get_buffer_rect ();
void window_maximized_changed (Window window)
{
WindowGeometry window_geometry = {};
window_geometry.inner = window.get_frame_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)
{
return unmaximized_state_geometry.@get (window);
}
public WindowGeometry? get_unmaximized_state_geometry (Window window)
{
return unmaximized_state_geometry.@get (window);
}
void window_removed (Window window)
{
window.notify.disconnect (window_notify);
window.unmanaged.disconnect (window_removed);
}
}
void window_removed (Window window)
{
window.notify.disconnect (window_notify);
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
{
public class WorkspaceManager : Object
{
public static void init (WindowManager wm)
requires (instance == null)
{
instance = new WorkspaceManager (wm);
}
public class WorkspaceManager : Object
{
public static void init (WindowManager wm)
requires (instance == null)
{
instance = new WorkspaceManager (wm);
}
public static unowned WorkspaceManager get_default ()
requires (instance != null)
{
return instance;
}
public static unowned WorkspaceManager get_default ()
requires (instance != null)
{
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;
int remove_freeze_count = 0;
Gee.LinkedList<Workspace> workspaces_marked_removed;
int remove_freeze_count = 0;
WorkspaceManager (WindowManager wm)
{
Object (wm: wm);
}
WorkspaceManager (WindowManager wm)
{
Object (wm: wm);
}
construct
{
workspaces_marked_removed = new Gee.LinkedList<Workspace> ();
construct
{
workspaces_marked_removed = new Gee.LinkedList<Workspace> ();
#if HAS_MUTTER330
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 ())
manager.override_workspace_layout (DisplayCorner.TOPLEFT, false, 1, -1);
if (Prefs.get_dynamic_workspaces ())
manager.override_workspace_layout (DisplayCorner.TOPLEFT, false, 1, -1);
for (var i = 0; i < manager.get_n_workspaces (); i++)
workspace_added (manager, i);
for (var i = 0; i < manager.get_n_workspaces (); i++)
workspace_added (manager, i);
Prefs.add_listener (prefs_listener);
Prefs.add_listener (prefs_listener);
manager.workspace_switched.connect_after (workspace_switched);
manager.workspace_added.connect (workspace_added);
manager.workspace_removed.connect_after (workspace_removed);
display.window_entered_monitor.connect (window_entered_monitor);
display.window_left_monitor.connect (window_left_monitor);
manager.workspace_switched.connect_after (workspace_switched);
manager.workspace_added.connect (workspace_added);
manager.workspace_removed.connect_after (workspace_removed);
display.window_entered_monitor.connect (window_entered_monitor);
display.window_left_monitor.connect (window_left_monitor);
// make sure the last workspace has no windows on it
if (Prefs.get_dynamic_workspaces ()
&& Utils.get_n_windows (manager.get_workspace_by_index (manager.get_n_workspaces () - 1)) > 0)
append_workspace ();
// make sure the last workspace has no windows on it
if (Prefs.get_dynamic_workspaces ()
&& Utils.get_n_windows (manager.get_workspace_by_index (manager.get_n_workspaces () - 1)) > 0)
append_workspace ();
#else
unowned Screen screen = wm.get_screen ();
unowned Screen screen = wm.get_screen ();
if (Prefs.get_dynamic_workspaces ())
screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, 1, -1);
if (Prefs.get_dynamic_workspaces ())
screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, 1, -1);
for (var i = 0; i < screen.get_n_workspaces (); i++)
workspace_added (screen, i);
for (var i = 0; i < screen.get_n_workspaces (); i++)
workspace_added (screen, i);
Prefs.add_listener (prefs_listener);
Prefs.add_listener (prefs_listener);
screen.workspace_switched.connect_after (workspace_switched);
screen.workspace_added.connect (workspace_added);
screen.workspace_removed.connect_after (workspace_removed);
screen.window_entered_monitor.connect (window_entered_monitor);
screen.window_left_monitor.connect (window_left_monitor);
screen.workspace_switched.connect_after (workspace_switched);
screen.workspace_added.connect (workspace_added);
screen.workspace_removed.connect_after (workspace_removed);
screen.window_entered_monitor.connect (window_entered_monitor);
screen.window_left_monitor.connect (window_left_monitor);
// make sure the last workspace has no windows on it
if (Prefs.get_dynamic_workspaces ()
&& Utils.get_n_windows (screen.get_workspace_by_index (screen.get_n_workspaces () - 1)) > 0)
append_workspace ();
// make sure the last workspace has no windows on it
if (Prefs.get_dynamic_workspaces ()
&& Utils.get_n_windows (screen.get_workspace_by_index (screen.get_n_workspaces () - 1)) > 0)
append_workspace ();
#endif
// There are some empty workspace at startup
cleanup ();
}
// There are some empty workspace at startup
cleanup ();
}
~WorkspaceManager ()
{
Prefs.remove_listener (prefs_listener);
~WorkspaceManager ()
{
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
unowned Meta.Display display = wm.get_display ();
unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
manager.append_new_workspace (false, display.get_current_time ());
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.append_new_workspace (false, screen.get_display ().get_current_time ());
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
}
}
/**
* 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
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
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
unowned Meta.Display display = workspace.get_display ();
unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
var time = display.get_current_time ();
unowned Meta.Workspace active_workspace = manager.get_active_workspace ();
unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
var time = display.get_current_time ();
unowned Meta.Workspace active_workspace = manager.get_active_workspace ();
#else
unowned Screen screen = workspace.get_screen ();
unowned Screen screen = workspace.get_screen ();
var time = screen.get_display ().get_current_time ();
unowned Meta.Workspace active_workspace = screen.get_active_workspace ();
var time = screen.get_display ().get_current_time ();
unowned Meta.Workspace active_workspace = screen.get_active_workspace ();
#endif
if (workspace == active_workspace) {
Workspace? next = null;
if (workspace == active_workspace) {
Workspace? next = null;
next = workspace.get_neighbor (MotionDirection.LEFT);
// if it's the first one we may have another one to the right
if (next == workspace || next == null)
next = workspace.get_neighbor (MotionDirection.RIGHT);
next = workspace.get_neighbor (MotionDirection.LEFT);
// if it's the first one we may have another one to the right
if (next == workspace || next == null)
next = workspace.get_neighbor (MotionDirection.RIGHT);
if (next != null)
next.activate (time);
}
if (next != null)
next.activate (time);
}
// workspace has already been removed
if (workspace in workspaces_marked_removed) {
return;
}
// workspace has already been removed
if (workspace in workspaces_marked_removed) {
return;
}
workspace.window_added.disconnect (window_added);
workspace.window_removed.disconnect (window_removed);
workspace.window_added.disconnect (window_added);
workspace.window_removed.disconnect (window_removed);
workspaces_marked_removed.add (workspace);
workspaces_marked_removed.add (workspace);
#if HAS_MUTTER330
manager.remove_workspace (workspace, time);
manager.remove_workspace (workspace, time);
#else
screen.remove_workspace (workspace, time);
screen.remove_workspace (workspace, time);
#endif
}
}
/**
* Temporarily disables removing workspaces when they are empty
*/
public void freeze_remove ()
{
remove_freeze_count++;
}
/**
* Temporarily disables removing workspaces when they are empty
*/
public void freeze_remove ()
{
remove_freeze_count++;
}
/**
* Undo the effect of freeze_remove()
*/
public void thaw_remove ()
{
remove_freeze_count--;
/**
* Undo the effect of freeze_remove()
*/
public void thaw_remove ()
{
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
* be removed. Particularily useful in conjunction with freeze/thaw_remove to
* cleanup after an operation that required stable workspace/window indices
*/
public void cleanup ()
{
if (!Prefs.get_dynamic_workspaces ())
return;
/**
* If workspaces are dynamic, checks if there are empty workspaces that should
* be removed. Particularily useful in conjunction with freeze/thaw_remove to
* cleanup after an operation that required stable workspace/window indices
*/
public void cleanup ()
{
if (!Prefs.get_dynamic_workspaces ())
return;
#if HAS_MUTTER330
unowned Meta.Display display = wm.get_display ();
unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
List<Meta.Workspace> workspaces = null;
for (int i = 0; i < manager.get_n_workspaces (); i++) {
workspaces.append (manager.get_workspace_by_index (i));
}
unowned Meta.WorkspaceManager manager = display.get_workspace_manager ();
List<Meta.Workspace> workspaces = null;
for (int i = 0; i < manager.get_n_workspaces (); i++) {
workspaces.append (manager.get_workspace_by_index (i));
}
foreach (var workspace in workspaces) {
var last_index = manager.get_n_workspaces () - 1;
if (Utils.get_n_windows (workspace) < 1
&& workspace.index () != last_index) {
remove_workspace (workspace);
}
}
foreach (var workspace in workspaces) {
var last_index = manager.get_n_workspaces () - 1;
if (Utils.get_n_windows (workspace) < 1
&& workspace.index () != last_index) {
remove_workspace (workspace);
}
}
#else
var screen = wm.get_screen ();
var last_index = screen.get_n_workspaces () - 1;
unowned GLib.List<Meta.Workspace> workspaces = screen.get_workspaces ();
var screen = wm.get_screen ();
var last_index = screen.get_n_workspaces () - 1;
unowned GLib.List<Meta.Workspace> workspaces = screen.get_workspaces ();
foreach (var workspace in workspaces) {
if (Utils.get_n_windows (workspace) < 1
&& workspace.index () != last_index) {
remove_workspace (workspace);
}
}
foreach (var workspace in workspaces) {
if (Utils.get_n_windows (workspace) < 1
&& workspace.index () != last_index) {
remove_workspace (workspace);
}
}
#endif
}
}
}
}
}