~gala-dev/gala/windowswitcher-fade-opacity

« back to all changes in this revision

Viewing changes to src/PluginManager.vala

  • Committer: RabbitBot
  • Author(s): Tom Beckmann, Rico Tzschichholz, Cody Garver
  • Date: 2014-04-06 18:30:23 UTC
  • mfrom: (368.1.21 plugins)
  • Revision ID: rabbitbot-20140406183023-0v1juolllz5u2fht
Add plugin support, move zoom functionality into a plugin

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//  
 
2
//  Copyright (C) 2014 Tom Beckmann
 
3
// 
 
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.
 
8
// 
 
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.
 
13
// 
 
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/>.
 
16
// 
 
17
 
 
18
namespace Gala
 
19
{
 
20
        delegate PluginInfo RegisterPluginFunction ();
 
21
 
 
22
        public class PluginManager : Object
 
23
        {
 
24
                static PluginManager? instance = null;
 
25
                public static PluginManager get_default ()
 
26
                {
 
27
                        if (instance == null)
 
28
                                instance = new PluginManager ();
 
29
 
 
30
                        return instance;
 
31
                }
 
32
 
 
33
                public signal void regions_changed ();
 
34
 
 
35
                public bool initialized { get; private set; default = false; }
 
36
 
 
37
                public X.Xrectangle[] regions { get; private set; }
 
38
 
 
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; }
 
43
 
 
44
                HashTable<string,Plugin> plugins;
 
45
                File plugin_dir;
 
46
 
 
47
                WindowManager? wm = null;
 
48
 
 
49
                Gee.LinkedList<PluginInfo?> load_later_plugins;
 
50
 
 
51
                PluginManager ()
 
52
                {
 
53
                        plugins = new HashTable<string,Plugin> (str_hash, str_equal);
 
54
                        load_later_plugins = new Gee.LinkedList<PluginInfo?> ();
 
55
 
 
56
                        if (!Module.supported ()) {
 
57
                                warning ("Modules are not supported on this platform");
 
58
                                return;
 
59
                        }
 
60
 
 
61
                        plugin_dir = File.new_for_path (Config.PLUGINDIR);
 
62
                        if (!plugin_dir.query_exists ())
 
63
                                return;
 
64
 
 
65
                        try {
 
66
                                var enumerator = plugin_dir.enumerate_children (FileAttribute.STANDARD_NAME +
 
67
                                        "," + FileAttribute.STANDARD_CONTENT_TYPE, 0);
 
68
                                FileInfo info;
 
69
                                while ((info = enumerator.next_file ()) != null) {
 
70
                                        if (info.get_content_type () == "application/x-sharedlib")
 
71
                                                load_module (info.get_name ());
 
72
                                }
 
73
                        } catch (Error e) {
 
74
                                warning (e.message);
 
75
                        }
 
76
 
 
77
                        try {
 
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 ());
 
81
                                        }
 
82
                                });
 
83
                        } catch (Error e) {
 
84
                                warning (e.message);
 
85
                        }
 
86
                }
 
87
 
 
88
                bool load_module (string plugin_name)
 
89
                {
 
90
                        var path = Module.build_path (plugin_dir.get_path (), plugin_name);
 
91
                        var module = Module.open (path, ModuleFlags.BIND_LOCAL);
 
92
                        if (module == null) {
 
93
                                warning (Module.error ());
 
94
                                return false;
 
95
                        }
 
96
 
 
97
                        void* function;
 
98
                        module.symbol ("register_plugin", out function);
 
99
                        if (function == null) {
 
100
                                warning ("%s failed to register: register_plugin() function not found", plugin_name);
 
101
                                return false;
 
102
                        }
 
103
                        RegisterPluginFunction register = (RegisterPluginFunction)function;
 
104
 
 
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);
 
108
                                return false;
 
109
                        }
 
110
 
 
111
                        if (!check_provides (info.name, info.provides)) {
 
112
                                return false;
 
113
                        }
 
