aboutsummaryrefslogtreecommitdiffstats
path: root/managers
diff options
context:
space:
mode:
authorRobert Bragg <robert@linux.intel.com>2010-08-18 05:05:02 +0100
committerRobert Bragg <robert@linux.intel.com>2010-12-09 22:46:46 +0000
commit3b3051ee42e27e3534bb0771cbafc3d3d9adc599 (patch)
treec9e5bf8b6ee6e78342847d217dde72a805a89749 /managers
parent98e75aaa63622b3146e7239ef954ba1abf6b4815 (diff)
downloadlibmatchboxwm2-3b3051ee42e27e3534bb0771cbafc3d3d9adc599.tar.gz
libmatchboxwm2-3b3051ee42e27e3534bb0771cbafc3d3d9adc599.tar.bz2
libmatchboxwm2-3b3051ee42e27e3534bb0771cbafc3d3d9adc599.zip
build: Don't provide CompMgr subclasses in libmatchbox
This makes it the responsibility of managers/ to provide their own CompMgr subclasses if they want to support compositing. This defines a new manager called "clutter" based on the simple manager and the mb-wm-comp-mgr-clutter code has been moved under managers/clutter. The way matchbox is now configured has been tweaked. There is now a --enable-compositing option that determines if libmatchbox supports compositing which is required if you want to implement a new manager that handles compositing. Also there is a --with-managers= option that takes a coma separated list of which managers to build, including simple,maemo and clutter.
Diffstat (limited to 'managers')
-rw-r--r--managers/clutter/Makefile.am22
-rw-r--r--managers/clutter/matchbox-window-manager-2-clutter.c155
-rw-r--r--managers/clutter/mb-wm-comp-mgr-clutter.c1610
-rw-r--r--managers/clutter/mb-wm-comp-mgr-clutter.h108
-rw-r--r--managers/clutter/tidy/tidy-texture-frame.c641
-rw-r--r--managers/clutter/tidy/tidy-texture-frame.h84
-rw-r--r--managers/simple/matchbox-window-manager-2-simple.c28
7 files changed, 2621 insertions, 27 deletions
diff --git a/managers/clutter/Makefile.am b/managers/clutter/Makefile.am
new file mode 100644
index 0000000..e207df5
--- /dev/null
+++ b/managers/clutter/Makefile.am
@@ -0,0 +1,22 @@
+INCLUDES = \
+ $(MBWM_INCS) \
+ $(MBWM_CFLAGS)
+
+bin_PROGRAMS = matchbox-window-manager-2-clutter
+
+matchbox_window_manager_2_clutter_SOURCES = \
+ matchbox-window-manager-2-clutter.c \
+ mb-wm-comp-mgr-clutter.h \
+ mb-wm-comp-mgr-clutter.c \
+ tidy/tidy-texture-frame.h \
+ tidy/tidy-texture-frame.c
+
+
+matchbox_window_manager_2_clutter_LDFLAGS = \
+ $(MBWM_DEBUG_LDFLAGS) \
+ $(LDFLAGS)
+
+matchbox_window_manager_2_clutter_LDADD = \
+ $(top_builddir)/matchbox/libmatchbox-@MBWM_API_VERSION@.la \
+ $(MBWM_LIBS)
+
diff --git a/managers/clutter/matchbox-window-manager-2-clutter.c b/managers/clutter/matchbox-window-manager-2-clutter.c
new file mode 100644
index 0000000..ab3b227
--- /dev/null
+++ b/managers/clutter/matchbox-window-manager-2-clutter.c
@@ -0,0 +1,155 @@
+#include "mb-wm-comp-mgr-clutter.h"
+#include <clutter/x11/clutter-x11.h>
+
+#include <matchbox/matchbox.h>
+#include <signal.h>
+
+#if USE_GTK
+#include <gdk/gdkx.h>
+#endif
+
+enum {
+ KEY_ACTION_PAGE_NEXT,
+ KEY_ACTION_PAGE_PREV,
+ KEY_ACTION_TOGGLE_FULLSCREEN,
+ KEY_ACTION_TOGGLE_DESKTOP,
+};
+
+static MBWMManager *wm = NULL;
+
+#if MBWM_WANT_DEBUG
+/*
+ * The Idea behind this is quite simple: when all managed windows are closed
+ * and the WM exits, there should have been an unref call for each ref call. To
+ * test do something like
+ *
+ * export DISPLAY=:whatever;
+ * export MB_DEBUG=obj-ref,obj-unref
+ * matchbox-window-manager-2-simple &
+ * gedit
+ * kill -TERM $(pidof gedit)
+ * kill -TERM $(pidof matchbox-window-manager-2-simple)
+ *
+ * If you see '=== object count at exit x ===' then we either have a leak
+ * (x > 0) or are unrefing a dangling pointer (x < 0).
+ */
+static void
+signal_handler (int sig)
+{
+ if (sig == SIGTERM)
+ {
+ int count;
+
+ mb_wm_object_unref (MB_WM_OBJECT (wm));
+ mb_wm_object_dump ();
+
+ exit (sig);
+ }
+}
+#endif
+
+void
+key_binding_func (MBWMManager *wm,
+ MBWMKeyBinding *binding,
+ void *userdata)
+{
+ printf(" ### got key press ### \n");
+ int action;
+
+ action = (int)(userdata);
+
+ switch (action)
+ {
+ case KEY_ACTION_PAGE_NEXT:
+ mb_wm_manager_cycle_apps (wm, False);
+ break;
+ case KEY_ACTION_PAGE_PREV:
+ mb_wm_manager_cycle_apps (wm, True);
+ break;
+ case KEY_ACTION_TOGGLE_FULLSCREEN:
+ printf(" ### KEY_ACTION_TOGGLE_FULLSCREEN ### \n");
+ break;
+ case KEY_ACTION_TOGGLE_DESKTOP:
+ printf(" ### KEY_ACTION_TOGGLE_DESKTOP ### \n");
+ mb_wm_manager_toggle_desktop (wm);
+ break;
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ Display * dpy = NULL;
+ MBWMCompMgr *compositor;
+
+#if MBWM_WANT_DEBUG
+ struct sigaction sa;
+ sigfillset(&sa.sa_mask);
+ sa.sa_handler = signal_handler;
+ sigaction(SIGTERM, &sa, NULL);
+#endif
+
+ mb_wm_object_init();
+
+#if USE_GTK
+ printf ("initializing gtk\n");
+
+ gtk_init (&argc, &argv);
+ dpy = GDK_DISPLAY();
+#endif
+
+ /*
+ * If using clutter, we share the display connection, and hook
+ * our xevent handler into the clutter main loop.
+ *
+ * If we are also doing gtk integration, we need to make clutter to
+ * use the gtk display connection.
+ */
+ if (dpy)
+ clutter_x11_set_display (dpy);
+
+#if USE_GTK
+ clutter_x11_disable_event_retrieval ();
+#endif
+
+ clutter_init (&argc, &argv);
+
+ if (!dpy)
+ dpy = clutter_x11_get_default_display ();
+
+ wm = mb_wm_manager_new_with_dpy (argc, argv, dpy);
+ compositor = mb_wm_comp_mgr_clutter_new (wm);
+ mb_wm_manager_run_with_compositor (wm, compositor);
+ mb_wm_object_unref (MB_WM_OBJECT (compositor));
+
+ if (wm == NULL)
+ mb_wm_util_fatal_error("OOM?");
+
+ mb_wm_keys_binding_add_with_spec (wm,
+ "<alt>d",
+ key_binding_func,
+ NULL,
+ (void*)KEY_ACTION_TOGGLE_DESKTOP);
+
+ mb_wm_keys_binding_add_with_spec (wm,
+ "<alt>n",
+ key_binding_func,
+ NULL,
+ (void*)KEY_ACTION_PAGE_NEXT);
+
+ mb_wm_keys_binding_add_with_spec (wm,
+ "<alt>p",
+ key_binding_func,
+ NULL,
+ (void*)KEY_ACTION_PAGE_PREV);
+
+ mb_wm_manager_main_loop(wm);
+
+ mb_wm_object_unref (MB_WM_OBJECT (wm));
+
+#if MBWM_WANT_DEBUG
+ mb_wm_object_dump ();
+#endif
+
+ return 1;
+}
diff --git a/managers/clutter/mb-wm-comp-mgr-clutter.c b/managers/clutter/mb-wm-comp-mgr-clutter.c
new file mode 100644
index 0000000..91163df
--- /dev/null
+++ b/managers/clutter/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 "matchbox.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/managers/clutter/mb-wm-comp-mgr-clutter.h b/managers/clutter/mb-wm-comp-mgr-clutter.h
new file mode 100644
index 0000000..c18fcbf
--- /dev/null
+++ b/managers/clutter/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 <matchbox/matchbox.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/managers/clutter/tidy/tidy-texture-frame.c b/managers/clutter/tidy/tidy-texture-frame.c
new file mode 100644
index 0000000..7ba4671
--- /dev/null
+++ b/managers/clutter/tidy/tidy-texture-frame.c
@@ -0,0 +1,641 @@
+/* tidy-texture-frame.h: Expandible texture actor
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:tidy-texture-frame
+ * @short_description: Stretch a texture to fit the entire allocation
+ *
+ * #TidyTextureFrame
+ *
+ */
+
+#include <cogl/cogl.h>
+
+#include "tidy-texture-frame.h"
+
+#define TIDY_PARAM_READABLE \
+ (G_PARAM_READABLE | \
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
+
+#define TIDY_PARAM_READWRITE \
+ (G_PARAM_READABLE | G_PARAM_WRITABLE | \
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
+
+enum
+{
+ PROP_0,
+
+ PROP_PARENT_TEXTURE,
+
+ PROP_LEFT,
+ PROP_TOP,
+ PROP_RIGHT,
+ PROP_BOTTOM
+};
+
+G_DEFINE_TYPE (TidyTextureFrame, tidy_texture_frame, CLUTTER_TYPE_ACTOR);
+
+#define TIDY_TEXTURE_FRAME_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFramePrivate))
+
+struct _TidyTextureFramePrivate
+{
+ ClutterTexture *parent_texture;
+
+ gfloat left;
+ gfloat top;
+ gfloat right;
+ gfloat bottom;
+
+ CoglHandle material;
+
+ guint needs_paint : 1;
+};
+
+static void
+tidy_texture_frame_get_preferred_width (ClutterActor *self,
+ gfloat for_height,
+ gfloat *min_width_p,
+ gfloat *natural_width_p)
+{
+ TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv;
+
+ if (G_UNLIKELY (priv->parent_texture == NULL))
+ {
+ if (min_width_p)
+ *min_width_p = 0;
+
+ if (natural_width_p)
+ *natural_width_p = 0;
+ }
+ else
+ {
+ ClutterActorClass *klass;
+
+ /* by directly querying the parent texture's class implementation
+ * we are going around any override mechanism the parent texture
+ * might have in place, and we ask directly for the original
+ * preferred width
+ */
+ klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
+ klass->get_preferred_width (CLUTTER_ACTOR (priv->parent_texture),
+ for_height,
+ min_width_p,
+ natural_width_p);
+ }
+}
+
+static void
+tidy_texture_frame_get_preferred_height (ClutterActor *self,
+ gfloat for_width,
+ gfloat *min_height_p,
+ gfloat *natural_height_p)
+{
+ TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv;
+
+ if (G_UNLIKELY (priv->parent_texture == NULL))
+ {
+ if (min_height_p)
+ *min_height_p = 0;
+
+ if (natural_height_p)
+ *natural_height_p = 0;
+ }
+ else
+ {
+ ClutterActorClass *klass;
+
+ /* by directly querying the parent texture's class implementation
+ * we are going around any override mechanism the parent texture
+ * might have in place, and we ask directly for the original
+ * preferred height
+ */
+ klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
+ klass->get_preferred_height (CLUTTER_ACTOR (priv->parent_texture),
+ for_width,
+ min_height_p,
+ natural_height_p);
+ }
+}
+
+static void
+tidy_texture_frame_realize (ClutterActor *self)
+{
+ TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv;
+
+ if (priv->material != COGL_INVALID_HANDLE)
+ return;
+
+ priv->material = cogl_material_new ();
+
+ CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
+}
+
+static void
+tidy_texture_frame_unrealize (ClutterActor *self)
+{
+ TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv;
+
+ if (priv->material == COGL_INVALID_HANDLE)
+ return;
+
+ cogl_handle_unref (priv->material);
+ priv->material = COGL_INVALID_HANDLE;
+
+ CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
+}
+
+static void
+tidy_texture_frame_paint (ClutterActor *self)
+{
+ TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv;
+ CoglHandle cogl_texture = COGL_INVALID_HANDLE;
+ ClutterActorBox box = { 0, };
+ gfloat width, height;
+ gfloat tex_width, tex_height;
+ gfloat ex, ey;
+ gfloat tx1, ty1, tx2, ty2;
+ guint8 opacity;
+
+ /* no need to paint stuff if we don't have a texture */
+ if (G_UNLIKELY (priv->parent_texture == NULL))
+ return;
+
+ if (!priv->needs_paint)
+ return;
+
+ /* parent texture may have been hidden, so need to make sure it gets
+ * realized
+ */
+ if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_texture))
+ clutter_actor_realize (CLUTTER_ACTOR (priv->parent_texture));
+
+ cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture);
+ if (cogl_texture == COGL_INVALID_HANDLE)
+ return;
+
+ tex_width = cogl_texture_get_width (cogl_texture);
+ tex_height = cogl_texture_get_height (cogl_texture);
+
+ clutter_actor_get_allocation_box (self, &box);
+ width = box.x2 - box.x1;
+ height = box.y2 - box.y1;
+
+ tx1 = priv->left / tex_width;
+ tx2 = (tex_width - priv->right) / tex_width;
+ ty1 = priv->top / tex_height;
+ ty2 = (tex_height - priv->bottom) / tex_height;
+
+ ex = width - priv->right;
+ if (ex < 0)
+ ex = priv->right; /* FIXME ? */
+
+ ey = height - priv->bottom;
+ if (ey < 0)
+ ey = priv->bottom; /* FIXME ? */
+
+ opacity = clutter_actor_get_paint_opacity (self);
+
+ g_assert (priv->material != COGL_INVALID_HANDLE);
+
+ /* set the source material using the parent texture's COGL handle */
+ cogl_material_set_color4ub (priv->material, opacity, opacity, opacity, opacity);
+ cogl_material_set_layer (priv->material, 0, cogl_texture);
+ cogl_set_source (priv->material);
+
+ /* top left corner */
+ cogl_rectangle_with_texture_coords (0, 0, priv->left, priv->top,
+ 0.0, 0.0,
+ tx1, ty1);
+
+ /* top middle */
+ cogl_rectangle_with_texture_coords (priv->left, 0, ex, priv->top,
+ tx1, 0.0,
+ tx2, ty1);
+
+ /* top right */
+ cogl_rectangle_with_texture_coords (ex, 0, width, priv->top,
+ tx2, 0.0,
+ 1.0, ty1);
+
+ /* mid left */
+ cogl_rectangle_with_texture_coords (0, priv->top, priv->left, ey,
+ 0.0, ty1,
+ tx1, ty2);
+
+ /* center */
+ cogl_rectangle_with_texture_coords (priv->left, priv->top, ex, ey,
+ tx1, ty1,
+ tx2, ty2);
+
+ /* mid right */
+ cogl_rectangle_with_texture_coords (ex, priv->top, width, ey,
+ tx2, ty1,
+ 1.0, ty2);
+
+ /* bottom left */
+ cogl_rectangle_with_texture_coords (0, ey, priv->left, height,
+ 0.0, ty2,
+ tx1, 1.0);
+
+ /* bottom center */
+ cogl_rectangle_with_texture_coords (priv->left, ey, ex, height,
+ tx1, ty2,
+ tx2, 1.0);
+
+ /* bottom right */
+ cogl_rectangle_with_texture_coords (ex, ey, width, height,
+ tx2, ty2,
+ 1.0, 1.0);
+}
+
+static inline void
+tidy_texture_frame_set_frame_internal (TidyTextureFrame *frame,
+ gfloat left,
+ gfloat top,
+ gfloat right,
+ gfloat bottom)
+{
+ TidyTextureFramePrivate *priv = frame->priv;
+ GObject *gobject = G_OBJECT (frame);
+ gboolean changed = FALSE;
+
+ g_object_freeze_notify (gobject);
+
+ if (priv->top != top)
+ {
+ priv->top = top;
+ g_object_notify (gobject, "top");
+ changed = TRUE;
+ }
+
+ if (priv->right != right)
+ {
+ priv->right = right;
+ g_object_notify (gobject, "right");
+ changed = TRUE;
+ }
+
+ if (priv->bottom != bottom)
+ {
+ priv->bottom = bottom;
+ g_object_notify (gobject, "bottom");
+ changed = TRUE;
+ }
+
+ if (priv->left != left)
+ {
+ priv->left = left;
+ g_object_notify (gobject, "left");
+ changed = TRUE;
+ }
+
+ if (changed && CLUTTER_ACTOR_IS_VISIBLE (frame))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (frame));
+
+ g_object_thaw_notify (gobject);
+}
+
+static void
+tidy_texture_frame_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TidyTextureFrame *frame = TIDY_TEXTURE_FRAME (gobject);
+ TidyTextureFramePrivate *priv = frame->priv;
+
+ switch (prop_id)
+ {
+ case PROP_PARENT_TEXTURE:
+ tidy_texture_frame_set_parent_texture (frame,
+ g_value_get_object (value));
+ break;
+
+ case PROP_TOP:
+ tidy_texture_frame_set_frame_internal (frame,
+ priv->left,
+ g_value_get_float (value),
+ priv->right,
+ priv->bottom);
+ break;
+
+ case PROP_RIGHT:
+ tidy_texture_frame_set_frame_internal (frame,
+ priv->top,
+ g_value_get_float (value),
+ priv->bottom,
+ priv->left);
+ break;
+
+ case PROP_BOTTOM:
+ tidy_texture_frame_set_frame_internal (frame,
+ priv->top,
+ priv->right,
+ g_value_get_float (value),
+ priv->left);
+ break;
+
+ case PROP_LEFT:
+ tidy_texture_frame_set_frame_internal (frame,
+ priv->top,
+ priv->right,
+ priv->bottom,
+ g_value_get_float (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tidy_texture_frame_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (gobject)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_PARENT_TEXTURE:
+ g_value_set_object (value, priv->parent_texture);
+ break;
+
+ case PROP_LEFT:
+ g_value_set_float (value, priv->left);
+ break;
+
+ case PROP_TOP:
+ g_value_set_float (value, priv->top);
+ break;
+
+ case PROP_RIGHT:
+ g_value_set_float (value, priv->right);
+ break;
+
+ case PROP_BOTTOM:
+ g_value_set_float (value, priv->bottom);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tidy_texture_frame_dispose (GObject *gobject)
+{
+ TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (gobject)->priv;
+
+ if (priv->parent_texture)
+ {
+ g_object_unref (priv->parent_texture);
+ priv->parent_texture = NULL;
+ }
+
+ if (priv->material)
+ {
+ cogl_handle_unref (priv->material);
+ priv->material = COGL_INVALID_HANDLE;
+ }
+
+ G_OBJECT_CLASS (tidy_texture_frame_parent_class)->dispose (gobject);
+}
+
+static void
+tidy_texture_frame_class_init (TidyTextureFrameClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (gobject_class, sizeof (TidyTextureFramePrivate));
+
+ actor_class->get_preferred_width =
+ tidy_texture_frame_get_preferred_width;
+ actor_class->get_preferred_height =
+ tidy_texture_frame_get_preferred_height;
+ actor_class->realize = tidy_texture_frame_realize;
+ actor_class->unrealize = tidy_texture_frame_unrealize;
+ actor_class->paint = tidy_texture_frame_paint;
+
+ gobject_class->set_property = tidy_texture_frame_set_property;
+ gobject_class->get_property = tidy_texture_frame_get_property;
+ gobject_class->dispose = tidy_texture_frame_dispose;
+
+ pspec = g_param_spec_object ("parent-texture",
+ "Parent Texture",
+ "The parent ClutterTexture",
+ CLUTTER_TYPE_TEXTURE,
+ TIDY_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT);
+ g_object_class_install_property (gobject_class, PROP_PARENT_TEXTURE, pspec);
+
+ pspec = g_param_spec_float ("left",
+ "Left",
+ "Left offset",
+ 0, G_MAXFLOAT,
+ 0,
+ TIDY_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_LEFT, pspec);
+
+ pspec = g_param_spec_float ("top",
+ "Top",
+ "Top offset",
+ 0, G_MAXFLOAT,
+ 0,
+ TIDY_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_TOP, pspec);
+
+ pspec = g_param_spec_float ("bottom",
+ "Bottom",
+ "Bottom offset",
+ 0, G_MAXFLOAT,
+ 0,
+ TIDY_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_BOTTOM, pspec);
+
+ pspec = g_param_spec_float ("right",
+ "Right",
+ "Right offset",
+ 0, G_MAXFLOAT,
+ 0,
+ TIDY_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_RIGHT, pspec);
+}
+
+static void
+tidy_texture_frame_init (TidyTextureFrame *self)
+{
+ TidyTextureFramePrivate *priv;
+
+ self->priv = priv = TIDY_TEXTURE_FRAME_GET_PRIVATE (self);
+
+ priv->material = COGL_INVALID_HANDLE;
+}
+
+/**
+ * tidy_texture_frame_new:
+ * @texture: a #ClutterTexture or %NULL
+ * @left: left margin preserving its content
+ * @top: top margin preserving its content
+ * @right: right margin preserving its content
+ * @bottom: bottom margin preserving its content
+ *
+ * A #TidyTextureFrame is a specialized texture that efficiently clones
+ * an area of the given @texture while keeping preserving portions of the
+ * same texture.
+ *
+ * A #TidyTextureFrame can be used to make a rectangular texture fit a
+ * given size without stretching its borders.
+ *
+ * Return value: the newly created #TidyTextureFrame
+ */
+ClutterActor*
+tidy_texture_frame_new (ClutterTexture *texture,
+ gfloat left,
+ gfloat top,
+ gfloat right,
+ gfloat bottom)
+{
+ g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
+
+ return g_object_new (TIDY_TYPE_TEXTURE_FRAME,
+ "parent-texture", texture,
+ "left", left,
+ "top", top,
+ "right", right,
+ "bottom", bottom,
+ NULL);
+}
+
+ClutterTexture *
+tidy_texture_frame_get_parent_texture (TidyTextureFrame *frame)
+{
+ g_return_val_if_fail (TIDY_IS_TEXTURE_FRAME (frame), NULL);
+
+ return frame->priv->parent_texture;
+}
+
+void
+tidy_texture_frame_set_parent_texture (TidyTextureFrame *frame,
+ ClutterTexture *texture)
+{
+ TidyTextureFramePrivate *priv;
+ gboolean was_visible;
+
+ g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame));
+ g_return_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture));
+
+ priv = frame->priv;
+
+ was_visible = CLUTTER_ACTOR_IS_VISIBLE (frame);
+
+ if (priv->parent_texture == texture)
+ return;
+
+ if (priv->parent_texture)
+ {
+ g_object_unref (priv->parent_texture);
+ priv->parent_texture = NULL;
+
+ if (was_visible)
+ clutter_actor_hide (CLUTTER_ACTOR (frame));
+ }
+
+ if (texture)
+ {
+ priv->parent_texture = g_object_ref (texture);
+
+ if (was_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture))
+ clutter_actor_show (CLUTTER_ACTOR (frame));
+ }
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
+
+ g_object_notify (G_OBJECT (frame), "parent-texture");
+}
+
+void
+tidy_texture_frame_set_frame (TidyTextureFrame *frame,
+ gfloat top,
+ gfloat right,
+ gfloat bottom,
+ gfloat left)
+{
+ g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame));
+
+ tidy_texture_frame_set_frame_internal (frame, top, right, bottom, left);
+}
+
+void
+tidy_texture_frame_get_frame (TidyTextureFrame *frame,
+ gfloat *top,
+ gfloat *right,
+ gfloat *bottom,
+ gfloat *left)
+{
+ TidyTextureFramePrivate *priv;
+
+ g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame));
+
+ priv = frame->priv;
+
+ if (top)
+ *top = priv->top;
+
+ if (right)
+ *right = priv->right;
+
+ if (bottom)
+ *bottom = priv->bottom;
+
+ if (left)
+ *left = priv->left;
+}
+
+/**
+ * tidy_texture_frame_set_needs_paint:
+ * @frame: a #TidyTextureframe
+ * @needs_paint: if %FALSE, the paint will be skipped
+ *
+ * Provides a hint to the texture frame that it is totally obscured
+ * and doesn't need to be painted. This would typically be called
+ * by a parent container if it detects the condition prior to
+ * painting its children and then unset afterwards.
+ *
+ * Since it is not supposed to have any effect on display, it does
+ * not queue a repaint.
+ */
+void
+tidy_texture_frame_set_needs_paint (TidyTextureFrame *frame,
+ gboolean needs_paint)
+{
+ TidyTextureFramePrivate *priv;
+
+ g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame));
+
+ priv = frame->priv;
+
+ priv->needs_paint = needs_paint;
+}
diff --git a/managers/clutter/tidy/tidy-texture-frame.h b/managers/clutter/tidy/tidy-texture-frame.h
new file mode 100644
index 0000000..71dd40c
--- /dev/null
+++ b/managers/clutter/tidy/tidy-texture-frame.h
@@ -0,0 +1,84 @@
+/* tidy-texture-frame.h: Expandible texture actor
+ *
+ * Copyright (C) 2007, 2008 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _HAVE_TIDY_TEXTURE_FRAME_H
+#define _HAVE_TIDY_TEXTURE_FRAME_H
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_TEXTURE_FRAME (tidy_texture_frame_get_type ())
+#define TIDY_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrame))
+#define TIDY_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass))
+#define TIDY_IS_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_TEXTURE_FRAME))
+#define TIDY_IS_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_TEXTURE_FRAME))
+#define TIDY_TEXTURE_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass))
+
+typedef struct _TidyTextureFrame TidyTextureFrame;
+typedef struct _TidyTextureFramePrivate TidyTextureFramePrivate;
+typedef struct _TidyTextureFrameClass TidyTextureFrameClass;
+
+struct _TidyTextureFrame
+{
+ /*< private >*/
+ ClutterActor parent_instance;
+
+ TidyTextureFramePrivate *priv;
+};
+
+struct _TidyTextureFrameClass
+{
+ ClutterActorClass parent_class;
+
+ /* padding for future expansion */
+ void (*_clutter_box_1) (void);
+ void (*_clutter_box_2) (void);
+ void (*_clutter_box_3) (void);
+ void (*_clutter_box_4) (void);
+};
+
+GType tidy_texture_frame_get_type (void) G_GNUC_CONST;
+ClutterActor * tidy_texture_frame_new (ClutterTexture *texture,
+ gfloat top,
+ gfloat right,
+ gfloat bottom,
+ gfloat left);
+void tidy_texture_frame_set_parent_texture (TidyTextureFrame *frame,
+ ClutterTexture *texture);
+ClutterTexture *tidy_texture_frame_get_parent_texture (TidyTextureFrame *frame);
+void tidy_texture_frame_set_frame (TidyTextureFrame *frame,
+ gfloat top,
+ gfloat right,
+ gfloat bottom,
+ gfloat left);
+void tidy_texture_frame_get_frame (TidyTextureFrame *frame,
+ gfloat *top,
+ gfloat *right,
+ gfloat *bottom,
+ gfloat *left);
+
+void tidy_texture_frame_set_needs_paint (TidyTextureFrame *frame,
+ gboolean needs_paint);
+
+G_END_DECLS
+
+#endif /* _HAVE_TIDY_TEXTURE_FRAME_H */
diff --git a/managers/simple/matchbox-window-manager-2-simple.c b/managers/simple/matchbox-window-manager-2-simple.c
index 5b68cde..5a3472a 100644
--- a/managers/simple/matchbox-window-manager-2-simple.c
+++ b/managers/simple/matchbox-window-manager-2-simple.c
@@ -1,10 +1,6 @@
#include <matchbox/matchbox.h>
#include <signal.h>
-#if ENABLE_CLUTTER_COMPOSITE_MANAGER
-# include <clutter/x11/clutter-x11.h>
-#endif
-
#if USE_GTK
#include <gdk/gdkx.h>
#endif
@@ -98,31 +94,9 @@ main(int argc, char **argv)
dpy = GDK_DISPLAY();
#endif
-#if ENABLE_CLUTTER_COMPOSITE_MANAGER
- /*
- * If using clutter, we share the display connection, and hook
- * our xevent handler into the clutter main loop.
- *
- * If we are also doing gtk integration, we need to make clutter to
- * use the gtk display connection.
- */
- if (dpy)
- clutter_x11_set_display (dpy);
-
-#if USE_GTK
- clutter_x11_disable_event_retrieval ();
-#endif
-
- clutter_init (&argc, &argv);
-
- if (!dpy)
- dpy = clutter_x11_get_default_display ();
-
-#endif
-
wm = mb_wm_new_with_dpy (argc, argv, dpy);
mb_wm_init (wm);
-
+
if (wm == NULL)
mb_wm_util_fatal_error("OOM?");