aboutsummaryrefslogtreecommitdiffstats
path: root/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c
diff options
context:
space:
mode:
Diffstat (limited to 'matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c')
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c1610
1 files changed, 1610 insertions, 0 deletions
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;
+}
+