mirror of
https://github.com/elementary/gala.git
synced 2024-09-11 07:05:30 +03:00
Convert all tabs to spaces (#684)
This commit is contained in:
parent
548ec08d89
commit
97cb42fb2d
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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, "&");
|
||||
text = tag_regex.replace (text, text.length, 0, "<");
|
||||
} catch (Error e) {}
|
||||
try {
|
||||
text = entity_regex.replace (markup, markup.length, 0, "&");
|
||||
text = tag_regex.replace (text, text.length, 0, "<");
|
||||
} 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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 ());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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, ¤t, sizeof (SettingsHashCache)) == 0) {
|
||||
return;
|
||||
}
|
||||
if (Memory.cmp (&settings_hash_cache, ¤t, sizeof (SettingsHashCache)) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Memory.copy (&settings_hash_cache, ¤t, sizeof (SettingsHashCache));
|
||||
Memory.copy (&settings_hash_cache, ¤t, 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 ()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
374
src/DBus.vala
374
src/DBus.vala
@ -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 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user