aboutsummaryrefslogtreecommitdiffstats
path: root/matchbox2/comp-mgr
diff options
context:
space:
mode:
Diffstat (limited to 'matchbox2/comp-mgr')
-rw-r--r--matchbox2/comp-mgr/Makefile.am32
-rw-r--r--matchbox2/comp-mgr/README70
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c1610
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.h108
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.c1837
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.h60
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr.c482
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr.h159
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