114
 
 
115
                        info.module_name = plugin_name;
 
116
                        module.make_resident ();
 
117
 
 
118
                        if (info.load_priority == LoadPriority.DEFERRED && !initialized) {
 
119
                                load_later_plugins.add (info);
 
120
                        } else {
 
121
                                load_plugin_class (info);
 
122
                        }
 
123
 
 
124
                        return true;
 
125
                }
 
126
 
 
127
                void load_plugin_class (PluginInfo info)
 
128
                {
 
129
                        var plugin = (Plugin)Object.@new (info.plugin_type);
 
130
                        plugins.set (info.module_name, plugin);
 
131
 
 
132
                        debug ("Loaded plugin %s (%s)", info.name, info.module_name);
 
133
 
 
134
                        if (initialized) {
 
135
                                initialize_plugin (info.module_name, plugin);
 
136
                                recalculate_regions ();
 
137
                        }
 
138
                }
 
139
 
 
140
                void initialize_plugin (string plugin_name, Plugin plugin)
 
141
                {
 
142
                        plugin.initialize (wm);
 
143
                        plugin.region_changed.connect (recalculate_regions);
 
144
                }
 
145
 
 
146
                bool check_provides (string name, PluginFunction provides)
 
147
                {
 
148
                        var message = "Plugins %s and %s both provide %s functionality, using first one only";
 
149
                        switch (provides) {
 
150
                                case PluginFunction.WORKSPACE_VIEW:
 
151
                                        if (workspace_view_provider != null) {
 
152
                                                warning (message, workspace_view_provider, name, "workspace view");
 
153
                                                return false;
 
154
                                        }
 
155
                                        workspace_view_provider = name;
 
156
                                        return true;
 
157
                                case PluginFunction.WINDOW_OVERVIEW:
 
158
                                        if (window_overview_provider != null) {
 
159
                                                warning (message, window_overview_provider, name, "window overview");
 
160
                                                return false;
 
161
                                        }
 
162
                                        window_overview_provider = name;
 
163
                                        return true;
 
164
                                case PluginFunction.DESKTOP:
 
165
                                        if (desktop_provider != null) {
 
166
                                                warning (message, desktop_provider, name, "desktop");
 
167
                                                return false;
 
168
                                        }
 
169
                                        desktop_provider = name;
 
170
                                        return true;
 
171
                                case PluginFunction.WINDOW_SWITCHER:
 
172
                                        if (window_switcher_provider != null) {
 
173
                                                warning (message, window_switcher_provider, name, "window switcher");
 
174
                                                return false;
 
175
                                        }
 
176
                                        window_switcher_provider = name;
 
177
                                        return true;
 
178
                        }
 
179
 
 
180
                        return true;
 
181
                }
 
182
 
 
183
                public void initialize (WindowManager _wm)
 
184
                {
 
185
                        wm = _wm;
 
186
 
 
187
                        plugins.@foreach (initialize_plugin);
 
188
                        recalculate_regions ();
 
189
 
 
190
                        initialized = true;
 
191
                }
 
192
 
 
193
                public void load_waiting_plugins ()
 
194
                {
 
195
                        foreach (var info in load_later_plugins) {
 
196
                                load_plugin_class (info);
 
197
                        }
 
198
 
 
199
                        load_later_plugins.clear ();
 
200
                }
 
201
 
 
202
                /**
 
203
                 * Iterate over all plugins and grab their regions, update the regions
 
204
                 * array accordingly and emit the regions_changed signal.
 
205
                 */
 
206
                void recalculate_regions ()
 
207
                {
 
208
                        X.Xrectangle[] regions = {};
 
209
 
 
210
                        plugins.@foreach ((name, plugin) => {
 
211
                                foreach (var region in plugin.region)
 
212
                                        regions += region;
 
213
                        });
 
214
 
 
215
                        this.regions = regions;
 
216
                        regions_changed ();
 
217
                }
 
218
        }
 
219
}
 
220