mirror of
https://github.com/elementary/gala.git
synced 2024-12-24 17:53:19 +03:00
Fix various little problems, add track_actor functionality, add extended
plugin info allowing plugins to replace built-in componenets, allow them to delay their load.
This commit is contained in:
parent
d8ac8c372e
commit
e26d4274a0
176
lib/Plugin.vala
176
lib/Plugin.vala
@ -17,11 +17,179 @@
|
||||
|
||||
namespace Gala
|
||||
{
|
||||
public interface Plugin : Object
|
||||
public enum PluginFunction
|
||||
{
|
||||
public abstract X.Xrectangle[] region { get; protected set; }
|
||||
public abstract void initialize (WindowManager wm);
|
||||
public abstract void destroy ();
|
||||
ADDITION,
|
||||
WINDOW_SWITCHER,
|
||||
DESKTOP,
|
||||
WORKSPACE_VIEW,
|
||||
WINDOW_OVERVIEW
|
||||
}
|
||||
|
||||
public struct PluginInfo
|
||||
{
|
||||
string name;
|
||||
string author;
|
||||
|
||||
/**
|
||||
* Type of your plugin class, has to be derived from the Plugin class.
|
||||
*/
|
||||
Type plugin_type;
|
||||
|
||||
/**
|
||||
* This property allows you to override default functionality of gala
|
||||
* so systems won't be instantiated next to each other. Use
|
||||
* PluginFunction.ADDITION if no special component is overridden.
|
||||
*/
|
||||
PluginFunction provides;
|
||||
|
||||
/**
|
||||
* Indicate that your plugin does not need to be started immediately on
|
||||
* gala's launch but can wait until there's a bit less stuff going on.
|
||||
* Especially use this if you're adding a completely new ui component.
|
||||
*/
|
||||
bool load_can_wait;
|
||||
|
||||
/**
|
||||
* You don't have to fill this field, it will be filled by gala with
|
||||
* the filename in which your module was found.
|
||||
*/
|
||||
string module_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class has to be implemented by every plugin.
|
||||
* Additionally, the plugin module is required to have a register_plugin
|
||||
* function which returns a PluginInfo struct.
|
||||
* The plugin_type field has to be the type of your plugin class derived
|
||||
* from this class.
|
||||
*/
|
||||
public abstract class Plugin : Object
|
||||
{
|
||||
/**
|
||||
* The region indicates an area where mouse events should be sent to
|
||||
* the stage, which means your actors, instead of the windows.
|
||||
*
|
||||
* It is calculated by the system whenever update_region is called.
|
||||
* You can influce it with the custom_region and the track_actor function.
|
||||
*/
|
||||
public X.Xrectangle[] region { get; set; }
|
||||
|
||||
/**
|
||||
* This list will be merged with the region property. See region for
|
||||
* more details. Changing this property will cause update_region to be
|
||||
* called. Default to null.
|
||||
*/
|
||||
protected X.Xrectangle[]? custom_region {
|
||||
get {
|
||||
return _custom_region;
|
||||
}
|
||||
protected set {
|
||||
_custom_region = value;
|
||||
update_region ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this property to true while animating an actor if you have tracked
|
||||
* actors to prevent constant recalculations of the regions during an
|
||||
* animation.
|
||||
*/
|
||||
protected bool freeze_track { get; protected set; default = false; }
|
||||
|
||||
private X.Xrectangle[]? _custom_region = null;
|
||||
private Gee.LinkedList<Clutter.Actor> tracked_actors = new Gee.LinkedList<Clutter.Actor> ();
|
||||
|
||||
/**
|
||||
* Emitted when update_region is called. Mainly for internal purposes.
|
||||
*/
|
||||
public signal void region_changed ();
|
||||
|
||||
/**
|
||||
* Once this method is called you can start adding actors to the stage
|
||||
* using via the windowmanager instance that is given to you.
|
||||
*
|
||||
* @param wm The window manager.
|
||||
*/
|
||||
public abstract void initialize (WindowManager wm);
|
||||
|
||||
/**
|
||||
* This method is currently not called in the code, however you should
|
||||
* still implement it to be compatible whenever we decide to use it.
|
||||
* It should make sure that everything your plugin added to the stage
|
||||
* is cleaned up.
|
||||
*/
|
||||
public abstract void destroy ();
|
||||
|
||||
/**
|
||||
* Listen to changes to the allocation of actor and update the region
|
||||
* accordingly. You may add multiple actors, their shapes will be
|
||||
* combined when one of them changes.
|
||||
*
|
||||
* @param actor The actor to be tracked
|
||||
*/
|
||||
public void track_actor (Clutter.Actor actor)
|
||||
{
|
||||
tracked_actors.add (actor);
|
||||
actor.allocation_changed.connect (actor_allocation_changed);
|
||||
|
||||
update_region ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop listening to allocation changes and remove the actor's
|
||||
* allocation from the region array.
|
||||
*/
|
||||
public void untrack_actor (Clutter.Actor actor)
|
||||
{
|
||||
if (tracked_actors.remove (actor)) {
|
||||
actor.allocation_changed.disconnect (actor_allocation_changed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* You can call this method to force the system to update the region that
|
||||
* is used by the window manager. It will automatically upon changes to
|
||||
* the custom_region property and when a tracked actor's allocation changes
|
||||
* unless freeze_track is set to true. You may need to call this function
|
||||
* after setting freeze_track back to false after an animation to make the
|
||||
* wm aware of the new position of the actor in question.
|
||||
*/
|
||||
public void update_region ()
|
||||
{
|
||||
var has_custom = custom_region != null;
|
||||
var len = tracked_actors.size + (has_custom ? custom_region.length : 0);
|
||||
|
||||
X.Xrectangle[] regions = new X.Xrectangle[len];
|
||||
var i = 0;
|
||||
|
||||
if (has_custom) {
|
||||
for (var j = 0; j < custom_region.length; j++) {
|
||||
regions[i++] = custom_region[j];
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var actor in tracked_actors) {
|
||||
float x, y, w, h;
|
||||
actor.get_transformed_position (out x, out y);
|
||||
actor.get_transformed_size (out w, out h);
|
||||
|
||||
if (w == 0 || h == 0)
|
||||
continue;
|
||||
|
||||
regions[i++] = { (short)x, (short)y, (short)w, (short)h };
|
||||
}
|
||||
|
||||
region = regions;
|
||||
|
||||
region_changed ();
|
||||
}
|
||||
|
||||
private void actor_allocation_changed (Clutter.ActorBox box, Clutter.AllocationFlags f)
|
||||
{
|
||||
if (!freeze_track)
|
||||
update_region ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@ namespace Gala
|
||||
public abstract void perform_action (ActionType type);
|
||||
public abstract void update_input_area ();
|
||||
public abstract void move_window (Meta.Window? window, Meta.MotionDirection direction);
|
||||
public abstract void switch_to_next_workspace (Meta.MotionDirection direction);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (C) 2012 Tom Beckmann
|
||||
// Copyright (C) 2014 Tom Beckmann
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@ -15,6 +15,13 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// note on compilation: If you want your own plugin within this source tree
|
||||
// don't forget to add the new subdirectory to the plugins' Makefile.am
|
||||
// SUBDIRS list and add your Makefile to the list of Makefiles found at
|
||||
// about the end of the configure.ac file AC_CONFIG_FILES.
|
||||
// The API is currently internal until the API is finalized, so you have
|
||||
// to build it in this source tree.
|
||||
|
||||
/*
|
||||
This is a template class showing some of the things that can be done
|
||||
with a gala plugin and how to do them.
|
||||
@ -22,10 +29,8 @@
|
||||
|
||||
namespace Gala.Plugins.Template
|
||||
{
|
||||
public class Main : Object, Gala.Plugin
|
||||
public class Main : Gala.Plugin
|
||||
{
|
||||
public X.Xrectangle[] region { get; protected set; default = {}; }
|
||||
|
||||
Gala.WindowManager? wm = null;
|
||||
const int PADDING = 50;
|
||||
|
||||
@ -33,7 +38,7 @@ namespace Gala.Plugins.Template
|
||||
|
||||
// This function is called as soon as Gala has started and gives you
|
||||
// an instance of the GalaWindowManager class.
|
||||
public void initialize (Gala.WindowManager wm)
|
||||
public override void initialize (Gala.WindowManager wm)
|
||||
{
|
||||
// we will save the instance to our wm property so we can use it later again
|
||||
// especially helpful when you have larger plugins with more functions,
|
||||
@ -58,18 +63,16 @@ namespace Gala.Plugins.Template
|
||||
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. We do so
|
||||
// by setting the region property. If you have multiple areas, you can just
|
||||
// put more rectangle in this array.
|
||||
// Gala will listen to updates on this property and update all the areas
|
||||
// any time this changes for any plugin, so don't change this excessively like
|
||||
// for example if you play an animation, only set the area on the destination
|
||||
// point of the animation instead of making it follow the animated element.
|
||||
X.Xrectangle red_box_area = {
|
||||
(short)red_box.x, (short)red_box.y,
|
||||
(short)red_box.width, (short)red_box.height
|
||||
};
|
||||
region = { red_box_area };
|
||||
// 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.
|
||||
@ -86,7 +89,7 @@ namespace Gala.Plugins.Template
|
||||
// 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 void destroy ()
|
||||
public override void destroy ()
|
||||
{
|
||||
// here you would destroy actors you added to the stage or remove
|
||||
// keybindings
|
||||
@ -97,11 +100,27 @@ namespace Gala.Plugins.Template
|
||||
}
|
||||
|
||||
// this little function just tells Gala which class of those you may have in
|
||||
// your plugin is the one you want to start with. Make sure it's public and
|
||||
// returning the type of the right class
|
||||
public Type register_plugin ()
|
||||
// your plugin is the one you want to start with and delivers some additional
|
||||
// details about your plugin. It also gives you the option to choose a specific
|
||||
// function which your plugin fulfils. Gala will then make sure that there is
|
||||
// no duplicate functionality.
|
||||
public Gala.PluginInfo register_plugin ()
|
||||
{
|
||||
return typeof (Gala.Plugins.Template.Main);
|
||||
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
|
||||
|
||||
false // 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.
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
|
58
plugins/template/Makefile.am
Normal file
58
plugins/template/Makefile.am
Normal file
@ -0,0 +1,58 @@
|
||||
include $(top_srcdir)/Makefile.common
|
||||
|
||||
VAPIDIR = $(top_srcdir)/vapi
|
||||
|
||||
BUILT_SOURCES = libgala_template_la_vala.stamp
|
||||
|
||||
libgala_template_la_LTLIBRARIES = libgala-template.la
|
||||
|
||||
libgala_template_ladir = $(pkglibdir)/plugins
|
||||
|
||||
libgala_template_la_LDFLAGS = \
|
||||
$(PLUGIN_LDFLAGS) \
|
||||
$(GALA_CORE_LDFLAGS) \
|
||||
$(top_builddir)/lib/libgala.la \
|
||||
$(NULL)
|
||||
|
||||
libgala_template_la_CFLAGS = \
|
||||
$(GALA_CORE_CFLAGS) \
|
||||
-include config.h \
|
||||
-w \
|
||||
-I$(top_builddir)/lib \
|
||||
$(NULL)
|
||||
|
||||
libgala_template_la_VALAFLAGS = \
|
||||
$(GALA_CORE_VALAFLAGS) \
|
||||
$(top_builddir)/lib/gala.vapi \
|
||||
--vapidir $(VAPIDIR) \
|
||||
$(VAPIDIR)/config.vapi \
|
||||
$(NULL)
|
||||
|
||||
libgala_template_la_LIBADD = \
|
||||
$(GALA_CORE_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
libgala_template_la_VALASOURCES = \
|
||||
Main.vala \
|
||||
$(NULL)
|
||||
|
||||
nodist_libgala_template_la_SOURCES = \
|
||||
$(BUILT_SOURCES) \
|
||||
$(libgala_template_la_VALASOURCES:.vala=.c) \
|
||||
$(NULL)
|
||||
|
||||
libgala_template_la_vala.stamp: $(libgala_template_la_VALASOURCES)
|
||||
$(AM_V_VALA)$(VALAC) \
|
||||
$(libgala_template_la_VALAFLAGS) \
|
||||
-C \
|
||||
$(filter %.vala %.c,$^)
|
||||
$(AM_V_at)touch $@
|
||||
|
||||
CLEANFILES = \
|
||||
$(nodist_libgala_template_la_SOURCES) \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(libgala_template_la_VALASOURCES) \
|
||||
$(NULL)
|
||||
|
@ -17,16 +17,15 @@
|
||||
|
||||
namespace Gala.Plugins.Zoom
|
||||
{
|
||||
public class Main : Object, Gala.Plugin
|
||||
public class Main : Gala.Plugin
|
||||
{
|
||||
public X.Xrectangle[] region { get; protected set; default = {}; }
|
||||
Gala.WindowManager? wm = null;
|
||||
|
||||
const uint MOUSE_POLL_TIME = 50;
|
||||
uint mouse_poll_timer = 0;
|
||||
float current_zoom = 1.0f;
|
||||
|
||||
public void initialize (Gala.WindowManager wm)
|
||||
public override void initialize (Gala.WindowManager wm)
|
||||
{
|
||||
this.wm = wm;
|
||||
var display = wm.get_screen ().get_display ();
|
||||
@ -36,7 +35,7 @@ namespace Gala.Plugins.Zoom
|
||||
display.add_keybinding ("zoom-out", schema, 0, zoom_out);
|
||||
}
|
||||
|
||||
public void destroy ()
|
||||
public override void destroy ()
|
||||
{
|
||||
if (wm == null)
|
||||
return;
|
||||
@ -115,8 +114,14 @@ namespace Gala.Plugins.Zoom
|
||||
}
|
||||
}
|
||||
|
||||
public Type register_plugin ()
|
||||
public Gala.PluginInfo register_plugin ()
|
||||
{
|
||||
return typeof (Gala.Plugins.Zoom.Main);
|
||||
return Gala.PluginInfo () {
|
||||
name = "Zoom",
|
||||
author = "Gala Developers",
|
||||
plugin_type = typeof (Gala.Plugins.Zoom.Main),
|
||||
provides = Gala.PluginFunction.ADDITION,
|
||||
load_can_wait = false
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -99,6 +99,7 @@ namespace Gala
|
||||
// add plugin's requested areas
|
||||
if (area == InputArea.FULLSCREEN || area == InputArea.HOT_CORNER) {
|
||||
foreach (var rect in PluginManager.get_default ().get_all_regions ()) {
|
||||
print ("%i %i %i %i\n", rect.x, rect.y, rect.width, rect.height);
|
||||
rects += rect;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
namespace Gala
|
||||
{
|
||||
delegate Type RegisterPluginFunction ();
|
||||
delegate PluginInfo RegisterPluginFunction ();
|
||||
|
||||
public class PluginManager : Object
|
||||
{
|
||||
@ -28,11 +28,21 @@ namespace Gala
|
||||
|
||||
public bool initialized { get; private set; default = false; }
|
||||
|
||||
public signal void regions_changed ();
|
||||
|
||||
X.Xrectangle[] regions;
|
||||
|
||||
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; }
|
||||
|
||||
Gee.LinkedList<PluginInfo?> load_later_plugins;
|
||||
|
||||
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");
|
||||
@ -44,9 +54,11 @@ namespace Gala
|
||||
return;
|
||||
|
||||
try {
|
||||
var enumerator = plugin_dir.enumerate_children (FileAttribute.STANDARD_NAME, 0);
|
||||
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) {
|
||||
@ -81,33 +93,87 @@ namespace Gala
|
||||
}
|
||||
RegisterPluginFunction register = (RegisterPluginFunction)function;
|
||||
|
||||
var type = register ();
|
||||
if (type.is_a (typeof (Plugin)) == 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;
|
||||
}
|
||||
|
||||
info.module_name = plugin_name;
|
||||
module.make_resident ();
|
||||
|
||||
var plugin = (Plugin)Object.@new (type);
|
||||
plugins.set (plugin_name, plugin);
|
||||
|
||||
if (initialized) {
|
||||
initialize_plugin (plugin_name, plugin);
|
||||
get_all_regions (true);
|
||||
if (info.load_can_wait) {
|
||||
load_later_plugins.add (info);
|
||||
} else {
|
||||
load_plugin_class (info);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void initialize_plugin (string name, Plugin 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);
|
||||
|
||||
if (initialized) {
|
||||
initialize_plugin (info.module_name, plugin);
|
||||
get_all_regions (true);
|
||||
}
|
||||
}
|
||||
|
||||
void initialize_plugin (string plugin_name, Plugin plugin)
|
||||
{
|
||||
plugin.initialize (wm);
|
||||
plugin.notify["region"].connect (() => {
|
||||
plugin.region_changed.connect (() => {
|
||||
get_all_regions (true);
|
||||
regions_changed ();
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void initialize (WindowManager _wm)
|
||||
{
|
||||
wm = _wm;
|
||||
@ -118,6 +184,13 @@ namespace Gala
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
public void load_waiting_plugins ()
|
||||
{
|
||||
foreach (var info in load_later_plugins) {
|
||||
load_plugin_class (info);
|
||||
}
|
||||
}
|
||||
|
||||
public X.Xrectangle[] get_all_regions (bool update = false)
|
||||
{
|
||||
if (update) {
|
||||
|
@ -218,28 +218,6 @@ namespace Gala
|
||||
}
|
||||
}
|
||||
|
||||
void switch_to_next_workspace (MotionDirection direction)
|
||||
{
|
||||
var display = screen.get_display ();
|
||||
var old_index = screen.get_active_workspace_index ();
|
||||
var neighbor = screen.get_active_workspace ().get_neighbor (direction);
|
||||
|
||||
neighbor.activate (display.get_current_time ());
|
||||
|
||||
// if we didnt switch, show a nudge-over animation. need to take the indices
|
||||
// here since the changing only applies after the animation ends
|
||||
if (old_index == 0 && direction == MotionDirection.LEFT ||
|
||||
old_index == screen.n_workspaces - 1 && direction == MotionDirection.RIGHT) {
|
||||
|
||||
var dest = (direction == MotionDirection.LEFT ? 32.0f : -32.0f);
|
||||
Compositor.get_window_group_for_screen (screen).animate (Clutter.AnimationMode.LINEAR, 100, x:dest);
|
||||
Clutter.Threads.Timeout.add (210, () => {
|
||||
Compositor.get_window_group_for_screen (screen).animate (Clutter.AnimationMode.LINEAR, 150, x:0.0f);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void key_focus_out ()
|
||||
{
|
||||
hide ();
|
||||
@ -261,7 +239,7 @@ namespace Gala
|
||||
if ((event.modifier_state & Clutter.ModifierType.SHIFT_MASK) != 0)
|
||||
wm.move_window (display.get_focus_window (), MotionDirection.LEFT);
|
||||
else
|
||||
switch_to_next_workspace (MotionDirection.LEFT);
|
||||
wm.switch_to_next_workspace (MotionDirection.LEFT);
|
||||
|
||||
last_switch_time = current_time;
|
||||
|
||||
@ -270,7 +248,7 @@ namespace Gala
|
||||
if ((event.modifier_state & Clutter.ModifierType.SHIFT_MASK) != 0)
|
||||
wm.move_window (display.get_focus_window (), MotionDirection.RIGHT);
|
||||
else
|
||||
switch_to_next_workspace (MotionDirection.RIGHT);
|
||||
wm.switch_to_next_workspace (MotionDirection.RIGHT);
|
||||
|
||||
last_switch_time = current_time;
|
||||
|
||||
@ -454,12 +432,5 @@ namespace Gala
|
||||
wins.x = 0.0f;
|
||||
wins.animate (Clutter.AnimationMode.EASE_OUT_EXPO, 500, y : 0.0f);
|
||||
}
|
||||
|
||||
public void handle_switch_to_workspace (Meta.Display display, Meta.Screen screen, Meta.Window? window,
|
||||
X.Event event, Meta.KeyBinding binding)
|
||||
{
|
||||
var direction = (binding.get_name () == "switch-to-workspace-left" ? MotionDirection.LEFT : MotionDirection.RIGHT);
|
||||
switch_to_next_workspace (direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,11 +21,11 @@ namespace Gala
|
||||
{
|
||||
public class WindowManagerGala : Meta.Plugin, WindowManager
|
||||
{
|
||||
PluginInfo info;
|
||||
Meta.PluginInfo info;
|
||||
|
||||
WindowSwitcher winswitcher;
|
||||
WorkspaceView workspace_view;
|
||||
WindowOverview window_overview;
|
||||
WindowSwitcher? winswitcher = null;
|
||||
WorkspaceView? workspace_view = null;
|
||||
WindowOverview? window_overview = null;
|
||||
|
||||
// used to detect which corner was used to trigger an action
|
||||
Clutter.Actor? last_hotcorner;
|
||||
@ -47,7 +47,7 @@ namespace Gala
|
||||
|
||||
public WindowManagerGala ()
|
||||
{
|
||||
info = PluginInfo () {name = "Gala", version = Config.VERSION, author = "Gala Developers",
|
||||
info = Meta.PluginInfo () {name = "Gala", version = Config.VERSION, author = "Gala Developers",
|
||||
license = "GPLv3", description = "A nice elementary window manager"};
|
||||
|
||||
Prefs.set_ignore_request_hide_titlebar (true);
|
||||
@ -77,9 +77,12 @@ namespace Gala
|
||||
screensaver = Bus.get_proxy_sync (BusType.SESSION, "org.gnome.ScreenSaver",
|
||||
"/org/gnome/ScreenSaver");
|
||||
screensaver.active_changed.connect (update_input_area);
|
||||
} catch (Error e) { warning (e.message); }
|
||||
} catch (Error e) {
|
||||
screensaver = null;
|
||||
warning (e.message);
|
||||
}
|
||||
|
||||
var stage = Compositor.get_stage_for_screen (screen) as Clutter.Stage;
|
||||
stage = Compositor.get_stage_for_screen (screen) as Clutter.Stage;
|
||||
|
||||
var color = BackgroundSettings.get_default ().primary_color;
|
||||
stage.background_color = Clutter.Color.from_string (color);
|
||||
@ -114,28 +117,12 @@ namespace Gala
|
||||
window_group.add_child (background_group);
|
||||
window_group.set_child_below_sibling (background_group, null);
|
||||
|
||||
workspace_view = new WorkspaceView (this);
|
||||
workspace_view.visible = false;
|
||||
|
||||
winswitcher = new WindowSwitcher (this);
|
||||
window_overview = new WindowOverview (this);
|
||||
|
||||
ui_group.add_child (workspace_view);
|
||||
ui_group.add_child (winswitcher);
|
||||
ui_group.add_child (window_overview);
|
||||
|
||||
var top_window_group = Compositor.get_top_window_group_for_screen (screen);
|
||||
stage.remove_child (top_window_group);
|
||||
ui_group.add_child (top_window_group);
|
||||
|
||||
/*keybindings*/
|
||||
|
||||
screen.get_display ().add_keybinding ("expose-windows", KeybindingSettings.get_default ().schema, 0, () => {
|
||||
window_overview.open (true);
|
||||
});
|
||||
screen.get_display ().add_keybinding ("expose-all-windows", KeybindingSettings.get_default ().schema, 0, () => {
|
||||
window_overview.open (true, true);
|
||||
});
|
||||
screen.get_display ().add_keybinding ("switch-to-workspace-first", KeybindingSettings.get_default ().schema, 0, () => {
|
||||
screen.get_workspace_by_index (0).activate (screen.get_display ().get_current_time ());
|
||||
});
|
||||
@ -182,19 +169,10 @@ namespace Gala
|
||||
} catch (Error e) { warning (e.message); }
|
||||
});
|
||||
|
||||
KeyBinding.set_custom_handler ("show-desktop", () => {
|
||||
workspace_view.show (true);
|
||||
});
|
||||
|
||||
//FIXME we have to investigate this. Apparently alt-tab is now bound to switch-applications
|
||||
// instead of windows, which we should probably handle too
|
||||
KeyBinding.set_custom_handler ("switch-applications", winswitcher.handle_switch_windows);
|
||||
KeyBinding.set_custom_handler ("switch-applications-backward", winswitcher.handle_switch_windows);
|
||||
|
||||
KeyBinding.set_custom_handler ("switch-to-workspace-up", () => {});
|
||||
KeyBinding.set_custom_handler ("switch-to-workspace-down", () => {});
|
||||
KeyBinding.set_custom_handler ("switch-to-workspace-left", workspace_view.handle_switch_to_workspace);
|
||||
KeyBinding.set_custom_handler ("switch-to-workspace-right", workspace_view.handle_switch_to_workspace);
|
||||
KeyBinding.set_custom_handler ("switch-to-workspace-left", handle_switch_to_workspace);
|
||||
KeyBinding.set_custom_handler ("switch-to-workspace-right", handle_switch_to_workspace);
|
||||
|
||||
KeyBinding.set_custom_handler ("move-to-workspace-up", () => {});
|
||||
KeyBinding.set_custom_handler ("move-to-workspace-down", () => {});
|
||||
@ -214,7 +192,43 @@ namespace Gala
|
||||
|
||||
BehaviorSettings.get_default ().schema.changed.connect ((key) => update_input_area ());
|
||||
|
||||
PluginManager.get_default ().initialize (this);
|
||||
// initialize plugins and add default components if no plugin overrides them
|
||||
var plugin_manager = PluginManager.get_default ();
|
||||
plugin_manager.initialize (this);
|
||||
plugin_manager.regions_changed.connect (update_input_area);
|
||||
|
||||
if (plugin_manager.workspace_view_provider == null) {
|
||||
workspace_view = new WorkspaceView (this);
|
||||
workspace_view.visible = false;
|
||||
ui_group.add_child (workspace_view);
|
||||
|
||||
KeyBinding.set_custom_handler ("show-desktop", () => {
|
||||
workspace_view.show (true);
|
||||
});
|
||||
}
|
||||
|
||||
if (plugin_manager.window_switcher_provider == null) {
|
||||
winswitcher = new WindowSwitcher (this);
|
||||
ui_group.add_child (winswitcher);
|
||||
|
||||
//FIXME we have to investigate this. Apparently alt-tab is now bound to switch-applications
|
||||
// instead of windows, which we should probably handle too
|
||||
KeyBinding.set_custom_handler ("switch-applications", winswitcher.handle_switch_windows);
|
||||
KeyBinding.set_custom_handler ("switch-applications-backward", winswitcher.handle_switch_windows);
|
||||
}
|
||||
|
||||
if (plugin_manager.window_overview_provider == null) {
|
||||
window_overview = new WindowOverview (this);
|
||||
ui_group.add_child (window_overview);
|
||||
|
||||
screen.get_display ().add_keybinding ("expose-windows", KeybindingSettings.get_default ().schema, 0, () => {
|
||||
window_overview.open (true);
|
||||
});
|
||||
screen.get_display ().add_keybinding ("expose-all-windows", KeybindingSettings.get_default ().schema, 0, () => {
|
||||
window_overview.open (true, true);
|
||||
});
|
||||
}
|
||||
|
||||
update_input_area ();
|
||||
|
||||
stage.show ();
|
||||
@ -222,6 +236,11 @@ namespace Gala
|
||||
// let the session manager move to the next phase
|
||||
Meta.register_with_session ();
|
||||
|
||||
Idle.add (() => {
|
||||
plugin_manager.load_waiting_plugins ();
|
||||
return false;
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -264,15 +283,49 @@ namespace Gala
|
||||
hot_corner.y = y;
|
||||
}
|
||||
|
||||
void handle_switch_to_workspace (Meta.Display display, Meta.Screen screen, Meta.Window? window,
|
||||
X.Event event, Meta.KeyBinding binding)
|
||||
{
|
||||
var direction = (binding.get_name () == "switch-to-workspace-left" ? MotionDirection.LEFT : MotionDirection.RIGHT);
|
||||
switch_to_next_workspace (direction);
|
||||
}
|
||||
|
||||
public void switch_to_next_workspace (MotionDirection direction)
|
||||
{
|
||||
var screen = get_screen ();
|
||||
var display = screen.get_display ();
|
||||
var old_index = screen.get_active_workspace_index ();
|
||||
var neighbor = screen.get_active_workspace ().get_neighbor (direction);
|
||||
|
||||
neighbor.activate (display.get_current_time ());
|
||||
|
||||
// if we didnt switch, show a nudge-over animation. need to take the indices
|
||||
// here since the changing only applies after the animation ends
|
||||
if (old_index == 0 && direction == MotionDirection.LEFT ||
|
||||
old_index == screen.n_workspaces - 1 && direction == MotionDirection.RIGHT) {
|
||||
|
||||
var dest = (direction == MotionDirection.LEFT ? 32.0f : -32.0f);
|
||||
ui_group.animate (Clutter.AnimationMode.LINEAR, 100, x:dest);
|
||||
Timeout.add (210, () => {
|
||||
ui_group.animate (Clutter.AnimationMode.LINEAR, 150, x:0.0f);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void update_input_area ()
|
||||
{
|
||||
var schema = BehaviorSettings.get_default ().schema;
|
||||
var screen = get_screen ();
|
||||
|
||||
if (screensaver != null && screensaver.get_active ()) {
|
||||
if (screensaver != null) {
|
||||
try {
|
||||
if (screensaver.get_active ()) {
|
||||
InternalUtils.set_input_area (screen, InputArea.NONE);
|
||||
return;
|
||||
}
|
||||
} catch (IOError e) { warning (e.message); }
|
||||
}
|
||||
|
||||
if (modal_count > 0)
|
||||
InternalUtils.set_input_area (screen, InputArea.FULLSCREEN);
|
||||
@ -1018,7 +1071,7 @@ namespace Gala
|
||||
return modal_count > 0;
|
||||
}
|
||||
|
||||
public override unowned PluginInfo? plugin_info ()
|
||||
public override unowned Meta.PluginInfo? plugin_info ()
|
||||
{
|
||||
return info;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user