/*- * Copyright (c) 2001 Jordan DeLong * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef PLUGIN_H #define PLUGIN_H /* * return values for plugin callbacks. if any plugin callback * returns PLUGIN_UNLOAD that plugin is immediatly unloaded. * certain plugin callbacks can return plugin using, which means * that they are using the event that caused the callback, * and the main code shouldn't call any more plugin callbacks * for it, or do any normal processing on it. */ #define PLUGIN_OK 0 #define PLUGIN_UNLOAD 1 #define PLUGIN_USING 2 /* * callbacks that may be registered by plugins, and macros to * call all the registered handlers for a callback. all callbacks * take parameters that depend on the type of the callback; all * plugin callback handlers also take a first parameter of the * type of the callback; this allows using one handler for multiple * callbacks who's handling is nearly identical. */ enum { /* * init_hints(int pcall, client_t *client, dgroup_t *dgroup); * * initialize windowmanager hints; the client passed in * is a newly-arriving client. the plugin may modify client * flags or set client->dgroup to affect how the client is * initially created. */ PCALL_INIT_HINTS = 0, #define plugin_init_hints(client) \ plugin_callback_all(PCALL_INIT_HINTS, 1, client) /* * window_birth(int pcall, client_t *client); * * signals arrival of a new client. this is called right * after the client's window is mapped for the first time. */ PCALL_WINDOW_BIRTH, #define plugin_window_birth(client) \ plugin_callback_all(PCALL_WINDOW_BIRTH, 1, client) /* * window_death(int pcall, client_t *client); * * signals the departure of a client. called immediatly * before the client_rm call, allowing the plugin to reference * client_t internals for one last time. */ PCALL_WINDOW_DEATH, #define plugin_window_death(client) \ plugin_callback_all(PCALL_WINDOW_DEATH, 1, client) /* * focus_change(int pcall, client_t *client); * * the X focus was changed to a different managed client * window; the client paramater is the client that just got * focused (also accessable as the client_focused global). */ PCALL_FOCUS_CHANGE, #define plugin_focus_change(client) \ plugin_callback_all(PCALL_FOCUS_CHANGE, 1, client) /* * geometry_change(int pcall, client_t *client); * * the client was resized or moved; a seperate callback * is used for zooming. */ PCALL_GEOMETRY_CHANGE, #define plugin_geometry_change(client) \ plugin_callback_all(PCALL_GEOMETRY_CHANGE, 1, client) /* * iconify_notify(int pcall, client_t *client); * * the client was iconified. */ PCALL_ICONIFY_NOTIFY, #define plugin_iconify_notify(client) \ plugin_callback_all(PCALL_ICONIFY_NOTIFY, 1, client) /* * restore_notify(int pcall, client_t *client); * * the client was restored (uniconified). */ PCALL_RESTORE_NOTIFY, #define plugin_restore_notify(client) \ plugin_callback_all(PCALL_RESTORE_NOTIFY, 1, client) /* * zoom_notify(int pcall, client_t *client); * * the client was zoomed (maximized). */ PCALL_ZOOM_NOTIFY, #define plugin_zoom_notify(client) \ plugin_callback_all(PCALL_ZOOM_NOTIFY, 1, client) /* * unzoom_notify(int pcall, client_t *client); * * the client was unzoomed. */ PCALL_UNZOOM_NOTIFY, #define plugin_unzoom_notify(client) \ plugin_callback_all(PCALL_UNZOOM_NOTIFY, 1, client) /* * raise_notify(int pcall, client_t *client, client_t *lowest); * * client was raised to the top of it's stacking layer. the * lowest parameter is set to lowest client that is above the * the one that was raised, or null if there is no such client. */ PCALL_RAISE_NOTIFY, #define plugin_raise_notify(client, lowest) \ plugin_callback_all(PCALL_RAISE_NOTIFY, 2, client, lowest) /* * lower_notify(int pcall, client_t *client, client_t *lowest); * * client was lowered to the bottom of it's stacking layer. * the lowest parameter is the same as in raise_notify(). */ PCALL_LOWER_NOTIFY, #define plugin_lower_notify(client, lowest) \ plugin_callback_all(PCALL_LOWER_NOTIFY, 2, client, lowest) /* * workspace_change(int pcall, screen_t *screen, desktop_t *desktop); * * the current workspace changed for desktop, on screen. * desktop is not neccesarily the current desktop for the screen. */ PCALL_WORKSPACE_CHANGE, #define plugin_workspace_change(screen, desktop) \ plugin_callback_all(PCALL_WORKSPACE_CHANGE, 2, screen, desktop) /* * desktop_change(int pcall, screen_t *screen, desktop_t *olddesk); * * the current desktop changed on screen. screen->desktop * contains the new current desktop, and a pointer to the old * desktop is given in olddesk. */ PCALL_DESKTOP_CHANGE, #define plugin_desktop_change(screen, olddesk) \ plugin_callback_all(PCALL_DESKTOP_CHANGE, 2, screen, olddesk) /* * anim_birth(int pcall, client_t *client); * * somewhat hackish callback that occurs before the window * gets mapped and signals new window arrival. the callback is * located at an appropriate time to do animations for newly * ariving windows. */ PCALL_ANIM_BIRTH, #define plugin_anim_birth(client) \ plugin_callback_all(PCALL_ANIM_BIRTH, 1, client) /* * root_button(int pcall, screen_t *screen, XButtonEvent *e); * * because clients can't plugin_setcontext on the root window, * this callback is provided to notify clients of root window * button presses and releases. the X button event and the screen * on which it occured are passed to the client. */ PCALL_ROOT_BUTTON, #define plugin_root_button(screen, e) \ plugin_callback_all(PCALL_ROOT_BUTTON, 2, screen, e) /* * property_notify(int pcall, client_t *client, XPropertyEvent *e); * * plugins can't plugin_setcontext on a client window to * handle window property changes because other plugins may * be interested in those changes as well; this callback is * provided to allow them to recieve property information without * doing a setcontext. */ PCALL_PROPERTY_NOTIFY, #define plugin_property_notify(client, e) \ plugin_callback_all(PCALL_PROPERTY_NOTIFY, 2, client, e) /* * map_request(int pcall, screen_t *screen, XMapRequestEvent *e); * * called when a new toplevel window attempts to map * itself. screen is the screen on which the request occured, * and e is the actual X event that cause the map request. * if the callback returns PLUGIN_USING, no client_t will * be created for this window. */ PCALL_MAP_REQUEST, #define plugin_map_request(screen, e) \ plugin_callback_all(PCALL_MAP_REQUEST, 2, screen, e) /* total number of plugin callback types */ PCALL_COUNT }; /* * an array of subparamaters; placed in the plugin structure * and in each parameter structure. */ struct subparams { int count; /* number of sub params */ param_t **params; /* the sub parameters */ }; /* * a tree of plugin parameters that are passed in for use by the plugin from * the user's rcfile. there is a pointer to one of these in the plugin_t * structure who's varname will */ struct param { char *name; /* name of the parameter */ char *value; /* value of the parameter */ subparams_t subparams; }; /* * plugin callout list entry structure; plugins register callbacks * by passing in an address of a handler function. the handler * is stored here as an (int *)(), but the handler routines do actually * take arguments who's type depends on the callback. this entries * are hung off the plugin structure, for calling callbacks for * particular plugins, as well as being hung off internal lists * based on callback type to save from traversing the full list * of all plugins. * * plugins may add or remove callback handlers at any time during * their operation; however most plugins are expected to add a few * callbacks in their start() routine and leave them alone from * then on. */ struct callback { LIST_ENTRY(callback) cb_list; /* callback list entry */ LIST_ENTRY(callback) cb_plug; /* plugin registered callbacks list */ plugin_t *plugin; /* plugin requesting the callback */ int (*handler)(); /* address of handler function */ int pcall; /* callback type */ }; typedef LIST_HEAD(, callback) callbacklist_t; /* * plugin structure; plugins are dlopened shared objects that * export set of routines that are called into by the main code. * the plugin may, during the calls into those routines, organize * other calls into the plugin text for notification or action on * certain events. all callbacks a plugin adds are automatically * removed for it when it is unloaded. */ struct plugin { void *hnd; /* handle from dlopen */ char *name; /* name the plugin was loaded as */ /* * these are functions that are called to alert * the plugin of the stages during startup/shutdown. * init is called during the rcfile parsing and * as such it shouldn't use any internal structures. * shutdown can be called at any time and should be * prepared to release memory; it shouldn't use any * of the internal structures unless it's sure that it * is safe to do so (due to setting some global or * some such in a handler for another callback). * start gets called immediatly after rcfile parsing * and indicates that it is time for the plugin to * begin normal operation. */ int (*init)(); /* plugin initialization routine */ void (*shutdown)(); /* plugin death routine */ int (*start)(); /* post-init plugin starting */ /* * all x events for windows that have a plugin_context * with this plugin (set by plugin_setcontext) will call * into the plugin for handling through this routine. */ int (*xevent_handler)(XEvent *); /* * list of callback handlers this plugin has * registered. */ callbacklist_t callback_list; /* * parameters for the plugin; all plugins can recieve * a tree of parameters from the rcfile. these parameters * are freed after rcfile parsing, so they should not be * used after (or during) the call to start. */ subparams_t params; LIST_ENTRY(plugin) p_list; }; typedef LIST_HEAD(, plugin) pluginlist_t; extern pluginlist_t plugin_list; extern plugin_t *plugin_this; void plugin_init(); void plugin_shutdown(); plugin_t *plugin_load(char *name, subparams_t *params, int doinit); void plugin_unload(plugin_t *plugin); void plugin_start(); void plugin_handle_event(plugin_t *plugin, XEvent *e); /* plugin callback management */ callback_t *plugin_callback_add(plugin_t *plugin, int pcall, void *handler); void plugin_callback_rm(callback_t *callback); int plugin_callback(plugin_t *plugin, int pcall, int argc, ...); int plugin_callback_all(int pcall, int argc, ...); /* parameter structure routines*/ param_t *plugin_param(char *name, char *value); int plugin_subparams_add(subparams_t *subparams, param_t *param); int plugin_subparams_merge(subparams_t *subparams, subparams_t *addition); void plugin_subparams_free(subparams_t *subparams); void plugin_param_free(param_t *param); /* * these are called from plugins to get param values. Some of * them need to make memory for the returned values; i.e. string * and color. */ param_t *plugin_find_param(subparams_t *subparams, char *name); int plugin_string_param(subparams_t *subparams, char *name, char **ret); int plugin_color_param(subparams_t *subparams, char *name, Pixel **ret); int plugin_pixmap_param(subparams_t *subparams, char *name, pixmap_t **ret); int plugin_dgroup_param(subparams_t *subparams, char *name, dgroup_t **ret); int plugin_int_param(subparams_t *subparams, char *name, int *ret); int plugin_double_param(subparams_t *subparams, char *name, double *ret); int plugin_bool_param(subparams_t *subparams, char *name, int *ret); int plugin_stacklayer_param(subparams_t *subparams, char *name, int *ret); /* * plugins call these to associate a non-managed window with it; * the purpose being to cause the main event code to call out to * the plugin to handle the event. */ void plugin_setcontext(plugin_t *plugin, Window wnd); void plugin_rmcontext(Window wnd); #endif