diff options
Diffstat (limited to 'matchbox2/comp-mgr')
-rw-r--r-- | matchbox2/comp-mgr/Makefile.am | 32 | ||||
-rw-r--r-- | matchbox2/comp-mgr/README | 70 | ||||
-rw-r--r-- | matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c | 1610 | ||||
-rw-r--r-- | matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.h | 108 | ||||
-rw-r--r-- | matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.c | 1837 | ||||
-rw-r--r-- | matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.h | 60 | ||||
-rw-r--r-- | matchbox2/comp-mgr/mb-wm-comp-mgr.c | 482 | ||||
-rw-r--r-- | matchbox2/comp-mgr/mb-wm-comp-mgr.h | 159 |
8 files changed, 4358 insertions, 0 deletions
diff --git a/matchbox2/comp-mgr/Makefile.am b/matchbox2/comp-mgr/Makefile.am new file mode 100644 index 0000000..e0384a6 --- /dev/null +++ b/matchbox2/comp-mgr/Makefile.am @@ -0,0 +1,32 @@ + +core_h = mb-wm-comp-mgr.h +core_c = mb-wm-comp-mgr.c + +if COMP_MGR_BACKEND +if ENABLE_CLUTTER_COMPOSITE_MANAGER +clutter_h = mb-wm-comp-clutter.h \ + tidy/tidy-texture-frame.h \ + $(NULL) + +clutter_c = mb-wm-comp-mgr-clutter.c \ + tidy/tidy-texture-frame.c \ + $(NULL) +else +xrender_h = mb-wm-comp-mgr-xrender.h +xrender_c = mb-wm-comp-mgr-xrender.c +endif +endif + +pkgincludedir = $(includedir)/$(MBWM2_INCDIR)/comp-mgr + +if ENABLE_LIBMATCHBOX +pkginclude_HEADERS = mb-wm-comp-mgr-clutter.h mb-wm-comp-mgr.h mb-wm-comp-mgr-xrender.h +endif +noinst_LTLIBRARIES = libmatchbox-window-manager-2-compmgr.la +libmatchbox_window_manager_2_compmgr_la_SOURCES = $(core_h) $(core_c) \ + $(xrender_h) $(xrender_c) \ + $(clutter_h) $(clutter_c) +libmatchbox_window_manager_2_compmgr_la_CFLAGS = $(MBWM_INCS) $(MBWM_CFLAGS) + +MAINTAINERCLEANFILES = Makefile.in + diff --git a/matchbox2/comp-mgr/README b/matchbox2/comp-mgr/README new file mode 100644 index 0000000..fb53cf1 --- /dev/null +++ b/matchbox2/comp-mgr/README @@ -0,0 +1,70 @@ + +BRIEF OVERVIEW OF THE COMPOSITING INFRASTRUCTURE +================================================ + +The composite manager framework consists of three primary classes, + + * MBWMCompMgr -- The compositor interface, + + * MBWMCompMgrClient -- Per-client, compositor- specific data, + + * MBWMCompMgrEffect -- A simple client effect. + +The whole framework, and its integration with the WM, can be outlined as +follows: + + + MBWindowManager: + | | + | --> client stack + | | + | --> MBWindowManagerClient + | | +========================================================================== + | | + | --> MBWMCompMgrClient + | | | + | | --> MBWMCompMgrBackendClient + | | + | event-effect mapping + | | + | -->an-event:effect-list pair + | | + | --> MBWMCompMgrEffect + | | + | --> MBWMCompMgrBackendEffect + | + --> MBWMCompMgr + | + --> MBWMCompMgrBackend + + +The framwork seeks to provide a clean separation between the WM and the CM -- +the implementation of the CM is opaque to the WM, which simply deffers to the +CM at appropriate points through its public interface. To this end each of the +MBWindowManagerClient objects managed by the WM holds a pointer to a +MBWMCompMgrClient object, which holds any per-client data that the CM +requires; this data is allocated when the WM calls +mb_wm_comp_mgr_register_client() and deallocated when it +calls mb_wm_comp_mgr_unregister_client(). + +As much as the CM internals are opaque to the WM, also the workings of the WM +are intended to be opaque to the CM; its API is hooked into common operations +that the WM carries out on its clients, such as map and unmap events, or +processing of damage notifications, but the CM per se is agnostic of the inner +workings of the WM. + +The effect framework is event driven. MBWMCompMgrEffect is a common interface +for simple effect, defined by a type, duration (in ms) and gravity. Each +MBWMCompMgrClient instance is then associated with a mapping between +effect-events (such as client window mapping, unmapping or minimizing) and a +list of effects that are to be triggered by the event; a small set of effects +(such as scaling, fading or sliding, is predefined, and the event-effect +mapping is defined on per-client-type basis by the theme. + +MBWMCompMgr, MBWMCompMgrClient and MBWMCompMgrEffect are abstract interfaces +that provide public API through which the WM communicates with the +CM; the CM itself is implememented by one or more backends, +which subclass these objects. Currently, two backends are included with MBWM2: +an XRender-based implementation MBWMCompMgrDefault, and a Clutter-based +implementation MBWMCompMgrClutter. diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c b/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c new file mode 100644 index 0000000..c1aaf8d --- /dev/null +++ b/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c @@ -0,0 +1,1610 @@ +/* + * Matchbox Window Manager - A lightweight window manager not for the + * desktop. + * + * Authored By Tomas Frydrych <tf@o-hand.com> + * + * Copyright (c) 2008 OpenedHand Ltd - http://o-hand.com + * + * 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 2, 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. + * + */ + +#include "mb-wm.h" +#include "mb-wm-client.h" +#include "mb-wm-comp-mgr.h" +#include "mb-wm-comp-mgr-clutter.h" +#include "mb-wm-theme.h" +#include "tidy/tidy-texture-frame.h" + +#include <clutter/clutter.h> +#include <clutter/x11/clutter-x11.h> +#if HAVE_CLUTTER_GLX +#include <clutter/glx/clutter-glx-texture-pixmap.h> +#endif +#include <X11/Xresource.h> +#include <X11/extensions/shape.h> +#include <X11/extensions/Xcomposite.h> + +#include <math.h> + +#define USE_DAMAGE_BOUNDING_BOX 1 + +#define SHADOW_RADIUS 4 +#define SHADOW_OPACITY 0.9 +#define SHADOW_OFFSET_X (-SHADOW_RADIUS) +#define SHADOW_OFFSET_Y (-SHADOW_RADIUS) + +#define MAX_TILE_SZ 16 /* make sure size/2 < MAX_TILE_SZ */ +#define WIDTH (3*MAX_TILE_SZ) +#define HEIGHT (3*MAX_TILE_SZ) + +#define CMGR(x) MB_WM_COMP_MGR_CLUTTER(x) +#define CCLIENT(x) MB_WM_COMP_MGR_CLUTTER_CLIENT(x) + +static unsigned char * +mbwm_cmc_shadow_gaussian_make_tile (); + +static void +mbwm_cmc_add_actor (MBWMCompMgrClutter *, MBWMCompMgrClutterClient *); + +/* + * A helper object to store manager's per-client data + */ +struct _MBWMCompMgrClutterClientPrivate +{ + ClutterActor *actor; /* Overall actor */ + ClutterActor *texture; /* The texture part of our actor */ + Pixmap pixmap; + int pxm_width; + int pxm_height; + int pxm_depth; + unsigned int flags; + Damage damage; + + int freeze_updates; + int needs_update : 1; +}; + +static void mbwm_cmc_client_show_real (MBWMCompMgrClient *client); +static void mbwm_cmc_client_hide_real (MBWMCompMgrClient *client); +static void mbwm_cmc_client_repair_real (MBWMCompMgrClient *client); +static void mbwm_cmc_client_configure_real (MBWMCompMgrClient *client); + +static void +mbwm_cmc_client_class_init (MBWMObjectClass *klass) +{ + MBWMCompMgrClientClass *c_klass = MB_WM_COMP_MGR_CLIENT_CLASS (klass); + + c_klass->show = mbwm_cmc_client_show_real; + c_klass->hide = mbwm_cmc_client_hide_real; + c_klass->repair = mbwm_cmc_client_repair_real; + c_klass->configure = mbwm_cmc_client_configure_real; + +#if MBWM_WANT_DEBUG + klass->klass_name = "MBWMCompMgrClutterClient"; +#endif +} + +static void +mbwm_cmc_client_freeze (MBWMCompMgrClutterClient *client) +{ + client->priv->freeze_updates++; +} + +static void +mbwm_cmc_client_unfreeze (MBWMCompMgrClutterClient * client) +{ + MBWMCompMgrClutterClientPrivate *priv = client->priv; + + priv->freeze_updates--; + + if (priv->freeze_updates < 0) + priv->freeze_updates = 0; + + if (!priv->freeze_updates && priv->needs_update) + mbwm_cmc_client_repair_real (MB_WM_COMP_MGR_CLIENT (client)); +} + + +/* + * Fetch the entire texture for our client + */ +static void +mbwm_cmc_fetch_texture (MBWMCompMgrClient *client) +{ + MBWMCompMgrClutterClient *cclient = CCLIENT(client); + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + MBWindowManagerClient *wm_client = client->wm_client; + MBWindowManager *wm = client->wm; + MBGeometry geom; + Window xwin; + Window root; + int x, y, w, h, bw, depth; +#ifdef HAVE_XEXT + /* Stuff we need for shaped windows */ + XRectangle *shp_rect; + int shp_order; + int shp_count; + int i; + + /* + * This is square of 32-bit comletely transparent values we use to + * clear bits of the texture from shaped windows; the size is a compromise + * between how much memory we want to allocate and how much tiling we are + * happy with. + * + * Make this power of 2 for efficient operation + */ +#define SHP_CLEAR_SIZE 4 + static int clear_init = 0; + static guint32 clear_data[SHP_CLEAR_SIZE * SHP_CLEAR_SIZE]; + + if (!clear_init) + { + memset (&clear_data, 0, sizeof (clear_data)); + clear_init = 1; + } +#endif + + if (!(priv->flags & MBWMCompMgrClutterClientMapped)) + return; + + xwin = + wm_client->xwin_frame ? wm_client->xwin_frame : wm_client->window->xwindow; + + if (priv->pixmap) + XFreePixmap (wm->xdpy, priv->pixmap); + + priv->pixmap = XCompositeNameWindowPixmap (wm->xdpy, xwin); + + if (!priv->pixmap) + return; + + XGetGeometry (wm->xdpy, priv->pixmap, &root, + &x, &y, &w, &h, &bw, &depth); + + mb_wm_client_get_coverage (wm_client, &geom); + + priv->pxm_width = w; + priv->pxm_height = h; + priv->pxm_depth = depth; + + clutter_actor_set_position (priv->actor, geom.x, geom.y); + clutter_actor_set_size (priv->texture, geom.width, geom.height); + + clutter_x11_texture_pixmap_set_pixmap ( + CLUTTER_X11_TEXTURE_PIXMAP (priv->texture), + priv->pixmap); + +#ifdef HAVE_XEXT + /* + * If the client is shaped, we have to manually clear any pixels in our + * texture in the non-visible areas. + */ + if (mb_wm_theme_is_client_shaped (wm->theme, wm_client)) + { + shp_rect = XShapeGetRectangles (wm->xdpy, xwin, + ShapeBounding, &shp_count, &shp_order); + + if (shp_rect && shp_count) + { + XserverRegion clear_rgn; + XRectangle rect; + XRectangle *clear_rect; + int clear_count; + XRectangle *r0, r1; + int c; + + rect.x = 0; + rect.y = 0; + rect.width = geom.width; + rect.height = geom.height; + + clear_rgn = XFixesCreateRegion (wm->xdpy, shp_rect, shp_count); + + XFixesInvertRegion (wm->xdpy, clear_rgn, &rect, clear_rgn); + + clear_rect = XFixesFetchRegion (wm->xdpy, clear_rgn, &clear_count); + + for (i = 0; i < clear_count; ++i) + { + int k, l; + + for (k = 0; k < clear_rect[i].width; k += SHP_CLEAR_SIZE) + for (l = 0; l < clear_rect[i].height; l += SHP_CLEAR_SIZE) + { + int w1 = clear_rect[i].width - k; + int h1 = clear_rect[i].height - l; + + if (w1 > SHP_CLEAR_SIZE) + w1 = SHP_CLEAR_SIZE; + + if (h1 > SHP_CLEAR_SIZE) + h1 = SHP_CLEAR_SIZE; + + clutter_texture_set_area_from_rgb_data ( + CLUTTER_TEXTURE (priv->texture), + (const guchar *)&clear_data, + TRUE, + clear_rect[i].x + k, + clear_rect[i].y + l, + w1, h1, + SHP_CLEAR_SIZE * 4, + 4, + CLUTTER_TEXTURE_RGB_FLAG_BGR, + NULL); + } + } + + XFixesDestroyRegion (wm->xdpy, clear_rgn); + + XFree (shp_rect); + + if (clear_rect) + XFree (clear_rect); + } + } + +#endif +} + +static int +mbwm_cmc_client_init (MBWMObject *obj, va_list vap) +{ + MBWMCompMgrClutterClient *cclient = CCLIENT (obj); + + cclient->priv = + mb_wm_util_malloc0 (sizeof (MBWMCompMgrClutterClientPrivate)); + + return 1; +} + +static void +mbwm_cmc_client_destroy (MBWMObject* obj) +{ + MBWMCompMgrClient *c = MB_WM_COMP_MGR_CLIENT (obj); + MBWMCompMgrClutterClient *cclient = CCLIENT (obj); + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + MBWindowManager *wm = c->wm; + MBWMCompMgrClutter *mgr = CMGR (wm->comp_mgr); + int i; + + if (priv->actor) + clutter_actor_destroy (priv->actor); + + if (priv->pixmap) + XFreePixmap (wm->xdpy, priv->pixmap); + + if (priv->damage) + XDamageDestroy (wm->xdpy, priv->damage); + + free (priv); +} + +int +mb_wm_comp_mgr_clutter_client_class_type () +{ + static int type = 0; + + if (UNLIKELY(type == 0)) + { + static MBWMObjectClassInfo info = { + sizeof (MBWMCompMgrClutterClientClass), + sizeof (MBWMCompMgrClutterClient), + mbwm_cmc_client_init, + mbwm_cmc_client_destroy, + mbwm_cmc_client_class_init + }; + + type = + mb_wm_object_register_class (&info, MB_WM_TYPE_COMP_MGR_CLIENT, 0); + } + + return type; +} + +/* + * This is a private method, hence static (all instances of this class are + * created automatically by the composite manager). + */ +static MBWMCompMgrClient * +mbwm_cmc_client_new (MBWindowManagerClient * client) +{ + MBWMObject *c; + + c = mb_wm_object_new (MB_WM_TYPE_COMP_MGR_CLUTTER_CLIENT, + MBWMObjectPropClient, client, + NULL); + + return MB_WM_COMP_MGR_CLIENT (c); +} + +static void +mbwm_cmc_client_hide_real (MBWMCompMgrClient * client) +{ + MBWMCompMgrClutterClient *cclient = CCLIENT (client); + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + + /* + * Do not hide the actor if effect is in progress + */ + if (priv->flags & MBWMCompMgrClutterClientEffectRunning) + return; + + clutter_actor_hide (priv->actor); +} + +static void +mbwm_cmc_client_show_real (MBWMCompMgrClient *client) +{ + MBWMCompMgrClutterClient *cclient = CCLIENT (client); + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + + if (!priv->actor) + { + /* + * This can happen if show() is called on our client before it is + * actually mapped (we only alocate the actor in response to map + * notification. + */ + return; + } + + /* + * Clear the don't update flag, if set + */ + priv->flags &= ~MBWMCompMgrClutterClientDontUpdate; + clutter_actor_show_all (priv->actor); +} + +void +mb_wm_comp_mgr_clutter_client_set_flags (MBWMCompMgrClutterClient *cclient, + MBWMCompMgrClutterClientFlags flags) +{ + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + + priv->flags |= flags; +} + + +void +mb_wm_comp_mgr_clutter_client_unset_flags (MBWMCompMgrClutterClient *cclient, + MBWMCompMgrClutterClientFlags flags) +{ + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + + priv->flags &= ~flags; +} + +MBWMCompMgrClutterClientFlags +mb_wm_comp_mgr_clutter_client_get_flags (MBWMCompMgrClutterClient *cclient) +{ + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + + return (MBWMCompMgrClutterClientFlags) priv->flags; +} + + +ClutterActor * +mb_wm_comp_mgr_clutter_client_get_actor (MBWMCompMgrClutterClient *cclient) +{ + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + + return g_object_ref(MB_WM_OBJECT (priv->actor)); +} + +/* + * Implementation of MBWMCompMgrClutter + */ +struct _MBWMCompMgrClutterPrivate +{ + ClutterActor * arena; + MBWMList * desktops; + ClutterActor * shadow; + + Window overlay_window; + + int freeze_stack; + + unsigned int restack_pending : 1; +}; + +static void +mbwm_cmc_private_free (MBWMCompMgrClutter *mgr) +{ + MBWMCompMgrClutterPrivate * priv = mgr->priv; + + if (priv->shadow) + clutter_actor_destroy (priv->shadow); + + free (priv); +} + +static void +mbwm_cmc_register_client_real (MBWMCompMgr * mgr, + MBWindowManagerClient * c) +{ + MBWMCompMgrClient *cclient; + MBWMCompMgrClutter *cmgr = CMGR (mgr); + MBWMCompMgrClutterClass *klass + = MB_WM_COMP_MGR_CLUTTER_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + if (c->cm_client) + return; + + cclient = klass->client_new (c); + c->cm_client = cclient; +} + +static void mbwm_cmc_turn_on_real (MBWMCompMgr *mgr); +static void mbwm_cmc_turn_off_real (MBWMCompMgr *mgr); +static void mbwm_cmc_map_notify_real (MBWMCompMgr *mgr, + MBWindowManagerClient *c); +static void mbwm_cmc_client_transition_real (MBWMCompMgr *mgr, + MBWindowManagerClient *c1, + MBWindowManagerClient *c2, + Bool reverse); +static void mbwm_cmc_client_event_real (MBWMCompMgr *mgr, + MBWindowManagerClient *client, + MBWMCompMgrClientEvent event); +static void mbwm_cmc_restack_real (MBWMCompMgr *mgr); +static Bool mb_wm_comp_mgr_is_my_window_real (MBWMCompMgr *mgr, Window xwin); +static void mbwm_cmc_select_desktop (MBWMCompMgr * mgr, + int desktop, int old_desktop); +static Bool mbwm_cmc_handle_damage (XDamageNotifyEvent *de, MBWMCompMgr*mgr); + +static void +mbwm_cmc_class_init (MBWMObjectClass *klass) +{ + MBWMCompMgrClass *cm_klass = MB_WM_COMP_MGR_CLASS (klass); + MBWMCompMgrClutterClass *clutter_klass = + MB_WM_COMP_MGR_CLUTTER_CLASS (klass); + +#if MBWM_WANT_DEBUG + klass->klass_name = "MBWMCompMgrClutter"; +#endif + + /* + * NB -- we do not need render() implementation, since that is taken care of + * automatically by clutter stage. + */ + cm_klass->register_client = mbwm_cmc_register_client_real; + cm_klass->turn_on = mbwm_cmc_turn_on_real; + cm_klass->turn_off = mbwm_cmc_turn_off_real; + cm_klass->map_notify = mbwm_cmc_map_notify_real; + cm_klass->my_window = mb_wm_comp_mgr_is_my_window_real; + cm_klass->client_transition = mbwm_cmc_client_transition_real; + cm_klass->client_event = mbwm_cmc_client_event_real; + cm_klass->restack = mbwm_cmc_restack_real; + cm_klass->select_desktop = mbwm_cmc_select_desktop; + cm_klass->handle_damage = mbwm_cmc_handle_damage; + + clutter_klass->client_new = mbwm_cmc_client_new; +} + +static int +mbwm_cmc_init (MBWMObject *obj, va_list vap) +{ + MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj); + MBWMCompMgrClutter * cmgr = CMGR (obj); + MBWMCompMgrClutterPrivate * priv; + MBWindowManager * wm = mgr->wm; + ClutterActor * desktop, * arena; + + priv = mb_wm_util_malloc0 (sizeof (MBWMCompMgrClutterPrivate)); + cmgr->priv = priv; + + XCompositeRedirectSubwindows (wm->xdpy, wm->root_win->xwindow, + CompositeRedirectManual); + + priv->arena = arena = clutter_group_new (); + clutter_container_add_actor (CLUTTER_CONTAINER (clutter_stage_get_default()), + arena); + clutter_actor_show (arena); + + desktop = clutter_group_new (); + clutter_actor_show (desktop); + clutter_container_add_actor (CLUTTER_CONTAINER (arena), desktop); + priv->desktops = mb_wm_util_list_append (priv->desktops, desktop); + + return 1; +} + +static void +mbwm_cmc_destroy (MBWMObject * obj) +{ + MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj); + MBWMCompMgrClutter * cmgr = CMGR (obj); + + mb_wm_comp_mgr_turn_off (mgr); + mbwm_cmc_private_free (cmgr); +} + +int +mb_wm_comp_mgr_clutter_class_type () +{ + static int type = 0; + + if (UNLIKELY(type == 0)) + { + static MBWMObjectClassInfo info = { + sizeof (MBWMCompMgrClutterClass), + sizeof (MBWMCompMgrClutter), + mbwm_cmc_init, + mbwm_cmc_destroy, + mbwm_cmc_class_init + }; + + type = mb_wm_object_register_class (&info, MB_WM_TYPE_COMP_MGR, 0); + } + + return type; +} + +/* Shuts the compositing down */ +static void +mbwm_cmc_turn_off_real (MBWMCompMgr *mgr) +{ + MBWindowManager * wm = mgr->wm; + MBWMCompMgrClutterPrivate * priv; + + if (!mgr) + return; + + priv = CMGR (mgr)->priv; + + if (mgr->disabled) + return; + + if (!mb_wm_stack_empty (wm)) + { + MBWindowManagerClient * c; + + mb_wm_stack_enumerate (wm, c) + { + mb_wm_comp_mgr_unregister_client (mgr, c); + } + } + + XCompositeReleaseOverlayWindow (wm->xdpy, wm->root_win->xwindow); + priv->overlay_window = None; + + mgr->disabled = True; +} + +static void +mbwm_cmc_turn_on_real (MBWMCompMgr *mgr) +{ + MBWindowManager * wm; + MBWMCompMgrClutterPrivate * priv; + + if (!mgr || !mgr->disabled) + return; + + priv = CMGR (mgr)->priv; + wm = mgr->wm; + + mgr->disabled = False; + + if (priv->overlay_window == None) + { + ClutterActor * stage = clutter_stage_get_default (); + ClutterColor clr = {0, 0, 0, 0xff }; + Window xwin; + XserverRegion region; + + /* + * Fetch the overlay window + */ + xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); + + priv->overlay_window = + XCompositeGetOverlayWindow (wm->xdpy, wm->root_win->xwindow); + + /* + * Reparent the stage window to the overlay window, this makes it + * magically work :) + */ + XReparentWindow (wm->xdpy, xwin, priv->overlay_window, 0, 0); + + /* + * Use xfixes shape to make events pass through the overlay window + * + * TODO -- this has certain drawbacks, notably when our client is + * tranformed (rotated, scaled, etc), the events will not be landing in + * the right place. The answer to that is event forwarding with + * translation. + */ + region = XFixesCreateRegion (wm->xdpy, NULL, 0); + + XFixesSetWindowShapeRegion (wm->xdpy, priv->overlay_window, + ShapeBounding, 0, 0, 0); + XFixesSetWindowShapeRegion (wm->xdpy, priv->overlay_window, + ShapeInput, 0, 0, region); + + XFixesDestroyRegion (wm->xdpy, region); + + clutter_actor_set_size (stage, wm->xdpy_width, wm->xdpy_height); + clutter_stage_set_color (CLUTTER_STAGE (stage), &clr); + + clutter_actor_show (stage); + } +} + +static void +mbwm_cmc_client_repair_real (MBWMCompMgrClient * client) +{ + MBWindowManagerClient *wm_client = client->wm_client; + MBWMCompMgrClutterClient *cclient = CCLIENT (client); + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + MBWindowManager *wm = client->wm; + XserverRegion parts; + int i, r_count; + XRectangle *r_damage; + XRectangle r_bounds; + + MBWM_NOTE (COMPOSITOR, "REPAIRING %x", wm_client->window->xwindow); + + if (!priv->actor) + return; + + if (priv->freeze_updates) + { + priv->needs_update = 1; + return; + } + + priv->needs_update = 0; + + if (!priv->pixmap) + { + /* + * First time we have been called since creation/configure, + * fetch the whole texture. + */ + MBWM_NOTE (DAMAGE, "Full screen repair."); + XDamageSubtract (wm->xdpy, priv->damage, None, None); + mbwm_cmc_fetch_texture (client); + return; + } + + /* + * Retrieve the damaged region and break it down into individual + * rectangles so we do not have to update the whole shebang. + */ + parts = XFixesCreateRegion (wm->xdpy, 0, 0); + XDamageSubtract (wm->xdpy, priv->damage, None, parts); + + r_damage = XFixesFetchRegionAndBounds (wm->xdpy, parts, + &r_count, + &r_bounds); + + if (r_damage) + { +#if USE_DAMAGE_BOUNDING_BOX + clutter_x11_texture_pixmap_update_area ( + CLUTTER_X11_TEXTURE_PIXMAP (priv->texture), + r_bounds.x, + r_bounds.y, + r_bounds.width, + r_bounds.height); +#else + for (i = 0; i < r_count; ++i) + { + MBWM_NOTE (DAMAGE, "Repairing %d,%d;%dx%d", + r_damage[i].x, + r_damage[i].y, + r_damage[i].width, + r_damage[i].height); + + clutter_x11_texture_pixmap_update_area ( + CLUTTER_X11_TEXTURE_PIXMAP (priv->texture), + r_damage[i].x, + r_damage[i].y, + r_damage[i].width, + r_damage[i].height); + } +#endif + XFree (r_damage); + } + + XFixesDestroyRegion (wm->xdpy, parts); +} + +static void +mbwm_cmc_client_configure_real (MBWMCompMgrClient * client) +{ + MBWindowManagerClient *wm_client = client->wm_client; + MBWMCompMgrClutterClient *cclient = CCLIENT (client); + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + + MBWM_NOTE (COMPOSITOR, "CONFIGURE request"); + + /* + * Release the backing pixmap; we will recreate it next time we get damage + * notification for this window. + */ + if (priv->pixmap) + { + XFreePixmap (client->wm->xdpy, priv->pixmap); + priv->pixmap = None; + } +} + +static Bool +mbwm_cmc_handle_damage (XDamageNotifyEvent * de, + MBWMCompMgr * mgr) +{ + MBWMCompMgrClutterPrivate * priv = CMGR (mgr)->priv; + MBWindowManager * wm = mgr->wm; + MBWindowManagerClient * c; + + c = mb_wm_managed_client_from_frame (wm, de->drawable); + + if (c && c->cm_client) + { + MBWMCompMgrClutterClient *cclient = CCLIENT (c->cm_client); + MBWMCompMgrClutterClientPrivate *cpriv = cclient->priv; + + if (!cpriv->actor || + (cpriv->flags & MBWMCompMgrClutterClientDontUpdate)) + return False; + + MBWM_NOTE (COMPOSITOR, + "Reparing window %x, geometry %d,%d;%dx%d; more %d\n", + de->drawable, + de->geometry.x, + de->geometry.y, + de->geometry.width, + de->geometry.height, + de->more); + + mbwm_cmc_client_repair_real (c->cm_client); + } + else + { + MBWM_NOTE (COMPOSITOR, "Failed to find client for window %x\n", + de->drawable); + } + + return False; +} + +static void +mbwm_cmc_freeze_stack (MBWMCompMgr *mgr) +{ + CMGR (mgr)->priv->freeze_stack++; +} + +static void +mbwm_cmc_unfreeze_stack (MBWMCompMgr *mgr) +{ + MBWMCompMgrClutterPrivate *priv = CMGR (mgr)->priv; + + priv->freeze_stack--; + + if (priv->freeze_stack < 0) + priv->freeze_stack = 0; + + if (!priv->freeze_stack && priv->restack_pending) + mbwm_cmc_restack_real ((MBWMCompMgr *)mgr); +} + +static void +mbwm_cmc_restack_real (MBWMCompMgr *mgr) +{ + MBWindowManager *wm = mgr->wm; + MBWMCompMgrClutter *cmgr = CMGR (mgr); + MBWMCompMgrClutterPrivate *priv = cmgr->priv; + MBWMList *l; + int i = 0; + + if (priv->freeze_stack) + { + priv->restack_pending = 1; + return; + } + + priv->restack_pending = 0; + + l = priv->desktops; + + if (!mb_wm_stack_empty (wm)) + { + MBWindowManagerClient * c; + + while (l) + { + ClutterActor *desktop = l->data; + ClutterActor * prev = NULL; + + mb_wm_stack_enumerate (wm, c) + { + MBWMCompMgrClutterClient * cc; + ClutterActor * a; + + if (mb_wm_client_get_desktop (c) != i) + continue; + + cc = CCLIENT (c->cm_client); + + a = cc->priv->actor; + + if (!a || clutter_actor_get_parent (a) != desktop) + continue; + + clutter_actor_raise (a, prev); + + prev = a; + } + + l = l->next; + ++i; + } + } +} + +MBWMList * +mb_wm_comp_mgr_clutter_get_desktops (MBWMCompMgrClutter *cmgr) +{ + return cmgr->priv->desktops; +} + +/* + * Gets the n-th desktop from our desktop list; if we do not have that many + * desktops, just append new ones. + */ +ClutterActor * +mb_wm_comp_mgr_clutter_get_nth_desktop (MBWMCompMgrClutter * cmgr, int desktop) +{ + MBWMCompMgrClutterPrivate * priv = cmgr->priv; + MBWMList * l = priv->desktops; + int i = 0; + + while (l && i != desktop) + { + ++i; + + if (l->next) + l = l->next; + else + { + /* End of the line -- append new desktop */ + ClutterActor * d = clutter_group_new (); + priv->desktops = mb_wm_util_list_append (priv->desktops, d); + clutter_container_add_actor (CLUTTER_CONTAINER (priv->arena), d); + + l = l->next; + } + } + + return CLUTTER_ACTOR (l->data); +} + +/* + * Returns the arena; this is an intermediate group which contains all the + * other actors the CM uses. The caller of this function holds a reference + * to the returned ClutterActor and must release it once no longer needed. + */ +ClutterActor * +mb_wm_comp_mgr_clutter_get_arena (MBWMCompMgrClutter *cmgr) +{ + MBWMCompMgrClutterPrivate * priv = cmgr->priv; + + return g_object_ref (priv->arena); +} + + +static void +mbwm_cmc_select_desktop (MBWMCompMgr * mgr, + int desktop, + int old_desktop) +{ + MBWMCompMgrClutter * cmgr = CMGR (mgr); + ClutterActor * d; + MBWMList * l; + + d = mb_wm_comp_mgr_clutter_get_nth_desktop (cmgr, desktop); + + l = cmgr->priv->desktops; + + while (l) + { + ClutterActor * a = l->data; + + if (a == d) + clutter_actor_show (a); + else + clutter_actor_hide (a); + + l = l->next; + } +} + +static void +mbwm_cmc_map_notify_real (MBWMCompMgr *mgr, + MBWindowManagerClient *c) +{ + MBWMCompMgrClutter *cmgr = CMGR (mgr); + MBWMCompMgrClient *client = c->cm_client; + MBWMCompMgrClutterClient *cclient = CCLIENT(client); + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + MBWindowManager *wm = client->wm; + ClutterActor *actor; + ClutterActor *texture; + ClutterActor *rect; + MBGeometry geom; + const MBWMList *l; + unsigned int shadow_clr[4]; + ClutterColor shadow_cclr; + MBWMCompMgrShadowType shadow_type; + MBWMClientType ctype = MB_WM_CLIENT_CLIENT_TYPE (c); + + if (mb_wm_client_is_hiding_from_desktop (c)) + { + /* + * We already have the resources, except we have to get a new + * backing pixmap + */ + Window xwin = c->xwin_frame ? c->xwin_frame : c->window->xwindow; + + /* + * FIXME -- Must rebind the pixmap to the texture -- this is not ideal + * since our texture already contains the correct data, but without + * this it will not update. Perhaps we some extension to the clutter + * API is needed here. + */ + mbwm_cmc_fetch_texture (client); + + clutter_actor_show (priv->actor); + return; + } + + /* + * We get called for windows as well as their children, so once we are + * mapped do nothing. + */ + if (priv->flags & MBWMCompMgrClutterClientMapped) + return; + + priv->flags |= MBWMCompMgrClutterClientMapped; + + priv->damage = XDamageCreate (wm->xdpy, + c->xwin_frame ? + c->xwin_frame : + c->window->xwindow, +#ifdef USE_DAMAGE_BOUNDING_BOX + XDamageReportBoundingBox +#else + XDamageReportNonEmpty +#endif + ); + + mb_wm_client_get_coverage (c, &geom); + + actor = g_object_ref (clutter_group_new ()); +#if HAVE_CLUTTER_GLX + texture = clutter_glx_texture_pixmap_new (); +#else + texture = clutter_x11_texture_pixmap_new (); +#endif + clutter_actor_show (texture); + + if (ctype == MBWMClientTypeDialog || + ctype == MBWMClientTypeMenu || + ctype == MBWMClientTypeNote || + ctype == MBWMClientTypeOverride) + { + shadow_type = mb_wm_theme_get_shadow_type (wm->theme); + + if (shadow_type == MBWM_COMP_MGR_SHADOW_NONE) + { + clutter_container_add (CLUTTER_CONTAINER (actor), texture, NULL); + } + else + { + if (shadow_type == MBWM_COMP_MGR_SHADOW_SIMPLE) + { + mb_wm_theme_get_shadow_color (wm->theme, + &shadow_clr[0], + &shadow_clr[1], + &shadow_clr[2], + &shadow_clr[3]); + + shadow_cclr.red = 0xff * shadow_clr[0] / 0xffff; + shadow_cclr.green = 0xff * shadow_clr[1] / 0xffff; + shadow_cclr.blue = 0xff * shadow_clr[2] / 0xffff; + shadow_cclr.alpha = 0xff * shadow_clr[3] / 0xffff; + + rect = clutter_rectangle_new_with_color (&shadow_cclr); + clutter_actor_set_position (rect, 4, 4); + } + else + { + ClutterActor * txt = cmgr->priv->shadow; + if (!txt) + { + unsigned char * data; + + data = mbwm_cmc_shadow_gaussian_make_tile (); + + txt = clutter_texture_new (); + + clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (txt), + data, + TRUE, + WIDTH, + HEIGHT, + WIDTH*4, + 4, + 0, + NULL); + free (data); + + cmgr->priv->shadow = txt; + } + + rect = tidy_texture_frame_new (CLUTTER_TEXTURE (txt), + MAX_TILE_SZ, + MAX_TILE_SZ, + MAX_TILE_SZ, + MAX_TILE_SZ); + clutter_actor_set_position (rect, + 2*SHADOW_RADIUS, 2*SHADOW_RADIUS); + } + + clutter_actor_set_size (rect, geom.width, geom.height); + clutter_actor_show (rect); + + clutter_container_add (CLUTTER_CONTAINER (actor), + rect, texture, NULL); + } + } + else + { + clutter_container_add (CLUTTER_CONTAINER (actor), texture, NULL); + } + + + priv->actor = actor; + priv->texture = texture; + + g_object_set_data (G_OBJECT (actor), "MBWMCompMgrClutterClient", cclient); + + clutter_actor_set_position (actor, geom.x, geom.y); + clutter_actor_set_size (texture, geom.width, geom.height); + + mbwm_cmc_add_actor (cmgr, cclient); +} + +static void +mbwm_cmc_transtion_fade_out_cb (ClutterAnimation *anim, + MBWMCompMgrClutterClient *client) +{ + client->priv->flags &= ~MBWMCompMgrClutterClientEffectRunning; + +#if 0 + /* FIXME -- see if we need this */ + mb_wm_object_unref (MB_WM_OBJECT (client)); +#endif +} + +static void +_fade_apply_behaviour_to_client (MBWindowManagerClient *wc, + unsigned long duration) +{ + MBWMList *l; + ClutterActor *a = CCLIENT (wc->cm_client)->priv->actor; + ClutterAnimation *anim; + + clutter_actor_set_opacity (a, 0); + + anim = clutter_actor_animate (a, + CLUTTER_EASE_IN_SINE, + duration, + "opacity", 0xff, + wc->cm_client); + + g_signal_connect_after (anim, "completed", + G_CALLBACK (mbwm_cmc_transtion_fade_out_cb), + NULL); + + l = mb_wm_client_get_transients (wc); + while (l) + { + MBWindowManagerClient * c = l->data; + + _fade_apply_behaviour_to_client (c, duration); + l = l->next; + } +} + +static void +mbwm_cmc_client_transition_fade (MBWMCompMgrClutterClient *cclient1, + MBWMCompMgrClutterClient *cclient2, + unsigned long duration) +{ + /* + * Fade is simple -- we only need to animate the second actor and its + * children, as the stacking order automatically takes care of the + * actor appearing to fade out from the first one + */ + cclient2->priv->flags |= MBWMCompMgrClutterClientEffectRunning; + + _fade_apply_behaviour_to_client (MB_WM_COMP_MGR_CLIENT (cclient2)->wm_client, + duration); +} + +static void +mbwm_cmc_client_transition_real (MBWMCompMgr *mgr, + MBWindowManagerClient *c1, + MBWindowManagerClient *c2, + Bool reverse) +{ + MBWMCompMgrClutterClient * cclient1 = CCLIENT (c1->cm_client); + MBWMCompMgrClutterClient * cclient2 = CCLIENT (c2->cm_client); + + mbwm_cmc_client_transition_fade (cclient1, cclient2, 100); +} + +static void +mbwm_cmc_client_event_completed_hide_cb (ClutterAnimation *anim, + MBWMCompMgrClutterClient *client) +{ + MBWMCompMgrClient *c = MB_WM_COMP_MGR_CLIENT (client); + + client->priv->flags &= ~MBWMCompMgrClutterClientEffectRunning; + clutter_actor_hide (client->priv->actor); + clutter_actor_set_scale (client->priv->actor, 1.0, 1.0); + mbwm_cmc_unfreeze_stack (c->wm->comp_mgr); + mbwm_cmc_client_unfreeze (client); + + /* + * Release the extra reference on the CM client that was added for the sake + * of the effect + */ + mb_wm_object_unref (MB_WM_OBJECT (client)); +} + +static void +mbwm_cmc_client_event_completed_cb (ClutterAnimation *anim, + MBWMCompMgrClutterClient *client) +{ + client->priv->flags &= ~MBWMCompMgrClutterClientEffectRunning; + + /* + * Release the extra reference on the CM client that was added for the sake + * of the effect + */ + mb_wm_object_unref (MB_WM_OBJECT (client)); +} + +static void +mbwm_cmc_client_event_real (MBWMCompMgr *mgr, + MBWindowManagerClient *client, + MBWMCompMgrClientEvent event) +{ + MBWMCompMgrClutterClient *cclient = CCLIENT (client->cm_client); + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + ClutterAnimation *anim = NULL; + + if (MB_WM_CLIENT_CLIENT_TYPE (client) != MBWMClientTypeApp) + return; + + /* FIXME -- this is where the animation is applied */ + switch (event) + { + case MBWMCompMgrClientEventMinimize: + mbwm_cmc_freeze_stack (mgr); + mbwm_cmc_client_freeze (cclient); + + mb_wm_object_ref (MB_WM_OBJECT (cclient)); + priv->flags |= MBWMCompMgrClutterClientEffectRunning; + + anim = clutter_actor_animate (priv->actor, + CLUTTER_EASE_IN_SINE, + 200, + "scale-x", 0.0, + "scale-y", 0.0, + NULL); + g_signal_connect_after (anim, "completed", + G_CALLBACK (mbwm_cmc_client_event_completed_hide_cb), + cclient); + break; + case MBWMCompMgrClientEventUnmap: + mbwm_cmc_freeze_stack (mgr); + mbwm_cmc_client_freeze (cclient); + + mb_wm_object_ref (MB_WM_OBJECT (cclient)); + priv->flags |= MBWMCompMgrClutterClientEffectRunning; + + anim = clutter_actor_animate (priv->actor, + CLUTTER_EASE_IN_SINE, + 200, + "scale-x", 0.0, + "scale-y", 0.0, + NULL); + g_signal_connect_after (anim, "completed", + G_CALLBACK (mbwm_cmc_client_event_completed_hide_cb), + cclient); + break; + case MBWMCompMgrClientEventMap: + mb_wm_object_ref (MB_WM_OBJECT (cclient)); + priv->flags |= MBWMCompMgrClutterClientEffectRunning; + + clutter_actor_set_scale_full (priv->actor, 0.0, 0.0, + clutter_actor_get_width (priv->actor)/ 2, + clutter_actor_get_height (priv->actor) / 2); + clutter_actor_show (priv->actor); + + anim = clutter_actor_animate (priv->actor, + CLUTTER_EASE_IN_SINE, + 200, + "scale-x", 1.0, + "scale-y", 1.0, + NULL); + g_signal_connect_after (anim, "completed", + G_CALLBACK (mbwm_cmc_client_event_completed_cb), + cclient); + break; + default:; + } +} + +/* + * Our windows which we need the WM to ingore are the overlay and the stage + * window. + */ +static Bool +mb_wm_comp_mgr_is_my_window_real (MBWMCompMgr * mgr, Window xwin) +{ + MBWMCompMgrClutterPrivate * priv = CMGR (mgr)->priv; + ClutterActor * stage; + + if (priv->overlay_window == xwin) + return True; + + stage = clutter_stage_get_default (); + + if (xwin == clutter_x11_get_stage_window (CLUTTER_STAGE (stage))) + return True; + + return False; +} + +static void +mbwm_cmc_add_actor (MBWMCompMgrClutter *cmgr, + MBWMCompMgrClutterClient *cclient) +{ + MBWindowManagerClient * c = MB_WM_COMP_MGR_CLIENT (cclient)->wm_client; + MBWMCompMgrClutterClientPrivate *priv = cclient->priv; + ClutterActor * d; + int desktop = mb_wm_client_get_desktop (c); + + /* + * Sanity check; if the desktop is unset, add to desktop 0. + */ + if (desktop < 0) + desktop = 0; + + d = mb_wm_comp_mgr_clutter_get_nth_desktop (cmgr, desktop); + + clutter_container_add_actor (CLUTTER_CONTAINER (d), priv->actor); +} + +MBWMCompMgr * +mb_wm_comp_mgr_clutter_new (MBWindowManager *wm) +{ + MBWMObject *mgr; + + mgr = mb_wm_object_new (MB_WM_TYPE_COMP_MGR_CLUTTER, + MBWMObjectPropWm, wm, + NULL); + + return MB_WM_COMP_MGR (mgr); +} + +/* ------------------------------- */ +/* Shadow Generation */ + +typedef struct MBGaussianMap +{ + int size; + double * data; +} MBGaussianMap; + +static double +gaussian (double r, double x, double y) +{ + return ((1 / (sqrt (2 * M_PI * r))) * + exp ((- (x * x + y * y)) / (2 * r * r))); +} + + +static MBGaussianMap * +mbwm_cmc_make_gaussian_map (double r) +{ + MBGaussianMap *c; + int size = ((int) ceil ((r * 3)) + 1) & ~1; + int center = size / 2; + int x, y; + double t = 0.0; + double g; + + c = malloc (sizeof (MBGaussianMap) + size * size * sizeof (double)); + c->size = size; + + c->data = (double *) (c + 1); + + for (y = 0; y < size; y++) + for (x = 0; x < size; x++) + { + g = gaussian (r, (double) (x - center), (double) (y - center)); + t += g; + c->data[y * size + x] = g; + } + + for (y = 0; y < size; y++) + for (x = 0; x < size; x++) + c->data[y*size + x] /= t; + + return c; +} + +static unsigned char +mbwm_cmc_sum_gaussian (MBGaussianMap * map, double opacity, + int x, int y, int width, int height) +{ + int fx, fy; + double * g_data; + double * g_line = map->data; + int g_size = map->size; + int center = g_size / 2; + int fx_start, fx_end; + int fy_start, fy_end; + double v; + unsigned int r; + + /* + * Compute set of filter values which are "in range", + * that's the set with: + * 0 <= x + (fx-center) && x + (fx-center) < width && + * 0 <= y + (fy-center) && y + (fy-center) < height + * + * 0 <= x + (fx - center) x + fx - center < width + * center - x <= fx fx < width + center - x + */ + + fx_start = center - x; + if (fx_start < 0) + fx_start = 0; + fx_end = width + center - x; + if (fx_end > g_size) + fx_end = g_size; + + fy_start = center - y; + if (fy_start < 0) + fy_start = 0; + fy_end = height + center - y; + if (fy_end > g_size) + fy_end = g_size; + + g_line = g_line + fy_start * g_size + fx_start; + + v = 0; + for (fy = fy_start; fy < fy_end; fy++) + { + g_data = g_line; + g_line += g_size; + + for (fx = fx_start; fx < fx_end; fx++) + v += *g_data++; + } + if (v > 1) + v = 1; + + v *= (opacity * 255.0); + + r = (unsigned int) v; + + return (unsigned char) r; +} + +static unsigned char * +mbwm_cmc_shadow_gaussian_make_tile () +{ + unsigned char * data; + int size; + int center; + int x, y; + unsigned char d; + int pwidth, pheight; + double opacity = SHADOW_OPACITY; + static MBGaussianMap * gaussian_map = NULL; + + struct _mypixel + { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + } * _d; + + + if (!gaussian_map) + gaussian_map = + mbwm_cmc_make_gaussian_map (SHADOW_RADIUS); + + size = gaussian_map->size; + center = size / 2; + + /* Top & bottom */ + + pwidth = MAX_TILE_SZ; + pheight = MAX_TILE_SZ; + + data = mb_wm_util_malloc0 (4 * WIDTH * HEIGHT); + + _d = (struct _mypixel*) data; + + /* N */ + for (y = 0; y < pheight; y++) + { + d = mbwm_cmc_sum_gaussian (gaussian_map, opacity, + center, y - center, + WIDTH, HEIGHT); + for (x = 0; x < pwidth; x++) + { + _d[y*3*pwidth + x + pwidth].r = 0; + _d[y*3*pwidth + x + pwidth].g = 0; + _d[y*3*pwidth + x + pwidth].b = 0; + _d[y*3*pwidth + x + pwidth].a = d; + } + + } + + /* S */ + pwidth = MAX_TILE_SZ; + pheight = MAX_TILE_SZ; + + for (y = 0; y < pheight; y++) + { + d = mbwm_cmc_sum_gaussian (gaussian_map, opacity, + center, y - center, + WIDTH, HEIGHT); + for (x = 0; x < pwidth; x++) + { + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].r = 0; + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].g = 0; + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].b = 0; + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].a = d; + } + + } + + + /* w */ + pwidth = MAX_TILE_SZ; + pheight = MAX_TILE_SZ; + + for (x = 0; x < pwidth; x++) + { + d = mbwm_cmc_sum_gaussian (gaussian_map, opacity, + x - center, center, + WIDTH, HEIGHT); + for (y = 0; y < pheight; y++) + { + _d[y*3*pwidth + 3*pwidth*pheight + x].r = 0; + _d[y*3*pwidth + 3*pwidth*pheight + x].g = 0; + _d[y*3*pwidth + 3*pwidth*pheight + x].b = 0; + _d[y*3*pwidth + 3*pwidth*pheight + x].a = d; + } + + } + + /* E */ + for (x = 0; x < pwidth; x++) + { + d = mbwm_cmc_sum_gaussian (gaussian_map, opacity, + x - center, center, + WIDTH, HEIGHT); + for (y = 0; y < pheight; y++) + { + _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].r = 0; + _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].g = 0; + _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].b = 0; + _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].a = d; + } + + } + + /* NW */ + pwidth = MAX_TILE_SZ; + pheight = MAX_TILE_SZ; + + for (x = 0; x < pwidth; x++) + for (y = 0; y < pheight; y++) + { + d = mbwm_cmc_sum_gaussian (gaussian_map, opacity, + x-center, y-center, + WIDTH, HEIGHT); + + _d[y*3*pwidth + x].r = 0; + _d[y*3*pwidth + x].g = 0; + _d[y*3*pwidth + x].b = 0; + _d[y*3*pwidth + x].a = d; + } + + /* SW */ + for (x = 0; x < pwidth; x++) + for (y = 0; y < pheight; y++) + { + d = mbwm_cmc_sum_gaussian (gaussian_map, opacity, + x-center, y-center, + WIDTH, HEIGHT); + + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].r = 0; + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].g = 0; + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].b = 0; + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].a = d; + } + + /* SE */ + for (x = 0; x < pwidth; x++) + for (y = 0; y < pheight; y++) + { + d = mbwm_cmc_sum_gaussian (gaussian_map, opacity, + x-center, y-center, + WIDTH, HEIGHT); + + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) + + 2*pwidth].r = 0; + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) + + 2*pwidth].g = 0; + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) + + 2*pwidth].b = 0; + _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) + + 2*pwidth].a = d; + } + + /* NE */ + for (x = 0; x < pwidth; x++) + for (y = 0; y < pheight; y++) + { + d = mbwm_cmc_sum_gaussian (gaussian_map, opacity, + x-center, y-center, WIDTH, HEIGHT); + + _d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].r = 0; + _d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].g = 0; + _d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].b = 0; + _d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].a = d; + } + + /* center */ + pwidth = MAX_TILE_SZ; + pheight = MAX_TILE_SZ; + + d = mbwm_cmc_sum_gaussian (gaussian_map, opacity, + center, center, WIDTH, HEIGHT); + + for (x = 0; x < pwidth; x++) + for (y = 0; y < pheight; y++) + { + _d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].r = 0; + _d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].g = 0; + _d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].b = 0; + _d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].a = d; + } + + return data; +} + diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.h b/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.h new file mode 100644 index 0000000..8c719d9 --- /dev/null +++ b/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.h @@ -0,0 +1,108 @@ +/* + * Matchbox Window Manager - A lightweight window manager not for the + * desktop. + * + * Authored By Tomas Frydrych <tf@o-hand.com> + * + * Copyright (c) 2008 OpenedHand Ltd - http://o-hand.com + * + * 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 2, 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. + * + */ + +#ifndef _HAVE_MB_WM_COMP_MGR_CLUTTER_H +#define _HAVE_MB_WM_COMP_MGR_CLUTTER_H + +#include <matchbox2/mb-wm-config.h> +#include <clutter/clutter.h> + +#define MB_WM_COMP_MGR_CLUTTER(c) ((MBWMCompMgrClutter*)(c)) +#define MB_WM_COMP_MGR_CLUTTER_CLASS(c) ((MBWMCompMgrClutterClass*)(c)) +#define MB_WM_TYPE_COMP_MGR_CLUTTER (mb_wm_comp_mgr_clutter_class_type ()) + +#define MB_WM_COMP_MGR_CLUTTER_CLIENT(c) ((MBWMCompMgrClutterClient*)(c)) +#define MB_WM_COMP_MGR_CLUTTER_CLIENT_CLASS(c) ((MBWMCompMgrClutterClientClass*)(c)) +#define MB_WM_TYPE_COMP_MGR_CLUTTER_CLIENT (mb_wm_comp_mgr_clutter_client_class_type ()) + +typedef struct _MBWMCompMgrClutter MBWMCompMgrClutter; +typedef struct _MBWMCompMgrClutterClass MBWMCompMgrClutterClass; +typedef struct _MBWMCompMgrClutterPrivate MBWMCompMgrClutterPrivate; + +typedef struct _MBWMCompMgrClutterClient MBWMCompMgrClutterClient; +typedef struct _MBWMCompMgrClutterClientClass MBWMCompMgrClutterClientClass; +typedef struct _MBWMCompMgrClutterClientPrivate MBWMCompMgrClutterClientPrivate; + +typedef enum +{ + MBWMCompMgrClutterClientMapped = (1<<0), + MBWMCompMgrClutterClientDontUpdate = (1<<1), + MBWMCompMgrClutterClientDone = (1<<2), + MBWMCompMgrClutterClientEffectRunning = (1<<3), +} MBWMCompMgrClutterClientFlags; + +struct _MBWMCompMgrClutter +{ + MBWMCompMgr parent; + MBWMCompMgrClutterPrivate *priv; +}; + +struct _MBWMCompMgrClutterClass +{ + MBWMCompMgrClass parent; + + MBWMCompMgrClient * (*client_new) (MBWindowManagerClient * client); +}; + +int +mb_wm_comp_mgr_clutter_class_type (); + +MBWMCompMgr* +mb_wm_comp_mgr_clutter_new (MBWindowManager *wm); + +struct _MBWMCompMgrClutterClient +{ + MBWMCompMgrClient parent; + + MBWMCompMgrClutterClientPrivate *priv; +}; + +struct _MBWMCompMgrClutterClientClass +{ + MBWMCompMgrClientClass parent; +}; + +int +mb_wm_comp_mgr_clutter_client_class_type (); + +ClutterActor * +mb_wm_comp_mgr_clutter_client_get_actor (MBWMCompMgrClutterClient *cclient); + +void +mb_wm_comp_mgr_clutter_client_set_flags (MBWMCompMgrClutterClient *cclient, + MBWMCompMgrClutterClientFlags flags); + +void +mb_wm_comp_mgr_clutter_client_unset_flags (MBWMCompMgrClutterClient *cclient, + MBWMCompMgrClutterClientFlags flags); + +MBWMCompMgrClutterClientFlags +mb_wm_comp_mgr_clutter_client_get_flags (MBWMCompMgrClutterClient *cclient); + +MBWMList * +mb_wm_comp_mgr_clutter_get_desktops (MBWMCompMgrClutter *cmgr); + +ClutterActor * +mb_wm_comp_mgr_clutter_get_nth_desktop (MBWMCompMgrClutter *cmgr, int desktop); + +ClutterActor * +mb_wm_comp_mgr_clutter_get_arena (MBWMCompMgrClutter *cmgr); + +#endif diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.c b/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.c new file mode 100644 index 0000000..fe7f75b --- /dev/null +++ b/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.c @@ -0,0 +1,1837 @@ +/* + * Matchbox Window Manager - A lightweight window manager not for the + * desktop. + * + * Authored By Matthew Allum <mallum@o-hand.com> + * Tomas Frydrych <tf@o-hand.com> + * + * Copyright (c) 2002, 2004, 2007, 2008 OpenedHand Ltd - http://o-hand.com + * + * 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 2, 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. + * + */ + +#include "mb-wm.h" +#include "mb-wm-client.h" +#include "mb-wm-comp-mgr.h" +#include "mb-wm-comp-mgr-xrender.h" + +#include <math.h> + +#include <X11/Xresource.h> +#include <X11/extensions/Xdamage.h> +#include <X11/extensions/Xrender.h> +#include <X11/extensions/Xcomposite.h> + +#define SHADOW_RADIUS 6 +#define SHADOW_OPACITY 0.75 +#define SHADOW_OFFSET_X (-SHADOW_RADIUS) +#define SHADOW_OFFSET_Y (-SHADOW_RADIUS) + +/* + * A helper object to store manager's per-client data + */ +struct MBWMCompMgrDefaultClient +{ + MBWMCompMgrClient parent; + + int damaged; + Damage damage; + Picture picture; + XserverRegion extents; + XserverRegion border_clip; +}; + +static void +mb_wm_comp_mgr_xrender_client_show_real (MBWMCompMgrClient * client); + +static void +mb_wm_comp_mgr_xrender_client_hide_real (MBWMCompMgrClient * client); + +static void +mb_wm_comp_mgr_xrender_client_repair_real (MBWMCompMgrClient * client); + +static void +mb_wm_comp_mgr_xrender_client_configure_real (MBWMCompMgrClient * client); + +static void +mb_wm_comp_mgr_xrender_client_class_init (MBWMObjectClass *klass) +{ + MBWMCompMgrClientClass *c_klass = MB_WM_COMP_MGR_CLIENT_CLASS (klass); + + c_klass->show = mb_wm_comp_mgr_xrender_client_show_real; + c_klass->hide = mb_wm_comp_mgr_xrender_client_hide_real; + c_klass->repair = mb_wm_comp_mgr_xrender_client_repair_real; + c_klass->configure = mb_wm_comp_mgr_xrender_client_configure_real; + +#if MBWM_WANT_DEBUG + klass->klass_name = "MBWMCompMgrDefaultClient"; +#endif +} + +static int +mb_wm_comp_mgr_xrender_client_init (MBWMObject *obj, va_list vap) +{ + MBWMCompMgrClient *client = MB_WM_COMP_MGR_CLIENT (obj); + MBWMCompMgrDefaultClient *dclient = MB_WM_COMP_MGR_DEFAULT_CLIENT (obj); + MBWindowManager *wm; + MBWindowManagerClient *wm_client = client->wm_client; + + if (!wm_client || !wm_client->wmref) + return 0; + + return 1; +} + +static void +mb_wm_comp_mgr_xrender_client_destroy (MBWMObject* obj) +{ + MBWMCompMgrClient * c = MB_WM_COMP_MGR_CLIENT (obj); + MBWMCompMgrDefaultClient * dc = MB_WM_COMP_MGR_DEFAULT_CLIENT (obj); + MBWindowManager * wm = c->wm; + + mb_wm_comp_mgr_client_hide (c); + + if (dc->damage) + XDamageDestroy (wm->xdpy, dc->damage); + + if (dc->picture) + XRenderFreePicture (wm->xdpy, dc->picture); + + if (dc->extents) + XFixesDestroyRegion (wm->xdpy, dc->extents); + + if (dc->border_clip) + XFixesDestroyRegion (wm->xdpy, dc->border_clip); +} + +int +mb_wm_comp_mgr_xrender_client_class_type () +{ + static int type = 0; + + if (UNLIKELY(type == 0)) + { + static MBWMObjectClassInfo info = { + sizeof (MBWMCompMgrDefaultClientClass), + sizeof (MBWMCompMgrDefaultClient), + mb_wm_comp_mgr_xrender_client_init, + mb_wm_comp_mgr_xrender_client_destroy, + mb_wm_comp_mgr_xrender_client_class_init + }; + + type = + mb_wm_object_register_class (&info, MB_WM_TYPE_COMP_MGR_CLIENT, 0); + } + + return type; +} + +/* + * This is a private method, hence static + */ +static MBWMCompMgrClient * +mb_wm_comp_mgr_xrender_client_new (MBWindowManagerClient * client) +{ + MBWMObject *c; + + c = mb_wm_object_new (MB_WM_TYPE_COMP_MGR_DEFAULT_CLIENT, + MBWMObjectPropClient, client, + NULL); + + return MB_WM_COMP_MGR_CLIENT (c); +} + +static void +mb_wm_comp_mgr_xrender_add_damage (MBWMCompMgr * mgr, XserverRegion damage); + +static XserverRegion +mb_wm_comp_mgr_xrender_client_extents (MBWMCompMgrClient *client); + +static void +mb_wm_comp_mgr_xrender_client_hide_real (MBWMCompMgrClient * client) +{ + MBWMCompMgrDefaultClient * dclient = MB_WM_COMP_MGR_DEFAULT_CLIENT (client); + MBWindowManagerClient * wm_client = client->wm_client; + MBWindowManager * wm = client->wm; + MBWMCompMgr * mgr = wm->comp_mgr; + MBWindowManagerClient * c; + Bool is_modal = mb_wm_client_is_modal (wm_client); + + if (is_modal && ((c = mb_wm_get_visible_main_client (wm)) != NULL)) + { + XserverRegion extents; + /* We need to make sure the any lowlighting on a 'parent' + * modal for app gets cleared. This is kind of a sledgehammer + * approach to it, but more suttle attempts oddly fail at times. + * + * FIXME: keep an eye on this for future revisions of composite + * - there may be a better way. + */ + mb_wm_comp_mgr_xrender_client_repair_real (c->cm_client); + extents = mb_wm_comp_mgr_xrender_client_extents (c->cm_client); + mb_wm_comp_mgr_xrender_add_damage (mgr, extents); + } + + if (dclient->damage) + { + XDamageDestroy (wm->xdpy, dclient->damage); + dclient->damage = None; + } + + if (dclient->extents) + { + mb_wm_comp_mgr_xrender_add_damage (mgr, dclient->extents); + dclient->extents = None; + } + + if (dclient->picture) + { + XRenderFreePicture (wm->xdpy, dclient->picture); + dclient->picture = None; + } +} + +static void +mb_wm_comp_mgr_xrender_client_show_real (MBWMCompMgrClient * client) +{ + MBWMCompMgrDefaultClient * dclient = MB_WM_COMP_MGR_DEFAULT_CLIENT (client); + MBWindowManagerClient * wm_client = client->wm_client; + MBWindowManager * wm = client->wm; + MBWMCompMgr * mgr = wm->comp_mgr; + XserverRegion region; + XRenderPictureAttributes pa; + MBWMClientType ctype = MB_WM_CLIENT_CLIENT_TYPE (wm_client); + Bool is_modal; + + /* + * Destroying / Recreating the client pictures should hopefully save + * some memory in the server. + */ + if (!dclient->picture) + { + pa.subwindow_mode = IncludeInferiors; + + dclient->picture = + XRenderCreatePicture (wm->xdpy, + wm_client->xwin_frame ? + wm_client->xwin_frame : + wm_client->window->xwindow, + client->is_argb32 ? + XRenderFindStandardFormat (wm->xdpy, + PictStandardARGB32) + + : XRenderFindVisualFormat (wm->xdpy, + wm_client->window->visual), + CPSubwindowMode, + &pa); + } + + if (dclient->damage != None) + XDamageDestroy (wm->xdpy, dclient->damage); + + dclient->damage = XDamageCreate (wm->xdpy, + wm_client->xwin_frame ? + wm_client->xwin_frame : + wm_client->window->xwindow, + XDamageReportNonEmpty); + + region = mb_wm_comp_mgr_xrender_client_extents (client); + + mb_wm_comp_mgr_xrender_add_damage (mgr, region); + + /* + * If the wm client is modal we have to add its parent to the damage + * in order for lowlighting to work + */ + if (mb_wm_client_is_modal (wm_client)) + { + MBWindowManagerClient * parent = + mb_wm_client_get_transient_for (wm_client); + + if (parent && parent->cm_client) + { + XserverRegion extents = + mb_wm_comp_mgr_xrender_client_extents (parent->cm_client); + + mb_wm_comp_mgr_xrender_add_damage (mgr, extents); + } + } + + if (!dclient->extents) + { + dclient->extents = mb_wm_comp_mgr_xrender_client_extents (client); + } +} + + +/* + * The Manager itself + */ + +typedef struct MBGaussianMap +{ + int size; + double * data; +} MBGaussianMap; + + +struct MBWMCompMgrDefaultPrivate +{ + MBGaussianMap * gaussian_map; + + Picture shadow_n_pic; + Picture shadow_e_pic; + Picture shadow_s_pic; + Picture shadow_w_pic; + + Picture shadow_ne_pic; + Picture shadow_nw_pic; + Picture shadow_se_pic; + Picture shadow_sw_pic; + + Picture shadow_pic; + + int shadow_dx; + int shadow_dy; + int shadow_padding_width; + int shadow_padding_height; + int shadow_style; + unsigned int shadow_color[4]; /* RGBA */ + + Picture trans_picture; + Picture black_picture; + Picture lowlight_picture; + unsigned int lowlight_params[4]; /* RGBA */ + + Picture root_picture; + Picture root_buffer; + + XserverRegion all_damage; + Bool dialog_shade; +}; + +static void +mb_wm_comp_mgr_xrender_private_free (MBWMCompMgrDefault *mgr) +{ + MBWMCompMgrDefaultPrivate * priv = mgr->priv; + Display * xdpy = MB_WM_COMP_MGR (mgr)->wm->xdpy; + + if (priv->gaussian_map) + free (priv->gaussian_map); + + XRenderFreePicture (xdpy, priv->shadow_n_pic); + XRenderFreePicture (xdpy, priv->shadow_e_pic); + XRenderFreePicture (xdpy, priv->shadow_s_pic); + XRenderFreePicture (xdpy, priv->shadow_w_pic); + + XRenderFreePicture (xdpy, priv->shadow_ne_pic); + XRenderFreePicture (xdpy, priv->shadow_nw_pic); + XRenderFreePicture (xdpy, priv->shadow_se_pic); + XRenderFreePicture (xdpy, priv->shadow_sw_pic); + + XRenderFreePicture (xdpy, priv->shadow_pic); + + XRenderFreePicture (xdpy, priv->black_picture); + XRenderFreePicture (xdpy, priv->lowlight_picture); + XRenderFreePicture (xdpy, priv->trans_picture); + + if (priv->root_picture) + XRenderFreePicture (xdpy, priv->root_picture); + + if (priv->root_buffer) + XRenderFreePicture (xdpy, priv->root_buffer); + + if (priv->all_damage) + XDamageDestroy (xdpy, priv->all_damage); + + free (priv); +} + +static void +mb_wm_comp_mgr_xrender_register_client_real (MBWMCompMgr * mgr, + MBWindowManagerClient * c) +{ + MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + + MBWM_NOTE (COMPOSITOR, "@@@@ registering client for %x @@@@\n", + c->window->xwindow); + + if (c->cm_client) + return; + + c->cm_client = mb_wm_comp_mgr_xrender_client_new (c); +} + +static void +mb_wm_comp_mgr_xrender_turn_on_real (MBWMCompMgr *mgr); + +static void +mb_wm_comp_mgr_xrender_turn_off_real (MBWMCompMgr *mgr); + +static void +mb_wm_comp_mgr_xrender_render_real (MBWMCompMgr *mgr); + +static Bool +mb_wm_comp_mgr_xrender_handle_damage (XDamageNotifyEvent * de, + MBWMCompMgr * mgr); + +static void +mb_wm_comp_mgr_xrender_class_init (MBWMObjectClass *klass) +{ + MBWMCompMgrClass *cm_klass = MB_WM_COMP_MGR_CLASS (klass); + +#if MBWM_WANT_DEBUG + klass->klass_name = "MBWMCompMgrDefault"; +#endif + + cm_klass->register_client = mb_wm_comp_mgr_xrender_register_client_real; + cm_klass->turn_on = mb_wm_comp_mgr_xrender_turn_on_real; + cm_klass->turn_off = mb_wm_comp_mgr_xrender_turn_off_real; + cm_klass->render = mb_wm_comp_mgr_xrender_render_real; + cm_klass->handle_damage = mb_wm_comp_mgr_xrender_handle_damage; +} + +static void +mb_wm_comp_mgr_xrender_init_pictures (MBWMCompMgr *mgr); + +static int +mb_wm_comp_mgr_xrender_init (MBWMObject *obj, va_list vap) +{ + MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj); + MBWMCompMgrDefault * dmgr = MB_WM_COMP_MGR_DEFAULT (obj); + MBWindowManager * wm = mgr->wm; + MBWMCompMgrDefaultPrivate * priv; + + if (!wm) + return 0; + + dmgr->priv = mb_wm_util_malloc0 (sizeof (MBWMCompMgrDefaultPrivate)); + priv = dmgr->priv; + + priv->shadow_dx = SHADOW_OFFSET_X; + priv->shadow_dy = SHADOW_OFFSET_Y; + + /* Not really used yet */ + priv->shadow_padding_width = 0; + priv->shadow_padding_height = 0; + + mgr->disabled = True; + + XCompositeRedirectSubwindows (wm->xdpy, wm->root_win->xwindow, + CompositeRedirectManual); + + mb_wm_theme_get_shadow_color (wm->theme, + &priv->shadow_color[0], + &priv->shadow_color[1], + &priv->shadow_color[2], + &priv->shadow_color[3]); + + mb_wm_theme_get_lowlight_color (wm->theme, + &priv->lowlight_params[0], + &priv->lowlight_params[1], + &priv->lowlight_params[2], + &priv->lowlight_params[3]); + + priv->shadow_style = mb_wm_theme_get_shadow_type (wm->theme); + + mb_wm_comp_mgr_xrender_init_pictures (mgr); + + return 1; +} + +static void +mb_wm_comp_mgr_xrender_destroy (MBWMObject * obj) +{ + MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj); + MBWMCompMgrDefault * dmgr = MB_WM_COMP_MGR_DEFAULT (obj); + + mb_wm_comp_mgr_turn_off (mgr); + mb_wm_comp_mgr_xrender_private_free (dmgr); +} + +int +mb_wm_comp_mgr_xrender_class_type () +{ + static int type = 0; + + if (UNLIKELY(type == 0)) + { + static MBWMObjectClassInfo info = { + sizeof (MBWMCompMgrDefaultClass), + sizeof (MBWMCompMgrDefault), + mb_wm_comp_mgr_xrender_init, + mb_wm_comp_mgr_xrender_destroy, + mb_wm_comp_mgr_xrender_class_init + }; + + type = mb_wm_object_register_class (&info, MB_WM_TYPE_COMP_MGR, 0); + } + + return type; +} + +/* Shadow Generation */ +static double +gaussian (double r, double x, double y) +{ + return ((1 / (sqrt (2 * M_PI * r))) * + exp ((- (x * x + y * y)) / (2 * r * r))); +} + + +static MBGaussianMap * +mb_wm_comp_mgr_xrender_make_gaussian_map (double r) +{ + MBGaussianMap *c; + int size = ((int) ceil ((r * 3)) + 1) & ~1; + int center = size / 2; + int x, y; + double t = 0.0; + double g; + + c = malloc (sizeof (MBGaussianMap) + size * size * sizeof (double)); + c->size = size; + + c->data = (double *) (c + 1); + + for (y = 0; y < size; y++) + for (x = 0; x < size; x++) + { + g = gaussian (r, (double) (x - center), (double) (y - center)); + t += g; + c->data[y * size + x] = g; + } + + for (y = 0; y < size; y++) + for (x = 0; x < size; x++) + c->data[y*size + x] /= t; + + return c; +} + +static unsigned char +mb_wm_comp_mgr_xrender_sum_gaussian (MBWMCompMgr * mgr, double opacity, + int x, int y, int width, int height) +{ + MBGaussianMap * map = MB_WM_COMP_MGR_DEFAULT (mgr)->priv->gaussian_map; + int fx, fy; + double * g_data; + double * g_line = map->data; + int g_size = map->size; + int center = g_size / 2; + int fx_start, fx_end; + int fy_start, fy_end; + double v; + + /* + * Compute set of filter values which are "in range", + * that's the set with: + * 0 <= x + (fx-center) && x + (fx-center) < width && + * 0 <= y + (fy-center) && y + (fy-center) < height + * + * 0 <= x + (fx - center) x + fx - center < width + * center - x <= fx fx < width + center - x + */ + + fx_start = center - x; + if (fx_start < 0) + fx_start = 0; + fx_end = width + center - x; + if (fx_end > g_size) + fx_end = g_size; + + fy_start = center - y; + if (fy_start < 0) + fy_start = 0; + fy_end = height + center - y; + if (fy_end > g_size) + fy_end = g_size; + + g_line = g_line + fy_start * g_size + fx_start; + + v = 0; + for (fy = fy_start; fy < fy_end; fy++) + { + g_data = g_line; + g_line += g_size; + + for (fx = fx_start; fx < fx_end; fx++) + v += *g_data++; + } + if (v > 1) + v = 1; + + return ((unsigned int) (v * opacity * 255.0)); +} + +#define MAX_TILE_SZ 16 /* make sure size/2 < MAX_TILE_SZ */ +#define WIDTH 320 +#define HEIGHT 320 + +static void +mb_wm_comp_mgr_xrender_shadow_setup_part (MBWMCompMgr * mgr, + XImage ** ximage, + Picture * pic, + Pixmap * pxm, + int width, + int height) +{ + MBWindowManager * wm = mgr->wm; + + *ximage = XCreateImage (wm->xdpy, DefaultVisual(wm->xdpy, wm->xscreen), + 8, ZPixmap, 0, 0, + width, height, 8, width * sizeof (unsigned char)); + + (*ximage)->data = malloc (width * height * sizeof (unsigned char)); + + *pxm = XCreatePixmap (wm->xdpy, wm->root_win->xwindow, + width, height, 8); + + *pic = XRenderCreatePicture (wm->xdpy, *pxm, + XRenderFindStandardFormat (wm->xdpy, + PictStandardA8), + 0, 0); +} + +static void +mb_wm_comp_mgr_xrender_shadow_finalise_part (MBWMCompMgr * mgr, + XImage * ximage, + Picture pic, + Pixmap pxm, + int width, + int height) +{ + MBWindowManager * wm = mgr->wm; + + GC gc = XCreateGC (wm->xdpy, pxm, 0, 0); + XPutImage (wm->xdpy, pxm, gc, ximage, 0, 0, 0, 0, width, height); + XDestroyImage (ximage); + XFreeGC (wm->xdpy, gc); + XFreePixmap (wm->xdpy, pxm); +} + +static void +mb_wm_comp_mgr_xrender_shadow_setup (MBWMCompMgr * mgr) +{ + MBWindowManager * wm = mgr->wm; + MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + XImage * ximage; + Pixmap pxm; + unsigned char * data; + int size; + int center; + int x, y; + unsigned char d; + int pwidth, pheight; + double opacity = SHADOW_OPACITY; + + if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_NONE) + return; + + if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_SIMPLE) + { + priv->shadow_padding_width = 0; + priv->shadow_padding_height = 0; + return; + } + + /* SHADOW_STYLE_GAUSSIAN */ + priv->gaussian_map = + mb_wm_comp_mgr_xrender_make_gaussian_map (SHADOW_RADIUS); + + priv->shadow_padding_width = priv->gaussian_map->size; + priv->shadow_padding_height = priv->gaussian_map->size; + + size = priv->gaussian_map->size; + center = size / 2; + + /* Top & bottom */ + pwidth = MAX_TILE_SZ; + pheight = size/2; + mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, + &ximage, &priv->shadow_n_pic, &pxm, + pwidth, pheight); + + data = (unsigned char*)ximage->data; + + for (y = 0; y < pheight; y++) + { + d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity, + center, y - center, + WIDTH, HEIGHT); + for (x = 0; x < pwidth; x++) + data[y * pwidth + x] = d; + } + + mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, priv->shadow_n_pic, + pxm, pwidth, pheight); + + pwidth = MAX_TILE_SZ; + pheight = MAX_TILE_SZ; + + mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_s_pic, + &pxm, pwidth, pheight); + + data = (unsigned char*)ximage->data; + + for (y = 0; y < pheight; y++) + { + d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity, + center, y - center, + WIDTH, HEIGHT); + for (x = 0; x < pwidth; x++) + data[(pheight - y - 1) * pwidth + x] = d; + } + + mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, priv->shadow_s_pic, + pxm, pwidth, pheight); + + /* Sides */ + pwidth = MAX_TILE_SZ; + pheight = MAX_TILE_SZ; + mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_w_pic, + &pxm, pwidth, pheight); + + data = (unsigned char*)ximage->data; + + for (x = 0; x < pwidth; x++) + { + d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity, + x - center, center, + WIDTH, HEIGHT); + for (y = 0; y < pheight; y++) + data[y * pwidth + (pwidth - x - 1)] = d; + } + + mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, priv->shadow_w_pic, + pxm, pwidth, pheight); + + mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_e_pic, + &pxm, pwidth, pheight); + + data = (unsigned char*)ximage->data; + + for (x = 0; x < pwidth; x++) + { + d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity, + x - center, center, + WIDTH, HEIGHT); + for (y = 0; y < pheight; y++) + data[y * pwidth + x] = d; + } + + mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, priv->shadow_e_pic, + pxm, pwidth, pheight); + + /* Corners */ + pwidth = MAX_TILE_SZ; + pheight = MAX_TILE_SZ; + mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_nw_pic, + &pxm, pwidth, pheight); + + data = (unsigned char*)ximage->data; + + for (x = 0; x < pwidth; x++) + for (y = 0; y < pheight; y++) + { + d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity, + x-center, y-center, + WIDTH, HEIGHT); + + data[y * pwidth + x] = d; + } + + mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, + priv->shadow_nw_pic, + pxm, pwidth, pheight); + + mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_sw_pic, + &pxm, pwidth, pheight); + + data = (unsigned char*)ximage->data; + + for (x = 0; x < pwidth; x++) + for (y = 0; y < pheight; y++) + { + d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity, + x-center, y-center, + WIDTH, HEIGHT); + + data[(pheight - y - 1) * pwidth + x] = d; + } + + mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, + priv->shadow_sw_pic, + pxm, pwidth, pheight); + + mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_se_pic, + &pxm, pwidth, pheight); + + data = (unsigned char*)ximage->data; + + for (x = 0; x < pwidth; x++) + for (y = 0; y < pheight; y++) + { + d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity, + x-center, y-center, + WIDTH, HEIGHT); + + data[(pheight - y - 1) * pwidth + (pwidth - x -1)] = d; + } + + mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, + priv->shadow_se_pic, + pxm, pwidth, pheight); + + mb_wm_comp_mgr_xrender_shadow_setup_part(mgr, &ximage, &priv->shadow_ne_pic, + &pxm, pwidth, pheight); + + data = (unsigned char*)ximage->data; + + for (x = 0; x < pwidth; x++) + for (y = 0; y < pheight; y++) + { + d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity, + x-center, y-center, WIDTH, HEIGHT); + + data[y * pwidth + (pwidth - x -1)] = d; + } + + mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, + priv->shadow_ne_pic, + pxm, pwidth, pheight); + + /* Finally center */ + pwidth = MAX_TILE_SZ; + pheight = MAX_TILE_SZ; + mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_pic, + &pxm, pwidth, pheight); + + data = (unsigned char*)ximage->data; + + d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity, + center, center, WIDTH, HEIGHT); + + for (x = 0; x < pwidth; x++) + for (y = 0; y < pheight; y++) + data[y * pwidth + x] = d; + + mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, priv->shadow_pic, + pxm, pwidth, pheight); + +} + +static Picture +mb_wm_comp_mgr_xrender_shadow_gaussian_make_picture (MBWMCompMgr * mgr, + int width, int height) +{ + MBWindowManager * wm = mgr->wm; + MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + Picture pic; + Pixmap pxm; + int pwidth, pheight, x, y, dw, dh; + + pxm = XCreatePixmap (wm->xdpy, wm->root_win->xwindow, width, height, 8); + pic = XRenderCreatePicture (wm->xdpy, pxm, + XRenderFindStandardFormat (wm->xdpy, + PictStandardA8), + 0,0); + + pwidth = MAX_TILE_SZ; + pheight = MAX_TILE_SZ; + + for (x=0; x < width; x += pwidth) + for (y=0; y < height; y += pheight) + { + if ( (y + pheight) > height ) + dh = pheight - ((y + pheight)-height); + else + dh = pheight; + + if ( (x + pwidth) > width ) + dw = pwidth - ((x + pwidth)-width); + else + dw = pwidth; + + XRenderComposite (wm->xdpy, PictOpSrc, + priv->shadow_pic, None, pic, + 0, 0, 0, 0, x, y, dw, dh); + } + + /* Top & bottom */ + if ( width > (MAX_TILE_SZ*2) ) + { + pwidth = MAX_TILE_SZ; pheight = MAX_TILE_SZ; + + for (x=0; x < width; x += pwidth ) + { + if ( (x + pwidth) > width ) + dw = pwidth - ((x + pwidth)-width); + else + dw = pwidth; + + XRenderComposite (wm->xdpy, PictOpSrc, + priv->shadow_n_pic, None, pic, + 0, 0, 0, 0, x, 0, dw, pheight); + XRenderComposite (wm->xdpy, PictOpSrc, + priv->shadow_s_pic, None, pic, + 0, 0, 0, 0, x, height - pheight, dw, pheight); + } + } + + /* Sides */ + if ( height > (MAX_TILE_SZ*2) ) + { + pwidth = MAX_TILE_SZ; pheight = MAX_TILE_SZ; + + for (y=0; y < height; y += pheight) + { + if ( (y + pheight) > height ) + dh = pheight - ((y + pheight)-height); + else + dh = pheight; + + XRenderComposite (wm->xdpy, PictOpSrc /* PictOpIn */, + priv->shadow_e_pic, None, pic, + 0, 0, 0, 0, 0, y, pwidth, dh); + XRenderComposite (wm->xdpy, PictOpSrc /* PictOpIn */, + priv->shadow_w_pic, None, pic, + 0, 0, 0, 0, width - pwidth, y, pwidth, dh); + } + } + + /* Corners */ + pwidth = MAX_TILE_SZ; pheight = MAX_TILE_SZ; + + XRenderComposite (wm->xdpy, PictOpSrc, priv->shadow_nw_pic, None, pic, + 0, 0, 0, 0, 0, 0, pwidth, pheight); + + XRenderComposite (wm->xdpy, PictOpSrc, priv->shadow_ne_pic, None, pic, + 0, 0, 0, 0, width - pwidth, 0, pwidth, pheight); + + XRenderComposite (wm->xdpy, PictOpSrc, priv->shadow_sw_pic, None, pic, + 0, 0, 0, 0, 0, height - pheight, pwidth, pheight); + + XRenderComposite (wm->xdpy, PictOpSrc, priv->shadow_se_pic, None, pic, + 0, 0, 0, 0, width - pwidth, height - pheight, + pwidth, pheight); + + XFreePixmap (wm->xdpy, pxm); + return pic; +} + +static XserverRegion +mb_wm_comp_mgr_xrender_client_extents (MBWMCompMgrClient *client) +{ + MBWindowManagerClient *wm_client = client->wm_client; + MBWindowManager *wm = client->wm; + MBWMCompMgr *mgr = wm->comp_mgr; + MBWMCompMgrDefaultPrivate *priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + MBGeometry geom; + XRectangle r; + MBWMClientType ctype = MB_WM_CLIENT_CLIENT_TYPE (wm_client); + XserverRegion extents; + + mb_wm_client_get_coverage (wm_client, &geom); + + r.x = geom.x; + r.y = geom.y; + r.width = geom.width; + r.height = geom.height; + + if (priv->shadow_style) + { + if (ctype == MBWMClientTypeDialog || + ctype == MBWMClientTypeMenu || + ctype == MBWMClientTypeOverride) + { + if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_SIMPLE) + { + r.width += priv->shadow_dx; + r.height += priv->shadow_dy; + } + else + { + r.x += priv->shadow_dx; + r.y += priv->shadow_dy; + r.width += priv->shadow_padding_width; + r.height += priv->shadow_padding_height; + } + } + } + + extents = XFixesCreateRegion (wm->xdpy, &r, 1); + + return extents; +} + +static XserverRegion +mb_wm_comp_mgr_xrender_client_border_size (MBWMCompMgrClient * client, + int x, int y) +{ + MBWindowManagerClient * wm_client = client->wm_client; + MBWindowManager * wm = client->wm; + XserverRegion border; + + border = XFixesCreateRegionFromWindow (wm->xdpy, + wm_client->xwin_frame ? + wm_client->xwin_frame : + wm_client->window->xwindow, + WindowRegionBounding); + /* translate this */ + XFixesTranslateRegion (wm->xdpy, border, x, y); + return border; +} + +static XserverRegion +mb_wm_comp_mgr_xrender_client_window_region (MBWMCompMgrClient *client, + Window xwin, int x, int y) +{ + MBWindowManagerClient * wm_client = client->wm_client; + MBWindowManager * wm = client->wm; + XserverRegion region; + + region = + XFixesCreateRegionFromWindow (wm->xdpy, xwin, WindowRegionBounding); + + /* translate this */ + XFixesTranslateRegion (wm->xdpy, region, x, y); + + return region; +} + +static Visual* +mb_wm_comp_mgr_xrender_get_argb32_visual (MBWMCompMgr * mgr) +{ + MBWindowManager * wm = mgr->wm; + XVisualInfo * xvi; + XVisualInfo template; + int nvi; + int i; + XRenderPictFormat * format; + Visual * visual = NULL; + + template.screen = wm->xscreen; + template.depth = 32; + template.class = TrueColor; + + if ((xvi = XGetVisualInfo (wm->xdpy, + VisualScreenMask|VisualDepthMask|VisualClassMask, + &template, + &nvi)) == NULL) + return NULL; + + for (i = 0; i < nvi; i++) + { + format = XRenderFindVisualFormat (wm->xdpy, xvi[i].visual); + if (format->type == PictTypeDirect && format->direct.alphaMask) + { + visual = xvi[i].visual; + break; + } + } + + XFree (xvi); + return visual; +} + +static void +mb_wm_comp_mgr_xrender_init_pictures (MBWMCompMgr *mgr) +{ + MBWindowManager * wm; + Window rwin; + MBWMCompMgrDefaultPrivate * priv; + Pixmap transPixmap, blackPixmap, lowlightPixmap, + redPixmap; + XRenderPictureAttributes pa; + XRenderColor c; + int i; + + if (!mgr) + return; + + wm = mgr->wm; + rwin = wm->root_win->xwindow; + priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + + { + Picture pics_to_free[] = { priv->trans_picture, + priv->black_picture, + priv->lowlight_picture, + priv->shadow_n_pic, + priv->shadow_e_pic, + priv->shadow_s_pic, + priv->shadow_w_pic, + priv->shadow_ne_pic, + priv->shadow_nw_pic, + priv->shadow_se_pic, + priv->shadow_sw_pic, + priv->shadow_pic }; + + for (i=0; i < (sizeof(pics_to_free)/sizeof(Picture)); i++) + if (pics_to_free[i] != None) + XRenderFreePicture (wm->xdpy, pics_to_free[i]); + } + + if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_GAUSSIAN) + mb_wm_comp_mgr_xrender_shadow_setup (mgr); + + pa.subwindow_mode = IncludeInferiors; + pa.repeat = True; + + transPixmap = XCreatePixmap (wm->xdpy, rwin, 1, 1, 8); + + priv->trans_picture + = XRenderCreatePicture (wm->xdpy, transPixmap, + XRenderFindStandardFormat (wm->xdpy, + PictStandardA8), + CPRepeat, + &pa); + + c.red = c.green = c.blue = 0; + c.alpha = 0xddff; + + XRenderFillRectangle (wm->xdpy, PictOpSrc, priv->trans_picture, + &c, 0, 0, 1, 1); + + /* black pixmap used for shadows */ + + blackPixmap = XCreatePixmap (wm->xdpy, rwin, 1, 1, 32); + + priv->black_picture + = XRenderCreatePicture (wm->xdpy, blackPixmap, + XRenderFindStandardFormat (wm->xdpy, + PictStandardARGB32), + CPRepeat, + &pa); + + c.red = priv->shadow_color[0]; + c.green = priv->shadow_color[1]; + c.blue = priv->shadow_color[2]; + + if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_GAUSSIAN) + c.alpha = 0xffff; + else + c.alpha = priv->shadow_color[3]; + + XRenderFillRectangle (wm->xdpy, PictOpSrc, priv->black_picture, + &c, 0, 0, 1, 1); + + /* Used for lowlights */ + lowlightPixmap = XCreatePixmap (wm->xdpy, rwin, 1, 1, 32); + priv->lowlight_picture + = XRenderCreatePicture (wm->xdpy, lowlightPixmap, + XRenderFindStandardFormat (wm->xdpy, + PictStandardARGB32), + CPRepeat, + &pa); + + c.red = priv->lowlight_params[0]; + c.green = priv->lowlight_params[1]; + c.blue = priv->lowlight_params[2]; + c.alpha = priv->lowlight_params[3]; + + XRenderFillRectangle (wm->xdpy, PictOpSrc, priv->lowlight_picture, + &c, 0, 0, 1, 1); + + + pa.repeat = False; + + priv->root_picture + = XRenderCreatePicture (wm->xdpy, rwin, + XRenderFindVisualFormat (wm->xdpy, + DefaultVisual (wm->xdpy, + wm->xscreen)), + CPSubwindowMode, + &pa); + + priv->all_damage = None; +} + +/* Shuts the compositing down */ +static void +mb_wm_comp_mgr_xrender_turn_off_real (MBWMCompMgr *mgr) +{ + MBWindowManager * wm; + Window rwin; + MBWMCompMgrDefaultPrivate * priv; + MBWMList * l; + + if (!mgr) + return; + + priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + + if (mgr->disabled) + return; + + wm = mgr->wm; + rwin = wm->root_win->xwindow; + + /* + * really shut down the composite manager. + */ + XCompositeUnredirectSubwindows (wm->xdpy, rwin, CompositeRedirectManual); + + if (priv->root_picture) + { + XRenderFreePicture (wm->xdpy, priv->root_picture); + priv->root_picture = None; + } + + if (priv->root_buffer) + { + XRenderFreePicture (wm->xdpy, priv->root_buffer); + priv->root_buffer = None; + } + + if (priv->all_damage) + { + XDamageDestroy (wm->xdpy, priv->all_damage); + priv->all_damage = None; + } + + /* Free up any client composite resources */ + l = wm->clients; + + while (l) + { + MBWindowManagerClient * wmc = l->data; + MBWMCompMgrClient * c = wmc->cm_client; + + if (c) + { + mb_wm_object_unref (MB_WM_OBJECT (c)); + wmc->cm_client = NULL; + } + + l = l->next; + } + + mgr->disabled = True; +} + +static void +mb_wm_comp_mgr_xrender_render_region (MBWMCompMgr *mgr, XserverRegion region); + +static void +mb_wm_comp_mgr_xrender_turn_on_real (MBWMCompMgr *mgr) +{ + MBWindowManager * wm; + Window rwin; + MBWMCompMgrDefaultPrivate * priv; + MBWMList * l; + + if (!mgr) + return; + + priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + + if (!mgr->disabled) + return; + + wm = mgr->wm; + rwin = wm->root_win->xwindow; + + XCompositeRedirectSubwindows (wm->xdpy, wm->root_win->xwindow, + CompositeRedirectManual); + + mb_wm_comp_mgr_xrender_init_pictures (mgr); + + XSync (wm->xdpy, False); + + mgr->disabled = False; + + if (!mb_wm_stack_empty (wm)) + { + MBWindowManagerClient * c; + + mb_wm_stack_enumerate (wm, c) + { + mb_wm_comp_mgr_xrender_register_client_real (mgr, c); + mb_wm_comp_mgr_xrender_client_show_real (c->cm_client); + } + + mb_wm_comp_mgr_xrender_render_region (mgr, None); + } +} + +static int +mb_wm_comp_mgr_xrender_client_get_translucency (MBWMCompMgrClient *client) +{ + MBWindowManagerClient * wm_client = client->wm_client; + + return wm_client->window->translucency; +} + +static void +mb_wm_comp_mgr_xrender_add_damage (MBWMCompMgr * mgr, XserverRegion damage) +{ + MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + MBWindowManager * wm = mgr->wm; + + if (priv->all_damage) + { + XFixesUnionRegion (wm->xdpy, priv->all_damage, priv->all_damage, + damage); + + XFixesDestroyRegion (wm->xdpy, damage); + } + else + priv->all_damage = damage; + + mb_wm_display_sync_queue (wm, MBWMSyncVisibility); +} + +static void +mb_wm_comp_mgr_xrender_client_repair_real (MBWMCompMgrClient * client) +{ + MBWindowManagerClient * wm_client = client->wm_client; + MBWindowManager * wm = client->wm; + MBWMCompMgr * mgr = wm->comp_mgr; + XserverRegion parts; + MBGeometry geom; + + parts = XFixesCreateRegion (wm->xdpy, 0, 0); + + /* translate region */ + XDamageSubtract (wm->xdpy, MB_WM_COMP_MGR_DEFAULT_CLIENT (client)->damage, + None, parts); + + mb_wm_client_get_coverage (wm_client, &geom); + + XFixesTranslateRegion (wm->xdpy, parts, geom.x, geom.y); + mb_wm_comp_mgr_xrender_add_damage (mgr, parts); +} + +static void +mb_wm_comp_mgr_xrender_client_configure_real (MBWMCompMgrClient * client) +{ + MBWMCompMgrDefaultClient * dclient = MB_WM_COMP_MGR_DEFAULT_CLIENT (client); + MBWindowManagerClient * wm_client = client->wm_client; + MBWindowManager * wm = client->wm; + MBWMCompMgr * mgr = wm->comp_mgr; + XserverRegion damage = None; + XserverRegion extents; + + extents = mb_wm_comp_mgr_xrender_client_extents (client); + + if (dclient->picture) + { + XRenderFreePicture (wm->xdpy, dclient->picture); + dclient->picture = None; + } + + damage = XFixesCreateRegion (wm->xdpy, 0, 0); + + if (dclient->extents) + { + XFixesCopyRegion (wm->xdpy, damage, dclient->extents); + XFixesDestroyRegion (wm->xdpy, dclient->extents); + } + + XFixesUnionRegion (wm->xdpy, damage, damage, extents); + + dclient->extents = extents; + + mb_wm_comp_mgr_xrender_add_damage (mgr, damage); +} + +static Bool +mb_wm_comp_mgr_xrender_handle_damage (XDamageNotifyEvent * de, + MBWMCompMgr * mgr) +{ + MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + MBWindowManager * wm = mgr->wm; + MBWindowManagerClient * c; + + c = mb_wm_managed_client_from_frame (wm, de->drawable); + + if (c && c->cm_client) + { + MBWM_NOTE (COMPOSITOR, + "Reparing window %x, a %d,%d;%dx%d, g %d,%d;%dx%d\n", + de->drawable, + de->area.x, + de->area.y, + de->area.width, + de->area.height, + de->geometry.x, + de->geometry.y, + de->geometry.width, + de->geometry.height); + + mb_wm_comp_mgr_xrender_client_repair_real (c->cm_client); + } + else + { + MBWM_NOTE (COMPOSITOR, "Failed to find client for window %x\n", + de->drawable); + } + + return False; +} + +static void +_render_a_client (MBWMCompMgrClient * client, + XserverRegion region, + int lowlight_type) /*0 none, 1 app, 2 full*/ +{ + MBWMCompMgrDefaultClient * dclient = MB_WM_COMP_MGR_DEFAULT_CLIENT (client); + MBWindowManagerClient * wm_client = client->wm_client; + MBWindowManager * wm = client->wm; + MBWMCompMgr * mgr = wm->comp_mgr; + MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + MBWMClientType ctype = MB_WM_CLIENT_CLIENT_TYPE (wm_client); + MBGeometry geom; + + if (!dclient->picture) + return; + + mb_wm_client_get_coverage (wm_client, &geom); + + /* Translucency only done for dialogs and overides */ + if ( !client->is_argb32 && + (ctype == MBWMClientTypeApp || + ctype == MBWMClientTypeDesktop || + ctype == MBWMClientTypeInput || + ctype == MBWMClientTypePanel || + mb_wm_comp_mgr_xrender_client_get_translucency (client) == -1)) + { + XserverRegion winborder; + + winborder = mb_wm_comp_mgr_xrender_client_border_size (client, + geom.x, geom.y); + + XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, region); + + XFixesSubtractRegion (wm->xdpy, region, region, winborder); + + XRenderComposite (wm->xdpy, PictOpSrc, + dclient->picture, + None, priv->root_buffer, + 0, 0, 0, 0, + geom.x, geom.y, geom.width, geom.height); + + XFixesDestroyRegion (wm->xdpy, winborder); + } + else if (client->is_argb32 || + mb_wm_comp_mgr_xrender_client_get_translucency (client) != -1) + { + /* + * If the client is translucent, paint the decors only (solid). + */ + MBWMList * l = wm_client->decor; + + while (l) + { + MBWMDecor * d = l->data; + MBGeometry * g = & d->geom; + XserverRegion r; + + r = mb_wm_comp_mgr_xrender_client_window_region (client, d->xwin, + g->x, g->y); + + XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, r); + XFixesSubtractRegion (wm->xdpy, region, region, r); + + XRenderComposite (wm->xdpy, PictOpSrc, + dclient->picture, + None, priv->root_buffer, + 0, 0, 0, 0, + geom.x + g->x, geom.y + g->y, + g->width, g->height); + + XFixesDestroyRegion (wm->xdpy, r); + + l = l->next; + } + } + + + /* Render lowlight dialog modal for app */ + if (lowlight_type == 1 && + (ctype & (MBWMClientTypeApp | MBWMClientTypeDesktop))) + { + int title_offset = 0; + + if (ctype == MBWMClientTypeApp) + title_offset = mb_wm_client_title_height (wm_client); + + XRenderComposite (wm->xdpy, PictOpOver, priv->lowlight_picture, None, + priv->root_buffer, + 0, 0, 0, 0, geom.x, geom.y + title_offset, + geom.width, geom.height - title_offset); + } + else if (lowlight_type == 2 /* && client->win_modal_blocker == None */) + { + /* Render lowlight dialog modal for root - e.g lowlight everything */ + XRenderComposite (wm->xdpy, PictOpOver, priv->lowlight_picture, None, + priv->root_buffer, + 0, 0, 0, 0, geom.x, geom.y, + geom.width, geom.height); + } + + if (dclient->border_clip) + { + XFixesDestroyRegion (wm->xdpy, dclient->border_clip); + dclient->border_clip = None; + } + + dclient->border_clip = XFixesCreateRegion (wm->xdpy, 0, 0); + XFixesCopyRegion (wm->xdpy, dclient->border_clip, region); +} + +static void +mb_wm_comp_mgr_xrender_render_real (MBWMCompMgr *mgr) +{ + MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + + mb_wm_comp_mgr_xrender_render_region (mgr, priv->all_damage); + + if (priv->all_damage) + { + XDamageDestroy (mgr->wm->xdpy, priv->all_damage); + priv->all_damage = None; + } +} + +static void +mb_wm_comp_mgr_xrender_render_region (MBWMCompMgr *mgr, XserverRegion region) +{ + MBWindowManager * wm = mgr->wm; + MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv; + MBWindowManagerClient * wmc_top, * wmc_temp, * wmc_solid = NULL; + int lowlight = 0; + int destroy_region = 0; + Bool done; + Bool top_translucent = False; + + if (mgr->disabled) + return; + + if (!region) + { + /* + * Fullscreen render + */ + XRectangle r; + + r.x = 0; + r.y = 0; + r.width = wm->xdpy_width; + r.height = wm->xdpy_height; + + region = XFixesCreateRegion (wm->xdpy, &r, 1); + destroy_region = 1; + } + + wmc_top = mb_wm_get_visible_main_client (wm); + + if (wmc_top) + top_translucent = + (mb_wm_comp_mgr_xrender_client_get_translucency(wmc_top->cm_client) == -1); + + if (!priv->root_buffer) + { + Pixmap rootPixmap = + XCreatePixmap (wm->xdpy, wm->root_win->xwindow, + wm->xdpy_width, wm->xdpy_height, + DefaultDepth (wm->xdpy, wm->xscreen)); + + priv->root_buffer = + XRenderCreatePicture (wm->xdpy, rootPixmap, + XRenderFindVisualFormat (wm->xdpy, + DefaultVisual (wm->xdpy, + wm->xscreen)), + 0, 0); + + XFreePixmap (wm->xdpy, rootPixmap); + } + + XFixesSetPictureClipRegion (wm->xdpy, priv->root_picture, 0, 0, region); + XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, region); + + XRenderComposite (wm->xdpy, PictOpSrc, priv->black_picture, + None, priv->root_buffer, 0, 0, 0, 0, 0, 0, + wm->xdpy_width, wm->xdpy_height); + + /* + * Check initially to see what kind of lowlight todo ( if any ) + */ + mb_wm_stack_enumerate_reverse (wm, wmc_temp) + { + MBWMClientType type = MB_WM_CLIENT_CLIENT_TYPE (wmc_temp); + Bool is_modal = mb_wm_client_is_modal (wmc_temp); + + if (type == MBWMClientTypeDialog && is_modal) + { + MBWMModality modality = mb_wm_get_modality_type (wm); + switch (modality) + { + case MBWMModalityNormal: + default: + lowlight = 1; + break; + case MBWMModalitySystem: + lowlight = 2; + break; + case MBWMModalityNone: + lowlight = 0; + break; + } + } + + if (wmc_temp == wmc_top) + break; + } + + /* Render top -> bottom */ + done = False; + mb_wm_stack_enumerate_reverse (wm, wmc_temp) + { + _render_a_client(wmc_temp->cm_client, region, lowlight); + + /* + * Render clients until we reach first client on/below the top + * which is not translucent and is either and application or desktop + * (to have adequate coverage). + */ + if (wmc_temp == wmc_top) + { + done = True; + } + + if (done && + (MB_WM_CLIENT_CLIENT_TYPE (wmc_temp) & + (MBWMClientTypeApp | MBWMClientTypeDesktop)) && + !wmc_temp->cm_client->is_argb32 && + mb_wm_comp_mgr_xrender_client_get_translucency (wmc_temp->cm_client) + == -1) + { + wmc_solid = wmc_temp; + break; + } + } + + if (!wmc_top) + { + /* Render block of boring black in case of no top app or desktop */ + XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, region); + + XRenderComposite (wm->xdpy, PictOpSrc, priv->black_picture, + None, priv->root_buffer, 0, 0, 0, 0, 0, 0, + wm->xdpy_width, wm->xdpy_height); + + XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, None); + + wmc_top = wm->stack_bottom; + } + + + XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, None); + + /* + * Now render shadows and any translucent clients but bottom -> top this + * time + * + * We start from the first solid client on the stack, so that any + * translucent windows on the top of the stack get correctly rendered. + */ + for (wmc_temp = wmc_solid ? wmc_solid : wmc_top; + wmc_temp; wmc_temp=wmc_temp->stacked_above) + { + MBWMClientType type = MB_WM_CLIENT_CLIENT_TYPE (wmc_temp); + MBWMCompMgrClient * c = wmc_temp->cm_client; + MBWMCompMgrDefaultClient * dc = MB_WM_COMP_MGR_DEFAULT_CLIENT (c); + Bool is_translucent; + + if (!dc || !dc->picture) + continue; + + /* + * We have to process all dialogs and, if the top client is translucent, + * any translucent windows as well. + */ + is_translucent = (c->is_argb32 || + mb_wm_comp_mgr_xrender_client_get_translucency (c) + != -1); + + if (mb_wm_client_is_mapped (wmc_temp) && + (type == MBWMClientTypeDialog || + type == MBWMClientTypeMenu || + type == MBWMClientTypeOverride || + (top_translucent && is_translucent))) + { + if (priv->shadow_style) + { + Picture shadow_pic; + MBGeometry geom; + + mb_wm_client_get_coverage (wmc_temp, &geom); + + if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_SIMPLE) + { + XserverRegion shadow_region; + + /* Grab 'shape' region of window */ + shadow_region = + mb_wm_comp_mgr_xrender_client_border_size (c, + geom.x, geom.y); + + /* Offset it. */ + XFixesTranslateRegion (wm->xdpy, shadow_region, + priv->shadow_dx, + priv->shadow_dy); + + /* Intersect it, so only border remains */ + XFixesIntersectRegion (wm->xdpy, shadow_region, + dc->border_clip, + shadow_region ); + + XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, + 0, 0, shadow_region); + + /* now paint them */ + if (wmc_temp->cm_client->is_argb32) + { + XRenderComposite (wm->xdpy, PictOpOver, + priv->black_picture, + dc->picture, + priv->root_buffer, + 0, 0, 0, 0, + geom.x + priv->shadow_dx, + geom.y + priv->shadow_dy, + geom.width + + priv->shadow_padding_width, + geom.height + + priv->shadow_padding_height); + } + else + { + XRenderComposite (wm->xdpy, PictOpOver, + priv->black_picture, + None, + priv->root_buffer, + 0, 0, 0, 0, + geom.x + priv->shadow_dx, + geom.y + priv->shadow_dy, + geom.width + + priv->shadow_padding_width, + geom.height + + priv->shadow_padding_height); + } + + /* Paint any translucent window contents, but no the + * decors. + */ + if (is_translucent) + { + MBGeometry * win_geom = & wmc_temp->window->geometry; + + XFixesDestroyRegion (wm->xdpy, shadow_region); + + shadow_region = + mb_wm_comp_mgr_xrender_client_border_size (c, + geom.x, geom.y); + + XFixesIntersectRegion (wm->xdpy, shadow_region, + dc->border_clip, shadow_region ); + + XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, + 0, 0, shadow_region); + + if (c->is_argb32) + XRenderComposite (wm->xdpy, PictOpOver, + dc->picture, None, + priv->root_buffer, + win_geom->x, win_geom->y, 0, 0, + win_geom->x + geom.x, + win_geom->y + geom.y, + win_geom->width, win_geom->height); + else + XRenderComposite (wm->xdpy, PictOpOver, + dc->picture, priv->trans_picture, + priv->root_buffer, + win_geom->x, win_geom->y, 0, 0, + win_geom->x + geom.x, + win_geom->y + geom.y, + win_geom->width, win_geom->height); + } + + XFixesDestroyRegion (wm->xdpy, shadow_region); + } + else /* GAUSSIAN */ + { + MBGeometry * win_geom = & wmc_temp->window->geometry; + + XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, + 0, 0, dc->border_clip); + + if (is_translucent) + { + /* No shadows currently for transparent windows */ + XRenderComposite (wm->xdpy, PictOpOver, + dc->picture, priv->trans_picture, + priv->root_buffer, + win_geom->x, win_geom->y, 0, 0, + win_geom->x + geom.x, + win_geom->y + geom.y, + win_geom->width, win_geom->height); + } + else + { + /* Combine pregenerated shadow tiles */ + shadow_pic = + mb_wm_comp_mgr_xrender_shadow_gaussian_make_picture (mgr, + geom.width + priv->shadow_padding_width, + geom.height + priv->shadow_padding_height); + + XRenderComposite (wm->xdpy, PictOpOver, + priv->black_picture, + shadow_pic, + priv->root_buffer, + win_geom->x, win_geom->y, 0, 0, + geom.x + priv->shadow_dx, + geom.y + priv->shadow_dy, + geom.width + + priv->shadow_padding_width, + geom.height + + priv->shadow_padding_height); + + XRenderFreePicture (wm->xdpy, shadow_pic); + } + } + } + } + } + + XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, None); + + XRenderComposite (wm->xdpy, PictOpSrc, priv->root_buffer, None, + priv->root_picture, + 0, 0, 0, 0, 0, 0, wm->xdpy_width, wm->xdpy_height); + + if (destroy_region) + XDamageDestroy (wm->xdpy, region); +} + +MBWMCompMgr * +mb_wm_comp_mgr_xrender_new (MBWindowManager *wm) +{ + MBWMObject *mgr; + + mgr = mb_wm_object_new (MB_WM_TYPE_COMP_MGR_DEFAULT, MBWMObjectPropWm, wm, NULL); + + return MB_WM_COMP_MGR (mgr); +} + diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.h b/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.h new file mode 100644 index 0000000..0a36bbc --- /dev/null +++ b/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.h @@ -0,0 +1,60 @@ +/* + * Matchbox Window Manager - A lightweight window manager not for the + * desktop. + * + * Authored By Matthew Allum <mallum@o-hand.com> + * Tomas Frydrych <tf@o-hand.com> + * + * Copyright (c) 2002, 2004, 2007 OpenedHand Ltd - http://o-hand.com + * + * 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 2, 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. + * + */ + +#ifndef _HAVE_MB_WM_COMP_MGR_DEFAULT_H +#define _HAVE_MB_WM_COMP_MGR_DEFAULT_H + +#include <matchbox2/mb-wm-config.h> + +#define MB_WM_COMP_MGR_DEFAULT(c) ((MBWMCompMgrDefault*)(c)) +#define MB_WM_COMP_MGR_DEFAULT_CLASS(c) ((MBWMCompMgrDefaultClass*)(c)) +#define MB_WM_TYPE_COMP_MGR_DEFAULT (mb_wm_comp_mgr_xrender_class_type ()) + +#define MB_WM_COMP_MGR_DEFAULT_CLIENT(c) ((MBWMCompMgrDefaultClient*)(c)) +#define MB_WM_COMP_MGR_DEFAULT_CLIENT_CLASS(c) ((MBWMCompMgrDefaultClientClass*)(c)) +#define MB_WM_TYPE_COMP_MGR_DEFAULT_CLIENT (mb_wm_comp_mgr_xrender_client_class_type ()) + +struct MBWMCompMgrDefault +{ + MBWMCompMgr parent; + MBWMCompMgrDefaultPrivate *priv; +}; + +struct MBWMCompMgrDefaultClass +{ + MBWMCompMgrClass parent; +}; + +int +mb_wm_comp_mgr_xrender_class_type (); + +MBWMCompMgr* +mb_wm_comp_mgr_xrender_new (MBWindowManager *wm); + +struct MBWMCompMgrDefaultClientClass +{ + MBWMCompMgrClientClass parent; +}; + +int +mb_wm_comp_mgr_xrender_client_class_type (); + +#endif diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr.c b/matchbox2/comp-mgr/mb-wm-comp-mgr.c new file mode 100644 index 0000000..68063c3 --- /dev/null +++ b/matchbox2/comp-mgr/mb-wm-comp-mgr.c @@ -0,0 +1,482 @@ +/* + * Matchbox Window Manager - A lightweight window manager not for the + * desktop. + * + * Authored By Tomas Frydrych <tf@o-hand.com> + * + * Copyright (c) 2002, 2004, 2007 OpenedHand Ltd - http://o-hand.com + * + * 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 2, 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. + * + */ + +#include "mb-wm.h" +#include "mb-wm-client.h" +#include "mb-wm-comp-mgr.h" +#include "mb-wm-theme.h" + +#include <X11/Xresource.h> +#include <X11/extensions/Xdamage.h> +#include <X11/extensions/Xrender.h> +#include <X11/extensions/Xcomposite.h> + +static void +mb_wm_comp_mgr_client_class_init (MBWMObjectClass *klass) +{ + MBWMCompMgrClientClass *c_klass = MB_WM_COMP_MGR_CLIENT_CLASS (klass); + +#if MBWM_WANT_DEBUG + klass->klass_name = "MBWMCompMgrClient"; +#endif +} + +static int +mb_wm_comp_mgr_client_init (MBWMObject *obj, va_list vap) +{ + MBWMCompMgrClient *client = MB_WM_COMP_MGR_CLIENT (obj); + MBWindowManagerClient *wm_client = NULL; + MBWMObjectProp prop; + XRenderPictFormat *format; + + prop = va_arg(vap, MBWMObjectProp); + while (prop) + { + switch (prop) + { + case MBWMObjectPropClient: + wm_client = va_arg(vap, MBWindowManagerClient *); + break; + default: + MBWMO_PROP_EAT (vap, prop); + } + + prop = va_arg(vap, MBWMObjectProp); + } + + if (!wm_client) + return 0; + + client->wm_client = wm_client; + client->wm = wm_client->wmref; + + /* Check visual */ + format = XRenderFindVisualFormat (client->wm->xdpy, + wm_client->window->visual); + + if (format && format->type == PictTypeDirect && format->direct.alphaMask) + client->is_argb32 = True; + + return 1; +} + +static void +mb_wm_comp_mgr_client_destroy (MBWMObject* obj) +{ + MBWMCompMgrClient *client = MB_WM_COMP_MGR_CLIENT (obj); + MBWindowManagerClient *wm_client = client->wm_client; +} + +int +mb_wm_comp_mgr_client_class_type () +{ + static int type = 0; + + if (UNLIKELY(type == 0)) + { + static MBWMObjectClassInfo info = { + sizeof (MBWMCompMgrClientClass), + sizeof (MBWMCompMgrClient), + mb_wm_comp_mgr_client_init, + mb_wm_comp_mgr_client_destroy, + mb_wm_comp_mgr_client_class_init + }; + + type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0); + } + + return type; +} + +void +mb_wm_comp_mgr_client_hide (MBWMCompMgrClient * client) +{ + MBWMCompMgrClientClass *klass; + + if (!client) + return; + + klass = MB_WM_COMP_MGR_CLIENT_CLASS (MB_WM_OBJECT_GET_CLASS (client)); + + MBWM_ASSERT (klass->hide != NULL); + klass->hide (client); +} + +void +mb_wm_comp_mgr_client_show (MBWMCompMgrClient * client) +{ + MBWMCompMgrClientClass *klass; + + if (!client) + return; + + klass = MB_WM_COMP_MGR_CLIENT_CLASS (MB_WM_OBJECT_GET_CLASS (client)); + + MBWM_ASSERT (klass->show != NULL); + klass->show (client); +} + +void +mb_wm_comp_mgr_client_configure (MBWMCompMgrClient * client) +{ + MBWMCompMgrClientClass *klass; + + if (!client) + return; + + klass = MB_WM_COMP_MGR_CLIENT_CLASS (MB_WM_OBJECT_GET_CLASS (client)); + + MBWM_ASSERT (klass->configure != NULL); + klass->configure (client); +} + +void +mb_wm_comp_mgr_client_repair (MBWMCompMgrClient * client) +{ + MBWMCompMgrClientClass *klass; + + if (!client) + return; + + klass = MB_WM_COMP_MGR_CLIENT_CLASS (MB_WM_OBJECT_GET_CLASS (client)); + + MBWM_ASSERT (klass->repair != NULL); + klass->repair (client); +} + + +/* + * MBWMCompMgr object + * + * Base class for the composite manager, providing the common interface + * through which the manager is access by the MBWindowManager object. + */ +static void +mb_wm_comp_mgr_class_init (MBWMObjectClass *klass) +{ +#if MBWM_WANT_DEBUG + klass->klass_name = "MBWMCompMgr"; +#endif +} + +static int +mb_wm_comp_mgr_init (MBWMObject *obj, va_list vap) +{ + MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj); + MBWindowManager * wm = NULL; + MBWMObjectProp prop; + + prop = va_arg(vap, MBWMObjectProp); + while (prop) + { + switch (prop) + { + case MBWMObjectPropWm: + wm = va_arg(vap, MBWindowManager *); + break; + default: + MBWMO_PROP_EAT (vap, prop); + } + + prop = va_arg(vap, MBWMObjectProp); + } + + if (!wm) + return 0; + + mgr->wm = wm; + mgr->disabled = True; + + return 1; +} + +static void +mb_wm_comp_mgr_destroy (MBWMObject* obj) +{ + MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj); + + mb_wm_comp_mgr_turn_off (mgr); +} + +int +mb_wm_comp_mgr_class_type () +{ + static int type = 0; + + if (UNLIKELY(type == 0)) + { + static MBWMObjectClassInfo info = { + sizeof (MBWMCompMgrClass), + sizeof (MBWMCompMgr), + mb_wm_comp_mgr_init, + mb_wm_comp_mgr_destroy, + mb_wm_comp_mgr_class_init + }; + + type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0); + } + + return type; +} + + +Bool +mb_wm_comp_mgr_enabled (MBWMCompMgr *mgr) +{ + if (!mgr || mgr->disabled) + return False; + + return True; +} + +/* + * Registers new client with the manager (i.e., when a window is created). + */ +void +mb_wm_comp_mgr_register_client (MBWMCompMgr * mgr, + MBWindowManagerClient * client) +{ + MBWMCompMgrClass *klass; + + if (!client) + return; + + klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + MBWM_ASSERT (klass->register_client != NULL); + klass->register_client (mgr, client); +} + +/* + * Unregisters existing client (e.g., when window unmaps or is destroyed + */ +void +mb_wm_comp_mgr_unregister_client (MBWMCompMgr * mgr, + MBWindowManagerClient * client) +{ + MBWMCompMgrClass *klass; + + if (!client) + return; + + klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + if (!client->cm_client) + return; + + if (klass->unregister_client) + klass->unregister_client (mgr, client); + + mb_wm_object_unref (MB_WM_OBJECT (client->cm_client)); + client->cm_client = NULL; +} + +/* + * Called to render the entire composited scene on screen. + */ +void +mb_wm_comp_mgr_render (MBWMCompMgr *mgr) +{ + MBWMCompMgrClass *klass; + + if (!mgr) + return; + + klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + if (klass->render) + klass->render (mgr); +} + +void +mb_wm_comp_mgr_restack (MBWMCompMgr *mgr) +{ + MBWMCompMgrClass *klass; + + if (!mgr) + return; + + klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + if (klass->restack) + klass->restack (mgr); +} + +/* + * Called when a window we are interested in maps. + */ +void +mb_wm_comp_mgr_map_notify (MBWMCompMgr *mgr, MBWindowManagerClient *c) +{ + MBWMCompMgrClass *klass; + + if (!mgr || !c || !c->cm_client) + return; + + klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + if (klass->map_notify) + klass->map_notify (mgr, c); + + /* + * Run map event effect *before* we call show() on the actor + * (the effect will take care of showing the actor, and if not, show() gets + * called by mb_wm_comp_mgr_map_notify()). + */ + if (!mb_wm_client_is_hiding_from_desktop (c)) + mb_wm_comp_mgr_do_effect (mgr, c, MBWMCompMgrClientEventMap); + + if (c->cm_client) + mb_wm_comp_mgr_client_show (c->cm_client); +} + +void +mb_wm_comp_mgr_unmap_notify (MBWMCompMgr *mgr, MBWindowManagerClient *c) +{ + MBWMCompMgrClass *klass; + + if (!mgr || !c || !c->cm_client) + return; + + klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + if (!mb_wm_client_is_hiding_from_desktop (c)) + mb_wm_comp_mgr_do_effect (mgr, c, MBWMCompMgrClientEventUnmap); + + if (klass->unmap_notify) + klass->unmap_notify (mgr, c); + + /* + * NB: cannot call hide() here, as at this point an effect could be running + * -- the subclass needs to take care of this from the effect and/or + * unmap_notify() function. + */ +} + +/* + * Runs a transition-effect from client c1 to client c2; the reverse argument + * indicates notional direction of the transition + */ +void +mb_wm_comp_mgr_do_transition (MBWMCompMgr * mgr, + MBWindowManagerClient *c1, + MBWindowManagerClient *c2, + Bool reverse) +{ + MBWMCompMgrClass *klass; + + /* + * Transitions can only be done for clients of the same type, so + * check the types here. + */ + if (!mgr || !c1 || !c2 || + MB_WM_CLIENT_CLIENT_TYPE (c1) != MB_WM_CLIENT_CLIENT_TYPE (c1)) + return; + + klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + if (klass->client_transition) + klass->client_transition (mgr, c1, c2, reverse); +} + +void +mb_wm_comp_mgr_do_effect (MBWMCompMgr * mgr, + MBWindowManagerClient * client, + MBWMCompMgrClientEvent event) +{ + MBWMCompMgrClass *klass; + + /* + * Transitions can only be done for clients of the same type, so + * check the types here. + */ + if (!mgr || !client) + return; + + klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + if (klass->client_event) + klass->client_event (mgr, client, event); +} + +void +mb_wm_comp_mgr_select_desktop (MBWMCompMgr * mgr, + int desktop, + int old_desktop) +{ + MBWMCompMgrClass *klass + = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + if (klass->select_desktop) + klass->select_desktop (mgr, desktop, old_desktop); +} + +void +mb_wm_comp_mgr_turn_on (MBWMCompMgr *mgr) +{ + MBWindowManager *wm = mgr->wm; + MBWMCompMgrClass *klass + = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + MBWM_ASSERT (klass->turn_on != NULL); + klass->turn_on (mgr); + + mgr->damage_cb_id = + mb_wm_main_context_x_event_handler_add (wm->main_ctx, + None, + wm->damage_event_base + XDamageNotify, + (MBWMXEventFunc)klass->handle_damage, + mgr); +} + +void +mb_wm_comp_mgr_turn_off (MBWMCompMgr *mgr) +{ + MBWindowManager *wm = mgr->wm; + MBWMCompMgrClass *klass + = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + MBWM_ASSERT (klass->turn_off != NULL); + klass->turn_off (mgr); + + mb_wm_main_context_x_event_handler_remove (wm->main_ctx, + wm->damage_event_base + XDamageNotify, + mgr->damage_cb_id); + + mgr->damage_cb_id = 0; +} + +/* + * Returns true if the window identified by id xwin is a special window + * that belongs to the compositing manager and should, therefore, be left + * alone by MBWMWindow manager (e.g., the overalay window). + */ +Bool +mb_wm_comp_mgr_is_my_window (MBWMCompMgr * mgr, Window xwin) +{ + MBWMCompMgrClass *klass + = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr)); + + if (klass->my_window) + return klass->my_window (mgr, xwin); + + return False; +} + diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr.h b/matchbox2/comp-mgr/mb-wm-comp-mgr.h new file mode 100644 index 0000000..98e9cbd --- /dev/null +++ b/matchbox2/comp-mgr/mb-wm-comp-mgr.h @@ -0,0 +1,159 @@ +/* + * Matchbox Window Manager - A lightweight window manager not for the + * desktop. + * + * Authored By Tomas Frydrych <tf@o-hand.com> + * + * Copyright (c) 2002, 2004, 2007 OpenedHand Ltd - http://o-hand.com + * + * 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 2, 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. + * + */ + +#ifndef _HAVE_MB_WM_COMP_MGR_H +#define _HAVE_MB_WM_COMP_MGR_H + +#include <X11/extensions/Xdamage.h> + +#define MB_WM_COMP_MGR(c) ((MBWMCompMgr*)(c)) +#define MB_WM_COMP_MGR_CLASS(c) ((MBWMCompMgrClass*)(c)) +#define MB_WM_TYPE_COMP_MGR (mb_wm_comp_mgr_class_type ()) + +#define MB_WM_COMP_MGR_CLIENT(c) ((MBWMCompMgrClient*)(c)) +#define MB_WM_COMP_MGR_CLIENT_CLASS(c) ((MBWMCompMgrClientClass*)(c)) +#define MB_WM_TYPE_COMP_MGR_CLIENT (mb_wm_comp_mgr_client_class_type ()) + +struct MBWMCompMgr +{ + MBWMObject parent; + + MBWindowManager *wm; + Bool disabled; + unsigned long damage_cb_id; +}; + +struct MBWMCompMgrClass +{ + MBWMObjectClass parent; + + void (*register_client) (MBWMCompMgr * mgr, MBWindowManagerClient *c); + void (*unregister_client) (MBWMCompMgr * mgr, MBWindowManagerClient *c); + void (*turn_on) (MBWMCompMgr * mgr); + void (*turn_off) (MBWMCompMgr * mgr); + void (*render) (MBWMCompMgr * mgr); + void (*restack) (MBWMCompMgr * mgr); + void (*map_notify) (MBWMCompMgr * mgr, MBWindowManagerClient *c); + void (*unmap_notify) (MBWMCompMgr * mgr, MBWindowManagerClient *c); + Bool (*handle_damage) (XDamageNotifyEvent * xev, MBWMCompMgr * mgr); + Bool (*my_window) (MBWMCompMgr * mgr, Window xwin); + void (*client_event) (MBWMCompMgr * mgr, + MBWindowManagerClient *c1, + MBWMCompMgrClientEvent event); + void (*client_transition) (MBWMCompMgr * mgr, + MBWindowManagerClient *c1, + MBWindowManagerClient *c2, + Bool reverse); + + void (*select_desktop) (MBWMCompMgr * mgr, + int desktop, int old_desktop); +}; + +int +mb_wm_comp_mgr_class_type (); + +void +mb_wm_comp_mgr_register_client (MBWMCompMgr * mgr, MBWindowManagerClient *c); + +void +mb_wm_comp_mgr_unregister_client (MBWMCompMgr * mgr, + MBWindowManagerClient *client); + +void +mb_wm_comp_mgr_turn_off (MBWMCompMgr *mgr); + +void +mb_wm_comp_mgr_turn_on (MBWMCompMgr *mgr); + +void +mb_wm_comp_mgr_render (MBWMCompMgr *mgr); + +void +mb_wm_comp_mgr_restack (MBWMCompMgr *mgr); + +void +mb_wm_comp_mgr_map_notify (MBWMCompMgr *mgr, MBWindowManagerClient *c); + +void +mb_wm_comp_mgr_unmap_notify (MBWMCompMgr *mgr, MBWindowManagerClient *c); + +Bool +mb_wm_comp_mgr_enabled (MBWMCompMgr *mgr); + +Bool +mb_wm_comp_mgr_handle_events (MBWMCompMgr * mgr, XEvent *ev); + +Bool +mb_wm_comp_mgr_is_my_window (MBWMCompMgr * mgr, Window xwin); + +void +mb_wm_comp_mgr_do_transition (MBWMCompMgr * mgr, + MBWindowManagerClient * c1, + MBWindowManagerClient * c2, + Bool reverse); + +void +mb_wm_comp_mgr_do_effect (MBWMCompMgr * mgr, + MBWindowManagerClient * client, + MBWMCompMgrClientEvent event); + +void +mb_wm_comp_mgr_select_desktop (MBWMCompMgr * mgr, + int desktop, + int old_desktop); + +struct MBWMCompMgrClient +{ + MBWMObject parent; + + MBWindowManager * wm; + MBWindowManagerClient * wm_client; + + /* Make private ? */ + Bool is_argb32; +}; + +struct MBWMCompMgrClientClass +{ + MBWMObjectClass parent; + + void (*show) (MBWMCompMgrClient * client); + void (*hide) (MBWMCompMgrClient * client); + void (*repair) (MBWMCompMgrClient * client); + void (*configure) (MBWMCompMgrClient * client); +}; + +int +mb_wm_comp_mgr_client_class_type (); + +void +mb_wm_comp_mgr_client_show (MBWMCompMgrClient * client); + +void +mb_wm_comp_mgr_client_hide (MBWMCompMgrClient * client); + +void +mb_wm_comp_mgr_client_repair (MBWMCompMgrClient * client); + +void +mb_wm_comp_mgr_client_configure (MBWMCompMgrClient * client); + + +#endif |