2
// Copyright (C) 2014 Tom Beckmann
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
14
// You should have received a copy of the GNU General Public License
15
// along with this program. If not, see <http://www.gnu.org/licenses/>.
20
delegate PluginInfo RegisterPluginFunction ();
22
public class PluginManager : Object
24
static PluginManager? instance = null;
25
public static PluginManager get_default ()
28
instance = new PluginManager ();
33
public signal void regions_changed ();
35
public bool initialized { get; private set; default = false; }
37
public X.Xrectangle[] regions { get; private set; }
39
public string? window_switcher_provider { get; private set; default = null; }
40
public string? desktop_provider { get; private set; default = null; }
41
public string? window_overview_provider { get; private set; default = null; }
42
public string? workspace_view_provider { get; private set; default = null; }
44
HashTable<string,Plugin> plugins;
47
WindowManager? wm = null;
49
Gee.LinkedList<PluginInfo?> load_later_plugins;
53
plugins = new HashTable<string,Plugin> (str_hash, str_equal);
54
load_later_plugins = new Gee.LinkedList<PluginInfo?> ();
56
if (!Module.supported ()) {
57
warning ("Modules are not supported on this platform");
61
plugin_dir = File.new_for_path (Config.PLUGINDIR);
62
if (!plugin_dir.query_exists ())
66
var enumerator = plugin_dir.enumerate_children (FileAttribute.STANDARD_NAME +
67
"," + FileAttribute.STANDARD_CONTENT_TYPE, 0);
69
while ((info = enumerator.next_file ()) != null) {
70
if (info.get_content_type () == "application/x-sharedlib")
71
load_module (info.get_name ());
78
plugin_dir.monitor_directory (FileMonitorFlags.NONE, null).changed.connect ((file, other_file, type) => {
79
if (type == FileMonitorEvent.CREATED) {
80
load_module (file.get_basename ());
88
bool load_module (string plugin_name)
90
var path = Module.build_path (plugin_dir.get_path (), plugin_name);
91
var module = Module.open (path, ModuleFlags.BIND_LOCAL);
93
warning (Module.error ());
98
module.symbol ("register_plugin", out function);
99
if (function == null) {
100
warning ("%s failed to register: register_plugin() function not found", plugin_name);
103
RegisterPluginFunction register = (RegisterPluginFunction)function;
105
var info = register ();
106
if (info.plugin_type.is_a (typeof (Plugin)) == false) {
107
warning ("%s does not return a class of type Plugin", plugin_name);
111
if (!check_provides (info.name, info.provides)) {
115
info.module_name = plugin_name;
116
module.make_resident ();
118
if (info.load_priority == LoadPriority.DEFERRED && !initialized) {
119
load_later_plugins.add (info);
121
load_plugin_class (info);
127
void load_plugin_class (PluginInfo info)
129
var plugin = (Plugin)Object.@new (info.plugin_type);
130
plugins.set (info.module_name, plugin);
132
debug ("Loaded plugin %s (%s)", info.name, info.module_name);
135
initialize_plugin (info.module_name, plugin);
136
recalculate_regions ();
140
void initialize_plugin (string plugin_name, Plugin plugin)
142
plugin.initialize (wm);
143
plugin.region_changed.connect (recalculate_regions);
146
bool check_provides (string name, PluginFunction provides)
148
var message = "Plugins %s and %s both provide %s functionality, using first one only";
150
case PluginFunction.WORKSPACE_VIEW:
151
if (workspace_view_provider != null) {
152
warning (message, workspace_view_provider, name, "workspace view");
155
workspace_view_provider = name;
157
case PluginFunction.WINDOW_OVERVIEW:
158
if (window_overview_provider != null) {
159
warning (message, window_overview_provider, name, "window overview");
162
window_overview_provider = name;
164
case PluginFunction.DESKTOP:
165
if (desktop_provider != null) {
166
warning (message, desktop_provider, name, "desktop");
169
desktop_provider = name;
171
case PluginFunction.WINDOW_SWITCHER:
172
if (window_switcher_provider != null) {
173
warning (message, window_switcher_provider, name, "window switcher");
176
window_switcher_provider = name;
183
public void initialize (WindowManager _wm)
187
plugins.@foreach (initialize_plugin);
188
recalculate_regions ();
193
public void load_waiting_plugins ()
195
foreach (var info in load_later_plugins) {
196
load_plugin_class (info);
199
load_later_plugins.clear ();
203
* Iterate over all plugins and grab their regions, update the regions
204
* array accordingly and emit the regions_changed signal.
206
void recalculate_regions ()
208
X.Xrectangle[] regions = {};
210
plugins.@foreach ((name, plugin) => {
211
foreach (var region in plugin.region)
215
this.regions = regions;