diff options
-rw-r--r-- | ChangeLog | 29 | ||||
-rw-r--r-- | configure.ac | 22 | ||||
-rw-r--r-- | data/themes/Default/theme.xml | 2 | ||||
-rw-r--r-- | src/comp-mgr/Makefile.am | 24 | ||||
-rw-r--r-- | src/comp-mgr/mb-wm-comp-mgr-clutter.c | 1144 | ||||
-rw-r--r-- | src/comp-mgr/mb-wm-comp-mgr-clutter.h | 74 | ||||
-rw-r--r-- | src/comp-mgr/mb-wm-comp-mgr-default.c | 24 | ||||
-rw-r--r-- | src/comp-mgr/mb-wm-comp-mgr-default.h | 4 | ||||
-rw-r--r-- | src/comp-mgr/mb-wm-comp-mgr.c | 331 | ||||
-rw-r--r-- | src/comp-mgr/mb-wm-comp-mgr.h | 66 | ||||
-rw-r--r-- | src/core/mb-window-manager.c | 183 | ||||
-rw-r--r-- | src/core/mb-window-manager.h | 15 | ||||
-rw-r--r-- | src/core/mb-wm-client.c | 40 | ||||
-rw-r--r-- | src/core/mb-wm-main-context.c | 16 | ||||
-rw-r--r-- | src/core/mb-wm-object-props.h | 7 | ||||
-rw-r--r-- | src/core/mb-wm-types.h | 44 | ||||
-rw-r--r-- | src/managers/maemo/maemo-window-manager.c | 4 | ||||
-rw-r--r-- | src/managers/simple/matchbox-window-manager-2-simple.c | 18 | ||||
-rw-r--r-- | src/theme-engines/mb-wm-theme-xml.c | 22 | ||||
-rw-r--r-- | src/theme-engines/mb-wm-theme-xml.h | 4 | ||||
-rw-r--r-- | src/theme-engines/mb-wm-theme.c | 165 | ||||
-rw-r--r-- | src/theme-engines/mb-wm-theme.h | 15 |
22 files changed, 2176 insertions, 77 deletions
@@ -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); |