// // 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 // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // namespace Gala { public enum PluginFunction { ADDITION, WINDOW_SWITCHER, WORKSPACE_VIEW, WINDOW_OVERVIEW } public enum LoadPriority { /** * Have your plugin loaded immediately once gala has started */ IMMEDIATE, /** * Allow gala to defer loading your plugin once it got the * major part of the initialization done */ DEFERRED } 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; /** * Give gala a hint for when to load your plugin. Especially use DEFERRED * if you're adding a completely new ui component that's not directly * related to the wm. */ LoadPriority load_priority; /** * 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 { /** * Emitted when update_region is called. Mainly for internal purposes. */ public signal void region_changed (); /** * 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. */ #if HAS_MUTTER45 private Mtk.Rectangle[] region; public unowned Mtk.Rectangle[] get_region () { #else private Meta.Rectangle[] region; public unowned Meta.Rectangle[] get_region () { #endif return region; } /** * 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. */ #if HAS_MUTTER45 private Mtk.Rectangle[]? _custom_region = null; protected unowned Mtk.Rectangle[]? get_custom_region () { #else private Meta.Rectangle[]? _custom_region = null; protected unowned Meta.Rectangle[]? get_custom_region () { #endif return _custom_region; } #if HAS_MUTTER45 protected void set_custom_region (Mtk.Rectangle[]? custom_region) { #else protected void set_custom_region (Meta.Rectangle[]? custom_region) { #endif _custom_region = custom_region; 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 { return _freeze_track; } set { _freeze_track = value; if (!_freeze_track) update_region (); } } private bool _freeze_track = false; private List tracked_actors = new List (); /** * Once this method is called you can start adding actors to the stage * 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.prepend (actor); actor.notify["allocation"].connect (on_actor_allocation_changed); update_region (); } /** * Stop listening to allocation changes and remove the actor's * allocation from the region array. * * @param actor The actor to stop listening the changes on */ public void untrack_actor (Clutter.Actor actor) { tracked_actors.remove (actor); actor.notify["allocation"].disconnect (on_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 () { unowned var custom_region = get_custom_region (); var has_custom = custom_region != null; var len = tracked_actors.length () + (has_custom ? custom_region.length : 0); #if HAS_MUTTER45 var regions = new Mtk.Rectangle[len]; #else var regions = new Meta.Rectangle[len]; #endif 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++] = { (int) x, (int) y, (int) w, (int) h }; } region = regions; region_changed (); } private void on_actor_allocation_changed (GLib.Object actor_object, GLib.ParamSpec pspec) { if (!freeze_track) update_region (); } } }