aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog29
-rw-r--r--configure.ac22
-rw-r--r--data/themes/Default/theme.xml2
-rw-r--r--src/comp-mgr/Makefile.am24
-rw-r--r--src/comp-mgr/mb-wm-comp-mgr-clutter.c1144
-rw-r--r--src/comp-mgr/mb-wm-comp-mgr-clutter.h74
-rw-r--r--src/comp-mgr/mb-wm-comp-mgr-default.c24
-rw-r--r--src/comp-mgr/mb-wm-comp-mgr-default.h4
-rw-r--r--src/comp-mgr/mb-wm-comp-mgr.c331
-rw-r--r--src/comp-mgr/mb-wm-comp-mgr.h66
-rw-r--r--src/core/mb-window-manager.c183
-rw-r--r--src/core/mb-window-manager.h15
-rw-r--r--src/core/mb-wm-client.c40
-rw-r--r--src/core/mb-wm-main-context.c16
-rw-r--r--src/core/mb-wm-object-props.h7
-rw-r--r--src/core/mb-wm-types.h44
-rw-r--r--src/managers/maemo/maemo-window-manager.c4
-rw-r--r--src/managers/simple/matchbox-window-manager-2-simple.c18
-rw-r--r--src/theme-engines/mb-wm-theme-xml.c22
-rw-r--r--src/theme-engines/mb-wm-theme-xml.h4
-rw-r--r--src/theme-engines/mb-wm-theme.c165
-rw-r--r--src/theme-engines/mb-wm-theme.h15
22 files changed, 2176 insertions, 77 deletions
diff --git a/ChangeLog b/ChangeLog
index 482ff4c..1d3292e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+2008-02-13 Tomas Frydrych <tf@o-hand.com>
+
+ * configure.ac
+ * src/comp-mgr/Makefile.am:
+ * src/comp-mgr/mb-wm-comp-mgr-default.c:
+ * src/comp-mgr/mb-wm-comp-mgr-default.h:
+ * src/comp-mgr/mb-wm-comp-mgr.c:
+ * src/comp-mgr/mb-wm-comp-mgr.h:
+ * src/core/mb-window-manager.c:
+ * src/core/mb-window-manager.h:
+ * src/core/mb-wm-client.c:
+ * src/core/mb-wm-main-context.c:
+ * src/core/mb-wm-object-props.h:
+ * src/core/mb-wm-types.h:
+ * src/managers/maemo/maemo-window-manager.c:
+ * src/managers/simple/matchbox-window-manager-2-simple.c:
+ Changes to improve the flexibility of the compositor framework.
+ Framework for compositor effects.
+ Initial implementation of a clutter-based compositor.
+
+ * src/theme-engines/mb-wm-theme-xml.c:
+ * src/theme-engines/mb-wm-theme-xml.h:
+ * src/theme-engines/mb-wm-theme.c:
+ * src/theme-engines/mb-wm-theme.h:
+ Added support for effects.
+
+ * data/themes/Default/theme.xml:
+ Added sample effect for application clients.
+
2008-01-31 Tomas Frydrych <tf@o-hand.com>
* src/client-types/mb-wm-client-dialog.c:
diff --git a/configure.ac b/configure.ac
index 6c80220..cb89a68 100644
--- a/configure.ac
+++ b/configure.ac
@@ -50,9 +50,16 @@ if test "x$use_gtk" = "xyes"; then
needed_pkgs="$needed_pkgs gtk+-2.0 "
fi
-if test "x$comp_mgr" = "xyes"; then
- needed_pkgs="$needed_pkgs xcomposite xdamage "
-fi
+case $comp_mgr in
+ yes | default ) comp_mgr="yes (default)"
+ needed_pkgs="$needed_pkgs xcomposite xdamage " ;;
+
+ clutter ) comp_mgr="yes (clutter)"
+ needed_pkgs="$needed_pkgs clutter-0.5 xcomposite xdamage "
+ gmloop="yes" ;;
+
+ * ) comp_mgr = no ;;
+esac
if test "x$want_debug" = "xyes"; then
MBWM_DEBUG_CFLAGS="-O0 $MBWM_DEBUG_CFLAGS -DMBWM_WANT_DEBUG"
@@ -85,11 +92,16 @@ if test "$use_gtk" = yes; then
AC_DEFINE(USE_GTK, 1, [GTK Integration])
fi
-AM_CONDITIONAL(ENABLE_COMPOSITE, [test "x$comp_mgr" = "xyes"])
-if test "$comp_mgr" = yes; then
+AM_CONDITIONAL(ENABLE_COMPOSITE, [test "x$comp_mgr" != "xno"])
+if test "$comp_mgr" != no; then
AC_DEFINE(ENABLE_COMPOSITE, 1, [Enable composite manager code])
fi
+AM_CONDITIONAL(USE_CLUTTER, [test "x$comp_mgr" = "xyes (clutter)"])
+if test "$comp_mgr" = "yes (clutter)"; then
+ AC_DEFINE(USE_CLUTTER, 1, [Use clutter for compositing])
+fi
+
AC_ARG_ENABLE(simple-manager,
[ --disable-simple-manager Do not build simple window manager],
[simple_manager=$enableval], [simple_manager=yes])
diff --git a/data/themes/Default/theme.xml b/data/themes/Default/theme.xml
index d7edbe5..95f9ab9 100644
--- a/data/themes/Default/theme.xml
+++ b/data/themes/Default/theme.xml
@@ -3,7 +3,7 @@
desc="" version="1.0" engine-version="2" engine-type="default"
shadow-type="gaussian" >
<img src="test.png" />
-<client type="app">
+<client type="app" effects="minimize:300|scale-down">
<decor type="north" clr-bg="#ff0000" clr-bg2="#ffffff" clr-fg="#ffffff"
height="22" font-family="Sans" font-size="18" clr-frame="#000000">
<button type="close" packing="end" clr-fg="#ffffff" clr-bg="#59595f"
diff --git a/src/comp-mgr/Makefile.am b/src/comp-mgr/Makefile.am
index e68de34..44c0ebd 100644
--- a/src/comp-mgr/Makefile.am
+++ b/src/comp-mgr/Makefile.am
@@ -1,12 +1,26 @@
noinst_LIBRARIES = libmatchbox-window-manager-2-compmgr.a
-core_h = mb-wm-comp-mgr.h \
- mb-wm-comp-mgr-default.h
+core_h = mb-wm-comp-mgr.h
-core_c = mb-wm-comp-mgr.c \
- mb-wm-comp-mgr-default.c
+if USE_CLUTTER
+clutter_h = mb-wm-comp-clutter.h
+else
+default_h = mb-wm-comp-mgr-default.h
+endif
+
+core_c = mb-wm-comp-mgr.c
+
+
+if USE_CLUTTER
+clutter_c = mb-wm-comp-mgr-clutter.c
+else
+default_c = mb-wm-comp-mgr-default.c
+endif
+
+libmatchbox_window_manager_2_compmgr_a_SOURCES = $(core_h) $(core_c) \
+ $(default_h) $(default_c) \
+ $(clutter_h) $(clutter_c)
-libmatchbox_window_manager_2_compmgr_a_SOURCES = $(core_h) $(core_c)
libmatchbox_window_manager_2_compmgr_a_CFLAGS = @MBWM_INCS@ @MBWM_CFLAGS@
MAINTAINERCLEANFILES = Makefile.in \ No newline at end of file
diff --git a/src/comp-mgr/mb-wm-comp-mgr-clutter.c b/src/comp-mgr/mb-wm-comp-mgr-clutter.c
new file mode 100644
index 0000000..a7bad35
--- /dev/null
+++ b/src/comp-mgr/mb-wm-comp-mgr-clutter.c
@@ -0,0 +1,1144 @@
+/*
+ * 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 <clutter/clutter.h>
+#include <clutter/clutter-x11.h>
+#include <clutter/clutter-x11-texture-pixmap.h>
+#include <clutter/clutter-glx-texture-pixmap.h>
+
+#include <X11/Xresource.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xrender.h>
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/shape.h>
+
+static void
+mb_wm_comp_mgr_clutter_add_actor (MBWMCompMgrClutter * , ClutterActor *);
+
+/*
+ * A helper object to store manager's per-client data
+ */
+struct MBWMCompMgrClutterClient
+{
+ MBWMCompMgrClient parent;
+ ClutterActor * actor;
+ Pixmap pixmap;
+ int pxm_width;
+ int pxm_height;
+ int pxm_depth;
+ Bool mapped;
+ Damage damage;
+
+ /* 1-based array holding timelines for effect events */
+ ClutterTimeline * timelines[_MBWMCompMgrEffectEventLast-1];
+};
+
+static void
+mb_wm_comp_mgr_clutter_client_show_real (MBWMCompMgrClient * client);
+
+static void
+mb_wm_comp_mgr_clutter_client_hide_real (MBWMCompMgrClient * client);
+
+static void
+mb_wm_comp_mgr_clutter_client_repair_real (MBWMCompMgrClient * client);
+
+static void
+mb_wm_comp_mgr_clutter_client_configure_real (MBWMCompMgrClient * client);
+
+static MBWMCompMgrEffect *
+mb_wm_comp_mgr_clutter_client_effect_new_real (MBWMCompMgrClient *client,
+ MBWMCompMgrEffectEvent event,
+ MBWMCompMgrEffectType type,
+ unsigned long duration);
+static void
+mb_wm_comp_mgr_clutter_client_class_init (MBWMObjectClass *klass)
+{
+ MBWMCompMgrClientClass *c_klass = MB_WM_COMP_MGR_CLIENT_CLASS (klass);
+
+ c_klass->show = mb_wm_comp_mgr_clutter_client_show_real;
+ c_klass->hide = mb_wm_comp_mgr_clutter_client_hide_real;
+ c_klass->repair = mb_wm_comp_mgr_clutter_client_repair_real;
+ c_klass->configure = mb_wm_comp_mgr_clutter_client_configure_real;
+ c_klass->effect_new = mb_wm_comp_mgr_clutter_client_effect_new_real;
+
+#ifdef MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMCompMgrClutterClient";
+#endif
+}
+
+/*
+ * Fetch the entire texture for our client
+ */
+static void
+mb_wm_comp_mgr_clutter_fetch_texture (MBWMCompMgrClient *client)
+{
+ MBWMCompMgrClutterClient *cclient = MB_WM_COMP_MGR_CLUTTER_CLIENT (client);
+ MBWindowManagerClient *wm_client = client->wm_client;
+ MBWindowManager *wm = wm_client->wmref;
+ Window xwin;
+ Window root;
+ int x, y, w, h, bw, depth;
+
+ if (!cclient->mapped)
+ return;
+
+ xwin =
+ wm_client->xwin_frame ? wm_client->xwin_frame : wm_client->window->xwindow;
+
+ if (cclient->pixmap)
+ XFreePixmap (wm->xdpy, cclient->pixmap);
+
+ cclient->pixmap = XCompositeNameWindowPixmap (wm->xdpy, xwin);
+
+ if (!cclient->pixmap)
+ return;
+
+ XGetGeometry (wm->xdpy, cclient->pixmap, &root, &x, &y, &w, &h, &bw, &depth);
+
+ cclient->pxm_width = w;
+ cclient->pxm_height = h;
+ cclient->pxm_depth = depth;
+
+ clutter_actor_set_size (cclient->actor, w, h);
+
+ clutter_x11_texture_pixmap_set_pixmap (
+ CLUTTER_X11_TEXTURE_PIXMAP (cclient->actor),
+ cclient->pixmap,
+ w, h, depth);
+}
+
+/*
+ * Update region x,y,width x height in our client texture.
+ */
+static void
+mb_wm_comp_mgr_clutter_update_texture (MBWMCompMgrClient *client,
+ int x, int y, int width, int height)
+{
+ MBWMCompMgrClutterClient *cclient = MB_WM_COMP_MGR_CLUTTER_CLIENT (client);
+ MBWindowManagerClient *wm_client = client->wm_client;
+ MBWindowManager *wm = wm_client->wmref;
+
+ if (!cclient->mapped)
+ return;
+
+ if (!cclient->pixmap)
+ {
+ mb_wm_comp_mgr_clutter_fetch_texture (client);
+ return;
+ }
+
+ clutter_x11_texture_pixmap_update_area (
+ CLUTTER_X11_TEXTURE_PIXMAP (cclient->actor),
+ x, y, width, height);
+}
+
+static int
+mb_wm_comp_mgr_clutter_client_init (MBWMObject *obj, va_list vap)
+{
+ return 1;
+}
+
+static void
+mb_wm_comp_mgr_clutter_client_destroy (MBWMObject* obj)
+{
+ MBWMCompMgrClient * c = MB_WM_COMP_MGR_CLIENT (obj);
+ MBWMCompMgrClutterClient * cc = MB_WM_COMP_MGR_CLUTTER_CLIENT (obj);
+ MBWindowManager * wm = c->wm_client->wmref;
+
+ mb_wm_comp_mgr_client_hide (c);
+
+ if (cc->actor)
+ g_object_unref (cc->actor);
+
+ if (cc->pixmap)
+ XFreePixmap (wm->xdpy, cc->pixmap);
+
+ if (cc->damage)
+ XDamageDestroy (wm->xdpy, cc->damage);
+}
+
+int
+mb_wm_comp_mgr_clutter_client_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMCompMgrClutterClientClass),
+ sizeof (MBWMCompMgrClutterClient),
+ mb_wm_comp_mgr_clutter_client_init,
+ mb_wm_comp_mgr_clutter_client_destroy,
+ mb_wm_comp_mgr_clutter_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 *
+mb_wm_comp_mgr_clutter_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
+mb_wm_comp_mgr_clutter_client_hide_real (MBWMCompMgrClient * client)
+{
+ MBWMCompMgrClutterClient * cclient = MB_WM_COMP_MGR_CLUTTER_CLIENT (client);
+
+ clutter_actor_hide (cclient->actor);
+}
+
+/*
+ * Helper function for manipulating damage. Gets the extents of this client,
+ * expressed as XserverRegion.
+ */
+static XserverRegion
+mb_wm_comp_mgr_clutter_client_extents (MBWMCompMgrClient *client)
+{
+ MBWindowManagerClient *wm_client = client->wm_client;
+ MBWindowManager *wm = wm_client->wmref;
+ MBGeometry geom;
+ XRectangle r;
+ XserverRegion extents;
+
+ mb_wm_client_get_coverage (wm_client, &geom);
+
+ r.x = geom.x;
+ r.y = geom.y;
+ r.width = geom.width;
+ r.height = geom.height;
+
+ extents = XFixesCreateRegion (wm->xdpy, &r, 1);
+
+ return extents;
+}
+
+/*
+ * Adds region damage to the overall damage of the client.
+ */
+static void
+mb_wm_comp_mgr_clutter_client_add_damage (MBWMCompMgrClutterClient * cclient,
+ XserverRegion damage)
+{
+ MBWindowManagerClient *wm_client =
+ MB_WM_COMP_MGR_CLIENT (cclient)->wm_client;
+ MBWindowManager *wm = wm_client->wmref;
+
+ XFixesUnionRegion (wm->xdpy,
+ cclient->damage,
+ cclient->damage,
+ damage);
+
+ XFixesDestroyRegion (wm->xdpy, damage);
+
+ mb_wm_display_sync_queue (wm, MBWMSyncVisibility);
+}
+
+static void
+mb_wm_comp_mgr_clutter_client_show_real (MBWMCompMgrClient * client)
+{
+ MBWMCompMgrClutterClient * cclient = MB_WM_COMP_MGR_CLUTTER_CLIENT (client);
+ MBGeometry geom;
+ XserverRegion region;
+ MBWindowManagerClient *wm_client =
+ MB_WM_COMP_MGR_CLIENT (cclient)->wm_client;
+ MBWindowManager *wm = wm_client->wmref;
+
+ MBWM_NOTE (COMPOSITOR, "showing client");
+
+ if (!cclient->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;
+ }
+
+ if (!cclient->damage)
+ cclient->damage = XDamageCreate (wm->xdpy,
+ wm_client->xwin_frame ?
+ wm_client->xwin_frame :
+ wm_client->window->xwindow,
+ XDamageReportNonEmpty);
+
+ /*
+ * FIXME -- is it really necessary to invalidate the entire client area
+ * here ?
+ */
+ region = mb_wm_comp_mgr_clutter_client_extents (client);
+
+ mb_wm_comp_mgr_clutter_client_add_damage (cclient, region);
+
+ clutter_actor_show (cclient->actor);
+}
+
+static MBWMCompMgrEffect *
+mb_wm_comp_mgr_clutter_effect_new (MBWMCompMgrEffectType type,
+ unsigned long duration,
+ ClutterTimeline * timeline,
+ ClutterBehaviour * behaviour);
+
+/*
+ * Helper method to get a timeline for given event (all effects associated with
+ * the same event share a single timeline.
+ */
+static ClutterTimeline *
+mb_wm_comp_mgr_clutter_client_get_timeline (MBWMCompMgrClient *client,
+ MBWMCompMgrEffectEvent event,
+ unsigned long duration)
+{
+ MBWMCompMgrClutterClient * cclient = MB_WM_COMP_MGR_CLUTTER_CLIENT (client);
+
+ if (!client || event >= _MBWMCompMgrEffectEventLast)
+ return NULL;
+
+ if (!cclient->timelines[event-1])
+ {
+ cclient->timelines[event-1] =
+ clutter_timeline_new_for_duration (duration);
+ }
+
+ return cclient->timelines[event-1];
+}
+
+/*
+ * Implementation of the MBWMCompMgrClient->effect_new() method.
+ */
+static MBWMCompMgrEffect *
+mb_wm_comp_mgr_clutter_client_effect_new_real (MBWMCompMgrClient *client,
+ MBWMCompMgrEffectEvent event,
+ MBWMCompMgrEffectType type,
+ unsigned long duration)
+{
+ MBWMCompMgrEffect * eff;
+ ClutterTimeline * timeline;
+ ClutterBehaviour * behaviour;
+ ClutterAlpha * alpha;
+ MBWMCompMgrClutterClient * cclient = MB_WM_COMP_MGR_CLUTTER_CLIENT (client);
+
+ timeline =
+ mb_wm_comp_mgr_clutter_client_get_timeline (client, event, duration);
+
+ if (!timeline)
+ return NULL;
+
+ alpha = clutter_alpha_new_full (timeline,
+ CLUTTER_ALPHA_RAMP_INC, NULL, NULL);
+
+ switch (type)
+ {
+ case MBWMCompMgrEffectScaleUp:
+ behaviour =
+ clutter_behaviour_scale_newx (alpha, 0, 0, CFX_ONE, CFX_ONE);
+ break;
+ case MBWMCompMgrEffectScaleDown:
+ behaviour =
+ clutter_behaviour_scale_newx (alpha, CFX_ONE, CFX_ONE, 0, 0);
+ break;
+ case MBWMCompMgrEffectSpinXCW:
+ behaviour = clutter_behaviour_rotate_newx (alpha,
+ CLUTTER_X_AXIS,
+ CLUTTER_ROTATE_CW,
+ 0,
+ CLUTTER_INT_TO_FIXED (360));
+ break;
+ case MBWMCompMgrEffectSpinXCCW:
+ behaviour = clutter_behaviour_rotate_newx (alpha,
+ CLUTTER_X_AXIS,
+ CLUTTER_ROTATE_CCW,
+ 0,
+ CLUTTER_INT_TO_FIXED (360));
+ break;
+ case MBWMCompMgrEffectSpinYCW:
+ behaviour = clutter_behaviour_rotate_newx (alpha,
+ CLUTTER_Y_AXIS,
+ CLUTTER_ROTATE_CW,
+ 0,
+ CLUTTER_INT_TO_FIXED (360));
+ break;
+ case MBWMCompMgrEffectSpinYCCW:
+ behaviour = clutter_behaviour_rotate_newx (alpha,
+ CLUTTER_Y_AXIS,
+ CLUTTER_ROTATE_CCW,
+ 0,
+ CLUTTER_INT_TO_FIXED (360));
+ break;
+ case MBWMCompMgrEffectSpinZCW:
+ behaviour = clutter_behaviour_rotate_newx (alpha,
+ CLUTTER_Z_AXIS,
+ CLUTTER_ROTATE_CW,
+ 0,
+ CLUTTER_INT_TO_FIXED (360));
+ break;
+ case MBWMCompMgrEffectSpinZCCW:
+ behaviour = clutter_behaviour_rotate_newx (alpha,
+ CLUTTER_Z_AXIS,
+ CLUTTER_ROTATE_CCW,
+ 0,
+ CLUTTER_INT_TO_FIXED (360));
+ break;
+ case MBWMCompMgrEffectFade:
+ behaviour = clutter_behaviour_opacity_new (alpha, 0xff, 0);
+ break;
+ case MBWMCompMgrEffectUnfade:
+ behaviour = clutter_behaviour_opacity_new (alpha, 0, 0xff);
+ break;
+
+ /* FIXME -- add the path behaviours here */
+ case MBWMCompMgrEffectSlideN:
+ break;
+ case MBWMCompMgrEffectSlideS:
+ break;
+ case MBWMCompMgrEffectSlideE:
+ break;
+ case MBWMCompMgrEffectSlideW:
+ break;
+ case MBWMCompMgrEffectSlideNW:
+ break;
+ case MBWMCompMgrEffectSlideNE:
+ break;
+ case MBWMCompMgrEffectSlideSW:
+ break;
+ case MBWMCompMgrEffectSlideSE:
+ break;
+ default:
+ ;
+ }
+
+ eff =
+ mb_wm_comp_mgr_clutter_effect_new (type, duration, timeline, behaviour);
+
+ if (eff)
+ {
+ /*
+ * We assume that the actor already exists -- if not, clutter will
+ * issue a warning here
+ */
+ clutter_behaviour_apply (behaviour, cclient->actor);
+ }
+
+ return eff;
+}
+
+/*
+ * Implementation of MBWMCompMgrClutter
+ */
+struct MBWMCompMgrClutterPrivate
+{
+ ClutterActor * stage;
+ Window overlay_window;
+ int damage_event;
+};
+
+static void
+mb_wm_comp_mgr_clutter_private_free (MBWMCompMgrClutter *mgr)
+{
+ MBWMCompMgrClutterPrivate * priv = mgr->priv;
+ free (priv);
+}
+
+static void
+mb_wm_comp_mgr_clutter_register_client_real (MBWMCompMgr * mgr,
+ MBWindowManagerClient * c)
+{
+ MBWMCompMgrClient *cc;
+ MBWMCompMgrClutter *cmgr = MB_WM_COMP_MGR_CLUTTER (mgr);
+
+ if (c->cm_client)
+ return;
+
+ cc = mb_wm_comp_mgr_clutter_client_new (c);
+ c->cm_client = cc;
+}
+
+static void
+mb_wm_comp_mgr_clutter_unregister_client_real (MBWMCompMgr * mgr,
+ MBWindowManagerClient * client)
+{
+ if (!client || !client->cm_client)
+ return;
+
+ mb_wm_object_unref (MB_WM_OBJECT (client->cm_client));
+ client->cm_client = NULL;
+}
+
+static void
+mb_wm_comp_mgr_clutter_turn_on_real (MBWMCompMgr *mgr);
+
+static void
+mb_wm_comp_mgr_clutter_turn_off_real (MBWMCompMgr *mgr);
+
+static void
+mb_wm_comp_mgr_clutter_render_real (MBWMCompMgr *mgr);
+
+static void
+mb_wm_comp_mgr_clutter_map_notify_real (MBWMCompMgr *mgr,
+ MBWindowManagerClient *c);
+
+static Bool
+mb_wm_comp_mgr_clutter_handle_events_real (MBWMCompMgr * mgr, XEvent *ev);
+
+static Bool
+mb_wm_comp_mgr_is_my_window_real (MBWMCompMgr * mgr, Window xwin);
+
+static void
+mb_wm_comp_mgr_clutter_class_init (MBWMObjectClass *klass)
+{
+ MBWMCompMgrClass *cm_klass = MB_WM_COMP_MGR_CLASS (klass);
+
+#ifdef MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMCompMgrClutter";
+#endif
+
+ cm_klass->register_client = mb_wm_comp_mgr_clutter_register_client_real;
+ cm_klass->unregister_client = mb_wm_comp_mgr_clutter_unregister_client_real;
+ cm_klass->turn_on = mb_wm_comp_mgr_clutter_turn_on_real;
+ cm_klass->turn_off = mb_wm_comp_mgr_clutter_turn_off_real;
+ cm_klass->render = mb_wm_comp_mgr_clutter_render_real;
+ cm_klass->map_notify = mb_wm_comp_mgr_clutter_map_notify_real;
+ cm_klass->handle_events = mb_wm_comp_mgr_clutter_handle_events_real;
+ cm_klass->my_window = mb_wm_comp_mgr_is_my_window_real;
+}
+
+/*
+ * Initializes the extension require by the manager
+ */
+static Bool
+mb_wm_comp_mgr_clutter_init_extensions (MBWMCompMgr *mgr)
+{
+ MBWindowManager * wm = mgr->wm;
+ MBWMCompMgrClutterPrivate * priv = MB_WM_COMP_MGR_CLUTTER (mgr)->priv;
+ int event_base, error_base;
+ int damage_error;
+ int xfixes_event, xfixes_error;
+
+ if (!XCompositeQueryExtension (wm->xdpy, &event_base, &error_base))
+ {
+ fprintf (stderr, "matchbox: No composite extension\n");
+ return False;
+ }
+
+ if (!XDamageQueryExtension (wm->xdpy, &priv->damage_event, &damage_error))
+ {
+ fprintf (stderr, "matchbox: No damage extension\n");
+ return False;
+ }
+
+ if (!XFixesQueryExtension (wm->xdpy, &xfixes_event, &xfixes_error))
+ {
+ fprintf (stderr, "matchbox: No XFixes extension\n");
+ return False;
+ }
+
+ XCompositeRedirectSubwindows (wm->xdpy, wm->root_win->xwindow,
+ CompositeRedirectManual);
+
+ return True;
+}
+
+static int
+mb_wm_comp_mgr_clutter_init (MBWMObject *obj, va_list vap)
+{
+ MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj);
+ MBWMCompMgrClutter * cmgr = MB_WM_COMP_MGR_CLUTTER (obj);
+ MBWMCompMgrClutterPrivate * priv;
+
+ priv = mb_wm_util_malloc0 (sizeof (MBWMCompMgrClutterPrivate));
+ cmgr->priv = priv;
+
+ if (!mb_wm_comp_mgr_clutter_init_extensions (mgr))
+ return 0;
+
+ priv->stage = clutter_stage_get_default ();
+
+ return 1;
+}
+
+static void
+mb_wm_comp_mgr_clutter_destroy (MBWMObject * obj)
+{
+ MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj);
+ MBWMCompMgrClutter * cmgr = MB_WM_COMP_MGR_CLUTTER (obj);
+
+ mb_wm_comp_mgr_turn_off (mgr);
+ mb_wm_comp_mgr_clutter_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),
+ mb_wm_comp_mgr_clutter_init,
+ mb_wm_comp_mgr_clutter_destroy,
+ mb_wm_comp_mgr_clutter_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_COMP_MGR, 0);
+ }
+
+ return type;
+}
+
+/* Shuts the compositing down */
+static void
+mb_wm_comp_mgr_clutter_turn_off_real (MBWMCompMgr *mgr)
+{
+ MBWindowManager * wm = mgr->wm;
+ MBWMCompMgrClutterPrivate * priv;
+
+ if (!mgr)
+ return;
+
+ priv = MB_WM_COMP_MGR_CLUTTER (mgr)->priv;
+
+ if (mgr->disabled)
+ return;
+
+ if (!mb_wm_stack_empty (wm))
+ {
+ MBWindowManagerClient * c;
+
+ mb_wm_stack_enumerate (wm, c)
+ {
+ mb_wm_comp_mgr_clutter_unregister_client_real (mgr, c);
+ }
+ }
+
+ XCompositeReleaseOverlayWindow (wm->xdpy, wm->root_win->xwindow);
+ priv->overlay_window = None;
+
+ mgr->disabled = True;
+}
+
+static void
+mb_wm_comp_mgr_clutter_turn_on_real (MBWMCompMgr *mgr)
+{
+ MBWindowManager * wm;
+ MBWMCompMgrClutterPrivate * priv;
+
+ if (!mgr || !mgr->disabled)
+ return;
+
+ priv = MB_WM_COMP_MGR_CLUTTER (mgr)->priv;
+ wm = mgr->wm;
+
+ mgr->disabled = False;
+
+ if (priv->overlay_window == None)
+ {
+ ClutterActor * stage = priv->stage;
+#ifdef MBWM_WANT_DEBUG
+ /*
+ * Special colour to please Iain's eyes ;)
+ */
+ ClutterColor clr = {0xff, 0, 0xff, 0xff };
+#else
+ ClutterColor clr = {0, 0, 0, 0xff };
+#endif
+ 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);
+ }
+
+ /*
+ * Take care of any pre-existing windows
+ */
+ if (!mb_wm_stack_empty (wm))
+ {
+ MBWindowManagerClient * c;
+
+ mb_wm_stack_enumerate (wm, c)
+ {
+ mb_wm_comp_mgr_clutter_register_client_real (mgr, c);
+
+ /*
+ * Need to call map_notify here manually, since we will have missed
+ * the original map notification when this client mapped, and
+ * we relly on it to create our actor.
+ */
+ mb_wm_comp_mgr_clutter_map_notify_real (mgr, c);
+ }
+ }
+}
+
+static void
+mb_wm_comp_mgr_clutter_client_repair_real (MBWMCompMgrClient * client)
+{
+ MBWindowManagerClient * wm_client = client->wm_client;
+ MBWMCompMgrClutterClient * cclient = MB_WM_COMP_MGR_CLUTTER_CLIENT (client);
+
+ MBWM_NOTE (COMPOSITOR, "REPAIRING %x", wm_client->window->xwindow);
+
+ if (!cclient->actor)
+ return;
+
+ XDamageSubtract (wm_client->wmref->xdpy,
+ cclient->damage, None, None );
+
+ mb_wm_comp_mgr_clutter_fetch_texture (client);
+}
+
+static void
+mb_wm_comp_mgr_clutter_client_configure_real (MBWMCompMgrClient * client)
+{
+ MBWindowManagerClient * wm_client = client->wm_client;
+ MBWMCompMgrClutterClient * cclient = MB_WM_COMP_MGR_CLUTTER_CLIENT (client);
+
+ MBWM_NOTE (COMPOSITOR, "CONFIGURE request");
+
+ mb_wm_comp_mgr_clutter_fetch_texture (client);
+}
+
+static Bool
+mb_wm_comp_mgr_clutter_handle_events_real (MBWMCompMgr * mgr, XEvent *ev)
+{
+ MBWMCompMgrClutterPrivate * priv = MB_WM_COMP_MGR_CLUTTER (mgr)->priv;
+ MBWindowManager * wm = mgr->wm;
+
+ if (ev->type == priv->damage_event + XDamageNotify)
+ {
+ XDamageNotifyEvent * de = (XDamageNotifyEvent*) ev;
+ MBWindowManagerClient * c;
+
+ c = mb_wm_managed_client_from_frame (wm, de->drawable);
+
+ if (c && c->cm_client)
+ {
+ XserverRegion parts;
+ int i, r_count;
+ XRectangle * r_damage;
+ XRectangle r_bounds;
+
+ MBWMCompMgrClutterClient *cclient =
+ MB_WM_COMP_MGR_CLUTTER_CLIENT (c->cm_client);
+
+ if (!cclient->actor)
+ return False;
+
+ /* FIXME -- see if we can make some use of the 'more' parameter
+ * to compress the damage events
+ */
+ 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);
+
+ /*
+ * 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, de->damage, None, parts);
+
+ r_damage = XFixesFetchRegionAndBounds (wm->xdpy, parts,
+ &r_count,
+ &r_bounds);
+
+ if (r_damage)
+ {
+ for (i = 0; i < r_count; ++i)
+ {
+ mb_wm_comp_mgr_clutter_update_texture (c->cm_client,
+ r_damage[i].x,
+ r_damage[i].y,
+ r_damage[i].width,
+ r_damage[i].height);
+ }
+
+ XFree (r_damage);
+ }
+
+ XFixesDestroyRegion (wm->xdpy, parts);
+ }
+ else
+ {
+ MBWM_NOTE (COMPOSITOR, "Failed to find client for window %x\n",
+ de->drawable);
+ }
+ }
+
+ return False;
+}
+
+static void
+mb_wm_comp_mgr_clutter_render_real (MBWMCompMgr *mgr)
+{
+ MBWMCompMgrClutterPrivate * priv = MB_WM_COMP_MGR_CLUTTER (mgr)->priv;
+ MBWindowManagerClient * wm_client;
+ MBWindowManager * wm = mgr->wm;
+
+ MBWM_NOTE (COMPOSITOR, "Rendering");
+
+ /*
+ * We do not need to do anything, as rendering is done automatically for us
+ * by clutter stage.
+ */
+}
+
+static void
+mb_wm_comp_mgr_clutter_map_notify_real (MBWMCompMgr *mgr,
+ MBWindowManagerClient *c)
+{
+ MBWMCompMgrClutter * cmgr = MB_WM_COMP_MGR_CLUTTER (mgr);
+ MBWMCompMgrClient * client = c->cm_client;
+ MBWMCompMgrClutterClient * cclient = MB_WM_COMP_MGR_CLUTTER_CLIENT (client);
+ ClutterActor *actor;
+ MBGeometry geom;
+ const MBWMList * l;
+
+ /*
+ * We get called for windows as well as their children, so once we are
+ * mapped do nothing.
+ */
+ if (cclient->mapped)
+ return;
+
+ cclient->mapped = True;
+ actor = g_object_ref (clutter_x11_texture_pixmap_new ());
+ cclient->actor = actor;
+
+ l =
+ mb_wm_theme_get_client_effects (c->wmref->theme, c);
+
+ while (l)
+ {
+ MBWMThemeEffects * t_effects = l->data;
+ MBWMList * m_effects;
+
+ m_effects = mb_wm_comp_mgr_client_get_effects (client,
+ t_effects->event,
+ t_effects->type,
+ t_effects->duration);
+
+ mb_wm_comp_mgr_client_add_effects (client, t_effects->event, m_effects);
+ l = l->next;
+ }
+
+
+ g_object_set_data (G_OBJECT (actor), "MBWMCompMgrClutterClient", cclient);
+
+ mb_wm_comp_mgr_clutter_fetch_texture (MB_WM_COMP_MGR_CLIENT (cclient));
+
+ mb_wm_client_get_coverage (c, &geom);
+ clutter_actor_set_position (actor, geom.x, geom.y);
+
+ mb_wm_comp_mgr_clutter_client_show_real (c->cm_client);
+
+ mb_wm_comp_mgr_clutter_add_actor (cmgr, actor);
+}
+
+/*
+ * 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 = MB_WM_COMP_MGR_CLUTTER (mgr)->priv;
+
+ if (priv->overlay_window == xwin)
+ return True;
+
+ if (priv->stage &&
+ (xwin == clutter_x11_get_stage_window (CLUTTER_STAGE (priv->stage))))
+ return True;
+
+ return False;
+}
+
+static void
+mb_wm_comp_mgr_clutter_remove_actor (MBWMCompMgrClutter * cmgr,
+ ClutterActor * a)
+{
+ clutter_container_remove_actor (CLUTTER_CONTAINER (cmgr->priv->stage), a);
+}
+
+static void
+mb_wm_comp_mgr_clutter_add_actor (MBWMCompMgrClutter * cmgr, ClutterActor * a)
+{
+ clutter_container_add_actor (CLUTTER_CONTAINER (cmgr->priv->stage), a);
+}
+
+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);
+}
+
+/*
+ * MBWMCompMgrClutterEffect
+ */
+struct MBWMCompMgrClutterEffect
+{
+ MBWMCompMgrEffect parent;
+ ClutterTimeline *timeline;
+ ClutterBehaviour *behaviour;
+};
+
+struct completed_cb_data
+{
+ MBWMCompMgrEffectCallback completed_cb;
+ void * cb_data;
+ gulong my_id;
+};
+
+
+/*
+ * Callback for ClutterTimeline::completed signal.
+ *
+ * One-off; get connected when the timeline is started, and disconnected
+ * again when it finishes.
+ */
+static void
+mb_wm_comp_mgr_clutter_effect_completed_cb (ClutterTimeline * t, void * data)
+{
+ struct completed_cb_data * d = data;
+
+ if (d->completed_cb)
+ d->completed_cb (d->cb_data);
+
+ g_signal_handler_disconnect (t, d->my_id);
+
+ free (d);
+}
+
+static void
+mb_wm_comp_mgr_clutter_effect_run_real (MBWMList * effects,
+ MBWMCompMgrEffectEvent event,
+ MBWMCompMgrEffectCallback completed_cb,
+ void * data)
+{
+ /*
+ * Since the entire effect group for a single event type shares
+ * a timeline, we just need to start it.
+ *
+ * TODO -- there is no need for the effect objects to carry the timeline
+ * point, so remove it; will need to change this API to take
+ * MBWMCompMgrClient pointer.
+ */
+ if (effects && effects->data)
+ {
+ MBWMCompMgrClutterEffect * eff = effects->data;
+ printf ("^^^^ running effect %p\n", eff);
+
+ if (eff->timeline)
+ {
+ GSList * actors;
+ ClutterActor *a;
+
+ if (completed_cb)
+ {
+ struct completed_cb_data * d =
+ mb_wm_util_malloc0 (sizeof (struct completed_cb_data));
+
+ d->completed_cb = completed_cb;
+ d->cb_data = data;
+
+ d->my_id = g_signal_connect (eff->timeline, "completed",
+ G_CALLBACK (mb_wm_comp_mgr_clutter_effect_completed_cb),
+ d);
+ }
+
+ actors = clutter_behaviour_get_actors (eff->behaviour);
+ a = actors->data;
+
+ clutter_actor_move_anchor_point_from_gravity (a,
+ CLUTTER_GRAVITY_NORTH_EAST);
+
+ clutter_timeline_start (eff->timeline);
+ }
+ }
+}
+
+static void
+mb_wm_comp_mgr_clutter_effect_class_init (MBWMObjectClass *klass)
+{
+ MBWMCompMgrEffectClass *c_klass = MB_WM_COMP_MGR_EFFECT_CLASS (klass);
+
+ c_klass->run = mb_wm_comp_mgr_clutter_effect_run_real;
+
+#ifdef MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMCompMgrClutterEffect";
+#endif
+}
+
+static int
+mb_wm_comp_mgr_clutter_effect_init (MBWMObject *obj, va_list vap)
+{
+ MBWMObjectProp prop;
+ ClutterTimeline *timeline;
+ ClutterBehaviour *behaviour;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropCompMgrClutterEffectTimeline:
+ timeline = va_arg(vap, ClutterTimeline *);
+ break;
+ case MBWMObjectPropCompMgrClutterEffectBehaviour:
+ behaviour = va_arg(vap, ClutterBehaviour *);
+ break;
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ if (!timeline || !behaviour)
+ return 0;
+
+ MB_WM_COMP_MGR_CLUTTER_EFFECT (obj)->timeline = timeline;
+ MB_WM_COMP_MGR_CLUTTER_EFFECT (obj)->behaviour = behaviour;
+
+ return 1;
+}
+
+static void
+mb_wm_comp_mgr_clutter_effect_destroy (MBWMObject* obj)
+{
+ MBWMCompMgrClutterEffect * e = MB_WM_COMP_MGR_CLUTTER_EFFECT (obj);
+
+ if (!e || !e->behaviour)
+ return;
+
+ g_object_unref (e->behaviour);
+ g_object_unref (e->timeline);
+}
+
+int
+mb_wm_comp_mgr_clutter_effect_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMCompMgrClutterEffectClass),
+ sizeof (MBWMCompMgrClutterEffect),
+ mb_wm_comp_mgr_clutter_effect_init,
+ mb_wm_comp_mgr_clutter_effect_destroy,
+ mb_wm_comp_mgr_clutter_effect_class_init
+ };
+
+ type =
+ mb_wm_object_register_class (&info, MB_WM_TYPE_COMP_MGR_EFFECT, 0);
+ }
+
+ return type;
+}
+
+/*
+ * This is private method for use by the manager, hence static.
+ */
+static MBWMCompMgrEffect *
+mb_wm_comp_mgr_clutter_effect_new (MBWMCompMgrEffectType type,
+ unsigned long duration,
+ ClutterTimeline * timeline,
+ ClutterBehaviour * behaviour)
+{
+ MBWMObject *e;
+
+ e =
+ mb_wm_object_new (MB_WM_TYPE_COMP_MGR_CLUTTER_EFFECT,
+ MBWMObjectPropCompMgrEffectType, type,
+ MBWMObjectPropCompMgrEffectDuration, duration,
+ MBWMObjectPropCompMgrClutterEffectTimeline, timeline,
+ MBWMObjectPropCompMgrClutterEffectBehaviour, behaviour,
+ NULL);
+
+ return MB_WM_COMP_MGR_EFFECT (e);
+}
diff --git a/src/comp-mgr/mb-wm-comp-mgr-clutter.h b/src/comp-mgr/mb-wm-comp-mgr-clutter.h
new file mode 100644
index 0000000..9984b6e
--- /dev/null
+++ b/src/comp-mgr/mb-wm-comp-mgr-clutter.h
@@ -0,0 +1,74 @@
+/*
+ * 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
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#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 ())
+
+#define MB_WM_COMP_MGR_CLUTTER_EFFECT(c) ((MBWMCompMgrClutterEffect*)(c))
+#define MB_WM_COMP_MGR_CLUTTER_EFFECT_CLASS(c) ((MBWMCompMgrClutterEffectClass*)(c))
+#define MB_WM_TYPE_COMP_MGR_CLUTTER_EFFECT (mb_wm_comp_mgr_clutter_effect_class_type ())
+
+
+struct MBWMCompMgrClutter
+{
+ MBWMCompMgr parent;
+ MBWMCompMgrClutterPrivate *priv;
+};
+
+struct MBWMCompMgrClutterClass
+{
+ MBWMCompMgrClass parent;
+};
+
+int
+mb_wm_comp_mgr_clutter_class_type ();
+
+MBWMCompMgr*
+mb_wm_comp_mgr_clutter_new (MBWindowManager *wm);
+
+struct MBWMCompMgrClutterClientClass
+{
+ MBWMCompMgrClientClass parent;
+};
+
+int
+mb_wm_comp_mgr_clutter_client_class_type ();
+
+struct MBWMCompMgrClutterEffectClass
+{
+ MBWMCompMgrEffectClass parent;
+};
+
+int
+mb_wm_comp_mgr_clutter_effect_class_type ();
+
+#endif
diff --git a/src/comp-mgr/mb-wm-comp-mgr-default.c b/src/comp-mgr/mb-wm-comp-mgr-default.c
index 0d7a204..067567d 100644
--- a/src/comp-mgr/mb-wm-comp-mgr-default.c
+++ b/src/comp-mgr/mb-wm-comp-mgr-default.c
@@ -48,7 +48,6 @@ struct MBWMCompMgrDefaultClient
Picture picture;
XserverRegion extents;
XserverRegion border_clip;
- Bool is_argb32;
};
static void
@@ -85,19 +84,12 @@ mb_wm_comp_mgr_default_client_init (MBWMObject *obj, va_list vap)
MBWMCompMgrDefaultClient *dclient = MB_WM_COMP_MGR_DEFAULT_CLIENT (obj);
MBWindowManager *wm;
MBWindowManagerClient *wm_client = client->wm_client;
- XRenderPictFormat *format;
if (!wm_client || !wm_client->wmref)
return 0;
wm = wm_client->wmref;
- /* Check visual */
- format = XRenderFindVisualFormat (wm->xdpy, wm_client->window->visual);
-
- if (format && format->type == PictTypeDirect && format->direct.alphaMask)
- dclient->is_argb32 = True;
-
return 1;
}
@@ -235,7 +227,7 @@ mb_wm_comp_mgr_default_client_show_real (MBWMCompMgrClient * client)
wm_client->xwin_frame ?
wm_client->xwin_frame :
wm_client->window->xwindow,
- dclient->is_argb32 ?
+ client->is_argb32 ?
XRenderFindStandardFormat (wm->xdpy,
PictStandardARGB32)
@@ -1421,6 +1413,8 @@ mb_wm_comp_mgr_default_handle_events_real (MBWMCompMgr * mgr, XEvent *ev)
MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
MBWindowManager * wm = mgr->wm;
+ printf ("### got event %d ###\n", ev->type);
+
if (ev->type == priv->damage_event + XDamageNotify)
{
XDamageNotifyEvent * de = (XDamageNotifyEvent*) ev;
@@ -1473,7 +1467,7 @@ _render_a_client (MBWMCompMgrClient * client,
mb_wm_client_get_coverage (wm_client, &geom);
/* Translucency only done for dialogs and overides */
- if ( !dclient->is_argb32 &&
+ if ( !client->is_argb32 &&
(ctype == MBWMClientTypeApp ||
ctype == MBWMClientTypeDesktop ||
ctype == MBWMClientTypeInput ||
@@ -1497,7 +1491,7 @@ _render_a_client (MBWMCompMgrClient * client,
XFixesDestroyRegion (wm->xdpy, winborder);
}
- else if (dclient->is_argb32 ||
+ else if (client->is_argb32 ||
mb_wm_comp_mgr_default_client_get_translucency (client) != -1)
{
/*
@@ -1687,7 +1681,7 @@ mb_wm_comp_mgr_default_render_region (MBWMCompMgr *mgr, XserverRegion region)
if (done &&
(MB_WM_CLIENT_CLIENT_TYPE (wmc_temp) &
(MBWMClientTypeApp | MBWMClientTypeDesktop)) &&
- !MB_WM_COMP_MGR_DEFAULT_CLIENT (wmc_temp->cm_client)->is_argb32 &&
+ !wmc_temp->cm_client->is_argb32 &&
mb_wm_comp_mgr_default_client_get_translucency (wmc_temp->cm_client)
== -1)
{
@@ -1735,7 +1729,7 @@ mb_wm_comp_mgr_default_render_region (MBWMCompMgr *mgr, XserverRegion region)
* We have to process all dialogs and, if the top client is translucent,
* any translucent windows as well.
*/
- is_translucent = (dc->is_argb32 ||
+ is_translucent = (c->is_argb32 ||
mb_wm_comp_mgr_default_client_get_translucency (c)
!= -1);
@@ -1775,7 +1769,7 @@ mb_wm_comp_mgr_default_render_region (MBWMCompMgr *mgr, XserverRegion region)
0, 0, shadow_region);
/* now paint them */
- if (MB_WM_COMP_MGR_DEFAULT_CLIENT (wmc_temp->cm_client)->is_argb32)
+ if (wmc_temp->cm_client->is_argb32)
{
XRenderComposite (wm->xdpy, PictOpOver,
priv->black_picture,
@@ -1823,7 +1817,7 @@ mb_wm_comp_mgr_default_render_region (MBWMCompMgr *mgr, XserverRegion region)
XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer,
0, 0, shadow_region);
- if (dc->is_argb32)
+ if (c->is_argb32)
XRenderComposite (wm->xdpy, PictOpOver,
dc->picture, None,
priv->root_buffer,
diff --git a/src/comp-mgr/mb-wm-comp-mgr-default.h b/src/comp-mgr/mb-wm-comp-mgr-default.h
index 3fb914b..bc5e4ad 100644
--- a/src/comp-mgr/mb-wm-comp-mgr-default.h
+++ b/src/comp-mgr/mb-wm-comp-mgr-default.h
@@ -42,7 +42,7 @@ struct MBWMCompMgrDefault
struct MBWMCompMgrDefaultClass
{
- MBWMCompMgr parent;
+ MBWMCompMgrClass parent;
};
int
@@ -53,7 +53,7 @@ mb_wm_comp_mgr_default_new (MBWindowManager *wm);
struct MBWMCompMgrDefaultClientClass
{
- MBWMObjectClass parent;
+ MBWMCompMgrClientClass parent;
};
int
diff --git a/src/comp-mgr/mb-wm-comp-mgr.c b/src/comp-mgr/mb-wm-comp-mgr.c
index 68fe8ca..5c086f1 100644
--- a/src/comp-mgr/mb-wm-comp-mgr.c
+++ b/src/comp-mgr/mb-wm-comp-mgr.c
@@ -21,6 +21,30 @@
#include "mb-wm.h"
#include "mb-wm-client.h"
#include "mb-wm-comp-mgr.h"
+#include "mb-wm-theme.h"
+
+#include <X11/Xresource.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xrender.h>
+#include <X11/extensions/Xcomposite.h>
+
+typedef struct _MBWMCompMgrEffectAssociation MBWMCompMgrEffectAssociation;
+
+/*
+ * A helper object used to translate the event-effect association defined
+ * by theme into a list of effect instances.
+ */
+struct _MBWMCompMgrEffectAssociation
+{
+ MBWMCompMgrEffectEvent event;
+ MBWMList * effects;
+};
+
+static MBWMCompMgrEffectAssociation *
+mb_wm_comp_mgr_effect_association_new ();
+
+static void
+mb_wm_comp_mgr_effect_association_free (MBWMCompMgrEffectAssociation * a);
static void
mb_wm_comp_mgr_client_class_init (MBWMObjectClass *klass)
@@ -38,6 +62,7 @@ mb_wm_comp_mgr_client_init (MBWMObject *obj, va_list vap)
MBWMCompMgrClient *client = MB_WM_COMP_MGR_CLIENT (obj);
MBWindowManagerClient *wm_client = NULL;
MBWMObjectProp prop;
+ XRenderPictFormat *format;
prop = va_arg(vap, MBWMObjectProp);
while (prop)
@@ -59,12 +84,28 @@ mb_wm_comp_mgr_client_init (MBWMObject *obj, va_list vap)
client->wm_client = wm_client;
+ /* Check visual */
+ format = XRenderFindVisualFormat (wm_client->wmref->xdpy,
+ wm_client->window->visual);
+
+ if (format && format->type == PictTypeDirect && format->direct.alphaMask)
+ client->is_argb32 = True;
+
return 1;
}
static void
mb_wm_comp_mgr_client_destroy (MBWMObject* obj)
{
+ MBWMList * l = MB_WM_COMP_MGR_CLIENT (obj)->effects;
+
+ while (l)
+ {
+ MBWMCompMgrEffectAssociation * a = l->data;
+ mb_wm_comp_mgr_effect_association_free (a);
+
+ l = l->next;
+ }
}
int
@@ -128,6 +169,84 @@ mb_wm_comp_mgr_client_repair (MBWMCompMgrClient * client)
klass->repair (client);
}
+/*
+ * Method for sub-classes to add effects to the (private) list
+ */
+void
+mb_wm_comp_mgr_client_add_effects (MBWMCompMgrClient * client,
+ MBWMCompMgrEffectEvent event,
+ MBWMList * effects)
+{
+ MBWMCompMgr * mgr = client->wm_client->wmref->comp_mgr;
+ MBWMCompMgrEffectAssociation * a;
+
+ MBWM_ASSERT (mgr);
+
+ a = mb_wm_comp_mgr_effect_association_new ();
+
+ a->effects = effects;
+ a->event = event;
+
+ client->effects = mb_wm_util_list_prepend (client->effects, a);
+}
+
+/*
+ * Runs all effects associated with this client for the given events.
+ *
+ * completed_cb is a callback function that will get called when the effect
+ * execution is completed (can be NULL), data is user data that will be passed
+ * to the callback function.
+ *
+ * For exmaple of use see mb_wm_client_iconize().w
+ */
+void
+mb_wm_comp_mgr_client_run_effect (MBWMCompMgrClient * client,
+ MBWMCompMgrEffectEvent event,
+ MBWMCompMgrEffectCallback completed_cb,
+ void * data)
+{
+ MBWMList * l = client->effects;
+ Bool done_effect = False;
+ MBWMCompMgrEffectClass * eklass;
+
+ if (!client)
+ return;
+
+ while (l)
+ {
+ MBWMCompMgrEffectAssociation * a = l->data;
+
+ if (a->event == event)
+ {
+ MBWMList * el = a->effects;
+ MBWMCompMgrEffect * eff = el->data;
+
+ eklass = MB_WM_COMP_MGR_EFFECT_CLASS (MB_WM_OBJECT_GET_CLASS (eff));
+
+ if (!eklass)
+ continue;
+
+ eklass->run (el, event, completed_cb, data);
+ done_effect = True;
+ }
+
+ l = l->next;
+ }
+
+ /*
+ * If there were no effects to run for this event, we manually call
+ * the callback to signal the effect is completed
+ */
+ if (!done_effect)
+ completed_cb (data);
+}
+
+/*
+ * MBWMCompMgr object
+ *
+ * Base class for the composite manager, providing the common interface
+ * through which the manager is access by the MBWindowManager object.
+ */
static void
mb_wm_comp_mgr_class_init (MBWMObjectClass *klass)
{
@@ -206,6 +325,9 @@ mb_wm_comp_mgr_enabled (MBWMCompMgr *mgr)
return True;
}
+/*
+ * Registers new client with the manager (i.e., when a window is created).
+ */
void
mb_wm_comp_mgr_register_client (MBWMCompMgr * mgr,
MBWindowManagerClient * client)
@@ -217,6 +339,9 @@ mb_wm_comp_mgr_register_client (MBWMCompMgr * mgr,
klass->register_client (mgr, client);
}
+/*
+ * Unregisters existing client (e.g., when window unmaps or is destroyed
+ */
void
mb_wm_comp_mgr_unregister_client (MBWMCompMgr * mgr,
MBWindowManagerClient * client)
@@ -228,16 +353,40 @@ mb_wm_comp_mgr_unregister_client (MBWMCompMgr * mgr,
klass->unregister_client (mgr, client);
}
+/*
+ * Called to render the entire composited scene on screen.
+ */
void
mb_wm_comp_mgr_render (MBWMCompMgr *mgr)
{
- MBWMCompMgrClass *klass
- = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+ MBWMCompMgrClass *klass;
+
+ if (!mgr)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
MBWM_ASSERT (klass->render != NULL);
klass->render (mgr);
}
+/*
+ * Called when a window we are interested in maps.
+ */
+void
+mb_wm_comp_mgr_map_notify (MBWMCompMgr *mgr, MBWindowManagerClient *c)
+{
+ MBWMCompMgrClass *klass;
+
+ if (!mgr || !c)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (klass->map_notify)
+ klass->map_notify (mgr, c);
+}
+
void
mb_wm_comp_mgr_turn_on (MBWMCompMgr *mgr)
{
@@ -258,6 +407,10 @@ mb_wm_comp_mgr_turn_off (MBWMCompMgr *mgr)
klass->turn_off (mgr);
}
+/*
+ * Carries out any processing of X events that is specific to the
+ * compositing manager (such as XDamage events).
+ */
Bool
mb_wm_comp_mgr_handle_events (MBWMCompMgr * mgr, XEvent *ev)
{
@@ -268,3 +421,177 @@ mb_wm_comp_mgr_handle_events (MBWMCompMgr * mgr, XEvent *ev)
return klass->handle_events (mgr, ev);
}
+/*
+ * Returns true if the window identified by id xwin is a special window
+ * that belongs to the compositing manager and should, therefore, be left
+ * alone by MBWMWindow manager (e.g., the overalay window).
+ */
+Bool
+mb_wm_comp_mgr_is_my_window (MBWMCompMgr * mgr, Window xwin)
+{
+ MBWMCompMgrClass *klass
+ = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (klass->my_window)
+ return klass->my_window (mgr, xwin);
+
+ return False;
+}
+
+/*
+ * Returns a list of MBWMCompMgrEffect objects of given type that are to be
+ * associated with the given client for the given event. The type parameter
+ * can be made up of more that one MBWMComMgrEffectType value, or-ed.
+ *
+ * This function provides a public API to translate the effects specified
+ * by theme into actual effect instances.
+ */
+MBWMList *
+mb_wm_comp_mgr_client_get_effects (MBWMCompMgrClient * client,
+ MBWMCompMgrEffectEvent event,
+ MBWMCompMgrEffectType type,
+ unsigned long duration)
+{
+ MBWMList *l = NULL;
+ MBWMCompMgrEffectType t = (MBWMCompMgrEffectType) 1;
+ MBWMCompMgrClientClass *klass =
+ MB_WM_COMP_MGR_CLIENT_CLASS (MB_WM_OBJECT_GET_CLASS (client));
+
+ if (!klass->effect_new)
+ return NULL;
+
+ while (t < _MBWMCompMgrEffectLast)
+ {
+ MBWMCompMgrEffect *e = NULL;
+
+ if (t & type)
+ e = klass->effect_new (client, event, t, duration);
+
+ if (e)
+ l = mb_wm_util_list_prepend (l, e);
+
+ t <<= 1;
+ }
+
+ return l;
+}
+
+
+/*
+ * Effect
+ *
+ * Effects are simple one-off transformations carried out on the client in
+ * response to some trigger event. The possible events are given by the
+ * MBWMCompMgrEffectEvent enum, while the nature effect is defined by
+ * MBWMCompMgrEffectType enum; effects are specified per window manager client
+ * type by the theme.
+ *
+ * Events and effect types form a one to many association (and the type
+ * enumeration is or-able).
+ *
+ * The base MBWMCompMgrEffect class provides some common infrastructure,
+ * notably the virtual run() method that needs to be implemented by
+ * the derrived classes.
+ *
+ * NB: the base class does not automatically associate effects with clients;
+ * this is the responsibility of the subclasses, mostly because the sub classes
+ * might want to allocate the effect objects at different times (for example,
+ * the MBWMCompMgrClutterEffect objects cannot be allocated until the
+ * the associated client has created its ClutterActor, which only happens when
+ * the client window maps).
+ */
+static MBWMCompMgrEffectAssociation *
+mb_wm_comp_mgr_effect_association_new ()
+{
+ void * a;
+
+ a = mb_wm_util_malloc0 (sizeof (MBWMCompMgrEffectAssociation));
+
+ return (MBWMCompMgrEffectAssociation*) a;
+}
+
+static void
+mb_wm_comp_mgr_effect_association_free (MBWMCompMgrEffectAssociation * a)
+{
+ MBWMList * l = a->effects;
+
+ while (l)
+ {
+ MBWMCompMgrEffect * e = l->data;
+ mb_wm_object_unref (MB_WM_OBJECT (e));
+
+ l = l->next;
+ }
+
+ free (a);
+}
+
+static void
+mb_wm_comp_mgr_effect_class_init (MBWMObjectClass *klass)
+{
+ MBWMCompMgrEffectClass *c_klass = MB_WM_COMP_MGR_EFFECT_CLASS (klass);
+
+#ifdef MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMCompMgrEffect";
+#endif
+}
+
+static int
+mb_wm_comp_mgr_effect_init (MBWMObject *obj, va_list vap)
+{
+ MBWMObjectProp prop;
+ MBWMCompMgrEffectType type = 0;
+ unsigned long duration = 0;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropCompMgrEffectType:
+ type = va_arg(vap, MBWMCompMgrEffectType);
+ break;
+ case MBWMObjectPropCompMgrEffectDuration:
+ duration = va_arg(vap, unsigned long);
+ break;
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ if (!type)
+ return 0;
+
+ MB_WM_COMP_MGR_EFFECT (obj)->type = type;
+ MB_WM_COMP_MGR_EFFECT (obj)->duration = duration;
+
+ return 1;
+}
+
+static void
+mb_wm_comp_mgr_effect_destroy (MBWMObject* obj)
+{
+}
+
+int
+mb_wm_comp_mgr_effect_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMCompMgrEffectClass),
+ sizeof (MBWMCompMgrEffect),
+ mb_wm_comp_mgr_effect_init,
+ mb_wm_comp_mgr_effect_destroy,
+ mb_wm_comp_mgr_effect_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
diff --git a/src/comp-mgr/mb-wm-comp-mgr.h b/src/comp-mgr/mb-wm-comp-mgr.h
index 7236a15..80bf00c 100644
--- a/src/comp-mgr/mb-wm-comp-mgr.h
+++ b/src/comp-mgr/mb-wm-comp-mgr.h
@@ -31,6 +31,10 @@
#define MB_WM_COMP_MGR_CLIENT_CLASS(c) ((MBWMCompMgrClientClass*)(c))
#define MB_WM_TYPE_COMP_MGR_CLIENT (mb_wm_comp_mgr_client_class_type ())
+#define MB_WM_COMP_MGR_EFFECT(c) ((MBWMCompMgrEffect*)(c))
+#define MB_WM_COMP_MGR_EFFECT_CLASS(c) ((MBWMCompMgrEffectClass*)(c))
+#define MB_WM_TYPE_COMP_MGR_EFFECT (mb_wm_comp_mgr_effect_class_type ())
+
struct MBWMCompMgr
{
MBWMObject parent;
@@ -48,7 +52,9 @@ struct MBWMCompMgrClass
void (*turn_on) (MBWMCompMgr * mgr);
void (*turn_off) (MBWMCompMgr * mgr);
void (*render) (MBWMCompMgr * mgr);
+ void (*map_notify) (MBWMCompMgr * mgr, MBWindowManagerClient *c);
Bool (*handle_events) (MBWMCompMgr * mgr, XEvent *ev);
+ Bool (*my_window) (MBWMCompMgr * mgr, Window xwin);
};
int
@@ -70,17 +76,27 @@ mb_wm_comp_mgr_turn_on (MBWMCompMgr *mgr);
void
mb_wm_comp_mgr_render (MBWMCompMgr *mgr);
+void
+mb_wm_comp_mgr_map_notify (MBWMCompMgr *mgr, MBWindowManagerClient *c);
+
Bool
mb_wm_comp_mgr_enabled (MBWMCompMgr *mgr);
Bool
mb_wm_comp_mgr_handle_events (MBWMCompMgr * mgr, XEvent *ev);
+Bool
+mb_wm_comp_mgr_is_my_window (MBWMCompMgr * mgr, Window xwin);
+
struct MBWMCompMgrClient
{
MBWMObject parent;
MBWindowManagerClient * wm_client;
+
+ /* Make private ? */
+ MBWMList * effects; /* List of MBWMCompMgrEffectAssociation */
+ Bool is_argb32;
};
struct MBWMCompMgrClientClass
@@ -89,8 +105,14 @@ struct MBWMCompMgrClientClass
void (*show) (MBWMCompMgrClient * client);
void (*hide) (MBWMCompMgrClient * client);
- void (*repair) (MBWMCompMgrClient * client);
- void (*configure) (MBWMCompMgrClient * client);
+ void (*repair) (MBWMCompMgrClient * client);
+ void (*configure) (MBWMCompMgrClient * client);
+
+ MBWMCompMgrEffect * (*effect_new) (MBWMCompMgrClient * client,
+ MBWMCompMgrEffectEvent event,
+ MBWMCompMgrEffectType type,
+ unsigned long duration);
+
};
int
@@ -108,4 +130,44 @@ mb_wm_comp_mgr_client_repair (MBWMCompMgrClient * client);
void
mb_wm_comp_mgr_client_configure (MBWMCompMgrClient * client);
+void
+mb_wm_comp_mgr_client_add_effects (MBWMCompMgrClient * client,
+ MBWMCompMgrEffectEvent event,
+ MBWMList * effects);
+
+void
+mb_wm_comp_mgr_client_run_effect (MBWMCompMgrClient * client,
+ MBWMCompMgrEffectEvent event,
+ MBWMCompMgrEffectCallback completed_cb,
+ void * data);
+
+MBWMList *
+mb_wm_comp_mgr_client_get_effects (MBWMCompMgrClient * client,
+ MBWMCompMgrEffectEvent event,
+ MBWMCompMgrEffectType type,
+ unsigned long duration);
+
+/*
+ * Generic effect that can applied to a client
+ */
+struct MBWMCompMgrEffect
+{
+ MBWMObject parent;
+ MBWMCompMgrEffectType type;
+ unsigned long duration;
+};
+
+struct MBWMCompMgrEffectClass
+{
+ MBWMObjectClass parent;
+
+ void (*run) (MBWMList * effects,
+ MBWMCompMgrEffectEvent event,
+ MBWMCompMgrEffectCallback completed_cb,
+ void * data);
+};
+
+int
+mb_wm_comp_mgr_effect_class_type ();
+
#endif
diff --git a/src/core/mb-window-manager.c b/src/core/mb-window-manager.c
index 80ca340..415c182 100644
--- a/src/core/mb-window-manager.c
+++ b/src/core/mb-window-manager.c
@@ -9,9 +9,14 @@
#include "../theme-engines/mb-wm-theme.h"
#ifdef ENABLE_COMPOSITE
-#include "mb-wm-comp-mgr.h"
-#include "mb-wm-comp-mgr-default.h"
-#include "../client-types/mb-wm-client-override.h"
+# include "mb-wm-comp-mgr.h"
+# ifdef USE_CLUTTER
+# include <clutter/clutter-x11.h>
+# include "mb-wm-comp-mgr-clutter.h"
+# else
+# include "mb-wm-comp-mgr-default.h"
+# endif
+# include "../client-types/mb-wm-client-override.h"
#endif
#include <stdarg.h>
@@ -29,7 +34,7 @@
#include <X11/cursorfont.h>
static void
-mb_wm_process_cmdline (MBWindowManager *wm, int argc, char **argv);
+mb_wm_process_cmdline (MBWindowManager *wm);
static void
mb_wm_focus_client (MBWindowManager *wm, MBWindowManagerClient *client);
@@ -40,8 +45,9 @@ mb_wm_activate_client_real (MBWindowManager * wm, MBWindowManagerClient *c);
static void
mb_wm_update_root_win_rectangles (MBWindowManager *wm);
-static MBWindowManagerClient *
-mb_wm_is_my_window (MBWindowManager *wm, Window xwin);
+static Bool
+mb_wm_is_my_window (MBWindowManager *wm, Window xwin,
+ MBWindowManagerClient **client);
static MBWindowManagerClient*
mb_wm_client_new_func (MBWindowManager *wm, MBWMClientWindow *win)
@@ -124,7 +130,11 @@ mb_wm_real_theme_new (MBWindowManager * wm, const char * path)
static MBWMCompMgr *
mb_wm_real_comp_mgr_new (MBWindowManager *wm)
{
+#ifdef USE_CLUTTER
+ return mb_wm_comp_mgr_clutter_new (wm);
+#else
return mb_wm_comp_mgr_default_new (wm);
+#endif
}
#endif
@@ -139,6 +149,29 @@ mb_wm_layout_new_real (MBWindowManager *wm)
return layout;
}
+#ifdef USE_CLUTTER
+static ClutterX11FilterReturn
+mb_wm_clutter_xevent_filter (XEvent *xev, ClutterEvent *cev, gpointer data)
+{
+ MBWindowManager * wm = data;
+
+ mb_wm_main_context_handle_x_event (xev, wm->main_ctx);
+
+ if (wm->sync_type)
+ mb_wm_sync (wm);
+
+ return CLUTTER_X11_FILTER_CONTINUE;
+}
+
+static void
+mb_wm_main_real (MBWindowManager *wm)
+{
+ clutter_x11_add_filter (mb_wm_clutter_xevent_filter, wm);
+
+ clutter_main ();
+}
+#endif
+
static void
mb_wm_class_init (MBWMObjectClass *klass)
{
@@ -154,6 +187,10 @@ mb_wm_class_init (MBWMObjectClass *klass)
wm_class->client_activate = mb_wm_activate_client_real;
wm_class->layout_new = mb_wm_layout_new_real;
+#ifdef USE_CLUTTER
+ wm_class->main = mb_wm_main_real;
+#endif
+
#ifdef ENABLE_COMPOSITE
wm_class->comp_mgr_new = mb_wm_real_comp_mgr_new;
#endif
@@ -225,6 +262,23 @@ mb_wm_new (int argc, char **argv)
return wm;
}
+MBWindowManager*
+mb_wm_new_with_dpy (int argc, char **argv, Display * dpy)
+{
+ MBWindowManager *wm = NULL;
+
+ wm = MB_WINDOW_MANAGER (mb_wm_object_new (MB_TYPE_WINDOW_MANAGER,
+ MBWMObjectPropArgc, argc,
+ MBWMObjectPropArgv, argv,
+ MBWMObjectPropDpy, dpy,
+ NULL));
+
+ if (!wm)
+ return wm;
+
+ return wm;
+}
+
Bool
test_key_press (XKeyEvent *xev,
void *userdata)
@@ -247,7 +301,7 @@ test_button_press (XButtonEvent *xev, void *userdata)
if (xev->button != 1)
return True;
- client = mb_wm_is_my_window (wm, xev->window);
+ mb_wm_is_my_window (wm, xev->window, &client);
if (!client)
return True;
@@ -504,16 +558,41 @@ mb_wm_handle_config_request (XConfigureRequestEvent *xev,
return True;
}
-static MBWindowManagerClient *
-mb_wm_is_my_window (MBWindowManager *wm, Window xwin)
+/*
+ * Check if this window belongs to the WM, and if it does, and is a client
+ * window, optionaly return the client.
+ */
+static Bool
+mb_wm_is_my_window (MBWindowManager *wm,
+ Window xwin,
+ MBWindowManagerClient **client)
{
MBWindowManagerClient *c;
+#ifdef ENABLE_COMPOSITE
+ if (wm->comp_mgr && mb_wm_comp_mgr_is_my_window (wm->comp_mgr, xwin))
+ {
+ /* Make sure to set the returned client to NULL, as this is a
+ * window that belongs to the composite manager, and so it has no
+ * client associated with it.
+ */
+ if (client)
+ *client = NULL;
+
+ return True;
+ }
+#endif
+
mb_wm_stack_enumerate_reverse(wm, c)
if (mb_wm_client_owns_xwindow (c, xwin))
- return c;
+ {
+ if (client)
+ *client = c;
- return NULL;
+ return True;
+ }
+
+ return False;
}
#ifdef ENABLE_COMPOSITE
@@ -539,8 +618,16 @@ mb_wm_handle_map_notify (XMapEvent *xev,
return True;
}
- if (mb_wm_is_my_window (wm, xev->window))
- return True;
+ if (mb_wm_is_my_window (wm, xev->window, &client))
+ {
+ if (wm->comp_mgr && client)
+ {
+ MBWM_NOTE (COMPOSITOR, "@@@@ client %p @@@@\n", client);
+ mb_wm_comp_mgr_map_notify (wm->comp_mgr, client);
+ }
+
+ return True;
+ }
win = mb_wm_client_window_new (wm, xev->window);
@@ -559,6 +646,7 @@ mb_wm_handle_map_notify (XMapEvent *xev,
}
mb_wm_manage_client (wm, client, True);
+ mb_wm_comp_mgr_map_notify (wm->comp_mgr, client);
return True;
}
@@ -576,9 +664,13 @@ mb_wm_handle_map_request (XMapRequestEvent *xev,
MBWM_MARK();
- if ((client = mb_wm_managed_client_from_xwindow(wm, xev->window)))
+ MBWM_NOTE (COMPOSITOR, "@@@@ Map Request for %x @@@@\n", xev->window);
+
+ if (mb_wm_is_my_window (wm, xev->window, &client))
{
- mb_wm_activate_client (wm, client);
+ if (client)
+ mb_wm_activate_client (wm, client);
+
return True;
}
@@ -903,8 +995,8 @@ mb_wm_unmanage_client (MBWindowManager *wm,
}
#ifdef ENABLE_COMPOSITE
- if (mb_wm_comp_mgr_enabled (wm->comp_mgr))
- mb_wm_comp_mgr_unregister_client (wm->comp_mgr, client);
+ if (mb_wm_comp_mgr_enabled (wm->comp_mgr))
+ mb_wm_comp_mgr_unregister_client (wm->comp_mgr, client);
#endif
if (wm->focused_client == client)
@@ -965,10 +1057,41 @@ mb_wm_managed_client_from_frame (MBWindowManager *wm, Window frame)
return NULL;
}
+/*
+ * Run the main loop; there are three options dependent on how we were
+ * configured at build time:
+ *
+ * * If configured without glib main loop integration, we defer to our own
+ * main loop implementation provided by MBWMMainContext.
+ *
+ * * If configured with glib main loop integration:
+ *
+ * * If there is an implemetation for the MBWindowManager main() virtual
+ * function, we call it.
+ *
+ * * Otherwise, start a normal glib main loop.
+ */
void
mb_wm_main_loop(MBWindowManager *wm)
{
+#ifndef USE_GLIB_MAINLOOP
mb_wm_main_context_loop (wm->main_ctx);
+#else
+ MBWindowManagerClass * wm_class =
+ MB_WINDOW_MANAGER_CLASS (MB_WM_OBJECT_GET_CLASS (wm));
+
+ if (!wm_class->main)
+ {
+ GMainLoop * loop = g_main_loop_new (NULL, FALSE);
+
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+ }
+ else
+ {
+ wm_class->main (wm);
+ }
+#endif
}
void
@@ -1128,12 +1251,12 @@ mb_wm_init_xdpy (MBWindowManager * wm, const char * display)
mb_wm_util_fatal_error("Display connection failed");
return 0;
}
-
- wm->xscreen = DefaultScreen(wm->xdpy);
- wm->xdpy_width = DisplayWidth(wm->xdpy, wm->xscreen);
- wm->xdpy_height = DisplayHeight(wm->xdpy, wm->xscreen);
}
+ wm->xscreen = DefaultScreen(wm->xdpy);
+ wm->xdpy_width = DisplayWidth(wm->xdpy, wm->xscreen);
+ wm->xdpy_height = DisplayHeight(wm->xdpy, wm->xscreen);
+
return 1;
}
@@ -1178,6 +1301,8 @@ mb_wm_init (MBWMObject *this, va_list vap)
case MBWMObjectPropArgv:
argv = va_arg(vap, char **);
break;
+ case MBWMObjectPropDpy:
+ wm->xdpy = va_arg(vap, Display *);
default:
MBWMO_PROP_EAT (vap, prop);
}
@@ -1187,10 +1312,13 @@ mb_wm_init (MBWMObject *this, va_list vap)
wm_class = (MBWindowManagerClass *) MB_WM_OBJECT_GET_CLASS (wm);
+ wm->argv = argv;
+ wm->argc = argc;
+
if (argc && argv && wm_class->process_cmdline)
- wm_class->process_cmdline (wm, argc, argv);
+ wm_class->process_cmdline (wm);
- if (!wm->xdpy && !mb_wm_init_xdpy (wm, NULL))
+ if (!mb_wm_init_xdpy (wm, NULL))
return 0;
if (getenv("MB_SYNC"))
@@ -1290,10 +1418,12 @@ mb_wm_init (MBWMObject *this, va_list vap)
}
static void
-mb_wm_process_cmdline (MBWindowManager *wm, int argc, char **argv)
+mb_wm_process_cmdline (MBWindowManager *wm)
{
int i;
const char * theme_path = NULL;
+ char ** argv = wm->argv;
+ int argc = wm->argc;
for (i = 0; i < argc; ++i)
{
@@ -1750,7 +1880,10 @@ mb_wm_compositing_on (MBWindowManager * wm)
wm->comp_mgr = wm_class->comp_mgr_new (wm);
if (wm->comp_mgr && !mb_wm_comp_mgr_enabled (wm->comp_mgr))
- mb_wm_comp_mgr_turn_on (wm->comp_mgr);
+ {
+ mb_wm_comp_mgr_turn_on (wm->comp_mgr);
+ XSync (wm->xdpy, False);
+ }
#endif
}
diff --git a/src/core/mb-window-manager.h b/src/core/mb-window-manager.h
index 024f5c5..b6a39f7 100644
--- a/src/core/mb-window-manager.h
+++ b/src/core/mb-window-manager.h
@@ -94,18 +94,21 @@ struct MBWindowManager
const char *theme_path;
MBWMModality modality_type;
+
+ char **argv;
+ int argc;
};
struct MBWindowManagerClass
{
MBWMObjectClass parent;
- void (*process_cmdline) (MBWindowManager * wm, int argc, char **argv);
+ void (*process_cmdline) (MBWindowManager * wm);
MBWindowManagerClient* (*client_new) (MBWindowManager *wm,
MBWMClientWindow *w);
MBWMLayout * (*layout_new) (MBWindowManager *wm);
-
+
/* These return True if now further action to be taken */
Bool (*client_activate) (MBWindowManager *wm, MBWindowManagerClient *c);
Bool (*client_responding) (MBWindowManager *wm, MBWindowManagerClient *c);
@@ -116,11 +119,16 @@ struct MBWindowManagerClass
#ifdef ENABLE_COMPOSITE
MBWMCompMgr * (*comp_mgr_new) (MBWindowManager *wm);
#endif
+
+ void (*main) (MBWindowManager *wm);
};
MBWindowManager *
mb_wm_new (int argc, char **argv);
+MBWindowManager *
+mb_wm_new_with_dpy (int argc, char **argv, Display * dpy);
+
void
mb_wm_set_layout (MBWindowManager *wm, MBWMLayout *layout);
@@ -201,4 +209,7 @@ mb_wm_compositing_enabled (MBWindowManager * wm);
MBWMModality
mb_wm_get_modality_type (MBWindowManager * wm);
+void
+mb_wm_sync (MBWindowManager *wm);
+
#endif
diff --git a/src/core/mb-wm-client.c b/src/core/mb-wm-client.c
index 7ade24a..6815ea5 100644
--- a/src/core/mb-wm-client.c
+++ b/src/core/mb-wm-client.c
@@ -959,6 +959,21 @@ mb_wm_client_reset_iconizing (MBWindowManagerClient *client)
client->priv->iconizing = False;
}
+#ifdef ENABLE_COMPOSITE
+static void
+mb_wm_client_effect_completed (void *data)
+{
+ MBWindowManagerClient *client = data;
+
+ client->priv->iconizing = True;
+
+
+ mb_wm_client_set_state (client,
+ MBWM_ATOM_NET_WM_STATE_HIDDEN,
+ MBWMClientWindowStateChangeAdd);
+}
+
+#endif
void
mb_wm_client_iconize (MBWindowManagerClient *client)
{
@@ -967,11 +982,28 @@ mb_wm_client_iconize (MBWindowManagerClient *client)
* This triggers an umap event, at which point the client gets unmanaged
* by the window manager.
*/
- client->priv->iconizing = True;
+#ifdef ENABLE_COMPOSITE
+ /*
+ * We cannot iconize the client until the effect finished, otherwise it
+ * will unmap before the effect takes place, so we do this in the callback.
+ */
+ if (mb_wm_compositing_enabled (client->wmref))
+ {
+ mb_wm_comp_mgr_client_run_effect (client->cm_client,
+ MBWMCompMgrEffectEventMinimize,
+ mb_wm_client_effect_completed,
+ client);
+ }
+ else
+#endif
+ {
+ client->priv->iconizing = True;
- mb_wm_client_set_state (client,
- MBWM_ATOM_NET_WM_STATE_HIDDEN,
- MBWMClientWindowStateChangeAdd);
+
+ mb_wm_client_set_state (client,
+ MBWM_ATOM_NET_WM_STATE_HIDDEN,
+ MBWMClientWindowStateChangeAdd);
+ }
}
int
diff --git a/src/core/mb-wm-main-context.c b/src/core/mb-wm-main-context.c
index d3729dd..160c9ea 100644
--- a/src/core/mb-wm-main-context.c
+++ b/src/core/mb-wm-main-context.c
@@ -90,7 +90,7 @@ mb_wm_main_context_destroy (MBWMObject *this)
}
#ifdef USE_GLIB_MAINLOOP
-static gboolean
+gboolean
mb_wm_main_context_gloop_xevent (gpointer userdata)
{
MBWMMainContext * ctx = userdata;
@@ -129,7 +129,8 @@ mb_wm_main_context_init (MBWMObject *this, va_list vap)
ctx->wm = wm;
#ifdef USE_GLIB_MAINLOOP
- g_idle_add (mb_wm_main_context_gloop_xevent, ctx);
+/* g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, */
+/* mb_wm_main_context_gloop_xevent, ctx, NULL); */
#endif
return 1;
@@ -167,7 +168,7 @@ mb_wm_main_context_new (MBWindowManager *wm)
return ctx;
}
-static Bool
+Bool
mb_wm_main_context_handle_x_event (XEvent *xev,
MBWMMainContext *ctx)
{
@@ -212,7 +213,6 @@ mb_wm_main_context_handle_x_event (XEvent *xev,
mb_wm_root_window_handle_message (wm->root_win,
(XClientMessageEvent *)xev);
}
-
break;
case Expose:
break;
@@ -473,6 +473,7 @@ mb_wm_main_context_spin_xevent (MBWMMainContext *ctx)
{
MBWindowManager * wm = ctx->wm;
XEvent xev;
+ clock_t ct = clock ();
if (!XEventsQueued (wm->xdpy, QueuedAfterFlush))
return False;
@@ -526,13 +527,6 @@ mb_wm_main_context_loop (MBWMMainContext *ctx)
if (wm->sync_type)
mb_wm_sync (wm);
}
-
-#else
- GMainLoop * loop = g_main_loop_new (NULL, FALSE);
-
- g_main_loop_run (loop);
-
- g_main_loop_unref (loop);
#endif
}
diff --git a/src/core/mb-wm-object-props.h b/src/core/mb-wm-object-props.h
index 1f2379f..435d30a 100644
--- a/src/core/mb-wm-object-props.h
+++ b/src/core/mb-wm-object-props.h
@@ -87,6 +87,13 @@ typedef enum MBWMObjectProp
MBWMObjectPropThemeCompositing = _MKOPROP(24, int),
MBWMObjectPropThemeShaped = _MKOPROP(25, int),
+ MBWMObjectPropCompMgrEffectType = _MKOPROP(26, int),
+ MBWMObjectPropCompMgrEffectDuration = _MKOPROP(27, unsigned long),
+ MBWMObjectPropCompMgrClutterEffectTimeline = _MKOPROP(28, void*),
+ MBWMObjectPropCompMgrClutterEffectBehaviour = _MKOPROP(29, void*),
+
+ MBWMObjectPropDpy = _MKOPROP(30, void*),
+
_MBWMObjectPropLastGlobal = 0x00fffff0,
}
MBWMObjectProp;
diff --git a/src/core/mb-wm-types.h b/src/core/mb-wm-types.h
index 4b908b9..95f5133 100644
--- a/src/core/mb-wm-types.h
+++ b/src/core/mb-wm-types.h
@@ -114,6 +114,16 @@ typedef struct MBWMCompMgrClientClass MBWMCompMgrClientClass;
typedef struct MBWMCompMgrDefaultClient MBWMCompMgrDefaultClient;
typedef struct MBWMCompMgrDefaultClientClass MBWMCompMgrDefaultClientClass;
typedef struct MBWMCompMgrDefaultClentPrivate MBWMCompMgrDefaultClientPrivate;
+typedef struct MBWMCompMgrClutter MBWMCompMgrClutter;
+typedef struct MBWMCompMgrClutterPrivate MBWMCompMgrClutterPrivate;
+typedef struct MBWMCompMgrClutterClass MBWMCompMgrClutterClass;
+typedef struct MBWMCompMgrClutterClient MBWMCompMgrClutterClient;
+typedef struct MBWMCompMgrClutterClientClass MBWMCompMgrClutterClientClass;
+typedef struct MBWMCompMgrClutterClentPrivate MBWMCompMgrClutterClientPrivate;
+typedef struct MBWMCompMgrEffect MBWMCompMgrEffect;
+typedef struct MBWMCompMgrEffectClass MBWMCompMgrEffectClass;
+typedef struct MBWMCompMgrClutterEffect MBWMCompMgrClutterEffect;
+typedef struct MBWMCompMgrClutterEffectClass MBWMCompMgrClutterEffectClass;
typedef enum MBWMClientType
{
@@ -129,6 +139,40 @@ typedef enum MBWMClientType
MBWMClientTypeLast = MBWMClientTypeOverride,
} MBWMClientType;
+typedef enum _MBWMCompMgrEffectEvent
+{
+ MBWMCompMgrEffectEventNone = 0,
+ MBWMCompMgrEffectEventMinimize,
+
+ _MBWMCompMgrEffectEventLast,
+} MBWMCompMgrEffectEvent;
+
+typedef enum _MBWMCompMgrEffectType
+{
+ MBWMCompMgrEffectScaleUp = (1<<0), /* 0 reserved for unknown */
+ MBWMCompMgrEffectScaleDown = (1<<1),
+ MBWMCompMgrEffectSpinXCW = (1<<2),
+ MBWMCompMgrEffectSpinXCCW = (1<<3),
+ MBWMCompMgrEffectSpinYCW = (1<<4),
+ MBWMCompMgrEffectSpinYCCW = (1<<5),
+ MBWMCompMgrEffectSpinZCW = (1<<6),
+ MBWMCompMgrEffectSpinZCCW = (1<<7),
+ MBWMCompMgrEffectFade = (1<<8),
+ MBWMCompMgrEffectUnfade = (1<<9),
+ MBWMCompMgrEffectSlideN = (1<<10),
+ MBWMCompMgrEffectSlideS = (1<<11),
+ MBWMCompMgrEffectSlideE = (1<<12),
+ MBWMCompMgrEffectSlideW = (1<<13),
+ MBWMCompMgrEffectSlideNW = (1<<14),
+ MBWMCompMgrEffectSlideNE = (1<<15),
+ MBWMCompMgrEffectSlideSW = (1<<16),
+ MBWMCompMgrEffectSlideSE = (1<<17),
+
+ _MBWMCompMgrEffectLast,
+} MBWMCompMgrEffectType;
+
+typedef void (*MBWMCompMgrEffectCallback) (void * data);
+
typedef unsigned long MBWMCookie;
typedef enum MBWMAtom
diff --git a/src/managers/maemo/maemo-window-manager.c b/src/managers/maemo/maemo-window-manager.c
index b952618..9090dd9 100644
--- a/src/managers/maemo/maemo-window-manager.c
+++ b/src/managers/maemo/maemo-window-manager.c
@@ -31,7 +31,7 @@
#include <stdarg.h>
static void
-maemo_window_manager_process_cmdline (MBWindowManager *, int , char **);
+maemo_window_manager_process_cmdline (MBWindowManager *);
static Bool
maemo_window_manager_client_activate (MBWindowManager * wm,
@@ -183,7 +183,7 @@ maemo_window_manager_process_cmdline (MBWindowManager *wm,
MB_WINDOW_MANAGER_CLASS(MB_WM_OBJECT_GET_PARENT_CLASS(MB_WM_OBJECT(wm)));
if (wm_class->process_cmdline)
- wm_class->process_cmdline (wm, argc, argv);
+ wm_class->process_cmdline (wm);
}
static Bool
diff --git a/src/managers/simple/matchbox-window-manager-2-simple.c b/src/managers/simple/matchbox-window-manager-2-simple.c
index a177f01..bfd8e1a 100644
--- a/src/managers/simple/matchbox-window-manager-2-simple.c
+++ b/src/managers/simple/matchbox-window-manager-2-simple.c
@@ -4,6 +4,10 @@
#include "mb-wm-client-dialog.h"
#include <signal.h>
+#ifdef USE_CLUTTER
+# include <clutter/clutter-x11.h>
+#endif
+
enum {
KEY_ACTION_PAGE_NEXT,
KEY_ACTION_PAGE_PREV,
@@ -75,6 +79,8 @@ key_binding_func (MBWindowManager *wm,
int
main(int argc, char **argv)
{
+ Display * dpy = NULL;
+
#ifdef MBWM_WANT_DEBUG
struct sigaction sa;
sigfillset(&sa.sa_mask);
@@ -84,7 +90,17 @@ main(int argc, char **argv)
mb_wm_object_init();
- wm = mb_wm_new(argc, argv);
+#ifdef USE_CLUTTER
+ /*
+ * If using clutter, we share the display connection, and hook
+ * our xevent handler into the clutter main loop.
+ */
+ clutter_init (&argc, &argv);
+
+ dpy = clutter_x11_get_default_display ();
+#endif
+
+ wm = mb_wm_new_with_dpy (argc, argv, dpy);
if (wm == NULL)
mb_wm_util_fatal_error("OOM?");
diff --git a/src/theme-engines/mb-wm-theme-xml.c b/src/theme-engines/mb-wm-theme-xml.c
index 7c4a528..28963c9 100644
--- a/src/theme-engines/mb-wm-theme-xml.c
+++ b/src/theme-engines/mb-wm-theme-xml.c
@@ -19,6 +19,7 @@
*/
#include "mb-wm-theme-xml.h"
+#include "mb-wm-theme.h"
/*****************************************************************
* XML Parser stuff
@@ -76,6 +77,14 @@ mb_wm_xml_decor_free (MBWMXmlDecor * d)
free (d);
}
+#ifdef ENABLE_COMPOSITE
+static void
+mb_wm_theme_effects_free (MBWMThemeEffects *e)
+{
+ free (e);
+}
+#endif
+
MBWMXmlClient *
mb_wm_xml_client_new ()
{
@@ -108,6 +117,19 @@ mb_wm_xml_client_free (MBWMXmlClient * c)
l = n;
}
+#ifdef ENABLE_COMPOSITE
+ l = c->effects;
+ while (l)
+ {
+ MBWMThemeEffects * e = l->data;
+ MBWMList * n = l->next;
+ mb_wm_theme_effects_free (e);
+ free (l);
+
+ l = n;
+ }
+#endif
+
free (c);
}
diff --git a/src/theme-engines/mb-wm-theme-xml.h b/src/theme-engines/mb-wm-theme-xml.h
index c236b29..53b20ce 100644
--- a/src/theme-engines/mb-wm-theme-xml.h
+++ b/src/theme-engines/mb-wm-theme-xml.h
@@ -64,6 +64,10 @@ typedef struct Client
MBWMList *decors;
MBWMClientLayoutHints layout_hints;
+
+#ifdef ENABLE_COMPOSITE
+ MBWMList *effects;
+#endif
}MBWMXmlClient;
MBWMXmlButton *
diff --git a/src/theme-engines/mb-wm-theme.c b/src/theme-engines/mb-wm-theme.c
index ddb7293..a50e234 100644
--- a/src/theme-engines/mb-wm-theme.c
+++ b/src/theme-engines/mb-wm-theme.c
@@ -600,6 +600,28 @@ mb_wm_theme_get_client_layout_hints (MBWMTheme * theme,
return c->layout_hints;
}
+#ifdef ENABLE_COMPOSITE
+const MBWMList *
+mb_wm_theme_get_client_effects (MBWMTheme * theme,
+ MBWindowManagerClient * client)
+{
+ MBWMXmlClient * c;
+ MBWMClientType c_type;
+
+ if (!client || !theme)
+ return NULL;
+
+ c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+
+ if (!theme->xml_clients ||
+ !(c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)))
+ {
+ return NULL;
+ }
+
+ return c->effects;
+}
+#endif
/*
* Returns True if the theme prescribes at least one value for the geometry
@@ -1022,6 +1044,149 @@ xml_element_start_cb (void *data, const char *tag, const char **expat_attr)
free (duph);
}
+#ifdef ENABLE_COMPOSITE
+ else if (!strcmp (*p, "effects") && *(p+1))
+ {
+ /* comma-separate list of effects in format
+ *
+ * event:duration|effect1|effect2 ...
+ */
+ char * dupe = strdup (*(p+1));
+ char * comma;
+ char * e = dupe;
+
+ while (e)
+ {
+ MBWMThemeEffects *eff;
+ char * bar;
+ char * colon;
+
+ comma = strchr (e, ',');
+
+ if (comma)
+ *comma = 0;
+
+ eff = mb_wm_util_malloc0 (sizeof (MBWMThemeEffects));
+
+ if (!strncmp (e, "minimize", 8))
+ {
+ eff->event = MBWMCompMgrEffectEventMinimize;
+ }
+ else
+ {
+ if (comma)
+ e = comma + 1;
+
+ continue;
+ }
+
+ colon = strchr (e, ':');
+
+ if (colon)
+ eff->duration = atoi (colon+1);
+ else
+ eff->duration = 100;
+
+ while (e && *e)
+ {
+ char * collon = NULL;
+
+ if (!strncmp (e, "scale-up", 8))
+ {
+ eff->type |= MBWMCompMgrEffectScaleUp;
+ }
+ else if (!strncmp (e, "scale-down", 12))
+ {
+ eff->type |= MBWMCompMgrEffectScaleDown;
+ }
+ else if (!strncmp (e, "scale-down", 12))
+ {
+ eff->type |= MBWMCompMgrEffectScaleDown;
+ }
+ else if (!strncmp (e, "spin-xcw", 8))
+ {
+ eff->type |= MBWMCompMgrEffectSpinXCW;
+ }
+ else if (!strncmp (e, "spin-xccw", 9))
+ {
+ eff->type |= MBWMCompMgrEffectSpinXCCW;
+ }
+ else if (!strncmp (e, "spin-ycw", 8))
+ {
+ eff->type |= MBWMCompMgrEffectSpinYCW;
+ }
+ else if (!strncmp (e, "spin-yccw", 9))
+ {
+ eff->type |= MBWMCompMgrEffectSpinYCCW;
+ }
+ else if (!strncmp (e, "spin-zcw", 8))
+ {
+ eff->type |= MBWMCompMgrEffectSpinZCW;
+ }
+ else if (!strncmp (e, "spin-zccw", 9))
+ {
+ eff->type |= MBWMCompMgrEffectSpinZCCW;
+ }
+ else if (!strncmp (e, "fade", 4))
+ {
+ eff->type |= MBWMCompMgrEffectFade;
+ }
+ else if (!strncmp (e, "unfade", 4))
+ {
+ eff->type |= MBWMCompMgrEffectUnfade;
+ }
+ else if (!strncmp (e, "slide-n", 7))
+ {
+ eff->type |= MBWMCompMgrEffectSlideN;
+ }
+ else if (!strncmp (e, "slide-s", 7))
+ {
+ eff->type |= MBWMCompMgrEffectSlideS;
+ }
+ else if (!strncmp (e, "slide-w", 7))
+ {
+ eff->type |= MBWMCompMgrEffectSlideW;
+ }
+ else if (!strncmp (e, "slide-e", 7))
+ {
+ eff->type |= MBWMCompMgrEffectSlideE;
+ }
+ else if (!strncmp (e, "slide-nw", 8))
+ {
+ eff->type |= MBWMCompMgrEffectSlideNW;
+ }
+ else if (!strncmp (e, "slide-sw", 8))
+ {
+ eff->type |= MBWMCompMgrEffectSlideSW;
+ }
+ else if (!strncmp (e, "slide-ne", 8))
+ {
+ eff->type |= MBWMCompMgrEffectSlideNE;
+ }
+ else if (!strncmp (e, "slide-se", 8))
+ {
+ eff->type |= MBWMCompMgrEffectSlideSE;
+ }
+
+ bar = strchr (e, '|');
+
+ if (bar)
+ e = bar + 1;
+ else
+ *e = 0;
+ }
+
+ c->effects = mb_wm_util_list_prepend (c->effects, eff);
+
+ if (comma)
+ e = comma + 1;
+ else
+ break;
+ }
+
+ free (dupe);
+ }
+#endif
p += 2;
}
diff --git a/src/theme-engines/mb-wm-theme.h b/src/theme-engines/mb-wm-theme.h
index f9e84ea..e0d2865 100644
--- a/src/theme-engines/mb-wm-theme.h
+++ b/src/theme-engines/mb-wm-theme.h
@@ -43,6 +43,15 @@
#define MB_WM_THEME_PNG_CLASS(c) ((MBWMThemePngClass*)(c))
#define MB_WM_TYPE_THEME_PNG (mb_wm_theme_png_class_type ())
+#ifdef ENABLE_COMPOSITE
+typedef struct _MBWMThemeEffects
+{
+ MBWMCompMgrEffectEvent event;
+ MBWMCompMgrEffectType type;
+ unsigned long duration;
+} MBWMThemeEffects;
+#endif
+
enum MBWMThemeCaps
{
MBWMThemeCapsFrameMainButtonActionAccept = (1<<0),
@@ -171,6 +180,12 @@ MBWMClientLayoutHints
mb_wm_theme_get_client_layout_hints (MBWMTheme * theme,
MBWindowManagerClient * client);
+#ifdef ENABLE_COMPOSITE
+const MBWMList *
+mb_wm_theme_get_client_effects (MBWMTheme * theme,
+ MBWindowManagerClient * client);
+#endif
+
Bool
mb_wm_theme_is_client_shaped (MBWMTheme * theme,
MBWindowManagerClient * client);