aboutsummaryrefslogtreecommitdiffstats
path: root/matchbox2
diff options
context:
space:
mode:
Diffstat (limited to 'matchbox2')
-rw-r--r--matchbox2/Makefile.am36
-rw-r--r--matchbox2/client-types/Makefile.am52
-rw-r--r--matchbox2/client-types/mb-wm-client-app.c240
-rw-r--r--matchbox2/client-types/mb-wm-client-app.h51
-rw-r--r--matchbox2/client-types/mb-wm-client-desktop.c196
-rw-r--r--matchbox2/client-types/mb-wm-client-desktop.h50
-rw-r--r--matchbox2/client-types/mb-wm-client-dialog.c359
-rw-r--r--matchbox2/client-types/mb-wm-client-dialog.h51
-rw-r--r--matchbox2/client-types/mb-wm-client-input.c184
-rw-r--r--matchbox2/client-types/mb-wm-client-input.h52
-rw-r--r--matchbox2/client-types/mb-wm-client-menu.c156
-rw-r--r--matchbox2/client-types/mb-wm-client-menu.h50
-rw-r--r--matchbox2/client-types/mb-wm-client-note.c153
-rw-r--r--matchbox2/client-types/mb-wm-client-note.h51
-rw-r--r--matchbox2/client-types/mb-wm-client-override.c124
-rw-r--r--matchbox2/client-types/mb-wm-client-override.h50
-rw-r--r--matchbox2/client-types/mb-wm-client-panel.c229
-rw-r--r--matchbox2/client-types/mb-wm-client-panel.h51
-rw-r--r--matchbox2/comp-mgr/Makefile.am32
-rw-r--r--matchbox2/comp-mgr/README70
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c1610
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.h108
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.c1837
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.h60
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr.c482
-rw-r--r--matchbox2/comp-mgr/mb-wm-comp-mgr.h159
-rw-r--r--matchbox2/core/Makefile.am49
-rw-r--r--matchbox2/core/mb-window-manager.c2252
-rw-r--r--matchbox2/core/mb-window-manager.h231
-rw-r--r--matchbox2/core/mb-wm-atoms.c116
-rw-r--r--matchbox2/core/mb-wm-atoms.h27
-rw-r--r--matchbox2/core/mb-wm-client-base.c742
-rw-r--r--matchbox2/core/mb-wm-client-base.h46
-rw-r--r--matchbox2/core/mb-wm-client-window.c1013
-rw-r--r--matchbox2/core/mb-wm-client-window.h177
-rw-r--r--matchbox2/core/mb-wm-client.c1120
-rw-r--r--matchbox2/core/mb-wm-client.h384
-rw-r--r--matchbox2/core/mb-wm-debug.c77
-rw-r--r--matchbox2/core/mb-wm-debug.h48
-rw-r--r--matchbox2/core/mb-wm-decor.c1190
-rw-r--r--matchbox2/core/mb-wm-decor.h241
-rw-r--r--matchbox2/core/mb-wm-keys.c379
-rw-r--r--matchbox2/core/mb-wm-keys.h55
-rw-r--r--matchbox2/core/mb-wm-layout.c753
-rw-r--r--matchbox2/core/mb-wm-layout.h76
-rw-r--r--matchbox2/core/mb-wm-macros.h104
-rw-r--r--matchbox2/core/mb-wm-main-context.c1116
-rw-r--r--matchbox2/core/mb-wm-main-context.h141
-rw-r--r--matchbox2/core/mb-wm-object-props.h104
-rw-r--r--matchbox2/core/mb-wm-object.c477
-rw-r--r--matchbox2/core/mb-wm-object.h130
-rw-r--r--matchbox2/core/mb-wm-props.c202
-rw-r--r--matchbox2/core/mb-wm-props.h118
-rw-r--r--matchbox2/core/mb-wm-root-window.c436
-rw-r--r--matchbox2/core/mb-wm-root-window.h57
-rw-r--r--matchbox2/core/mb-wm-stack.c325
-rw-r--r--matchbox2/core/mb-wm-stack.h96
-rw-r--r--matchbox2/core/mb-wm-types.h443
-rw-r--r--matchbox2/core/mb-wm-util.c289
-rw-r--r--matchbox2/core/mb-wm-util.h118
-rw-r--r--matchbox2/core/mb-wm.h62
-rw-r--r--matchbox2/core/xas.c906
-rw-r--r--matchbox2/core/xas.h114
-rw-r--r--matchbox2/mb-wm-config.h.in35
-rw-r--r--matchbox2/theme-engines/Makefile.am19
-rw-r--r--matchbox2/theme-engines/mb-wm-theme-png.c1306
-rw-r--r--matchbox2/theme-engines/mb-wm-theme-png.h56
-rw-r--r--matchbox2/theme-engines/mb-wm-theme-xml.c212
-rw-r--r--matchbox2/theme-engines/mb-wm-theme-xml.h106
-rw-r--r--matchbox2/theme-engines/mb-wm-theme.c2099
-rw-r--r--matchbox2/theme-engines/mb-wm-theme.h214
71 files changed, 24754 insertions, 0 deletions
diff --git a/matchbox2/Makefile.am b/matchbox2/Makefile.am
new file mode 100644
index 0000000..0ccbac3
--- /dev/null
+++ b/matchbox2/Makefile.am
@@ -0,0 +1,36 @@
+if ENABLE_COMPOSITE
+comp=comp-mgr
+complib= \
+ client-types/libmb-wm-client-override.la \
+ $(comp)/libmatchbox-window-manager-2-compmgr.la
+endif
+
+MAINTAINERCLEANFILES = Makefile.in
+
+pkgincludedir = $(includedir)/$(MBWM2_INCDIR)
+
+SUBDIRS = core client-types theme-engines $(comp)
+
+if ENABLE_LIBMATCHBOX
+lib_LTLIBRARIES = libmatchbox2-@MBWM2_API_VERSION@.la
+
+
+libmatchbox2_@MBWM2_API_VERSION@_la_LIBADD = \
+ core/libmatchbox-window-manager-2-core.la \
+ client-types/libmb-wm-client-app.la \
+ client-types/libmb-wm-client-desktop.la \
+ client-types/libmb-wm-client-dialog.la \
+ client-types/libmb-wm-client-input.la \
+ client-types/libmb-wm-client-menu.la \
+ client-types/libmb-wm-client-note.la \
+ client-types/libmb-wm-client-panel.la \
+ theme-engines/libmb-theme.la \
+ $(complib)
+
+libmatchbox2_@MBWM2_API_VERSION@_la_SOURCES =
+
+pkginclude_HEADERS = *.h
+
+else
+endif
+
diff --git a/matchbox2/client-types/Makefile.am b/matchbox2/client-types/Makefile.am
new file mode 100644
index 0000000..8bb7990
--- /dev/null
+++ b/matchbox2/client-types/Makefile.am
@@ -0,0 +1,52 @@
+if ENABLE_COMPOSITE
+compmgr_libs = libmb-wm-client-override.la
+compmgr_ltlibs = libmb-wm-client-override.la
+endif
+
+THEME_LIBS = $(MBWM_THEME_LIBS)/libmb-theme.la
+
+INCLUDES = $(MBWM_INCS) $(MBWM_CFLAGS)
+LDADD =$(THEME_LIBS)
+DEPENDENCIES = $(THEME_LIBS)
+
+pkgincludedir = $(includedir)/$(MBWM2_INCDIR)/client-types
+
+if ENABLE_LIBMATCHBOX
+pkginclude_HEADERS = mb-wm-client-app.h \
+ mb-wm-client-dialog.h \
+ mb-wm-client-menu.h \
+ mb-wm-client-override.h \
+ mb-wm-client-desktop.h \
+ mb-wm-client-input.h \
+ mb-wm-client-note.h \
+ mb-wm-client-panel.h
+endif
+
+noinst_LTLIBRARIES = libmb-wm-client-app.la \
+ libmb-wm-client-panel.la \
+ libmb-wm-client-dialog.la \
+ libmb-wm-client-note.la \
+ libmb-wm-client-input.la \
+ libmb-wm-client-desktop.la \
+ libmb-wm-client-menu.la \
+ $(compmgr_ltlibs)
+
+libmb_wm_client_app_la_SOURCES = mb-wm-client-app.c mb-wm-client-app.h
+libmb_wm_client_panel_la_SOURCES = mb-wm-client-panel.c mb-wm-client-panel.h
+libmb_wm_client_dialog_la_SOURCES = mb-wm-client-dialog.c mb-wm-client-dialog.h
+libmb_wm_client_note_la_SOURCES = mb-wm-client-note.c mb-wm-client-note.h
+libmb_wm_client_input_la_SOURCES = mb-wm-client-input.c mb-wm-client-input.h
+libmb_wm_client_desktop_la_SOURCES = mb-wm-client-desktop.c mb-wm-client-desktop.h
+libmb_wm_client_menu_la_SOURCES = mb-wm-client-menu.c mb-wm-client-menu.h
+libmb_wm_client_override_la_SOURCES= mb-wm-client-override.c \
+ mb-wm-client-override.h
+libmb_wm_client_app_la_CFLAGS =
+libmb_wm_client_panel_la_CFLAGS =
+libmb_wm_client_dialog_la_CFLAGS =
+libmb_wm_client_note_la_CFLAGS =
+libmb_wm_client_input_la_CFLAGS =
+libmb_wm_client_desktop_la_CFLAGS =
+libmb_wm_client_menu_la_CFLAGS =
+libmb_wm_client_override_la_CFLAGS =
+
+MAINTAINERCLEANFILES = config.h.in Makefile.in
diff --git a/matchbox2/client-types/mb-wm-client-app.c b/matchbox2/client-types/mb-wm-client-app.c
new file mode 100644
index 0000000..3aa9d2e
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-app.c
@@ -0,0 +1,240 @@
+#include "mb-wm-client-app.h"
+
+#include "mb-wm-theme.h"
+
+static Bool
+mb_wm_client_app_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags);
+
+static MBWMStackLayerType
+mb_wm_client_app_stacking_layer (MBWindowManagerClient *client);
+
+static void
+mb_wm_client_app_theme_change (MBWindowManagerClient *client);
+
+static void
+mb_wm_client_app_class_init (MBWMObjectClass *klass)
+{
+ MBWindowManagerClientClass *client;
+ MBWMClientAppClass * client_app;
+
+ MBWM_MARK();
+
+ client = (MBWindowManagerClientClass *)klass;
+ client_app = (MBWMClientAppClass *)klass;
+
+ MBWM_DBG("client->stack is %p", client->stack);
+
+ client->client_type = MBWMClientTypeApp;
+ client->geometry = mb_wm_client_app_request_geometry;
+ client->theme_change = mb_wm_client_app_theme_change;
+ client->stacking_layer = mb_wm_client_app_stacking_layer;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMClientApp";
+#endif
+}
+
+static void
+mb_wm_client_app_destroy (MBWMObject *this)
+{
+}
+
+
+static int
+mb_wm_client_app_init (MBWMObject *this, va_list vap)
+{
+ MBWindowManagerClient *client = MB_WM_CLIENT (this);
+ MBWindowManager *wm = NULL;
+ MBWMClientAppClass *app_class;
+
+ app_class = MB_WM_CLIENT_APP_CLASS (MB_WM_OBJECT_GET_CLASS (this));
+
+#if 0
+ /*
+ * Property parsing not needed for now, as there are no ClientApp specific
+ * properties
+ */
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ if (prop == MBWMObjectPropWm)
+ {
+ wm = va_arg(vap, MBWindowManager *);
+ break;
+ }
+ else
+ MBWMO_PROP_EAT (vap, prop);
+
+ prop = va_arg (vap, MBWMObjectProp);
+ }
+#endif
+
+ wm = client->wmref;
+
+ if (!wm)
+ return 0;
+
+ {
+ Atom actions[] = {
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_CLOSE],
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_FULLSCREEN]
+ };
+
+ XChangeProperty (wm->xdpy, client->window->xwindow,
+ wm->atoms[MBWM_ATOM_NET_WM_ALLOWED_ACTIONS],
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *)actions,
+ sizeof (actions)/sizeof (actions[0]));
+ }
+
+ client->stacking_layer = MBWMStackLayerMid;
+
+ mb_wm_client_set_layout_hints (client,
+ LayoutPrefGrowToFreeSpace|LayoutPrefVisible);
+
+ if (!client->window->undecorated)
+ {
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeNorth);
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeSouth);
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeWest);
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeEast);
+ }
+
+ return 1;
+}
+
+int
+mb_wm_client_app_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMClientAppClass),
+ sizeof (MBWMClientApp),
+ mb_wm_client_app_init,
+ mb_wm_client_app_destroy,
+ mb_wm_client_app_class_init
+ };
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_CLIENT_BASE, 0);
+ }
+
+ return type;
+}
+
+static Bool
+mb_wm_client_app_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags)
+{
+ if (flags & (MBWMClientReqGeomIsViaLayoutManager |
+ MBWMClientReqGeomForced |
+ MBWMClientReqGeomIsViaUserAction))
+ {
+ int north, south, west, east;
+ MBWindowManager *wm = client->wmref;
+
+ if ((client->window->ewmh_state & MBWMClientWindowEWMHStateFullscreen)||
+ !client->decor)
+ {
+ /* Undecorated window */
+ client->window->geometry.x = new_geometry->x;
+ client->window->geometry.y = new_geometry->y;
+ client->window->geometry.width = new_geometry->width;
+ client->window->geometry.height = new_geometry->height;
+
+ client->frame_geometry.x = new_geometry->x;
+ client->frame_geometry.y = new_geometry->y;
+ client->frame_geometry.width = new_geometry->width;
+ client->frame_geometry.height = new_geometry->height;
+ }
+ else
+ {
+ mb_wm_theme_get_decor_dimensions (wm->theme, client,
+ &north, &south, &west, &east);
+
+ client->frame_geometry.x = new_geometry->x;
+ client->frame_geometry.y = new_geometry->y;
+ client->frame_geometry.width = new_geometry->width;
+ client->frame_geometry.height = new_geometry->height;
+
+ client->window->geometry.x
+ = client->frame_geometry.x + west;
+ client->window->geometry.y
+ = client->frame_geometry.y + north;
+ client->window->geometry.width
+ = client->frame_geometry.width - (west + east);
+ client->window->geometry.height
+ = client->frame_geometry.height - (south + north);
+ }
+
+ mb_wm_client_geometry_mark_dirty (client);
+
+ return True; /* Geometry accepted */
+ }
+
+ return False;
+}
+
+static void
+mb_wm_client_app_theme_change (MBWindowManagerClient *client)
+{
+ MBWMList * l = client->decor;
+
+ while (l)
+ {
+ MBWMDecor * d = l->data;
+ MBWMList * n = l->next;
+
+ mb_wm_object_unref (MB_WM_OBJECT (d));
+ free (l);
+
+ l = n;
+ }
+
+ client->decor = NULL;
+
+ if (!client->window->undecorated)
+ {
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeNorth);
+
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeSouth);
+
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeWest);
+
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeEast);
+ }
+
+ mb_wm_client_geometry_mark_dirty (client);
+ mb_wm_client_visibility_mark_dirty (client);
+}
+
+static MBWMStackLayerType
+mb_wm_client_app_stacking_layer (MBWindowManagerClient *client)
+{
+ if (client->window->ewmh_state & MBWMClientWindowEWMHStateFullscreen)
+ return MBWMStackLayerTopMid;
+
+ return client->stacking_layer;
+}
+
+MBWindowManagerClient*
+mb_wm_client_app_new (MBWindowManager *wm, MBWMClientWindow *win)
+{
+ MBWindowManagerClient *client;
+
+ client = MB_WM_CLIENT(mb_wm_object_new (MB_WM_TYPE_CLIENT_APP,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropClientWindow, win,
+ NULL));
+
+ return client;
+}
+
diff --git a/matchbox2/client-types/mb-wm-client-app.h b/matchbox2/client-types/mb-wm-client-app.h
new file mode 100644
index 0000000..c058d0c
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-app.h
@@ -0,0 +1,51 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_CLIENT_APP_H
+#define _HAVE_MB_CLIENT_APP_H
+
+#include <matchbox2/core/mb-wm.h>
+
+typedef struct MBWMClientApp MBWMClientApp;
+typedef struct MBWMClientAppClass MBWMClientAppClass;
+
+#define MB_WM_CLIENT_APP(c) ((MBWMClientApp*)(c))
+#define MB_WM_CLIENT_APP_CLASS(c) ((MBWMClientAppClass*)(c))
+#define MB_WM_TYPE_CLIENT_APP (mb_wm_client_app_class_type ())
+#define MB_WM_IS_CLIENT_APP(c) (MB_WM_OBJECT_TYPE(c)==MB_WM_TYPE_CLIENT_APP)
+
+struct MBWMClientApp
+{
+ MBWMClientBase parent;
+};
+
+struct MBWMClientAppClass
+{
+ MBWMClientBaseClass parent;
+
+};
+
+MBWindowManagerClient*
+mb_wm_client_app_new(MBWindowManager *wm, MBWMClientWindow *win);
+
+int
+mb_wm_client_app_class_type ();
+
+#endif
diff --git a/matchbox2/client-types/mb-wm-client-desktop.c b/matchbox2/client-types/mb-wm-client-desktop.c
new file mode 100644
index 0000000..81ce628
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-desktop.c
@@ -0,0 +1,196 @@
+#include "mb-wm-client-desktop.h"
+#include "mb-wm-theme.h"
+
+static Bool
+mb_wm_client_desktop_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags);
+
+static MBWMStackLayerType
+mb_wm_client_desktop_stacking_layer (MBWindowManagerClient *client);
+
+static void
+mb_wm_client_desktop_theme_change (MBWindowManagerClient *client);
+
+static void
+mb_wm_client_desktop_class_init (MBWMObjectClass *klass)
+{
+ MBWindowManagerClientClass *client;
+ MBWMClientDesktopClass * client_desktop;
+
+ MBWM_MARK();
+
+ client = (MBWindowManagerClientClass *)klass;
+ client_desktop = (MBWMClientDesktopClass *)klass;
+
+ client->client_type = MBWMClientTypeDesktop;
+ client->geometry = mb_wm_client_desktop_request_geometry;
+ client->stacking_layer = mb_wm_client_desktop_stacking_layer;
+ client->theme_change = mb_wm_client_desktop_theme_change;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMClientDesktop";
+#endif
+}
+
+static void
+mb_wm_client_desktop_destroy (MBWMObject *this)
+{
+}
+
+static int
+mb_wm_client_desktop_init (MBWMObject *this, va_list vap)
+{
+ MBWindowManagerClient *client = MB_WM_CLIENT (this);
+ MBWindowManager *wm = NULL;
+ MBWMClientDesktopClass *inp_class;
+ MBGeometry geom;
+
+ inp_class = MB_WM_CLIENT_DESKTOP_CLASS (MB_WM_OBJECT_GET_CLASS (this));
+
+ wm = client->wmref;
+
+ if (!wm)
+ return 0;
+
+ client->stacking_layer = MBWMStackLayerBottom;
+
+ mb_wm_client_set_layout_hints (client,
+ LayoutPrefFullscreen|LayoutPrefVisible);
+
+ if (!client->window->undecorated)
+ {
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeNorth);
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeSouth);
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeWest);
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeEast);
+ }
+
+ /*
+ * Initialize window geometry, so that the frame size is correct
+ */
+ geom.x = 0;
+ geom.y = 0;
+ geom.width = wm->xdpy_width;
+ geom.height = wm->xdpy_height;
+
+ mb_wm_client_desktop_request_geometry (client, &geom,
+ MBWMClientReqGeomForced);
+
+ return 1;
+}
+
+int
+mb_wm_client_desktop_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMClientDesktopClass),
+ sizeof (MBWMClientDesktop),
+ mb_wm_client_desktop_init,
+ mb_wm_client_desktop_destroy,
+ mb_wm_client_desktop_class_init
+ };
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_CLIENT_BASE, 0);
+ }
+
+ return type;
+}
+
+static Bool
+mb_wm_client_desktop_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags)
+{
+ if (flags & (MBWMClientReqGeomIsViaLayoutManager|MBWMClientReqGeomForced))
+ {
+ int north = 0, south = 0, west = 0, east = 0;
+ MBWindowManager *wm = client->wmref;
+
+ if (client->decor)
+ mb_wm_theme_get_decor_dimensions (wm->theme, client,
+ &north, &south, &west, &east);
+
+ client->frame_geometry.x = new_geometry->x;
+ client->frame_geometry.y = new_geometry->y;
+ client->frame_geometry.width = new_geometry->width;
+ client->frame_geometry.height = new_geometry->height;
+
+ client->window->geometry.x
+ = client->frame_geometry.x + west;
+ client->window->geometry.y
+ = client->frame_geometry.y + north;
+ client->window->geometry.width
+ = client->frame_geometry.width - (west + east);
+ client->window->geometry.height
+ = client->frame_geometry.height - (south + north);
+
+ mb_wm_client_geometry_mark_dirty (client);
+
+ return True; /* Geometry accepted */
+ }
+ return False;
+}
+
+static MBWMStackLayerType
+mb_wm_client_desktop_stacking_layer (MBWindowManagerClient *client)
+{
+ if (client->wmref->flags & MBWindowManagerFlagDesktop)
+ return MBWMStackLayerMid;
+
+ return MBWMStackLayerBottom;
+}
+
+static void
+mb_wm_client_desktop_theme_change (MBWindowManagerClient *client)
+{
+ MBWMList * l = client->decor;
+
+ while (l)
+ {
+ MBWMDecor * d = l->data;
+ MBWMList * n = l->next;
+
+ mb_wm_object_unref (MB_WM_OBJECT (d));
+ free (l);
+
+ l = n;
+ }
+
+ client->decor = NULL;
+
+ if (!client->window->undecorated)
+ {
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeNorth);
+
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeSouth);
+
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeWest);
+
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeEast);
+ }
+
+ mb_wm_client_geometry_mark_dirty (client);
+ mb_wm_client_visibility_mark_dirty (client);
+}
+
+MBWindowManagerClient*
+mb_wm_client_desktop_new (MBWindowManager *wm, MBWMClientWindow *win)
+{
+ MBWindowManagerClient *client;
+
+ client = MB_WM_CLIENT(mb_wm_object_new (MB_WM_TYPE_CLIENT_DESKTOP,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropClientWindow, win,
+ NULL));
+
+ return client;
+}
+
diff --git a/matchbox2/client-types/mb-wm-client-desktop.h b/matchbox2/client-types/mb-wm-client-desktop.h
new file mode 100644
index 0000000..c132cdb
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-desktop.h
@@ -0,0 +1,50 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_CLIENT_DESKTOP_H
+#define _HAVE_MB_CLIENT_DESKTOP_H
+
+#include <matchbox2/core/mb-wm.h>
+
+typedef struct MBWMClientDesktop MBWMClientDesktop;
+typedef struct MBWMClientDesktopClass MBWMClientDesktopClass;
+
+#define MB_WM_CLIENT_DESKTOP(c) ((MBWMClientDesktop*)(c))
+#define MB_WM_CLIENT_DESKTOP_CLASS(c) ((MBWMClientDesktopClass*)(c))
+#define MB_WM_TYPE_CLIENT_DESKTOP (mb_wm_client_desktop_class_type ())
+#define MB_WM_IS_CLIENT_DESKTOP(c) (MB_WM_OBJECT_TYPE(c)==MB_WM_TYPE_CLIENT_DESKTOP)
+
+struct MBWMClientDesktop
+{
+ MBWMClientBase parent;
+};
+
+struct MBWMClientDesktopClass
+{
+ MBWMClientBaseClass parent;
+};
+
+MBWindowManagerClient*
+mb_wm_client_desktop_new(MBWindowManager *wm, MBWMClientWindow *win);
+
+int
+mb_wm_client_desktop_class_type ();
+
+#endif
diff --git a/matchbox2/client-types/mb-wm-client-dialog.c b/matchbox2/client-types/mb-wm-client-dialog.c
new file mode 100644
index 0000000..e4bcdfb
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-dialog.c
@@ -0,0 +1,359 @@
+#include "mb-wm-client-dialog.h"
+
+#include "mb-wm-theme.h"
+
+static Bool
+mb_wm_client_dialog_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags);
+
+static void
+mb_wm_client_dialog_theme_change (MBWindowManagerClient *client);
+
+static void
+mb_wm_client_dialog_show (MBWindowManagerClient *client)
+{
+ MBWindowManagerClientClass *parent_klass = NULL;
+
+ /*
+ * We need the parent of the MBWMClientDialogClass to chain up
+ */
+ if (MB_WM_IS_CLIENT_DIALOG (client))
+ parent_klass = MB_WM_CLIENT_CLASS (MB_WM_OBJECT_GET_PARENT_CLASS (client));
+ else
+ {
+ /*
+ * A derived klass -- need to traverse the klass hierarchy to get to
+ * the dialog klass
+ */
+ MBWMObjectClass * object_klass = MB_WM_OBJECT_GET_PARENT_CLASS (client);
+
+ while (object_klass && object_klass->type != MB_WM_TYPE_CLIENT_DIALOG)
+ object_klass = object_klass->parent;
+
+ if (object_klass && object_klass->parent)
+ parent_klass = MB_WM_CLIENT_CLASS (object_klass->parent);
+ }
+
+ if (client->transient_for != NULL)
+ {
+ MBWindowManager * wm = client->wmref;
+
+ /*
+ * If an attempt has been made to activate a hidden
+ * dialog, activate its parent app first.
+ *
+ * Note this is mainly to work with some task selectors
+ * ( eg the gnome one, which activates top dialog ).
+ */
+ MBWindowManagerClient *parent = client->transient_for;
+
+ while (parent->transient_for != NULL)
+ parent = parent->transient_for;
+
+ if (parent != mb_wm_get_visible_main_client(wm))
+ mb_wm_client_show (parent);
+ }
+
+ if (parent_klass && parent_klass->show)
+ parent_klass->show(client);
+}
+
+static void
+mb_wm_client_dialog_class_init (MBWMObjectClass *klass)
+{
+ MBWindowManagerClientClass *client;
+
+ MBWM_MARK();
+
+ client = (MBWindowManagerClientClass *)klass;
+
+ client->client_type = MBWMClientTypeDialog;
+ client->geometry = mb_wm_client_dialog_request_geometry;
+ client->show = mb_wm_client_dialog_show;
+ client->theme_change = mb_wm_client_dialog_theme_change;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMClientDialog";
+#endif
+}
+
+static void
+mb_wm_client_dialog_destroy (MBWMObject *this)
+{
+}
+
+static int
+mb_wm_client_dialog_init (MBWMObject *this, va_list vap)
+{
+ MBWindowManagerClient *client = MB_WM_CLIENT (this);
+ MBWindowManager *wm = client->wmref;
+ MBWMClientWindow *win = client->window;
+ MBGeometry geom;
+ int n, s, w, e;
+ Atom actions[] = {
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_CLOSE],
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_MOVE],
+ };
+
+ XChangeProperty (wm->xdpy, win->xwindow,
+ wm->atoms[MBWM_ATOM_NET_WM_ALLOWED_ACTIONS],
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *)actions,
+ sizeof (actions)/sizeof (actions[0]));
+
+
+ mb_wm_client_set_layout_hints (client,
+ LayoutPrefPositionFree |
+ LayoutPrefMovable |
+ LayoutPrefVisible);
+
+ if (!client->window->undecorated)
+ {
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeNorth);
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeSouth);
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeWest);
+ mb_wm_theme_create_decor (wm->theme, client, MBWMDecorTypeEast);
+ }
+
+ if (win->xwin_transient_for
+ && win->xwin_transient_for != win->xwindow
+ && win->xwin_transient_for != wm->root_win->xwindow)
+ {
+ MBWM_DBG ("Adding to '%lx' transient list",
+ win->xwin_transient_for);
+ mb_wm_client_add_transient
+ (mb_wm_managed_client_from_xwindow (wm,
+ win->xwin_transient_for),
+ client);
+ client->stacking_layer = 0; /* We stack with whatever transient too */
+ }
+ else
+ {
+ MBWM_DBG ("Dialog is transient to root");
+ /* Stack with 'always on top' */
+ client->stacking_layer = MBWMStackLayerTopMid;
+ }
+
+ /* center if window sets 0,0
+ * Only do this for dialogs, not derived classes.
+ * FIXME needs to work on frame, not window.
+ */
+ if (MB_WM_IS_CLIENT_DIALOG (client) &&
+ client->window->geometry.x == 0 && client->window->geometry.y == 0)
+ {
+ MBGeometry avail_geom;
+
+ mb_wm_get_display_geometry (wm, &avail_geom);
+
+ client->window->geometry.x
+ = (avail_geom.width - client->window->geometry.width) / 2;
+ client->window->geometry.y
+ = (avail_geom.height - client->window->geometry.height) / 2;
+ }
+
+ mb_wm_client_geometry_mark_dirty (client);
+ mb_wm_client_visibility_mark_dirty (client);
+
+ if (!wm->theme)
+ return 1;
+
+ /*
+ * Since dialogs are free-sized, they do not necessarily get a request for
+ * geometry from the layout manager -- we have to set the initial geometry
+ * here
+ */
+ mb_wm_theme_get_decor_dimensions (wm->theme, client, &n, &s, &w, &e);
+
+ geom.x = client->window->geometry.x;
+ geom.y = client->window->geometry.y;
+ geom.width = client->window->geometry.width + w + e;
+ geom.height = client->window->geometry.height + n + s;
+
+ mb_wm_client_dialog_request_geometry (client, &geom,
+ MBWMClientReqGeomForced);
+
+ return 1;
+}
+
+int
+mb_wm_client_dialog_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMClientDialogClass),
+ sizeof (MBWMClientDialog),
+ mb_wm_client_dialog_init,
+ mb_wm_client_dialog_destroy,
+ mb_wm_client_dialog_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_CLIENT_BASE, 0);
+ }
+
+ return type;
+}
+
+static Bool
+mb_wm_client_dialog_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags)
+{
+ const MBGeometry * geom;
+ Bool change_pos;
+ Bool change_size;
+
+ /*
+ * When we get an internal geometry request, like from the layout manager,
+ * the new geometry applies to the frame; however, if the request is
+ * external from ConfigureRequest, it is new geometry of the client window,
+ * so we need to take care to handle this right.
+ */
+ geom = (flags & MBWMClientReqGeomIsViaConfigureReq) ?
+ &client->window->geometry : &client->frame_geometry;
+
+ change_pos = (geom->x != new_geometry->x || geom->y != new_geometry->y);
+
+ change_size = (geom->width != new_geometry->width ||
+ geom->height != new_geometry->height);
+
+ if (change_size)
+ {
+ int north = 0, south = 0, west = 0, east = 0;
+ MBWindowManager *wm = client->wmref;
+
+ if (client->decor)
+ mb_wm_theme_get_decor_dimensions (wm->theme, client,
+ &north, &south, &west, &east);
+
+ if (flags & MBWMClientReqGeomIsViaConfigureReq)
+ {
+ /*
+ * Calculate the frame size from the window size
+ */
+ MBWM_DBG ("ConfigureRequest [%d,%d;%dx%d] -> [%d,%d;%dx%d]\n",
+ client->window->geometry.x,
+ client->window->geometry.y,
+ client->window->geometry.width,
+ client->window->geometry.height,
+ new_geometry->x,
+ new_geometry->y,
+ new_geometry->width,
+ new_geometry->height);
+
+ client->window->geometry.x = new_geometry->x;
+ client->window->geometry.y = new_geometry->y;
+ client->window->geometry.width = new_geometry->width;
+ client->window->geometry.height = new_geometry->height;
+
+ client->frame_geometry.x
+ = client->window->geometry.x - west;
+ client->frame_geometry.y
+ = client->window->geometry.y - north;
+ client->frame_geometry.width
+ = client->window->geometry.width + (west + east);
+ client->frame_geometry.height
+ = client->window->geometry.height + (south + north);
+ }
+ else
+ {
+ /*
+ * Internal request, e.g., from layout manager; work out client
+ * window size from the provided frame size.
+ */
+ client->frame_geometry.x = new_geometry->x;
+ client->frame_geometry.y = new_geometry->y;
+ client->frame_geometry.width = new_geometry->width;
+ client->frame_geometry.height = new_geometry->height;
+
+ client->window->geometry.x
+ = client->frame_geometry.x + west;
+ client->window->geometry.y
+ = client->frame_geometry.y + north;
+ client->window->geometry.width
+ = client->frame_geometry.width - (west + east);
+ client->window->geometry.height
+ = client->frame_geometry.height - (south + north);
+ }
+
+ mb_wm_client_geometry_mark_dirty (client);
+
+ return True; /* Geometry accepted */
+ }
+ else if (change_pos)
+ {
+ /*
+ * Change of position only, just move both windows, no need to
+ * mess about with the decor.
+ */
+ int x_diff = geom->x - new_geometry->x;
+ int y_diff = geom->y - new_geometry->y;
+
+ client->frame_geometry.x -= x_diff;
+ client->frame_geometry.y -= y_diff;
+ client->window->geometry.x -= x_diff;
+ client->window->geometry.y -= y_diff;
+
+ mb_wm_client_geometry_mark_dirty (client);
+
+ return True;
+ }
+
+ return True; /* Geometry accepted */
+}
+
+static void
+mb_wm_client_dialog_theme_change (MBWindowManagerClient *client)
+{
+ MBWMList * l = client->decor;
+
+ while (l)
+ {
+ MBWMDecor * d = l->data;
+ MBWMList * n = l->next;
+
+ mb_wm_object_unref (MB_WM_OBJECT (d));
+ free (l);
+
+ l = n;
+ }
+
+ client->decor = NULL;
+
+ if (!client->window->undecorated)
+ {
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeNorth);
+
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeSouth);
+
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeWest);
+
+ mb_wm_theme_create_decor (client->wmref->theme,
+ client, MBWMDecorTypeEast);
+ }
+
+ mb_wm_client_geometry_mark_dirty (client);
+ mb_wm_client_visibility_mark_dirty (client);
+}
+
+
+MBWindowManagerClient*
+mb_wm_client_dialog_new (MBWindowManager *wm, MBWMClientWindow *win)
+{
+ MBWindowManagerClient *client;
+
+ client
+ = MB_WM_CLIENT(mb_wm_object_new (MB_WM_TYPE_CLIENT_DIALOG,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropClientWindow, win,
+ NULL));
+
+ return client;
+}
+
diff --git a/matchbox2/client-types/mb-wm-client-dialog.h b/matchbox2/client-types/mb-wm-client-dialog.h
new file mode 100644
index 0000000..de9db01
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-dialog.h
@@ -0,0 +1,51 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_CLIENT_DIALOG_H
+#define _HAVE_MB_CLIENT_DIALOG_H
+
+#include <matchbox2/core/mb-wm.h>
+
+typedef struct MBWMClientDialog MBWMClientDialog;
+typedef struct MBWMClientDialogClass MBWMClientDialogClass;
+
+#define MB_WM_CLIENT_DIALOG(c) ((MBWMClientDialog*)(c))
+#define MB_WM_CLIENT_DIALOG_CLASS(c) ((MBWMClientDialogClass*)(c))
+#define MB_WM_TYPE_CLIENT_DIALOG (mb_wm_client_dialog_class_type ())
+#define MB_WM_IS_CLIENT_DIALOG(c) (MB_WM_OBJECT_TYPE(c)==MB_WM_TYPE_CLIENT_DIALOG)
+
+struct MBWMClientDialog
+{
+ MBWMClientBase parent;
+ MBWMDecorButton *button_close;
+};
+
+struct MBWMClientDialogClass
+{
+ MBWMClientBaseClass parent;
+};
+
+MBWindowManagerClient*
+mb_wm_client_dialog_new (MBWindowManager *wm, MBWMClientWindow *win);
+
+int
+mb_wm_client_dialog_class_type ();
+
+#endif
diff --git a/matchbox2/client-types/mb-wm-client-input.c b/matchbox2/client-types/mb-wm-client-input.c
new file mode 100644
index 0000000..3a63d40
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-input.c
@@ -0,0 +1,184 @@
+#include "mb-wm-client-input.h"
+
+static void
+mb_wm_client_input_detransitise (MBWindowManagerClient *client);
+
+static void
+mb_wm_client_input_realize (MBWindowManagerClient *client);
+
+static Bool
+mb_wm_client_input_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags);
+
+static void
+mb_wm_client_input_stack (MBWindowManagerClient *client, int flags);
+
+static void
+mb_wm_client_input_class_init (MBWMObjectClass *klass)
+{
+ MBWindowManagerClientClass *client;
+ MBWMClientInputClass * client_input;
+
+ MBWM_MARK();
+
+ client = (MBWindowManagerClientClass *)klass;
+ client_input = (MBWMClientInputClass *)klass;
+
+ MBWM_DBG("client->stack is %p", client->stack);
+
+ client->client_type = MBWMClientTypeInput;
+ client->geometry = mb_wm_client_input_request_geometry;
+ client->stack = mb_wm_client_input_stack;
+ client->realize = mb_wm_client_input_realize;
+ client->detransitise = mb_wm_client_input_detransitise;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMClientInput";
+#endif
+}
+
+static void
+mb_wm_client_input_destroy (MBWMObject *this)
+{
+}
+
+static int
+mb_wm_client_input_init (MBWMObject *this, va_list vap)
+{
+ MBWMClientInput *client_input = MB_WM_CLIENT_INPUT (this);
+ MBWindowManagerClient *client = MB_WM_CLIENT (this);
+ MBWindowManager *wm = client->wmref;
+ MBWMClientWindow *win = client->window;
+
+ if (win->xwin_transient_for
+ && win->xwin_transient_for != win->xwindow
+ && win->xwin_transient_for != wm->root_win->xwindow)
+ {
+ MBWindowManagerClient * t =
+ mb_wm_managed_client_from_xwindow (wm,
+ win->xwin_transient_for);
+
+ mb_wm_client_get_coverage (t, & client_input->transient_geom);
+
+ MBWM_DBG ("Adding to '%lx' transient list", win->xwin_transient_for);
+ mb_wm_client_add_transient (t, client);
+ client->stacking_layer = 0; /* We stack with whatever transient too */
+ }
+ else
+ {
+ MBWM_DBG ("Input is transient to root");
+ /* Stack with 'always on top' */
+ client->stacking_layer = MBWMStackLayerTopMid;
+ }
+
+ mb_wm_client_set_layout_hints (client,
+ LayoutPrefReserveSouth|LayoutPrefVisible);
+
+ return 1;
+}
+
+int
+mb_wm_client_input_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMClientInputClass),
+ sizeof (MBWMClientInput),
+ mb_wm_client_input_init,
+ mb_wm_client_input_destroy,
+ mb_wm_client_input_class_init
+ };
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_CLIENT_BASE, 0);
+ }
+
+ return type;
+}
+
+static void
+mb_wm_client_input_realize (MBWindowManagerClient *client)
+{
+ /*
+ * Must reparent the window to our root, otherwise we restacking of
+ * pre-existing windows might fail.
+ */
+ XReparentWindow(client->wmref->xdpy, MB_WM_CLIENT_XWIN(client),
+ client->wmref->root_win->xwindow, 0, 0);
+
+ return;
+}
+
+static Bool
+mb_wm_client_input_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags)
+{
+ if (flags &
+ (MBWMClientReqGeomIsViaLayoutManager|MBWMClientReqGeomIsViaConfigureReq))
+ {
+ client->frame_geometry.x = new_geometry->x;
+ client->frame_geometry.y = new_geometry->y;
+ client->frame_geometry.width = new_geometry->width;
+ client->frame_geometry.height = new_geometry->height;
+
+ client->window->geometry.x = client->frame_geometry.x;
+ client->window->geometry.y = client->frame_geometry.y;
+ client->window->geometry.width = client->frame_geometry.width;
+ client->window->geometry.height = client->frame_geometry.height;
+
+ mb_wm_client_geometry_mark_dirty (client);
+
+ return True; /* Geometry accepted */
+ }
+ return False;
+}
+
+static void
+mb_wm_client_input_stack (MBWindowManagerClient *client, int flags)
+{
+ MBWM_MARK();
+
+ mb_wm_stack_move_client_above_type (client,
+ MBWMClientTypeApp|MBWMClientTypeDesktop);
+}
+
+MBWindowManagerClient*
+mb_wm_client_input_new (MBWindowManager *wm, MBWMClientWindow *win)
+{
+ MBWindowManagerClient *client;
+
+ client = MB_WM_CLIENT(mb_wm_object_new (MB_WM_TYPE_CLIENT_INPUT,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropClientWindow, win,
+ NULL));
+
+ return client;
+}
+
+static void
+mb_wm_client_input_detransitise (MBWindowManagerClient *client)
+{
+ MBWMClientInput * input = MB_WM_CLIENT_INPUT (client);
+
+ /*
+ * If the IM is not transient, or it is transient for something other
+ * than an application or dialog, just return from here.
+ *
+ * If it is transient for an app or dialog, adjust the geometry accordingly.
+ */
+ if (!client->transient_for ||
+ MB_WM_CLIENT_CLIENT_TYPE (client->transient_for) !=
+ (MBWMClientTypeApp | MBWMClientTypeDialog))
+ return;
+
+ if (input->transient_geom.width && input->transient_geom.height)
+ {
+ mb_wm_client_request_geometry (client->transient_for,
+ &input->transient_geom,
+ MBWMClientReqGeomForced);
+ }
+}
+
diff --git a/matchbox2/client-types/mb-wm-client-input.h b/matchbox2/client-types/mb-wm-client-input.h
new file mode 100644
index 0000000..ea63bd6
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-input.h
@@ -0,0 +1,52 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_CLIENT_INPUT_H
+#define _HAVE_MB_CLIENT_INPUT_H
+
+#include <matchbox2/core/mb-wm.h>
+
+typedef struct MBWMClientInput MBWMClientInput;
+typedef struct MBWMClientInputClass MBWMClientInputClass;
+
+#define MB_WM_CLIENT_INPUT(c) ((MBWMClientInput*)(c))
+#define MB_WM_CLIENT_INPUT_CLASS(c) ((MBWMClientInputClass*)(c))
+#define MB_WM_TYPE_CLIENT_INPUT (mb_wm_client_input_class_type ())
+#define MB_WM_IS_CLIENT_INPUT(c) (MB_WM_OBJECT_TYPE(c)==MB_WM_TYPE_CLIENT_INPUT)
+
+struct MBWMClientInput
+{
+ MBWMClientBase parent;
+
+ MBGeometry transient_geom;
+};
+
+struct MBWMClientInputClass
+{
+ MBWMClientBaseClass parent;
+};
+
+MBWindowManagerClient*
+mb_wm_client_input_new (MBWindowManager *wm, MBWMClientWindow *win);
+
+int
+mb_wm_client_input_class_type ();
+
+#endif
diff --git a/matchbox2/client-types/mb-wm-client-menu.c b/matchbox2/client-types/mb-wm-client-menu.c
new file mode 100644
index 0000000..b68f771
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-menu.c
@@ -0,0 +1,156 @@
+#include "mb-wm-client-menu.h"
+
+#include "mb-wm-theme.h"
+
+static Bool
+mb_wm_client_menu_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags);
+
+static void
+mb_wm_client_menu_realize (MBWindowManagerClient *client)
+{
+ /*
+ * Must reparent the window to our root, otherwise we restacking of
+ * pre-existing windows might fail.
+ */
+ XReparentWindow(client->wmref->xdpy, MB_WM_CLIENT_XWIN(client),
+ client->wmref->root_win->xwindow, 0, 0);
+}
+
+static void
+mb_wm_client_menu_class_init (MBWMObjectClass *klass)
+{
+ MBWindowManagerClientClass *client;
+
+ MBWM_MARK();
+
+ client = (MBWindowManagerClientClass *)klass;
+
+ client->client_type = MBWMClientTypeMenu;
+ client->geometry = mb_wm_client_menu_request_geometry;
+ client->realize = mb_wm_client_menu_realize;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMClientMenu";
+#endif
+}
+
+static void
+mb_wm_client_menu_destroy (MBWMObject *this)
+{
+}
+
+static int
+mb_wm_client_menu_init (MBWMObject *this, va_list vap)
+{
+ MBWindowManagerClient *client = MB_WM_CLIENT (this);
+ MBWindowManager *wm = client->wmref;
+ MBWMClientWindow *win = client->window;
+ Atom actions[] = {
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_CLOSE],
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_MOVE],
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_RESIZE],
+ };
+
+ XChangeProperty (wm->xdpy, win->xwindow,
+ wm->atoms[MBWM_ATOM_NET_WM_ALLOWED_ACTIONS],
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *)actions,
+ sizeof (actions)/sizeof (actions[0]));
+
+ mb_wm_client_set_layout_hints (client,
+ LayoutPrefPositionFree|LayoutPrefVisible|
+ LayoutPrefFixedX|LayoutPrefFixedY);
+
+ /*
+ * Stack menus on the top of the stacking order, regardless of whether they
+ * declare themselves transient or not.
+ *
+ * (Gtk menus do kbd and pointer grabs and do not take kindly to being
+ * restacked.)
+ */
+#if 0
+ if (win->xwin_transient_for
+ && win->xwin_transient_for != win->xwindow
+ && win->xwin_transient_for != wm->root_win->xwindow)
+ {
+ MBWM_DBG ("Adding to '%lx' transient list",
+ win->xwin_transient_for);
+ mb_wm_client_add_transient
+ (mb_wm_managed_client_from_xwindow (wm,
+ win->xwin_transient_for),
+ client);
+ client->stacking_layer = 0; /* We stack with whatever transient too */
+ }
+ else
+ {
+ MBWM_DBG ("Menu is transient to root");
+ /* Stack with 'always on top' */
+ client->stacking_layer = MBWMStackLayerTopMid;
+ }
+#else
+ client->stacking_layer = MBWMStackLayerTop;
+#endif
+
+ return 1;
+}
+
+int
+mb_wm_client_menu_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMClientMenuClass),
+ sizeof (MBWMClientMenu),
+ mb_wm_client_menu_init,
+ mb_wm_client_menu_destroy,
+ mb_wm_client_menu_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_CLIENT_BASE, 0);
+ }
+
+ return type;
+}
+
+static Bool
+mb_wm_client_menu_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags)
+{
+ if (client->window->geometry.x != new_geometry->x
+ || client->window->geometry.y != new_geometry->y
+ || client->window->geometry.width != new_geometry->width
+ || client->window->geometry.height != new_geometry->height)
+ {
+ client->window->geometry.x = new_geometry->x;
+ client->window->geometry.y = new_geometry->y;
+ client->window->geometry.width = new_geometry->width;
+ client->window->geometry.height = new_geometry->height;
+
+ mb_wm_client_geometry_mark_dirty (client);
+
+ return True; /* Geometry accepted */
+ }
+
+ return True; /* Geometry accepted */
+}
+
+MBWindowManagerClient*
+mb_wm_client_menu_new (MBWindowManager *wm, MBWMClientWindow *win)
+{
+ MBWindowManagerClient *client;
+
+ client
+ = MB_WM_CLIENT(mb_wm_object_new (MB_WM_TYPE_CLIENT_MENU,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropClientWindow, win,
+ NULL));
+
+ return client;
+}
+
diff --git a/matchbox2/client-types/mb-wm-client-menu.h b/matchbox2/client-types/mb-wm-client-menu.h
new file mode 100644
index 0000000..ac54e86
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-menu.h
@@ -0,0 +1,50 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_CLIENT_MENU_H
+#define _HAVE_MB_CLIENT_MENU_H
+
+#include <matchbox2/core/mb-wm.h>
+
+typedef struct MBWMClientMenu MBWMClientMenu;
+typedef struct MBWMClientMenuClass MBWMClientMenuClass;
+
+#define MB_WM_CLIENT_MENU(c) ((MBWMClientMenu*)(c))
+#define MB_WM_CLIENT_MENU_CLASS(c) ((MBWMClientMenuClass*)(c))
+#define MB_WM_TYPE_CLIENT_MENU (mb_wm_client_menu_class_type ())
+#define MB_WM_IS_CLIENT_MENU(c) (MB_WM_OBJECT_TYPE(c)==MB_WM_TYPE_CLIENT_MENU)
+
+struct MBWMClientMenu
+{
+ MBWMClientBase parent;
+};
+
+struct MBWMClientMenuClass
+{
+ MBWMClientBaseClass parent;
+};
+
+MBWindowManagerClient*
+mb_wm_client_menu_new (MBWindowManager *wm, MBWMClientWindow *win);
+
+int
+mb_wm_client_menu_class_type ();
+
+#endif
diff --git a/matchbox2/client-types/mb-wm-client-note.c b/matchbox2/client-types/mb-wm-client-note.c
new file mode 100644
index 0000000..d0bb770
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-note.c
@@ -0,0 +1,153 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2007 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mb-wm-client-note.h"
+
+#include "mb-wm-theme.h"
+
+static void
+mb_wm_client_note_class_init (MBWMObjectClass *klass)
+{
+ MBWindowManagerClientClass *client;
+
+ MBWM_MARK();
+
+ client = (MBWindowManagerClientClass *)klass;
+
+ client->client_type = MBWMClientTypeNote;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMClientNote";
+#endif
+}
+
+static void
+mb_wm_client_note_destroy (MBWMObject *this)
+{
+}
+
+static int
+mb_wm_client_note_init (MBWMObject *this, va_list vap)
+{
+ MBWindowManagerClient *client = MB_WM_CLIENT (this);
+ MBWindowManager *wm = client->wmref;
+ MBWMClientWindow *win = client->window;
+ MBGeometry geom;
+ Bool change = False;
+ Atom actions[] = {
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_CLOSE],
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_MOVE],
+ };
+
+ geom = client->frame_geometry;
+
+ if (geom.x >= wm->xdpy_width)
+ {
+ geom.x = wm->xdpy_width - geom.width;
+ change = True;
+ }
+
+ if (geom.y >= wm->xdpy_height)
+ {
+ geom.y = wm->xdpy_height - geom.height;
+ change = True;
+ }
+
+ switch (win->gravity)
+ {
+ case SouthGravity:
+ geom.y = wm->xdpy_height - geom.height;
+ change = True;
+ break;
+ case EastGravity:
+ geom.x = wm->xdpy_width - geom.width;
+ change = True;
+ break;
+ case SouthEastGravity:
+ geom.y = wm->xdpy_height - geom.height;
+ geom.x = wm->xdpy_width - geom.width;
+ change = True;
+ break;
+ case NorthGravity:
+ geom.y = 0;
+ change = True;
+ break;
+ case WestGravity:
+ geom.x = 0;
+ change = True;
+ break;
+ case NorthWestGravity:
+ case CenterGravity:
+ case StaticGravity:
+ default:
+ ;
+ }
+
+ if (change)
+ {
+ mb_wm_client_request_geometry (client, &geom, MBWMClientReqGeomForced);
+ mb_wm_client_geometry_mark_dirty (client);
+ }
+
+
+ XChangeProperty (wm->xdpy, win->xwindow,
+ wm->atoms[MBWM_ATOM_NET_WM_ALLOWED_ACTIONS],
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *)actions,
+ sizeof (actions)/sizeof (actions[0]));
+
+ return 1;
+}
+
+int
+mb_wm_client_note_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMClientNoteClass),
+ sizeof (MBWMClientNote),
+ mb_wm_client_note_init,
+ mb_wm_client_note_destroy,
+ mb_wm_client_note_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_CLIENT_DIALOG, 0);
+ }
+
+ return type;
+}
+
+MBWindowManagerClient*
+mb_wm_client_note_new (MBWindowManager *wm, MBWMClientWindow *win)
+{
+ MBWindowManagerClient *client;
+
+ client
+ = MB_WM_CLIENT (mb_wm_object_new (MB_WM_TYPE_CLIENT_NOTE,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropClientWindow, win,
+ NULL));
+
+ return client;
+}
+
diff --git a/matchbox2/client-types/mb-wm-client-note.h b/matchbox2/client-types/mb-wm-client-note.h
new file mode 100644
index 0000000..d2390ae
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-note.h
@@ -0,0 +1,51 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2007 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _HAVE_MB_CLIENT_NOTE_H
+#define _HAVE_MB_CLIENT_NOTE_H
+
+#include <matchbox2/core/mb-wm.h>
+#include <matchbox2/client-types/mb-wm-client-dialog.h>
+
+typedef struct MBWMClientNote MBWMClientNote;
+typedef struct MBWMClientNoteClass MBWMClientNoteClass;
+
+#define MB_WM_CLIENT_NOTE(c) ((MBWMClientNote*)(c))
+#define MB_WM_CLIENT_NOTE_CLASS(c) ((MBWMClientNoteClass*)(c))
+#define MB_WM_TYPE_CLIENT_NOTE (mb_wm_client_note_class_type ())
+#define MB_WM_IS_CLIENT_NOTE(c) (MB_WM_OBJECT_TYPE(c)==MB_WM_TYPE_CLIENT_NOTE)
+
+struct MBWMClientNote
+{
+ MBWMClientDialog parent;
+};
+
+struct MBWMClientNoteClass
+{
+ MBWMClientDialogClass parent;
+};
+
+MBWindowManagerClient*
+mb_wm_client_note_new (MBWindowManager *wm, MBWMClientWindow *win);
+
+int
+mb_wm_client_note_class_type ();
+
+#endif
diff --git a/matchbox2/client-types/mb-wm-client-override.c b/matchbox2/client-types/mb-wm-client-override.c
new file mode 100644
index 0000000..238ce73
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-override.c
@@ -0,0 +1,124 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2007 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mb-wm-client-override.h"
+
+#include "mb-wm-theme.h"
+
+static void
+mb_wm_client_override_stack (MBWindowManagerClient *client,
+ int flags)
+{
+ MBWMList * t = mb_wm_client_get_transients (client);
+
+ mb_wm_stack_move_top(client);
+
+ mb_wm_util_list_foreach (t, (MBWMListForEachCB)mb_wm_client_stack,
+ (void*)flags);
+
+ mb_wm_util_list_free (t);
+}
+
+static void
+mb_wm_client_override_class_init (MBWMObjectClass *klass)
+{
+ MBWindowManagerClientClass *client;
+
+ MBWM_MARK();
+
+ client = (MBWindowManagerClientClass *)klass;
+
+ client->client_type = MBWMClientTypeOverride;
+ client->stack = mb_wm_client_override_stack;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMClientOverride";
+#endif
+}
+
+static void
+mb_wm_client_override_destroy (MBWMObject *this)
+{
+}
+
+static int
+mb_wm_client_override_init (MBWMObject *this, va_list vap)
+{
+ MBWindowManagerClient *client = MB_WM_CLIENT (this);
+ MBWindowManager *wm = client->wmref;
+ MBWMClientWindow *win = client->window;
+
+ if (win->xwin_transient_for
+ && win->xwin_transient_for != win->xwindow
+ && win->xwin_transient_for != wm->root_win->xwindow)
+ {
+ MBWM_DBG ("Adding to '%lx' transient list",
+ win->xwin_transient_for);
+ mb_wm_client_add_transient
+ (mb_wm_managed_client_from_xwindow (wm,
+ win->xwin_transient_for),
+ client);
+ client->stacking_layer = 0; /* We stack with whatever transient too */
+ }
+ else
+ {
+ MBWM_DBG ("Override is transient to root or intransient");
+ /* Stack with 'always on top' */
+ client->stacking_layer = MBWMStackLayerTop;
+ }
+
+ return 1;
+}
+
+int
+mb_wm_client_override_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMClientOverrideClass),
+ sizeof (MBWMClientOverride),
+ mb_wm_client_override_init,
+ mb_wm_client_override_destroy,
+ mb_wm_client_override_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_CLIENT, 0);
+ }
+
+ return type;
+}
+
+MBWindowManagerClient*
+mb_wm_client_override_new (MBWindowManager *wm, MBWMClientWindow *win)
+{
+ MBWindowManagerClient *client;
+
+ client
+ = MB_WM_CLIENT(mb_wm_object_new (MB_WM_TYPE_CLIENT_OVERRIDE,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropClientWindow, win,
+ NULL));
+
+ return client;
+}
+
diff --git a/matchbox2/client-types/mb-wm-client-override.h b/matchbox2/client-types/mb-wm-client-override.h
new file mode 100644
index 0000000..a804a39
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-override.h
@@ -0,0 +1,50 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2007 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _HAVE_MB_CLIENT_OVERRIDE_H
+#define _HAVE_MB_CLIENT_OVERRIDE_H
+
+#include <matchbox2/core/mb-wm.h>
+
+typedef struct MBWMClientOverride MBWMClientOverride;
+typedef struct MBWMClientOverrideClass MBWMClientOverrideClass;
+
+#define MB_WM_CLIENT_OVERRIDE(c) ((MBWMClientOverride*)(c))
+#define MB_WM_CLIENT_OVERRIDE_CLASS(c) ((MBWMClientOverrideClass*)(c))
+#define MB_WM_TYPE_CLIENT_OVERRIDE (mb_wm_client_override_class_type ())
+#define MB_WM_IS_CLIENT_OVERRIDE(c) (MB_WM_OBJECT_TYPE(c)==MB_WM_TYPE_CLIENT_OVERRIDE)
+
+struct MBWMClientOverride
+{
+ MBWindowManagerClient parent;
+};
+
+struct MBWMClientOverrideClass
+{
+ MBWindowManagerClientClass parent;
+};
+
+MBWindowManagerClient*
+mb_wm_client_override_new (MBWindowManager *wm, MBWMClientWindow *win);
+
+int
+mb_wm_client_override_class_type ();
+
+#endif
diff --git a/matchbox2/client-types/mb-wm-client-panel.c b/matchbox2/client-types/mb-wm-client-panel.c
new file mode 100644
index 0000000..c915d6b
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-panel.c
@@ -0,0 +1,229 @@
+#include "mb-wm-client-panel.h"
+#include "mb-wm-theme.h"
+
+static void
+mb_wm_client_panel_realize (MBWindowManagerClient *client);
+
+static Bool
+mb_wm_client_panel_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags);
+
+static MBWMStackLayerType
+mb_wm_client_panel_stacking_layer (MBWindowManagerClient *client);
+
+static void
+mb_wm_client_panel_stack (MBWindowManagerClient *client, int flags);
+
+static void
+mb_wm_client_panel_class_init (MBWMObjectClass *klass)
+{
+ MBWindowManagerClientClass *client;
+
+ client = (MBWindowManagerClientClass *)klass;
+
+ client->client_type = MBWMClientTypePanel;
+
+ client->realize = mb_wm_client_panel_realize;
+ client->geometry = mb_wm_client_panel_request_geometry;
+ client->stacking_layer = mb_wm_client_panel_stacking_layer;
+ client->stack = mb_wm_client_panel_stack;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMClientPanel";
+#endif
+}
+
+static int
+mb_wm_client_panel_init (MBWMObject *this, va_list vap)
+{
+ MBWindowManagerClient * client = MB_WM_CLIENT (this);
+ MBGeometry * win_geo = &client->window->geometry;
+ MBGeometry geom;
+ MBWMTheme * theme = client->wmref->theme;
+
+ if (theme && mb_wm_theme_get_client_geometry (theme, client, &geom))
+ {
+ /* The theme prescribes geometry for the panel, resize the
+ * window accordingly
+ */
+ MBWMClientWindow * win = client->window;
+ MBWindowManager * wm = client->wmref;
+ int g_x, g_y, x, y, w, h;
+ unsigned int g_w, g_h, g_bw, g_d;
+
+ x = geom.x;
+ y = geom.y;
+ w = geom.width;
+ h = geom.height;
+
+ /* If some of the theme values are unset, we have to get the current
+ * values for the window in their place -- this is a round trip, so
+ * we only do this when necessary
+ */
+ if (x < 0 || y < 0 || w < 0 || h < 0)
+ {
+ Window root;
+ XGetGeometry (wm->xdpy, win->xwindow,
+ &root, &g_x, &g_y, &g_w, &g_h, &g_bw, &g_d);
+ }
+
+ if (x < 0)
+ x = g_x;
+
+ if (y < 0)
+ y = g_y;
+
+ if (w < 0)
+ w = g_w;
+
+ if (h < 0)
+ h = g_h;
+
+ win->geometry.x = x;
+ win->geometry.y = y;
+ win->geometry.width = w;
+ win->geometry.height = h;
+
+ mb_wm_client_geometry_mark_dirty (client);
+ }
+
+ if (!client->layout_hints)
+ {
+ /*
+ * The theme did not prescribe layout hints, work something out
+ */
+ MBWMClientLayoutHints hints = LayoutPrefVisible;
+
+ if (win_geo->width > win_geo->height)
+ if (win_geo->y < (client->wmref->xdpy_height/2))
+ hints |= LayoutPrefReserveEdgeNorth;
+ else
+ hints |= LayoutPrefReserveEdgeSouth;
+ else
+ if (win_geo->x < (client->wmref->xdpy_width/2))
+ hints |= LayoutPrefReserveEdgeWest;
+ else
+ hints |= LayoutPrefReserveEdgeEast;
+
+ mb_wm_client_set_layout_hints (client, hints);
+ }
+ else
+ {
+ /* Make sure we are marked as visible */
+ mb_wm_client_set_layout_hint (client, LayoutPrefVisible, True);
+ }
+
+ if (client->layout_hints & LayoutPrefOverlaps)
+ client->stacking_layer = MBWMStackLayerTopMid;
+ else
+ client->stacking_layer = MBWMStackLayerBottomMid;
+
+ return 1;
+}
+
+static void
+mb_wm_client_panel_destroy (MBWMObject *this)
+{
+}
+
+int
+mb_wm_client_panel_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMClientPanelClass),
+ sizeof (MBWMClientPanel),
+ mb_wm_client_panel_init,
+ mb_wm_client_panel_destroy,
+ mb_wm_client_panel_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_CLIENT_BASE, 0);
+ }
+
+ return type;
+}
+
+static void
+mb_wm_client_panel_realize (MBWindowManagerClient *client)
+{
+ /*
+ * Must reparent the window to our root, otherwise we restacking of
+ * pre-existing windows might fail.
+ */
+ XReparentWindow(client->wmref->xdpy, MB_WM_CLIENT_XWIN(client),
+ client->wmref->root_win->xwindow, 0, 0);
+
+ return;
+}
+
+static Bool
+mb_wm_client_panel_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags)
+{
+ if (client->window->geometry.x != new_geometry->x
+ || client->window->geometry.y != new_geometry->y
+ || client->window->geometry.width != new_geometry->width
+ || client->window->geometry.height != new_geometry->height)
+ {
+ client->window->geometry.x = new_geometry->x;
+ client->window->geometry.y = new_geometry->y;
+ client->window->geometry.width = new_geometry->width;
+ client->window->geometry.height = new_geometry->height;
+
+ mb_wm_client_geometry_mark_dirty (client);
+ }
+
+ return True;
+}
+
+static void
+mb_wm_client_panel_stack (MBWindowManagerClient *client, int flags)
+{
+ /*
+ * If this is 'normal' panel, we stack with the default value.
+ *
+ * If this is an overlaping panel, stack immediately above the top-level
+ * application.
+ */
+ if (!(client->layout_hints & LayoutPrefOverlaps))
+ {
+ mb_wm_stack_move_top (client);
+ return;
+ }
+
+ mb_wm_stack_move_client_above_type (client,
+ MBWMClientTypeApp|MBWMClientTypeDesktop);
+}
+
+static MBWMStackLayerType
+mb_wm_client_panel_stacking_layer (MBWindowManagerClient *client)
+{
+ /*
+ * If we are showing desktop, ensure that we stack above it.
+ */
+ if (client->wmref->flags & MBWindowManagerFlagDesktop)
+ return MBWMStackLayerTopMid;
+
+ return client->stacking_layer;
+}
+
+MBWindowManagerClient*
+mb_wm_client_panel_new(MBWindowManager *wm, MBWMClientWindow *win)
+{
+ MBWindowManagerClient *client = NULL;
+
+ client = MB_WM_CLIENT(mb_wm_object_new (MB_WM_TYPE_CLIENT_PANEL,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropClientWindow, win,
+ NULL));
+
+ return client;
+}
+
+
diff --git a/matchbox2/client-types/mb-wm-client-panel.h b/matchbox2/client-types/mb-wm-client-panel.h
new file mode 100644
index 0000000..4be2585
--- /dev/null
+++ b/matchbox2/client-types/mb-wm-client-panel.h
@@ -0,0 +1,51 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_CLIENT_PANEL_H
+#define _HAVE_MB_CLIENT_PANEL_H
+
+#include <matchbox2/core/mb-wm.h>
+
+typedef struct MBWMClientPanel MBWMClientPanel;
+typedef struct MBWMClientPanelClass MBWMClientPanelClass;
+
+#define MB_WM_CLIENT_PANEL(c) ((MBWMClientPanel*)(c))
+#define MB_WM_CLIENT_PANEL_CLASS(c) ((MBWMClientPanelClass*)(c))
+#define MB_WM_TYPE_CLIENT_PANEL (mb_wm_client_panel_class_type ())
+#define MB_WM_IS_CLIENT_PANEL(c) \
+ (MB_WM_OBJECT_TYPE(c)==MB_WM_TYPE_CLIENT_PANEL)
+
+struct MBWMClientPanel
+{
+ MBWMClientBase parent;
+};
+
+struct MBWMClientPanelClass
+{
+ MBWMClientBaseClass parent;
+};
+
+MBWindowManagerClient*
+mb_wm_client_panel_new(MBWindowManager *wm, MBWMClientWindow *win);
+
+int
+mb_wm_client_panel_class_type ();
+
+#endif
diff --git a/matchbox2/comp-mgr/Makefile.am b/matchbox2/comp-mgr/Makefile.am
new file mode 100644
index 0000000..e0384a6
--- /dev/null
+++ b/matchbox2/comp-mgr/Makefile.am
@@ -0,0 +1,32 @@
+
+core_h = mb-wm-comp-mgr.h
+core_c = mb-wm-comp-mgr.c
+
+if COMP_MGR_BACKEND
+if ENABLE_CLUTTER_COMPOSITE_MANAGER
+clutter_h = mb-wm-comp-clutter.h \
+ tidy/tidy-texture-frame.h \
+ $(NULL)
+
+clutter_c = mb-wm-comp-mgr-clutter.c \
+ tidy/tidy-texture-frame.c \
+ $(NULL)
+else
+xrender_h = mb-wm-comp-mgr-xrender.h
+xrender_c = mb-wm-comp-mgr-xrender.c
+endif
+endif
+
+pkgincludedir = $(includedir)/$(MBWM2_INCDIR)/comp-mgr
+
+if ENABLE_LIBMATCHBOX
+pkginclude_HEADERS = mb-wm-comp-mgr-clutter.h mb-wm-comp-mgr.h mb-wm-comp-mgr-xrender.h
+endif
+noinst_LTLIBRARIES = libmatchbox-window-manager-2-compmgr.la
+libmatchbox_window_manager_2_compmgr_la_SOURCES = $(core_h) $(core_c) \
+ $(xrender_h) $(xrender_c) \
+ $(clutter_h) $(clutter_c)
+libmatchbox_window_manager_2_compmgr_la_CFLAGS = $(MBWM_INCS) $(MBWM_CFLAGS)
+
+MAINTAINERCLEANFILES = Makefile.in
+
diff --git a/matchbox2/comp-mgr/README b/matchbox2/comp-mgr/README
new file mode 100644
index 0000000..fb53cf1
--- /dev/null
+++ b/matchbox2/comp-mgr/README
@@ -0,0 +1,70 @@
+
+BRIEF OVERVIEW OF THE COMPOSITING INFRASTRUCTURE
+================================================
+
+The composite manager framework consists of three primary classes,
+
+ * MBWMCompMgr -- The compositor interface,
+
+ * MBWMCompMgrClient -- Per-client, compositor- specific data,
+
+ * MBWMCompMgrEffect -- A simple client effect.
+
+The whole framework, and its integration with the WM, can be outlined as
+follows:
+
+
+ MBWindowManager:
+ | |
+ | --> client stack
+ | |
+ | --> MBWindowManagerClient
+ | |
+==========================================================================
+ | |
+ | --> MBWMCompMgrClient
+ | | |
+ | | --> MBWMCompMgrBackendClient
+ | |
+ | event-effect mapping
+ | |
+ | -->an-event:effect-list pair
+ | |
+ | --> MBWMCompMgrEffect
+ | |
+ | --> MBWMCompMgrBackendEffect
+ |
+ --> MBWMCompMgr
+ |
+ --> MBWMCompMgrBackend
+
+
+The framwork seeks to provide a clean separation between the WM and the CM --
+the implementation of the CM is opaque to the WM, which simply deffers to the
+CM at appropriate points through its public interface. To this end each of the
+MBWindowManagerClient objects managed by the WM holds a pointer to a
+MBWMCompMgrClient object, which holds any per-client data that the CM
+requires; this data is allocated when the WM calls
+mb_wm_comp_mgr_register_client() and deallocated when it
+calls mb_wm_comp_mgr_unregister_client().
+
+As much as the CM internals are opaque to the WM, also the workings of the WM
+are intended to be opaque to the CM; its API is hooked into common operations
+that the WM carries out on its clients, such as map and unmap events, or
+processing of damage notifications, but the CM per se is agnostic of the inner
+workings of the WM.
+
+The effect framework is event driven. MBWMCompMgrEffect is a common interface
+for simple effect, defined by a type, duration (in ms) and gravity. Each
+MBWMCompMgrClient instance is then associated with a mapping between
+effect-events (such as client window mapping, unmapping or minimizing) and a
+list of effects that are to be triggered by the event; a small set of effects
+(such as scaling, fading or sliding, is predefined, and the event-effect
+mapping is defined on per-client-type basis by the theme.
+
+MBWMCompMgr, MBWMCompMgrClient and MBWMCompMgrEffect are abstract interfaces
+that provide public API through which the WM communicates with the
+CM; the CM itself is implememented by one or more backends,
+which subclass these objects. Currently, two backends are included with MBWM2:
+an XRender-based implementation MBWMCompMgrDefault, and a Clutter-based
+implementation MBWMCompMgrClutter.
diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c b/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c
new file mode 100644
index 0000000..c1aaf8d
--- /dev/null
+++ b/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.c
@@ -0,0 +1,1610 @@
+/*
+ * Matchbox Window Manager - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2008 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mb-wm.h"
+#include "mb-wm-client.h"
+#include "mb-wm-comp-mgr.h"
+#include "mb-wm-comp-mgr-clutter.h"
+#include "mb-wm-theme.h"
+#include "tidy/tidy-texture-frame.h"
+
+#include <clutter/clutter.h>
+#include <clutter/x11/clutter-x11.h>
+#if HAVE_CLUTTER_GLX
+#include <clutter/glx/clutter-glx-texture-pixmap.h>
+#endif
+#include <X11/Xresource.h>
+#include <X11/extensions/shape.h>
+#include <X11/extensions/Xcomposite.h>
+
+#include <math.h>
+
+#define USE_DAMAGE_BOUNDING_BOX 1
+
+#define SHADOW_RADIUS 4
+#define SHADOW_OPACITY 0.9
+#define SHADOW_OFFSET_X (-SHADOW_RADIUS)
+#define SHADOW_OFFSET_Y (-SHADOW_RADIUS)
+
+#define MAX_TILE_SZ 16 /* make sure size/2 < MAX_TILE_SZ */
+#define WIDTH (3*MAX_TILE_SZ)
+#define HEIGHT (3*MAX_TILE_SZ)
+
+#define CMGR(x) MB_WM_COMP_MGR_CLUTTER(x)
+#define CCLIENT(x) MB_WM_COMP_MGR_CLUTTER_CLIENT(x)
+
+static unsigned char *
+mbwm_cmc_shadow_gaussian_make_tile ();
+
+static void
+mbwm_cmc_add_actor (MBWMCompMgrClutter *, MBWMCompMgrClutterClient *);
+
+/*
+ * A helper object to store manager's per-client data
+ */
+struct _MBWMCompMgrClutterClientPrivate
+{
+ ClutterActor *actor; /* Overall actor */
+ ClutterActor *texture; /* The texture part of our actor */
+ Pixmap pixmap;
+ int pxm_width;
+ int pxm_height;
+ int pxm_depth;
+ unsigned int flags;
+ Damage damage;
+
+ int freeze_updates;
+ int needs_update : 1;
+};
+
+static void mbwm_cmc_client_show_real (MBWMCompMgrClient *client);
+static void mbwm_cmc_client_hide_real (MBWMCompMgrClient *client);
+static void mbwm_cmc_client_repair_real (MBWMCompMgrClient *client);
+static void mbwm_cmc_client_configure_real (MBWMCompMgrClient *client);
+
+static void
+mbwm_cmc_client_class_init (MBWMObjectClass *klass)
+{
+ MBWMCompMgrClientClass *c_klass = MB_WM_COMP_MGR_CLIENT_CLASS (klass);
+
+ c_klass->show = mbwm_cmc_client_show_real;
+ c_klass->hide = mbwm_cmc_client_hide_real;
+ c_klass->repair = mbwm_cmc_client_repair_real;
+ c_klass->configure = mbwm_cmc_client_configure_real;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMCompMgrClutterClient";
+#endif
+}
+
+static void
+mbwm_cmc_client_freeze (MBWMCompMgrClutterClient *client)
+{
+ client->priv->freeze_updates++;
+}
+
+static void
+mbwm_cmc_client_unfreeze (MBWMCompMgrClutterClient * client)
+{
+ MBWMCompMgrClutterClientPrivate *priv = client->priv;
+
+ priv->freeze_updates--;
+
+ if (priv->freeze_updates < 0)
+ priv->freeze_updates = 0;
+
+ if (!priv->freeze_updates && priv->needs_update)
+ mbwm_cmc_client_repair_real (MB_WM_COMP_MGR_CLIENT (client));
+}
+
+
+/*
+ * Fetch the entire texture for our client
+ */
+static void
+mbwm_cmc_fetch_texture (MBWMCompMgrClient *client)
+{
+ MBWMCompMgrClutterClient *cclient = CCLIENT(client);
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+ MBWindowManagerClient *wm_client = client->wm_client;
+ MBWindowManager *wm = client->wm;
+ MBGeometry geom;
+ Window xwin;
+ Window root;
+ int x, y, w, h, bw, depth;
+#ifdef HAVE_XEXT
+ /* Stuff we need for shaped windows */
+ XRectangle *shp_rect;
+ int shp_order;
+ int shp_count;
+ int i;
+
+ /*
+ * This is square of 32-bit comletely transparent values we use to
+ * clear bits of the texture from shaped windows; the size is a compromise
+ * between how much memory we want to allocate and how much tiling we are
+ * happy with.
+ *
+ * Make this power of 2 for efficient operation
+ */
+#define SHP_CLEAR_SIZE 4
+ static int clear_init = 0;
+ static guint32 clear_data[SHP_CLEAR_SIZE * SHP_CLEAR_SIZE];
+
+ if (!clear_init)
+ {
+ memset (&clear_data, 0, sizeof (clear_data));
+ clear_init = 1;
+ }
+#endif
+
+ if (!(priv->flags & MBWMCompMgrClutterClientMapped))
+ return;
+
+ xwin =
+ wm_client->xwin_frame ? wm_client->xwin_frame : wm_client->window->xwindow;
+
+ if (priv->pixmap)
+ XFreePixmap (wm->xdpy, priv->pixmap);
+
+ priv->pixmap = XCompositeNameWindowPixmap (wm->xdpy, xwin);
+
+ if (!priv->pixmap)
+ return;
+
+ XGetGeometry (wm->xdpy, priv->pixmap, &root,
+ &x, &y, &w, &h, &bw, &depth);
+
+ mb_wm_client_get_coverage (wm_client, &geom);
+
+ priv->pxm_width = w;
+ priv->pxm_height = h;
+ priv->pxm_depth = depth;
+
+ clutter_actor_set_position (priv->actor, geom.x, geom.y);
+ clutter_actor_set_size (priv->texture, geom.width, geom.height);
+
+ clutter_x11_texture_pixmap_set_pixmap (
+ CLUTTER_X11_TEXTURE_PIXMAP (priv->texture),
+ priv->pixmap);
+
+#ifdef HAVE_XEXT
+ /*
+ * If the client is shaped, we have to manually clear any pixels in our
+ * texture in the non-visible areas.
+ */
+ if (mb_wm_theme_is_client_shaped (wm->theme, wm_client))
+ {
+ shp_rect = XShapeGetRectangles (wm->xdpy, xwin,
+ ShapeBounding, &shp_count, &shp_order);
+
+ if (shp_rect && shp_count)
+ {
+ XserverRegion clear_rgn;
+ XRectangle rect;
+ XRectangle *clear_rect;
+ int clear_count;
+ XRectangle *r0, r1;
+ int c;
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = geom.width;
+ rect.height = geom.height;
+
+ clear_rgn = XFixesCreateRegion (wm->xdpy, shp_rect, shp_count);
+
+ XFixesInvertRegion (wm->xdpy, clear_rgn, &rect, clear_rgn);
+
+ clear_rect = XFixesFetchRegion (wm->xdpy, clear_rgn, &clear_count);
+
+ for (i = 0; i < clear_count; ++i)
+ {
+ int k, l;
+
+ for (k = 0; k < clear_rect[i].width; k += SHP_CLEAR_SIZE)
+ for (l = 0; l < clear_rect[i].height; l += SHP_CLEAR_SIZE)
+ {
+ int w1 = clear_rect[i].width - k;
+ int h1 = clear_rect[i].height - l;
+
+ if (w1 > SHP_CLEAR_SIZE)
+ w1 = SHP_CLEAR_SIZE;
+
+ if (h1 > SHP_CLEAR_SIZE)
+ h1 = SHP_CLEAR_SIZE;
+
+ clutter_texture_set_area_from_rgb_data (
+ CLUTTER_TEXTURE (priv->texture),
+ (const guchar *)&clear_data,
+ TRUE,
+ clear_rect[i].x + k,
+ clear_rect[i].y + l,
+ w1, h1,
+ SHP_CLEAR_SIZE * 4,
+ 4,
+ CLUTTER_TEXTURE_RGB_FLAG_BGR,
+ NULL);
+ }
+ }
+
+ XFixesDestroyRegion (wm->xdpy, clear_rgn);
+
+ XFree (shp_rect);
+
+ if (clear_rect)
+ XFree (clear_rect);
+ }
+ }
+
+#endif
+}
+
+static int
+mbwm_cmc_client_init (MBWMObject *obj, va_list vap)
+{
+ MBWMCompMgrClutterClient *cclient = CCLIENT (obj);
+
+ cclient->priv =
+ mb_wm_util_malloc0 (sizeof (MBWMCompMgrClutterClientPrivate));
+
+ return 1;
+}
+
+static void
+mbwm_cmc_client_destroy (MBWMObject* obj)
+{
+ MBWMCompMgrClient *c = MB_WM_COMP_MGR_CLIENT (obj);
+ MBWMCompMgrClutterClient *cclient = CCLIENT (obj);
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+ MBWindowManager *wm = c->wm;
+ MBWMCompMgrClutter *mgr = CMGR (wm->comp_mgr);
+ int i;
+
+ if (priv->actor)
+ clutter_actor_destroy (priv->actor);
+
+ if (priv->pixmap)
+ XFreePixmap (wm->xdpy, priv->pixmap);
+
+ if (priv->damage)
+ XDamageDestroy (wm->xdpy, priv->damage);
+
+ free (priv);
+}
+
+int
+mb_wm_comp_mgr_clutter_client_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMCompMgrClutterClientClass),
+ sizeof (MBWMCompMgrClutterClient),
+ mbwm_cmc_client_init,
+ mbwm_cmc_client_destroy,
+ mbwm_cmc_client_class_init
+ };
+
+ type =
+ mb_wm_object_register_class (&info, MB_WM_TYPE_COMP_MGR_CLIENT, 0);
+ }
+
+ return type;
+}
+
+/*
+ * This is a private method, hence static (all instances of this class are
+ * created automatically by the composite manager).
+ */
+static MBWMCompMgrClient *
+mbwm_cmc_client_new (MBWindowManagerClient * client)
+{
+ MBWMObject *c;
+
+ c = mb_wm_object_new (MB_WM_TYPE_COMP_MGR_CLUTTER_CLIENT,
+ MBWMObjectPropClient, client,
+ NULL);
+
+ return MB_WM_COMP_MGR_CLIENT (c);
+}
+
+static void
+mbwm_cmc_client_hide_real (MBWMCompMgrClient * client)
+{
+ MBWMCompMgrClutterClient *cclient = CCLIENT (client);
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+
+ /*
+ * Do not hide the actor if effect is in progress
+ */
+ if (priv->flags & MBWMCompMgrClutterClientEffectRunning)
+ return;
+
+ clutter_actor_hide (priv->actor);
+}
+
+static void
+mbwm_cmc_client_show_real (MBWMCompMgrClient *client)
+{
+ MBWMCompMgrClutterClient *cclient = CCLIENT (client);
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+
+ if (!priv->actor)
+ {
+ /*
+ * This can happen if show() is called on our client before it is
+ * actually mapped (we only alocate the actor in response to map
+ * notification.
+ */
+ return;
+ }
+
+ /*
+ * Clear the don't update flag, if set
+ */
+ priv->flags &= ~MBWMCompMgrClutterClientDontUpdate;
+ clutter_actor_show_all (priv->actor);
+}
+
+void
+mb_wm_comp_mgr_clutter_client_set_flags (MBWMCompMgrClutterClient *cclient,
+ MBWMCompMgrClutterClientFlags flags)
+{
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+
+ priv->flags |= flags;
+}
+
+
+void
+mb_wm_comp_mgr_clutter_client_unset_flags (MBWMCompMgrClutterClient *cclient,
+ MBWMCompMgrClutterClientFlags flags)
+{
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+
+ priv->flags &= ~flags;
+}
+
+MBWMCompMgrClutterClientFlags
+mb_wm_comp_mgr_clutter_client_get_flags (MBWMCompMgrClutterClient *cclient)
+{
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+
+ return (MBWMCompMgrClutterClientFlags) priv->flags;
+}
+
+
+ClutterActor *
+mb_wm_comp_mgr_clutter_client_get_actor (MBWMCompMgrClutterClient *cclient)
+{
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+
+ return g_object_ref(MB_WM_OBJECT (priv->actor));
+}
+
+/*
+ * Implementation of MBWMCompMgrClutter
+ */
+struct _MBWMCompMgrClutterPrivate
+{
+ ClutterActor * arena;
+ MBWMList * desktops;
+ ClutterActor * shadow;
+
+ Window overlay_window;
+
+ int freeze_stack;
+
+ unsigned int restack_pending : 1;
+};
+
+static void
+mbwm_cmc_private_free (MBWMCompMgrClutter *mgr)
+{
+ MBWMCompMgrClutterPrivate * priv = mgr->priv;
+
+ if (priv->shadow)
+ clutter_actor_destroy (priv->shadow);
+
+ free (priv);
+}
+
+static void
+mbwm_cmc_register_client_real (MBWMCompMgr * mgr,
+ MBWindowManagerClient * c)
+{
+ MBWMCompMgrClient *cclient;
+ MBWMCompMgrClutter *cmgr = CMGR (mgr);
+ MBWMCompMgrClutterClass *klass
+ = MB_WM_COMP_MGR_CLUTTER_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (c->cm_client)
+ return;
+
+ cclient = klass->client_new (c);
+ c->cm_client = cclient;
+}
+
+static void mbwm_cmc_turn_on_real (MBWMCompMgr *mgr);
+static void mbwm_cmc_turn_off_real (MBWMCompMgr *mgr);
+static void mbwm_cmc_map_notify_real (MBWMCompMgr *mgr,
+ MBWindowManagerClient *c);
+static void mbwm_cmc_client_transition_real (MBWMCompMgr *mgr,
+ MBWindowManagerClient *c1,
+ MBWindowManagerClient *c2,
+ Bool reverse);
+static void mbwm_cmc_client_event_real (MBWMCompMgr *mgr,
+ MBWindowManagerClient *client,
+ MBWMCompMgrClientEvent event);
+static void mbwm_cmc_restack_real (MBWMCompMgr *mgr);
+static Bool mb_wm_comp_mgr_is_my_window_real (MBWMCompMgr *mgr, Window xwin);
+static void mbwm_cmc_select_desktop (MBWMCompMgr * mgr,
+ int desktop, int old_desktop);
+static Bool mbwm_cmc_handle_damage (XDamageNotifyEvent *de, MBWMCompMgr*mgr);
+
+static void
+mbwm_cmc_class_init (MBWMObjectClass *klass)
+{
+ MBWMCompMgrClass *cm_klass = MB_WM_COMP_MGR_CLASS (klass);
+ MBWMCompMgrClutterClass *clutter_klass =
+ MB_WM_COMP_MGR_CLUTTER_CLASS (klass);
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMCompMgrClutter";
+#endif
+
+ /*
+ * NB -- we do not need render() implementation, since that is taken care of
+ * automatically by clutter stage.
+ */
+ cm_klass->register_client = mbwm_cmc_register_client_real;
+ cm_klass->turn_on = mbwm_cmc_turn_on_real;
+ cm_klass->turn_off = mbwm_cmc_turn_off_real;
+ cm_klass->map_notify = mbwm_cmc_map_notify_real;
+ cm_klass->my_window = mb_wm_comp_mgr_is_my_window_real;
+ cm_klass->client_transition = mbwm_cmc_client_transition_real;
+ cm_klass->client_event = mbwm_cmc_client_event_real;
+ cm_klass->restack = mbwm_cmc_restack_real;
+ cm_klass->select_desktop = mbwm_cmc_select_desktop;
+ cm_klass->handle_damage = mbwm_cmc_handle_damage;
+
+ clutter_klass->client_new = mbwm_cmc_client_new;
+}
+
+static int
+mbwm_cmc_init (MBWMObject *obj, va_list vap)
+{
+ MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj);
+ MBWMCompMgrClutter * cmgr = CMGR (obj);
+ MBWMCompMgrClutterPrivate * priv;
+ MBWindowManager * wm = mgr->wm;
+ ClutterActor * desktop, * arena;
+
+ priv = mb_wm_util_malloc0 (sizeof (MBWMCompMgrClutterPrivate));
+ cmgr->priv = priv;
+
+ XCompositeRedirectSubwindows (wm->xdpy, wm->root_win->xwindow,
+ CompositeRedirectManual);
+
+ priv->arena = arena = clutter_group_new ();
+ clutter_container_add_actor (CLUTTER_CONTAINER (clutter_stage_get_default()),
+ arena);
+ clutter_actor_show (arena);
+
+ desktop = clutter_group_new ();
+ clutter_actor_show (desktop);
+ clutter_container_add_actor (CLUTTER_CONTAINER (arena), desktop);
+ priv->desktops = mb_wm_util_list_append (priv->desktops, desktop);
+
+ return 1;
+}
+
+static void
+mbwm_cmc_destroy (MBWMObject * obj)
+{
+ MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj);
+ MBWMCompMgrClutter * cmgr = CMGR (obj);
+
+ mb_wm_comp_mgr_turn_off (mgr);
+ mbwm_cmc_private_free (cmgr);
+}
+
+int
+mb_wm_comp_mgr_clutter_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMCompMgrClutterClass),
+ sizeof (MBWMCompMgrClutter),
+ mbwm_cmc_init,
+ mbwm_cmc_destroy,
+ mbwm_cmc_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_COMP_MGR, 0);
+ }
+
+ return type;
+}
+
+/* Shuts the compositing down */
+static void
+mbwm_cmc_turn_off_real (MBWMCompMgr *mgr)
+{
+ MBWindowManager * wm = mgr->wm;
+ MBWMCompMgrClutterPrivate * priv;
+
+ if (!mgr)
+ return;
+
+ priv = CMGR (mgr)->priv;
+
+ if (mgr->disabled)
+ return;
+
+ if (!mb_wm_stack_empty (wm))
+ {
+ MBWindowManagerClient * c;
+
+ mb_wm_stack_enumerate (wm, c)
+ {
+ mb_wm_comp_mgr_unregister_client (mgr, c);
+ }
+ }
+
+ XCompositeReleaseOverlayWindow (wm->xdpy, wm->root_win->xwindow);
+ priv->overlay_window = None;
+
+ mgr->disabled = True;
+}
+
+static void
+mbwm_cmc_turn_on_real (MBWMCompMgr *mgr)
+{
+ MBWindowManager * wm;
+ MBWMCompMgrClutterPrivate * priv;
+
+ if (!mgr || !mgr->disabled)
+ return;
+
+ priv = CMGR (mgr)->priv;
+ wm = mgr->wm;
+
+ mgr->disabled = False;
+
+ if (priv->overlay_window == None)
+ {
+ ClutterActor * stage = clutter_stage_get_default ();
+ ClutterColor clr = {0, 0, 0, 0xff };
+ Window xwin;
+ XserverRegion region;
+
+ /*
+ * Fetch the overlay window
+ */
+ xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
+
+ priv->overlay_window =
+ XCompositeGetOverlayWindow (wm->xdpy, wm->root_win->xwindow);
+
+ /*
+ * Reparent the stage window to the overlay window, this makes it
+ * magically work :)
+ */
+ XReparentWindow (wm->xdpy, xwin, priv->overlay_window, 0, 0);
+
+ /*
+ * Use xfixes shape to make events pass through the overlay window
+ *
+ * TODO -- this has certain drawbacks, notably when our client is
+ * tranformed (rotated, scaled, etc), the events will not be landing in
+ * the right place. The answer to that is event forwarding with
+ * translation.
+ */
+ region = XFixesCreateRegion (wm->xdpy, NULL, 0);
+
+ XFixesSetWindowShapeRegion (wm->xdpy, priv->overlay_window,
+ ShapeBounding, 0, 0, 0);
+ XFixesSetWindowShapeRegion (wm->xdpy, priv->overlay_window,
+ ShapeInput, 0, 0, region);
+
+ XFixesDestroyRegion (wm->xdpy, region);
+
+ clutter_actor_set_size (stage, wm->xdpy_width, wm->xdpy_height);
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &clr);
+
+ clutter_actor_show (stage);
+ }
+}
+
+static void
+mbwm_cmc_client_repair_real (MBWMCompMgrClient * client)
+{
+ MBWindowManagerClient *wm_client = client->wm_client;
+ MBWMCompMgrClutterClient *cclient = CCLIENT (client);
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+ MBWindowManager *wm = client->wm;
+ XserverRegion parts;
+ int i, r_count;
+ XRectangle *r_damage;
+ XRectangle r_bounds;
+
+ MBWM_NOTE (COMPOSITOR, "REPAIRING %x", wm_client->window->xwindow);
+
+ if (!priv->actor)
+ return;
+
+ if (priv->freeze_updates)
+ {
+ priv->needs_update = 1;
+ return;
+ }
+
+ priv->needs_update = 0;
+
+ if (!priv->pixmap)
+ {
+ /*
+ * First time we have been called since creation/configure,
+ * fetch the whole texture.
+ */
+ MBWM_NOTE (DAMAGE, "Full screen repair.");
+ XDamageSubtract (wm->xdpy, priv->damage, None, None);
+ mbwm_cmc_fetch_texture (client);
+ return;
+ }
+
+ /*
+ * Retrieve the damaged region and break it down into individual
+ * rectangles so we do not have to update the whole shebang.
+ */
+ parts = XFixesCreateRegion (wm->xdpy, 0, 0);
+ XDamageSubtract (wm->xdpy, priv->damage, None, parts);
+
+ r_damage = XFixesFetchRegionAndBounds (wm->xdpy, parts,
+ &r_count,
+ &r_bounds);
+
+ if (r_damage)
+ {
+#if USE_DAMAGE_BOUNDING_BOX
+ clutter_x11_texture_pixmap_update_area (
+ CLUTTER_X11_TEXTURE_PIXMAP (priv->texture),
+ r_bounds.x,
+ r_bounds.y,
+ r_bounds.width,
+ r_bounds.height);
+#else
+ for (i = 0; i < r_count; ++i)
+ {
+ MBWM_NOTE (DAMAGE, "Repairing %d,%d;%dx%d",
+ r_damage[i].x,
+ r_damage[i].y,
+ r_damage[i].width,
+ r_damage[i].height);
+
+ clutter_x11_texture_pixmap_update_area (
+ CLUTTER_X11_TEXTURE_PIXMAP (priv->texture),
+ r_damage[i].x,
+ r_damage[i].y,
+ r_damage[i].width,
+ r_damage[i].height);
+ }
+#endif
+ XFree (r_damage);
+ }
+
+ XFixesDestroyRegion (wm->xdpy, parts);
+}
+
+static void
+mbwm_cmc_client_configure_real (MBWMCompMgrClient * client)
+{
+ MBWindowManagerClient *wm_client = client->wm_client;
+ MBWMCompMgrClutterClient *cclient = CCLIENT (client);
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+
+ MBWM_NOTE (COMPOSITOR, "CONFIGURE request");
+
+ /*
+ * Release the backing pixmap; we will recreate it next time we get damage
+ * notification for this window.
+ */
+ if (priv->pixmap)
+ {
+ XFreePixmap (client->wm->xdpy, priv->pixmap);
+ priv->pixmap = None;
+ }
+}
+
+static Bool
+mbwm_cmc_handle_damage (XDamageNotifyEvent * de,
+ MBWMCompMgr * mgr)
+{
+ MBWMCompMgrClutterPrivate * priv = CMGR (mgr)->priv;
+ MBWindowManager * wm = mgr->wm;
+ MBWindowManagerClient * c;
+
+ c = mb_wm_managed_client_from_frame (wm, de->drawable);
+
+ if (c && c->cm_client)
+ {
+ MBWMCompMgrClutterClient *cclient = CCLIENT (c->cm_client);
+ MBWMCompMgrClutterClientPrivate *cpriv = cclient->priv;
+
+ if (!cpriv->actor ||
+ (cpriv->flags & MBWMCompMgrClutterClientDontUpdate))
+ return False;
+
+ MBWM_NOTE (COMPOSITOR,
+ "Reparing window %x, geometry %d,%d;%dx%d; more %d\n",
+ de->drawable,
+ de->geometry.x,
+ de->geometry.y,
+ de->geometry.width,
+ de->geometry.height,
+ de->more);
+
+ mbwm_cmc_client_repair_real (c->cm_client);
+ }
+ else
+ {
+ MBWM_NOTE (COMPOSITOR, "Failed to find client for window %x\n",
+ de->drawable);
+ }
+
+ return False;
+}
+
+static void
+mbwm_cmc_freeze_stack (MBWMCompMgr *mgr)
+{
+ CMGR (mgr)->priv->freeze_stack++;
+}
+
+static void
+mbwm_cmc_unfreeze_stack (MBWMCompMgr *mgr)
+{
+ MBWMCompMgrClutterPrivate *priv = CMGR (mgr)->priv;
+
+ priv->freeze_stack--;
+
+ if (priv->freeze_stack < 0)
+ priv->freeze_stack = 0;
+
+ if (!priv->freeze_stack && priv->restack_pending)
+ mbwm_cmc_restack_real ((MBWMCompMgr *)mgr);
+}
+
+static void
+mbwm_cmc_restack_real (MBWMCompMgr *mgr)
+{
+ MBWindowManager *wm = mgr->wm;
+ MBWMCompMgrClutter *cmgr = CMGR (mgr);
+ MBWMCompMgrClutterPrivate *priv = cmgr->priv;
+ MBWMList *l;
+ int i = 0;
+
+ if (priv->freeze_stack)
+ {
+ priv->restack_pending = 1;
+ return;
+ }
+
+ priv->restack_pending = 0;
+
+ l = priv->desktops;
+
+ if (!mb_wm_stack_empty (wm))
+ {
+ MBWindowManagerClient * c;
+
+ while (l)
+ {
+ ClutterActor *desktop = l->data;
+ ClutterActor * prev = NULL;
+
+ mb_wm_stack_enumerate (wm, c)
+ {
+ MBWMCompMgrClutterClient * cc;
+ ClutterActor * a;
+
+ if (mb_wm_client_get_desktop (c) != i)
+ continue;
+
+ cc = CCLIENT (c->cm_client);
+
+ a = cc->priv->actor;
+
+ if (!a || clutter_actor_get_parent (a) != desktop)
+ continue;
+
+ clutter_actor_raise (a, prev);
+
+ prev = a;
+ }
+
+ l = l->next;
+ ++i;
+ }
+ }
+}
+
+MBWMList *
+mb_wm_comp_mgr_clutter_get_desktops (MBWMCompMgrClutter *cmgr)
+{
+ return cmgr->priv->desktops;
+}
+
+/*
+ * Gets the n-th desktop from our desktop list; if we do not have that many
+ * desktops, just append new ones.
+ */
+ClutterActor *
+mb_wm_comp_mgr_clutter_get_nth_desktop (MBWMCompMgrClutter * cmgr, int desktop)
+{
+ MBWMCompMgrClutterPrivate * priv = cmgr->priv;
+ MBWMList * l = priv->desktops;
+ int i = 0;
+
+ while (l && i != desktop)
+ {
+ ++i;
+
+ if (l->next)
+ l = l->next;
+ else
+ {
+ /* End of the line -- append new desktop */
+ ClutterActor * d = clutter_group_new ();
+ priv->desktops = mb_wm_util_list_append (priv->desktops, d);
+ clutter_container_add_actor (CLUTTER_CONTAINER (priv->arena), d);
+
+ l = l->next;
+ }
+ }
+
+ return CLUTTER_ACTOR (l->data);
+}
+
+/*
+ * Returns the arena; this is an intermediate group which contains all the
+ * other actors the CM uses. The caller of this function holds a reference
+ * to the returned ClutterActor and must release it once no longer needed.
+ */
+ClutterActor *
+mb_wm_comp_mgr_clutter_get_arena (MBWMCompMgrClutter *cmgr)
+{
+ MBWMCompMgrClutterPrivate * priv = cmgr->priv;
+
+ return g_object_ref (priv->arena);
+}
+
+
+static void
+mbwm_cmc_select_desktop (MBWMCompMgr * mgr,
+ int desktop,
+ int old_desktop)
+{
+ MBWMCompMgrClutter * cmgr = CMGR (mgr);
+ ClutterActor * d;
+ MBWMList * l;
+
+ d = mb_wm_comp_mgr_clutter_get_nth_desktop (cmgr, desktop);
+
+ l = cmgr->priv->desktops;
+
+ while (l)
+ {
+ ClutterActor * a = l->data;
+
+ if (a == d)
+ clutter_actor_show (a);
+ else
+ clutter_actor_hide (a);
+
+ l = l->next;
+ }
+}
+
+static void
+mbwm_cmc_map_notify_real (MBWMCompMgr *mgr,
+ MBWindowManagerClient *c)
+{
+ MBWMCompMgrClutter *cmgr = CMGR (mgr);
+ MBWMCompMgrClient *client = c->cm_client;
+ MBWMCompMgrClutterClient *cclient = CCLIENT(client);
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+ MBWindowManager *wm = client->wm;
+ ClutterActor *actor;
+ ClutterActor *texture;
+ ClutterActor *rect;
+ MBGeometry geom;
+ const MBWMList *l;
+ unsigned int shadow_clr[4];
+ ClutterColor shadow_cclr;
+ MBWMCompMgrShadowType shadow_type;
+ MBWMClientType ctype = MB_WM_CLIENT_CLIENT_TYPE (c);
+
+ if (mb_wm_client_is_hiding_from_desktop (c))
+ {
+ /*
+ * We already have the resources, except we have to get a new
+ * backing pixmap
+ */
+ Window xwin = c->xwin_frame ? c->xwin_frame : c->window->xwindow;
+
+ /*
+ * FIXME -- Must rebind the pixmap to the texture -- this is not ideal
+ * since our texture already contains the correct data, but without
+ * this it will not update. Perhaps we some extension to the clutter
+ * API is needed here.
+ */
+ mbwm_cmc_fetch_texture (client);
+
+ clutter_actor_show (priv->actor);
+ return;
+ }
+
+ /*
+ * We get called for windows as well as their children, so once we are
+ * mapped do nothing.
+ */
+ if (priv->flags & MBWMCompMgrClutterClientMapped)
+ return;
+
+ priv->flags |= MBWMCompMgrClutterClientMapped;
+
+ priv->damage = XDamageCreate (wm->xdpy,
+ c->xwin_frame ?
+ c->xwin_frame :
+ c->window->xwindow,
+#ifdef USE_DAMAGE_BOUNDING_BOX
+ XDamageReportBoundingBox
+#else
+ XDamageReportNonEmpty
+#endif
+ );
+
+ mb_wm_client_get_coverage (c, &geom);
+
+ actor = g_object_ref (clutter_group_new ());
+#if HAVE_CLUTTER_GLX
+ texture = clutter_glx_texture_pixmap_new ();
+#else
+ texture = clutter_x11_texture_pixmap_new ();
+#endif
+ clutter_actor_show (texture);
+
+ if (ctype == MBWMClientTypeDialog ||
+ ctype == MBWMClientTypeMenu ||
+ ctype == MBWMClientTypeNote ||
+ ctype == MBWMClientTypeOverride)
+ {
+ shadow_type = mb_wm_theme_get_shadow_type (wm->theme);
+
+ if (shadow_type == MBWM_COMP_MGR_SHADOW_NONE)
+ {
+ clutter_container_add (CLUTTER_CONTAINER (actor), texture, NULL);
+ }
+ else
+ {
+ if (shadow_type == MBWM_COMP_MGR_SHADOW_SIMPLE)
+ {
+ mb_wm_theme_get_shadow_color (wm->theme,
+ &shadow_clr[0],
+ &shadow_clr[1],
+ &shadow_clr[2],
+ &shadow_clr[3]);
+
+ shadow_cclr.red = 0xff * shadow_clr[0] / 0xffff;
+ shadow_cclr.green = 0xff * shadow_clr[1] / 0xffff;
+ shadow_cclr.blue = 0xff * shadow_clr[2] / 0xffff;
+ shadow_cclr.alpha = 0xff * shadow_clr[3] / 0xffff;
+
+ rect = clutter_rectangle_new_with_color (&shadow_cclr);
+ clutter_actor_set_position (rect, 4, 4);
+ }
+ else
+ {
+ ClutterActor * txt = cmgr->priv->shadow;
+ if (!txt)
+ {
+ unsigned char * data;
+
+ data = mbwm_cmc_shadow_gaussian_make_tile ();
+
+ txt = clutter_texture_new ();
+
+ clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (txt),
+ data,
+ TRUE,
+ WIDTH,
+ HEIGHT,
+ WIDTH*4,
+ 4,
+ 0,
+ NULL);
+ free (data);
+
+ cmgr->priv->shadow = txt;
+ }
+
+ rect = tidy_texture_frame_new (CLUTTER_TEXTURE (txt),
+ MAX_TILE_SZ,
+ MAX_TILE_SZ,
+ MAX_TILE_SZ,
+ MAX_TILE_SZ);
+ clutter_actor_set_position (rect,
+ 2*SHADOW_RADIUS, 2*SHADOW_RADIUS);
+ }
+
+ clutter_actor_set_size (rect, geom.width, geom.height);
+ clutter_actor_show (rect);
+
+ clutter_container_add (CLUTTER_CONTAINER (actor),
+ rect, texture, NULL);
+ }
+ }
+ else
+ {
+ clutter_container_add (CLUTTER_CONTAINER (actor), texture, NULL);
+ }
+
+
+ priv->actor = actor;
+ priv->texture = texture;
+
+ g_object_set_data (G_OBJECT (actor), "MBWMCompMgrClutterClient", cclient);
+
+ clutter_actor_set_position (actor, geom.x, geom.y);
+ clutter_actor_set_size (texture, geom.width, geom.height);
+
+ mbwm_cmc_add_actor (cmgr, cclient);
+}
+
+static void
+mbwm_cmc_transtion_fade_out_cb (ClutterAnimation *anim,
+ MBWMCompMgrClutterClient *client)
+{
+ client->priv->flags &= ~MBWMCompMgrClutterClientEffectRunning;
+
+#if 0
+ /* FIXME -- see if we need this */
+ mb_wm_object_unref (MB_WM_OBJECT (client));
+#endif
+}
+
+static void
+_fade_apply_behaviour_to_client (MBWindowManagerClient *wc,
+ unsigned long duration)
+{
+ MBWMList *l;
+ ClutterActor *a = CCLIENT (wc->cm_client)->priv->actor;
+ ClutterAnimation *anim;
+
+ clutter_actor_set_opacity (a, 0);
+
+ anim = clutter_actor_animate (a,
+ CLUTTER_EASE_IN_SINE,
+ duration,
+ "opacity", 0xff,
+ wc->cm_client);
+
+ g_signal_connect_after (anim, "completed",
+ G_CALLBACK (mbwm_cmc_transtion_fade_out_cb),
+ NULL);
+
+ l = mb_wm_client_get_transients (wc);
+ while (l)
+ {
+ MBWindowManagerClient * c = l->data;
+
+ _fade_apply_behaviour_to_client (c, duration);
+ l = l->next;
+ }
+}
+
+static void
+mbwm_cmc_client_transition_fade (MBWMCompMgrClutterClient *cclient1,
+ MBWMCompMgrClutterClient *cclient2,
+ unsigned long duration)
+{
+ /*
+ * Fade is simple -- we only need to animate the second actor and its
+ * children, as the stacking order automatically takes care of the
+ * actor appearing to fade out from the first one
+ */
+ cclient2->priv->flags |= MBWMCompMgrClutterClientEffectRunning;
+
+ _fade_apply_behaviour_to_client (MB_WM_COMP_MGR_CLIENT (cclient2)->wm_client,
+ duration);
+}
+
+static void
+mbwm_cmc_client_transition_real (MBWMCompMgr *mgr,
+ MBWindowManagerClient *c1,
+ MBWindowManagerClient *c2,
+ Bool reverse)
+{
+ MBWMCompMgrClutterClient * cclient1 = CCLIENT (c1->cm_client);
+ MBWMCompMgrClutterClient * cclient2 = CCLIENT (c2->cm_client);
+
+ mbwm_cmc_client_transition_fade (cclient1, cclient2, 100);
+}
+
+static void
+mbwm_cmc_client_event_completed_hide_cb (ClutterAnimation *anim,
+ MBWMCompMgrClutterClient *client)
+{
+ MBWMCompMgrClient *c = MB_WM_COMP_MGR_CLIENT (client);
+
+ client->priv->flags &= ~MBWMCompMgrClutterClientEffectRunning;
+ clutter_actor_hide (client->priv->actor);
+ clutter_actor_set_scale (client->priv->actor, 1.0, 1.0);
+ mbwm_cmc_unfreeze_stack (c->wm->comp_mgr);
+ mbwm_cmc_client_unfreeze (client);
+
+ /*
+ * Release the extra reference on the CM client that was added for the sake
+ * of the effect
+ */
+ mb_wm_object_unref (MB_WM_OBJECT (client));
+}
+
+static void
+mbwm_cmc_client_event_completed_cb (ClutterAnimation *anim,
+ MBWMCompMgrClutterClient *client)
+{
+ client->priv->flags &= ~MBWMCompMgrClutterClientEffectRunning;
+
+ /*
+ * Release the extra reference on the CM client that was added for the sake
+ * of the effect
+ */
+ mb_wm_object_unref (MB_WM_OBJECT (client));
+}
+
+static void
+mbwm_cmc_client_event_real (MBWMCompMgr *mgr,
+ MBWindowManagerClient *client,
+ MBWMCompMgrClientEvent event)
+{
+ MBWMCompMgrClutterClient *cclient = CCLIENT (client->cm_client);
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+ ClutterAnimation *anim = NULL;
+
+ if (MB_WM_CLIENT_CLIENT_TYPE (client) != MBWMClientTypeApp)
+ return;
+
+ /* FIXME -- this is where the animation is applied */
+ switch (event)
+ {
+ case MBWMCompMgrClientEventMinimize:
+ mbwm_cmc_freeze_stack (mgr);
+ mbwm_cmc_client_freeze (cclient);
+
+ mb_wm_object_ref (MB_WM_OBJECT (cclient));
+ priv->flags |= MBWMCompMgrClutterClientEffectRunning;
+
+ anim = clutter_actor_animate (priv->actor,
+ CLUTTER_EASE_IN_SINE,
+ 200,
+ "scale-x", 0.0,
+ "scale-y", 0.0,
+ NULL);
+ g_signal_connect_after (anim, "completed",
+ G_CALLBACK (mbwm_cmc_client_event_completed_hide_cb),
+ cclient);
+ break;
+ case MBWMCompMgrClientEventUnmap:
+ mbwm_cmc_freeze_stack (mgr);
+ mbwm_cmc_client_freeze (cclient);
+
+ mb_wm_object_ref (MB_WM_OBJECT (cclient));
+ priv->flags |= MBWMCompMgrClutterClientEffectRunning;
+
+ anim = clutter_actor_animate (priv->actor,
+ CLUTTER_EASE_IN_SINE,
+ 200,
+ "scale-x", 0.0,
+ "scale-y", 0.0,
+ NULL);
+ g_signal_connect_after (anim, "completed",
+ G_CALLBACK (mbwm_cmc_client_event_completed_hide_cb),
+ cclient);
+ break;
+ case MBWMCompMgrClientEventMap:
+ mb_wm_object_ref (MB_WM_OBJECT (cclient));
+ priv->flags |= MBWMCompMgrClutterClientEffectRunning;
+
+ clutter_actor_set_scale_full (priv->actor, 0.0, 0.0,
+ clutter_actor_get_width (priv->actor)/ 2,
+ clutter_actor_get_height (priv->actor) / 2);
+ clutter_actor_show (priv->actor);
+
+ anim = clutter_actor_animate (priv->actor,
+ CLUTTER_EASE_IN_SINE,
+ 200,
+ "scale-x", 1.0,
+ "scale-y", 1.0,
+ NULL);
+ g_signal_connect_after (anim, "completed",
+ G_CALLBACK (mbwm_cmc_client_event_completed_cb),
+ cclient);
+ break;
+ default:;
+ }
+}
+
+/*
+ * Our windows which we need the WM to ingore are the overlay and the stage
+ * window.
+ */
+static Bool
+mb_wm_comp_mgr_is_my_window_real (MBWMCompMgr * mgr, Window xwin)
+{
+ MBWMCompMgrClutterPrivate * priv = CMGR (mgr)->priv;
+ ClutterActor * stage;
+
+ if (priv->overlay_window == xwin)
+ return True;
+
+ stage = clutter_stage_get_default ();
+
+ if (xwin == clutter_x11_get_stage_window (CLUTTER_STAGE (stage)))
+ return True;
+
+ return False;
+}
+
+static void
+mbwm_cmc_add_actor (MBWMCompMgrClutter *cmgr,
+ MBWMCompMgrClutterClient *cclient)
+{
+ MBWindowManagerClient * c = MB_WM_COMP_MGR_CLIENT (cclient)->wm_client;
+ MBWMCompMgrClutterClientPrivate *priv = cclient->priv;
+ ClutterActor * d;
+ int desktop = mb_wm_client_get_desktop (c);
+
+ /*
+ * Sanity check; if the desktop is unset, add to desktop 0.
+ */
+ if (desktop < 0)
+ desktop = 0;
+
+ d = mb_wm_comp_mgr_clutter_get_nth_desktop (cmgr, desktop);
+
+ clutter_container_add_actor (CLUTTER_CONTAINER (d), priv->actor);
+}
+
+MBWMCompMgr *
+mb_wm_comp_mgr_clutter_new (MBWindowManager *wm)
+{
+ MBWMObject *mgr;
+
+ mgr = mb_wm_object_new (MB_WM_TYPE_COMP_MGR_CLUTTER,
+ MBWMObjectPropWm, wm,
+ NULL);
+
+ return MB_WM_COMP_MGR (mgr);
+}
+
+/* ------------------------------- */
+/* Shadow Generation */
+
+typedef struct MBGaussianMap
+{
+ int size;
+ double * data;
+} MBGaussianMap;
+
+static double
+gaussian (double r, double x, double y)
+{
+ return ((1 / (sqrt (2 * M_PI * r))) *
+ exp ((- (x * x + y * y)) / (2 * r * r)));
+}
+
+
+static MBGaussianMap *
+mbwm_cmc_make_gaussian_map (double r)
+{
+ MBGaussianMap *c;
+ int size = ((int) ceil ((r * 3)) + 1) & ~1;
+ int center = size / 2;
+ int x, y;
+ double t = 0.0;
+ double g;
+
+ c = malloc (sizeof (MBGaussianMap) + size * size * sizeof (double));
+ c->size = size;
+
+ c->data = (double *) (c + 1);
+
+ for (y = 0; y < size; y++)
+ for (x = 0; x < size; x++)
+ {
+ g = gaussian (r, (double) (x - center), (double) (y - center));
+ t += g;
+ c->data[y * size + x] = g;
+ }
+
+ for (y = 0; y < size; y++)
+ for (x = 0; x < size; x++)
+ c->data[y*size + x] /= t;
+
+ return c;
+}
+
+static unsigned char
+mbwm_cmc_sum_gaussian (MBGaussianMap * map, double opacity,
+ int x, int y, int width, int height)
+{
+ int fx, fy;
+ double * g_data;
+ double * g_line = map->data;
+ int g_size = map->size;
+ int center = g_size / 2;
+ int fx_start, fx_end;
+ int fy_start, fy_end;
+ double v;
+ unsigned int r;
+
+ /*
+ * Compute set of filter values which are "in range",
+ * that's the set with:
+ * 0 <= x + (fx-center) && x + (fx-center) < width &&
+ * 0 <= y + (fy-center) && y + (fy-center) < height
+ *
+ * 0 <= x + (fx - center) x + fx - center < width
+ * center - x <= fx fx < width + center - x
+ */
+
+ fx_start = center - x;
+ if (fx_start < 0)
+ fx_start = 0;
+ fx_end = width + center - x;
+ if (fx_end > g_size)
+ fx_end = g_size;
+
+ fy_start = center - y;
+ if (fy_start < 0)
+ fy_start = 0;
+ fy_end = height + center - y;
+ if (fy_end > g_size)
+ fy_end = g_size;
+
+ g_line = g_line + fy_start * g_size + fx_start;
+
+ v = 0;
+ for (fy = fy_start; fy < fy_end; fy++)
+ {
+ g_data = g_line;
+ g_line += g_size;
+
+ for (fx = fx_start; fx < fx_end; fx++)
+ v += *g_data++;
+ }
+ if (v > 1)
+ v = 1;
+
+ v *= (opacity * 255.0);
+
+ r = (unsigned int) v;
+
+ return (unsigned char) r;
+}
+
+static unsigned char *
+mbwm_cmc_shadow_gaussian_make_tile ()
+{
+ unsigned char * data;
+ int size;
+ int center;
+ int x, y;
+ unsigned char d;
+ int pwidth, pheight;
+ double opacity = SHADOW_OPACITY;
+ static MBGaussianMap * gaussian_map = NULL;
+
+ struct _mypixel
+ {
+ unsigned char r;
+ unsigned char g;
+ unsigned char b;
+ unsigned char a;
+ } * _d;
+
+
+ if (!gaussian_map)
+ gaussian_map =
+ mbwm_cmc_make_gaussian_map (SHADOW_RADIUS);
+
+ size = gaussian_map->size;
+ center = size / 2;
+
+ /* Top & bottom */
+
+ pwidth = MAX_TILE_SZ;
+ pheight = MAX_TILE_SZ;
+
+ data = mb_wm_util_malloc0 (4 * WIDTH * HEIGHT);
+
+ _d = (struct _mypixel*) data;
+
+ /* N */
+ for (y = 0; y < pheight; y++)
+ {
+ d = mbwm_cmc_sum_gaussian (gaussian_map, opacity,
+ center, y - center,
+ WIDTH, HEIGHT);
+ for (x = 0; x < pwidth; x++)
+ {
+ _d[y*3*pwidth + x + pwidth].r = 0;
+ _d[y*3*pwidth + x + pwidth].g = 0;
+ _d[y*3*pwidth + x + pwidth].b = 0;
+ _d[y*3*pwidth + x + pwidth].a = d;
+ }
+
+ }
+
+ /* S */
+ pwidth = MAX_TILE_SZ;
+ pheight = MAX_TILE_SZ;
+
+ for (y = 0; y < pheight; y++)
+ {
+ d = mbwm_cmc_sum_gaussian (gaussian_map, opacity,
+ center, y - center,
+ WIDTH, HEIGHT);
+ for (x = 0; x < pwidth; x++)
+ {
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].r = 0;
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].g = 0;
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].b = 0;
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x + pwidth].a = d;
+ }
+
+ }
+
+
+ /* w */
+ pwidth = MAX_TILE_SZ;
+ pheight = MAX_TILE_SZ;
+
+ for (x = 0; x < pwidth; x++)
+ {
+ d = mbwm_cmc_sum_gaussian (gaussian_map, opacity,
+ x - center, center,
+ WIDTH, HEIGHT);
+ for (y = 0; y < pheight; y++)
+ {
+ _d[y*3*pwidth + 3*pwidth*pheight + x].r = 0;
+ _d[y*3*pwidth + 3*pwidth*pheight + x].g = 0;
+ _d[y*3*pwidth + 3*pwidth*pheight + x].b = 0;
+ _d[y*3*pwidth + 3*pwidth*pheight + x].a = d;
+ }
+
+ }
+
+ /* E */
+ for (x = 0; x < pwidth; x++)
+ {
+ d = mbwm_cmc_sum_gaussian (gaussian_map, opacity,
+ x - center, center,
+ WIDTH, HEIGHT);
+ for (y = 0; y < pheight; y++)
+ {
+ _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].r = 0;
+ _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].g = 0;
+ _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].b = 0;
+ _d[y*3*pwidth + 3*pwidth*pheight + (pwidth-x-1) + 2*pwidth].a = d;
+ }
+
+ }
+
+ /* NW */
+ pwidth = MAX_TILE_SZ;
+ pheight = MAX_TILE_SZ;
+
+ for (x = 0; x < pwidth; x++)
+ for (y = 0; y < pheight; y++)
+ {
+ d = mbwm_cmc_sum_gaussian (gaussian_map, opacity,
+ x-center, y-center,
+ WIDTH, HEIGHT);
+
+ _d[y*3*pwidth + x].r = 0;
+ _d[y*3*pwidth + x].g = 0;
+ _d[y*3*pwidth + x].b = 0;
+ _d[y*3*pwidth + x].a = d;
+ }
+
+ /* SW */
+ for (x = 0; x < pwidth; x++)
+ for (y = 0; y < pheight; y++)
+ {
+ d = mbwm_cmc_sum_gaussian (gaussian_map, opacity,
+ x-center, y-center,
+ WIDTH, HEIGHT);
+
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].r = 0;
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].g = 0;
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].b = 0;
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + x].a = d;
+ }
+
+ /* SE */
+ for (x = 0; x < pwidth; x++)
+ for (y = 0; y < pheight; y++)
+ {
+ d = mbwm_cmc_sum_gaussian (gaussian_map, opacity,
+ x-center, y-center,
+ WIDTH, HEIGHT);
+
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
+ 2*pwidth].r = 0;
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
+ 2*pwidth].g = 0;
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
+ 2*pwidth].b = 0;
+ _d[(pheight-y-1)*3*pwidth + 6*pwidth*pheight + (pwidth-x-1) +
+ 2*pwidth].a = d;
+ }
+
+ /* NE */
+ for (x = 0; x < pwidth; x++)
+ for (y = 0; y < pheight; y++)
+ {
+ d = mbwm_cmc_sum_gaussian (gaussian_map, opacity,
+ x-center, y-center, WIDTH, HEIGHT);
+
+ _d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].r = 0;
+ _d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].g = 0;
+ _d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].b = 0;
+ _d[y*3*pwidth + (pwidth - x - 1) + 2*pwidth].a = d;
+ }
+
+ /* center */
+ pwidth = MAX_TILE_SZ;
+ pheight = MAX_TILE_SZ;
+
+ d = mbwm_cmc_sum_gaussian (gaussian_map, opacity,
+ center, center, WIDTH, HEIGHT);
+
+ for (x = 0; x < pwidth; x++)
+ for (y = 0; y < pheight; y++)
+ {
+ _d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].r = 0;
+ _d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].g = 0;
+ _d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].b = 0;
+ _d[y*3*pwidth + 3*pwidth*pheight + x + pwidth].a = d;
+ }
+
+ return data;
+}
+
diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.h b/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.h
new file mode 100644
index 0000000..8c719d9
--- /dev/null
+++ b/matchbox2/comp-mgr/mb-wm-comp-mgr-clutter.h
@@ -0,0 +1,108 @@
+/*
+ * Matchbox Window Manager - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2008 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _HAVE_MB_WM_COMP_MGR_CLUTTER_H
+#define _HAVE_MB_WM_COMP_MGR_CLUTTER_H
+
+#include <matchbox2/mb-wm-config.h>
+#include <clutter/clutter.h>
+
+#define MB_WM_COMP_MGR_CLUTTER(c) ((MBWMCompMgrClutter*)(c))
+#define MB_WM_COMP_MGR_CLUTTER_CLASS(c) ((MBWMCompMgrClutterClass*)(c))
+#define MB_WM_TYPE_COMP_MGR_CLUTTER (mb_wm_comp_mgr_clutter_class_type ())
+
+#define MB_WM_COMP_MGR_CLUTTER_CLIENT(c) ((MBWMCompMgrClutterClient*)(c))
+#define MB_WM_COMP_MGR_CLUTTER_CLIENT_CLASS(c) ((MBWMCompMgrClutterClientClass*)(c))
+#define MB_WM_TYPE_COMP_MGR_CLUTTER_CLIENT (mb_wm_comp_mgr_clutter_client_class_type ())
+
+typedef struct _MBWMCompMgrClutter MBWMCompMgrClutter;
+typedef struct _MBWMCompMgrClutterClass MBWMCompMgrClutterClass;
+typedef struct _MBWMCompMgrClutterPrivate MBWMCompMgrClutterPrivate;
+
+typedef struct _MBWMCompMgrClutterClient MBWMCompMgrClutterClient;
+typedef struct _MBWMCompMgrClutterClientClass MBWMCompMgrClutterClientClass;
+typedef struct _MBWMCompMgrClutterClientPrivate MBWMCompMgrClutterClientPrivate;
+
+typedef enum
+{
+ MBWMCompMgrClutterClientMapped = (1<<0),
+ MBWMCompMgrClutterClientDontUpdate = (1<<1),
+ MBWMCompMgrClutterClientDone = (1<<2),
+ MBWMCompMgrClutterClientEffectRunning = (1<<3),
+} MBWMCompMgrClutterClientFlags;
+
+struct _MBWMCompMgrClutter
+{
+ MBWMCompMgr parent;
+ MBWMCompMgrClutterPrivate *priv;
+};
+
+struct _MBWMCompMgrClutterClass
+{
+ MBWMCompMgrClass parent;
+
+ MBWMCompMgrClient * (*client_new) (MBWindowManagerClient * client);
+};
+
+int
+mb_wm_comp_mgr_clutter_class_type ();
+
+MBWMCompMgr*
+mb_wm_comp_mgr_clutter_new (MBWindowManager *wm);
+
+struct _MBWMCompMgrClutterClient
+{
+ MBWMCompMgrClient parent;
+
+ MBWMCompMgrClutterClientPrivate *priv;
+};
+
+struct _MBWMCompMgrClutterClientClass
+{
+ MBWMCompMgrClientClass parent;
+};
+
+int
+mb_wm_comp_mgr_clutter_client_class_type ();
+
+ClutterActor *
+mb_wm_comp_mgr_clutter_client_get_actor (MBWMCompMgrClutterClient *cclient);
+
+void
+mb_wm_comp_mgr_clutter_client_set_flags (MBWMCompMgrClutterClient *cclient,
+ MBWMCompMgrClutterClientFlags flags);
+
+void
+mb_wm_comp_mgr_clutter_client_unset_flags (MBWMCompMgrClutterClient *cclient,
+ MBWMCompMgrClutterClientFlags flags);
+
+MBWMCompMgrClutterClientFlags
+mb_wm_comp_mgr_clutter_client_get_flags (MBWMCompMgrClutterClient *cclient);
+
+MBWMList *
+mb_wm_comp_mgr_clutter_get_desktops (MBWMCompMgrClutter *cmgr);
+
+ClutterActor *
+mb_wm_comp_mgr_clutter_get_nth_desktop (MBWMCompMgrClutter *cmgr, int desktop);
+
+ClutterActor *
+mb_wm_comp_mgr_clutter_get_arena (MBWMCompMgrClutter *cmgr);
+
+#endif
diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.c b/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.c
new file mode 100644
index 0000000..fe7f75b
--- /dev/null
+++ b/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.c
@@ -0,0 +1,1837 @@
+/*
+ * Matchbox Window Manager - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ * Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2002, 2004, 2007, 2008 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mb-wm.h"
+#include "mb-wm-client.h"
+#include "mb-wm-comp-mgr.h"
+#include "mb-wm-comp-mgr-xrender.h"
+
+#include <math.h>
+
+#include <X11/Xresource.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xrender.h>
+#include <X11/extensions/Xcomposite.h>
+
+#define SHADOW_RADIUS 6
+#define SHADOW_OPACITY 0.75
+#define SHADOW_OFFSET_X (-SHADOW_RADIUS)
+#define SHADOW_OFFSET_Y (-SHADOW_RADIUS)
+
+/*
+ * A helper object to store manager's per-client data
+ */
+struct MBWMCompMgrDefaultClient
+{
+ MBWMCompMgrClient parent;
+
+ int damaged;
+ Damage damage;
+ Picture picture;
+ XserverRegion extents;
+ XserverRegion border_clip;
+};
+
+static void
+mb_wm_comp_mgr_xrender_client_show_real (MBWMCompMgrClient * client);
+
+static void
+mb_wm_comp_mgr_xrender_client_hide_real (MBWMCompMgrClient * client);
+
+static void
+mb_wm_comp_mgr_xrender_client_repair_real (MBWMCompMgrClient * client);
+
+static void
+mb_wm_comp_mgr_xrender_client_configure_real (MBWMCompMgrClient * client);
+
+static void
+mb_wm_comp_mgr_xrender_client_class_init (MBWMObjectClass *klass)
+{
+ MBWMCompMgrClientClass *c_klass = MB_WM_COMP_MGR_CLIENT_CLASS (klass);
+
+ c_klass->show = mb_wm_comp_mgr_xrender_client_show_real;
+ c_klass->hide = mb_wm_comp_mgr_xrender_client_hide_real;
+ c_klass->repair = mb_wm_comp_mgr_xrender_client_repair_real;
+ c_klass->configure = mb_wm_comp_mgr_xrender_client_configure_real;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMCompMgrDefaultClient";
+#endif
+}
+
+static int
+mb_wm_comp_mgr_xrender_client_init (MBWMObject *obj, va_list vap)
+{
+ MBWMCompMgrClient *client = MB_WM_COMP_MGR_CLIENT (obj);
+ MBWMCompMgrDefaultClient *dclient = MB_WM_COMP_MGR_DEFAULT_CLIENT (obj);
+ MBWindowManager *wm;
+ MBWindowManagerClient *wm_client = client->wm_client;
+
+ if (!wm_client || !wm_client->wmref)
+ return 0;
+
+ return 1;
+}
+
+static void
+mb_wm_comp_mgr_xrender_client_destroy (MBWMObject* obj)
+{
+ MBWMCompMgrClient * c = MB_WM_COMP_MGR_CLIENT (obj);
+ MBWMCompMgrDefaultClient * dc = MB_WM_COMP_MGR_DEFAULT_CLIENT (obj);
+ MBWindowManager * wm = c->wm;
+
+ mb_wm_comp_mgr_client_hide (c);
+
+ if (dc->damage)
+ XDamageDestroy (wm->xdpy, dc->damage);
+
+ if (dc->picture)
+ XRenderFreePicture (wm->xdpy, dc->picture);
+
+ if (dc->extents)
+ XFixesDestroyRegion (wm->xdpy, dc->extents);
+
+ if (dc->border_clip)
+ XFixesDestroyRegion (wm->xdpy, dc->border_clip);
+}
+
+int
+mb_wm_comp_mgr_xrender_client_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMCompMgrDefaultClientClass),
+ sizeof (MBWMCompMgrDefaultClient),
+ mb_wm_comp_mgr_xrender_client_init,
+ mb_wm_comp_mgr_xrender_client_destroy,
+ mb_wm_comp_mgr_xrender_client_class_init
+ };
+
+ type =
+ mb_wm_object_register_class (&info, MB_WM_TYPE_COMP_MGR_CLIENT, 0);
+ }
+
+ return type;
+}
+
+/*
+ * This is a private method, hence static
+ */
+static MBWMCompMgrClient *
+mb_wm_comp_mgr_xrender_client_new (MBWindowManagerClient * client)
+{
+ MBWMObject *c;
+
+ c = mb_wm_object_new (MB_WM_TYPE_COMP_MGR_DEFAULT_CLIENT,
+ MBWMObjectPropClient, client,
+ NULL);
+
+ return MB_WM_COMP_MGR_CLIENT (c);
+}
+
+static void
+mb_wm_comp_mgr_xrender_add_damage (MBWMCompMgr * mgr, XserverRegion damage);
+
+static XserverRegion
+mb_wm_comp_mgr_xrender_client_extents (MBWMCompMgrClient *client);
+
+static void
+mb_wm_comp_mgr_xrender_client_hide_real (MBWMCompMgrClient * client)
+{
+ MBWMCompMgrDefaultClient * dclient = MB_WM_COMP_MGR_DEFAULT_CLIENT (client);
+ MBWindowManagerClient * wm_client = client->wm_client;
+ MBWindowManager * wm = client->wm;
+ MBWMCompMgr * mgr = wm->comp_mgr;
+ MBWindowManagerClient * c;
+ Bool is_modal = mb_wm_client_is_modal (wm_client);
+
+ if (is_modal && ((c = mb_wm_get_visible_main_client (wm)) != NULL))
+ {
+ XserverRegion extents;
+ /* We need to make sure the any lowlighting on a 'parent'
+ * modal for app gets cleared. This is kind of a sledgehammer
+ * approach to it, but more suttle attempts oddly fail at times.
+ *
+ * FIXME: keep an eye on this for future revisions of composite
+ * - there may be a better way.
+ */
+ mb_wm_comp_mgr_xrender_client_repair_real (c->cm_client);
+ extents = mb_wm_comp_mgr_xrender_client_extents (c->cm_client);
+ mb_wm_comp_mgr_xrender_add_damage (mgr, extents);
+ }
+
+ if (dclient->damage)
+ {
+ XDamageDestroy (wm->xdpy, dclient->damage);
+ dclient->damage = None;
+ }
+
+ if (dclient->extents)
+ {
+ mb_wm_comp_mgr_xrender_add_damage (mgr, dclient->extents);
+ dclient->extents = None;
+ }
+
+ if (dclient->picture)
+ {
+ XRenderFreePicture (wm->xdpy, dclient->picture);
+ dclient->picture = None;
+ }
+}
+
+static void
+mb_wm_comp_mgr_xrender_client_show_real (MBWMCompMgrClient * client)
+{
+ MBWMCompMgrDefaultClient * dclient = MB_WM_COMP_MGR_DEFAULT_CLIENT (client);
+ MBWindowManagerClient * wm_client = client->wm_client;
+ MBWindowManager * wm = client->wm;
+ MBWMCompMgr * mgr = wm->comp_mgr;
+ XserverRegion region;
+ XRenderPictureAttributes pa;
+ MBWMClientType ctype = MB_WM_CLIENT_CLIENT_TYPE (wm_client);
+ Bool is_modal;
+
+ /*
+ * Destroying / Recreating the client pictures should hopefully save
+ * some memory in the server.
+ */
+ if (!dclient->picture)
+ {
+ pa.subwindow_mode = IncludeInferiors;
+
+ dclient->picture =
+ XRenderCreatePicture (wm->xdpy,
+ wm_client->xwin_frame ?
+ wm_client->xwin_frame :
+ wm_client->window->xwindow,
+ client->is_argb32 ?
+ XRenderFindStandardFormat (wm->xdpy,
+ PictStandardARGB32)
+
+ : XRenderFindVisualFormat (wm->xdpy,
+ wm_client->window->visual),
+ CPSubwindowMode,
+ &pa);
+ }
+
+ if (dclient->damage != None)
+ XDamageDestroy (wm->xdpy, dclient->damage);
+
+ dclient->damage = XDamageCreate (wm->xdpy,
+ wm_client->xwin_frame ?
+ wm_client->xwin_frame :
+ wm_client->window->xwindow,
+ XDamageReportNonEmpty);
+
+ region = mb_wm_comp_mgr_xrender_client_extents (client);
+
+ mb_wm_comp_mgr_xrender_add_damage (mgr, region);
+
+ /*
+ * If the wm client is modal we have to add its parent to the damage
+ * in order for lowlighting to work
+ */
+ if (mb_wm_client_is_modal (wm_client))
+ {
+ MBWindowManagerClient * parent =
+ mb_wm_client_get_transient_for (wm_client);
+
+ if (parent && parent->cm_client)
+ {
+ XserverRegion extents =
+ mb_wm_comp_mgr_xrender_client_extents (parent->cm_client);
+
+ mb_wm_comp_mgr_xrender_add_damage (mgr, extents);
+ }
+ }
+
+ if (!dclient->extents)
+ {
+ dclient->extents = mb_wm_comp_mgr_xrender_client_extents (client);
+ }
+}
+
+
+/*
+ * The Manager itself
+ */
+
+typedef struct MBGaussianMap
+{
+ int size;
+ double * data;
+} MBGaussianMap;
+
+
+struct MBWMCompMgrDefaultPrivate
+{
+ MBGaussianMap * gaussian_map;
+
+ Picture shadow_n_pic;
+ Picture shadow_e_pic;
+ Picture shadow_s_pic;
+ Picture shadow_w_pic;
+
+ Picture shadow_ne_pic;
+ Picture shadow_nw_pic;
+ Picture shadow_se_pic;
+ Picture shadow_sw_pic;
+
+ Picture shadow_pic;
+
+ int shadow_dx;
+ int shadow_dy;
+ int shadow_padding_width;
+ int shadow_padding_height;
+ int shadow_style;
+ unsigned int shadow_color[4]; /* RGBA */
+
+ Picture trans_picture;
+ Picture black_picture;
+ Picture lowlight_picture;
+ unsigned int lowlight_params[4]; /* RGBA */
+
+ Picture root_picture;
+ Picture root_buffer;
+
+ XserverRegion all_damage;
+ Bool dialog_shade;
+};
+
+static void
+mb_wm_comp_mgr_xrender_private_free (MBWMCompMgrDefault *mgr)
+{
+ MBWMCompMgrDefaultPrivate * priv = mgr->priv;
+ Display * xdpy = MB_WM_COMP_MGR (mgr)->wm->xdpy;
+
+ if (priv->gaussian_map)
+ free (priv->gaussian_map);
+
+ XRenderFreePicture (xdpy, priv->shadow_n_pic);
+ XRenderFreePicture (xdpy, priv->shadow_e_pic);
+ XRenderFreePicture (xdpy, priv->shadow_s_pic);
+ XRenderFreePicture (xdpy, priv->shadow_w_pic);
+
+ XRenderFreePicture (xdpy, priv->shadow_ne_pic);
+ XRenderFreePicture (xdpy, priv->shadow_nw_pic);
+ XRenderFreePicture (xdpy, priv->shadow_se_pic);
+ XRenderFreePicture (xdpy, priv->shadow_sw_pic);
+
+ XRenderFreePicture (xdpy, priv->shadow_pic);
+
+ XRenderFreePicture (xdpy, priv->black_picture);
+ XRenderFreePicture (xdpy, priv->lowlight_picture);
+ XRenderFreePicture (xdpy, priv->trans_picture);
+
+ if (priv->root_picture)
+ XRenderFreePicture (xdpy, priv->root_picture);
+
+ if (priv->root_buffer)
+ XRenderFreePicture (xdpy, priv->root_buffer);
+
+ if (priv->all_damage)
+ XDamageDestroy (xdpy, priv->all_damage);
+
+ free (priv);
+}
+
+static void
+mb_wm_comp_mgr_xrender_register_client_real (MBWMCompMgr * mgr,
+ MBWindowManagerClient * c)
+{
+ MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+
+ MBWM_NOTE (COMPOSITOR, "@@@@ registering client for %x @@@@\n",
+ c->window->xwindow);
+
+ if (c->cm_client)
+ return;
+
+ c->cm_client = mb_wm_comp_mgr_xrender_client_new (c);
+}
+
+static void
+mb_wm_comp_mgr_xrender_turn_on_real (MBWMCompMgr *mgr);
+
+static void
+mb_wm_comp_mgr_xrender_turn_off_real (MBWMCompMgr *mgr);
+
+static void
+mb_wm_comp_mgr_xrender_render_real (MBWMCompMgr *mgr);
+
+static Bool
+mb_wm_comp_mgr_xrender_handle_damage (XDamageNotifyEvent * de,
+ MBWMCompMgr * mgr);
+
+static void
+mb_wm_comp_mgr_xrender_class_init (MBWMObjectClass *klass)
+{
+ MBWMCompMgrClass *cm_klass = MB_WM_COMP_MGR_CLASS (klass);
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMCompMgrDefault";
+#endif
+
+ cm_klass->register_client = mb_wm_comp_mgr_xrender_register_client_real;
+ cm_klass->turn_on = mb_wm_comp_mgr_xrender_turn_on_real;
+ cm_klass->turn_off = mb_wm_comp_mgr_xrender_turn_off_real;
+ cm_klass->render = mb_wm_comp_mgr_xrender_render_real;
+ cm_klass->handle_damage = mb_wm_comp_mgr_xrender_handle_damage;
+}
+
+static void
+mb_wm_comp_mgr_xrender_init_pictures (MBWMCompMgr *mgr);
+
+static int
+mb_wm_comp_mgr_xrender_init (MBWMObject *obj, va_list vap)
+{
+ MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj);
+ MBWMCompMgrDefault * dmgr = MB_WM_COMP_MGR_DEFAULT (obj);
+ MBWindowManager * wm = mgr->wm;
+ MBWMCompMgrDefaultPrivate * priv;
+
+ if (!wm)
+ return 0;
+
+ dmgr->priv = mb_wm_util_malloc0 (sizeof (MBWMCompMgrDefaultPrivate));
+ priv = dmgr->priv;
+
+ priv->shadow_dx = SHADOW_OFFSET_X;
+ priv->shadow_dy = SHADOW_OFFSET_Y;
+
+ /* Not really used yet */
+ priv->shadow_padding_width = 0;
+ priv->shadow_padding_height = 0;
+
+ mgr->disabled = True;
+
+ XCompositeRedirectSubwindows (wm->xdpy, wm->root_win->xwindow,
+ CompositeRedirectManual);
+
+ mb_wm_theme_get_shadow_color (wm->theme,
+ &priv->shadow_color[0],
+ &priv->shadow_color[1],
+ &priv->shadow_color[2],
+ &priv->shadow_color[3]);
+
+ mb_wm_theme_get_lowlight_color (wm->theme,
+ &priv->lowlight_params[0],
+ &priv->lowlight_params[1],
+ &priv->lowlight_params[2],
+ &priv->lowlight_params[3]);
+
+ priv->shadow_style = mb_wm_theme_get_shadow_type (wm->theme);
+
+ mb_wm_comp_mgr_xrender_init_pictures (mgr);
+
+ return 1;
+}
+
+static void
+mb_wm_comp_mgr_xrender_destroy (MBWMObject * obj)
+{
+ MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj);
+ MBWMCompMgrDefault * dmgr = MB_WM_COMP_MGR_DEFAULT (obj);
+
+ mb_wm_comp_mgr_turn_off (mgr);
+ mb_wm_comp_mgr_xrender_private_free (dmgr);
+}
+
+int
+mb_wm_comp_mgr_xrender_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMCompMgrDefaultClass),
+ sizeof (MBWMCompMgrDefault),
+ mb_wm_comp_mgr_xrender_init,
+ mb_wm_comp_mgr_xrender_destroy,
+ mb_wm_comp_mgr_xrender_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_COMP_MGR, 0);
+ }
+
+ return type;
+}
+
+/* Shadow Generation */
+static double
+gaussian (double r, double x, double y)
+{
+ return ((1 / (sqrt (2 * M_PI * r))) *
+ exp ((- (x * x + y * y)) / (2 * r * r)));
+}
+
+
+static MBGaussianMap *
+mb_wm_comp_mgr_xrender_make_gaussian_map (double r)
+{
+ MBGaussianMap *c;
+ int size = ((int) ceil ((r * 3)) + 1) & ~1;
+ int center = size / 2;
+ int x, y;
+ double t = 0.0;
+ double g;
+
+ c = malloc (sizeof (MBGaussianMap) + size * size * sizeof (double));
+ c->size = size;
+
+ c->data = (double *) (c + 1);
+
+ for (y = 0; y < size; y++)
+ for (x = 0; x < size; x++)
+ {
+ g = gaussian (r, (double) (x - center), (double) (y - center));
+ t += g;
+ c->data[y * size + x] = g;
+ }
+
+ for (y = 0; y < size; y++)
+ for (x = 0; x < size; x++)
+ c->data[y*size + x] /= t;
+
+ return c;
+}
+
+static unsigned char
+mb_wm_comp_mgr_xrender_sum_gaussian (MBWMCompMgr * mgr, double opacity,
+ int x, int y, int width, int height)
+{
+ MBGaussianMap * map = MB_WM_COMP_MGR_DEFAULT (mgr)->priv->gaussian_map;
+ int fx, fy;
+ double * g_data;
+ double * g_line = map->data;
+ int g_size = map->size;
+ int center = g_size / 2;
+ int fx_start, fx_end;
+ int fy_start, fy_end;
+ double v;
+
+ /*
+ * Compute set of filter values which are "in range",
+ * that's the set with:
+ * 0 <= x + (fx-center) && x + (fx-center) < width &&
+ * 0 <= y + (fy-center) && y + (fy-center) < height
+ *
+ * 0 <= x + (fx - center) x + fx - center < width
+ * center - x <= fx fx < width + center - x
+ */
+
+ fx_start = center - x;
+ if (fx_start < 0)
+ fx_start = 0;
+ fx_end = width + center - x;
+ if (fx_end > g_size)
+ fx_end = g_size;
+
+ fy_start = center - y;
+ if (fy_start < 0)
+ fy_start = 0;
+ fy_end = height + center - y;
+ if (fy_end > g_size)
+ fy_end = g_size;
+
+ g_line = g_line + fy_start * g_size + fx_start;
+
+ v = 0;
+ for (fy = fy_start; fy < fy_end; fy++)
+ {
+ g_data = g_line;
+ g_line += g_size;
+
+ for (fx = fx_start; fx < fx_end; fx++)
+ v += *g_data++;
+ }
+ if (v > 1)
+ v = 1;
+
+ return ((unsigned int) (v * opacity * 255.0));
+}
+
+#define MAX_TILE_SZ 16 /* make sure size/2 < MAX_TILE_SZ */
+#define WIDTH 320
+#define HEIGHT 320
+
+static void
+mb_wm_comp_mgr_xrender_shadow_setup_part (MBWMCompMgr * mgr,
+ XImage ** ximage,
+ Picture * pic,
+ Pixmap * pxm,
+ int width,
+ int height)
+{
+ MBWindowManager * wm = mgr->wm;
+
+ *ximage = XCreateImage (wm->xdpy, DefaultVisual(wm->xdpy, wm->xscreen),
+ 8, ZPixmap, 0, 0,
+ width, height, 8, width * sizeof (unsigned char));
+
+ (*ximage)->data = malloc (width * height * sizeof (unsigned char));
+
+ *pxm = XCreatePixmap (wm->xdpy, wm->root_win->xwindow,
+ width, height, 8);
+
+ *pic = XRenderCreatePicture (wm->xdpy, *pxm,
+ XRenderFindStandardFormat (wm->xdpy,
+ PictStandardA8),
+ 0, 0);
+}
+
+static void
+mb_wm_comp_mgr_xrender_shadow_finalise_part (MBWMCompMgr * mgr,
+ XImage * ximage,
+ Picture pic,
+ Pixmap pxm,
+ int width,
+ int height)
+{
+ MBWindowManager * wm = mgr->wm;
+
+ GC gc = XCreateGC (wm->xdpy, pxm, 0, 0);
+ XPutImage (wm->xdpy, pxm, gc, ximage, 0, 0, 0, 0, width, height);
+ XDestroyImage (ximage);
+ XFreeGC (wm->xdpy, gc);
+ XFreePixmap (wm->xdpy, pxm);
+}
+
+static void
+mb_wm_comp_mgr_xrender_shadow_setup (MBWMCompMgr * mgr)
+{
+ MBWindowManager * wm = mgr->wm;
+ MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+ XImage * ximage;
+ Pixmap pxm;
+ unsigned char * data;
+ int size;
+ int center;
+ int x, y;
+ unsigned char d;
+ int pwidth, pheight;
+ double opacity = SHADOW_OPACITY;
+
+ if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_NONE)
+ return;
+
+ if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_SIMPLE)
+ {
+ priv->shadow_padding_width = 0;
+ priv->shadow_padding_height = 0;
+ return;
+ }
+
+ /* SHADOW_STYLE_GAUSSIAN */
+ priv->gaussian_map =
+ mb_wm_comp_mgr_xrender_make_gaussian_map (SHADOW_RADIUS);
+
+ priv->shadow_padding_width = priv->gaussian_map->size;
+ priv->shadow_padding_height = priv->gaussian_map->size;
+
+ size = priv->gaussian_map->size;
+ center = size / 2;
+
+ /* Top & bottom */
+ pwidth = MAX_TILE_SZ;
+ pheight = size/2;
+ mb_wm_comp_mgr_xrender_shadow_setup_part (mgr,
+ &ximage, &priv->shadow_n_pic, &pxm,
+ pwidth, pheight);
+
+ data = (unsigned char*)ximage->data;
+
+ for (y = 0; y < pheight; y++)
+ {
+ d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity,
+ center, y - center,
+ WIDTH, HEIGHT);
+ for (x = 0; x < pwidth; x++)
+ data[y * pwidth + x] = d;
+ }
+
+ mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, priv->shadow_n_pic,
+ pxm, pwidth, pheight);
+
+ pwidth = MAX_TILE_SZ;
+ pheight = MAX_TILE_SZ;
+
+ mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_s_pic,
+ &pxm, pwidth, pheight);
+
+ data = (unsigned char*)ximage->data;
+
+ for (y = 0; y < pheight; y++)
+ {
+ d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity,
+ center, y - center,
+ WIDTH, HEIGHT);
+ for (x = 0; x < pwidth; x++)
+ data[(pheight - y - 1) * pwidth + x] = d;
+ }
+
+ mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, priv->shadow_s_pic,
+ pxm, pwidth, pheight);
+
+ /* Sides */
+ pwidth = MAX_TILE_SZ;
+ pheight = MAX_TILE_SZ;
+ mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_w_pic,
+ &pxm, pwidth, pheight);
+
+ data = (unsigned char*)ximage->data;
+
+ for (x = 0; x < pwidth; x++)
+ {
+ d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity,
+ x - center, center,
+ WIDTH, HEIGHT);
+ for (y = 0; y < pheight; y++)
+ data[y * pwidth + (pwidth - x - 1)] = d;
+ }
+
+ mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, priv->shadow_w_pic,
+ pxm, pwidth, pheight);
+
+ mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_e_pic,
+ &pxm, pwidth, pheight);
+
+ data = (unsigned char*)ximage->data;
+
+ for (x = 0; x < pwidth; x++)
+ {
+ d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity,
+ x - center, center,
+ WIDTH, HEIGHT);
+ for (y = 0; y < pheight; y++)
+ data[y * pwidth + x] = d;
+ }
+
+ mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, priv->shadow_e_pic,
+ pxm, pwidth, pheight);
+
+ /* Corners */
+ pwidth = MAX_TILE_SZ;
+ pheight = MAX_TILE_SZ;
+ mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_nw_pic,
+ &pxm, pwidth, pheight);
+
+ data = (unsigned char*)ximage->data;
+
+ for (x = 0; x < pwidth; x++)
+ for (y = 0; y < pheight; y++)
+ {
+ d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity,
+ x-center, y-center,
+ WIDTH, HEIGHT);
+
+ data[y * pwidth + x] = d;
+ }
+
+ mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage,
+ priv->shadow_nw_pic,
+ pxm, pwidth, pheight);
+
+ mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_sw_pic,
+ &pxm, pwidth, pheight);
+
+ data = (unsigned char*)ximage->data;
+
+ for (x = 0; x < pwidth; x++)
+ for (y = 0; y < pheight; y++)
+ {
+ d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity,
+ x-center, y-center,
+ WIDTH, HEIGHT);
+
+ data[(pheight - y - 1) * pwidth + x] = d;
+ }
+
+ mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage,
+ priv->shadow_sw_pic,
+ pxm, pwidth, pheight);
+
+ mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_se_pic,
+ &pxm, pwidth, pheight);
+
+ data = (unsigned char*)ximage->data;
+
+ for (x = 0; x < pwidth; x++)
+ for (y = 0; y < pheight; y++)
+ {
+ d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity,
+ x-center, y-center,
+ WIDTH, HEIGHT);
+
+ data[(pheight - y - 1) * pwidth + (pwidth - x -1)] = d;
+ }
+
+ mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage,
+ priv->shadow_se_pic,
+ pxm, pwidth, pheight);
+
+ mb_wm_comp_mgr_xrender_shadow_setup_part(mgr, &ximage, &priv->shadow_ne_pic,
+ &pxm, pwidth, pheight);
+
+ data = (unsigned char*)ximage->data;
+
+ for (x = 0; x < pwidth; x++)
+ for (y = 0; y < pheight; y++)
+ {
+ d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity,
+ x-center, y-center, WIDTH, HEIGHT);
+
+ data[y * pwidth + (pwidth - x -1)] = d;
+ }
+
+ mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage,
+ priv->shadow_ne_pic,
+ pxm, pwidth, pheight);
+
+ /* Finally center */
+ pwidth = MAX_TILE_SZ;
+ pheight = MAX_TILE_SZ;
+ mb_wm_comp_mgr_xrender_shadow_setup_part (mgr, &ximage, &priv->shadow_pic,
+ &pxm, pwidth, pheight);
+
+ data = (unsigned char*)ximage->data;
+
+ d = mb_wm_comp_mgr_xrender_sum_gaussian (mgr, opacity,
+ center, center, WIDTH, HEIGHT);
+
+ for (x = 0; x < pwidth; x++)
+ for (y = 0; y < pheight; y++)
+ data[y * pwidth + x] = d;
+
+ mb_wm_comp_mgr_xrender_shadow_finalise_part (mgr, ximage, priv->shadow_pic,
+ pxm, pwidth, pheight);
+
+}
+
+static Picture
+mb_wm_comp_mgr_xrender_shadow_gaussian_make_picture (MBWMCompMgr * mgr,
+ int width, int height)
+{
+ MBWindowManager * wm = mgr->wm;
+ MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+ Picture pic;
+ Pixmap pxm;
+ int pwidth, pheight, x, y, dw, dh;
+
+ pxm = XCreatePixmap (wm->xdpy, wm->root_win->xwindow, width, height, 8);
+ pic = XRenderCreatePicture (wm->xdpy, pxm,
+ XRenderFindStandardFormat (wm->xdpy,
+ PictStandardA8),
+ 0,0);
+
+ pwidth = MAX_TILE_SZ;
+ pheight = MAX_TILE_SZ;
+
+ for (x=0; x < width; x += pwidth)
+ for (y=0; y < height; y += pheight)
+ {
+ if ( (y + pheight) > height )
+ dh = pheight - ((y + pheight)-height);
+ else
+ dh = pheight;
+
+ if ( (x + pwidth) > width )
+ dw = pwidth - ((x + pwidth)-width);
+ else
+ dw = pwidth;
+
+ XRenderComposite (wm->xdpy, PictOpSrc,
+ priv->shadow_pic, None, pic,
+ 0, 0, 0, 0, x, y, dw, dh);
+ }
+
+ /* Top & bottom */
+ if ( width > (MAX_TILE_SZ*2) )
+ {
+ pwidth = MAX_TILE_SZ; pheight = MAX_TILE_SZ;
+
+ for (x=0; x < width; x += pwidth )
+ {
+ if ( (x + pwidth) > width )
+ dw = pwidth - ((x + pwidth)-width);
+ else
+ dw = pwidth;
+
+ XRenderComposite (wm->xdpy, PictOpSrc,
+ priv->shadow_n_pic, None, pic,
+ 0, 0, 0, 0, x, 0, dw, pheight);
+ XRenderComposite (wm->xdpy, PictOpSrc,
+ priv->shadow_s_pic, None, pic,
+ 0, 0, 0, 0, x, height - pheight, dw, pheight);
+ }
+ }
+
+ /* Sides */
+ if ( height > (MAX_TILE_SZ*2) )
+ {
+ pwidth = MAX_TILE_SZ; pheight = MAX_TILE_SZ;
+
+ for (y=0; y < height; y += pheight)
+ {
+ if ( (y + pheight) > height )
+ dh = pheight - ((y + pheight)-height);
+ else
+ dh = pheight;
+
+ XRenderComposite (wm->xdpy, PictOpSrc /* PictOpIn */,
+ priv->shadow_e_pic, None, pic,
+ 0, 0, 0, 0, 0, y, pwidth, dh);
+ XRenderComposite (wm->xdpy, PictOpSrc /* PictOpIn */,
+ priv->shadow_w_pic, None, pic,
+ 0, 0, 0, 0, width - pwidth, y, pwidth, dh);
+ }
+ }
+
+ /* Corners */
+ pwidth = MAX_TILE_SZ; pheight = MAX_TILE_SZ;
+
+ XRenderComposite (wm->xdpy, PictOpSrc, priv->shadow_nw_pic, None, pic,
+ 0, 0, 0, 0, 0, 0, pwidth, pheight);
+
+ XRenderComposite (wm->xdpy, PictOpSrc, priv->shadow_ne_pic, None, pic,
+ 0, 0, 0, 0, width - pwidth, 0, pwidth, pheight);
+
+ XRenderComposite (wm->xdpy, PictOpSrc, priv->shadow_sw_pic, None, pic,
+ 0, 0, 0, 0, 0, height - pheight, pwidth, pheight);
+
+ XRenderComposite (wm->xdpy, PictOpSrc, priv->shadow_se_pic, None, pic,
+ 0, 0, 0, 0, width - pwidth, height - pheight,
+ pwidth, pheight);
+
+ XFreePixmap (wm->xdpy, pxm);
+ return pic;
+}
+
+static XserverRegion
+mb_wm_comp_mgr_xrender_client_extents (MBWMCompMgrClient *client)
+{
+ MBWindowManagerClient *wm_client = client->wm_client;
+ MBWindowManager *wm = client->wm;
+ MBWMCompMgr *mgr = wm->comp_mgr;
+ MBWMCompMgrDefaultPrivate *priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+ MBGeometry geom;
+ XRectangle r;
+ MBWMClientType ctype = MB_WM_CLIENT_CLIENT_TYPE (wm_client);
+ XserverRegion extents;
+
+ mb_wm_client_get_coverage (wm_client, &geom);
+
+ r.x = geom.x;
+ r.y = geom.y;
+ r.width = geom.width;
+ r.height = geom.height;
+
+ if (priv->shadow_style)
+ {
+ if (ctype == MBWMClientTypeDialog ||
+ ctype == MBWMClientTypeMenu ||
+ ctype == MBWMClientTypeOverride)
+ {
+ if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_SIMPLE)
+ {
+ r.width += priv->shadow_dx;
+ r.height += priv->shadow_dy;
+ }
+ else
+ {
+ r.x += priv->shadow_dx;
+ r.y += priv->shadow_dy;
+ r.width += priv->shadow_padding_width;
+ r.height += priv->shadow_padding_height;
+ }
+ }
+ }
+
+ extents = XFixesCreateRegion (wm->xdpy, &r, 1);
+
+ return extents;
+}
+
+static XserverRegion
+mb_wm_comp_mgr_xrender_client_border_size (MBWMCompMgrClient * client,
+ int x, int y)
+{
+ MBWindowManagerClient * wm_client = client->wm_client;
+ MBWindowManager * wm = client->wm;
+ XserverRegion border;
+
+ border = XFixesCreateRegionFromWindow (wm->xdpy,
+ wm_client->xwin_frame ?
+ wm_client->xwin_frame :
+ wm_client->window->xwindow,
+ WindowRegionBounding);
+ /* translate this */
+ XFixesTranslateRegion (wm->xdpy, border, x, y);
+ return border;
+}
+
+static XserverRegion
+mb_wm_comp_mgr_xrender_client_window_region (MBWMCompMgrClient *client,
+ Window xwin, int x, int y)
+{
+ MBWindowManagerClient * wm_client = client->wm_client;
+ MBWindowManager * wm = client->wm;
+ XserverRegion region;
+
+ region =
+ XFixesCreateRegionFromWindow (wm->xdpy, xwin, WindowRegionBounding);
+
+ /* translate this */
+ XFixesTranslateRegion (wm->xdpy, region, x, y);
+
+ return region;
+}
+
+static Visual*
+mb_wm_comp_mgr_xrender_get_argb32_visual (MBWMCompMgr * mgr)
+{
+ MBWindowManager * wm = mgr->wm;
+ XVisualInfo * xvi;
+ XVisualInfo template;
+ int nvi;
+ int i;
+ XRenderPictFormat * format;
+ Visual * visual = NULL;
+
+ template.screen = wm->xscreen;
+ template.depth = 32;
+ template.class = TrueColor;
+
+ if ((xvi = XGetVisualInfo (wm->xdpy,
+ VisualScreenMask|VisualDepthMask|VisualClassMask,
+ &template,
+ &nvi)) == NULL)
+ return NULL;
+
+ for (i = 0; i < nvi; i++)
+ {
+ format = XRenderFindVisualFormat (wm->xdpy, xvi[i].visual);
+ if (format->type == PictTypeDirect && format->direct.alphaMask)
+ {
+ visual = xvi[i].visual;
+ break;
+ }
+ }
+
+ XFree (xvi);
+ return visual;
+}
+
+static void
+mb_wm_comp_mgr_xrender_init_pictures (MBWMCompMgr *mgr)
+{
+ MBWindowManager * wm;
+ Window rwin;
+ MBWMCompMgrDefaultPrivate * priv;
+ Pixmap transPixmap, blackPixmap, lowlightPixmap,
+ redPixmap;
+ XRenderPictureAttributes pa;
+ XRenderColor c;
+ int i;
+
+ if (!mgr)
+ return;
+
+ wm = mgr->wm;
+ rwin = wm->root_win->xwindow;
+ priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+
+ {
+ Picture pics_to_free[] = { priv->trans_picture,
+ priv->black_picture,
+ priv->lowlight_picture,
+ priv->shadow_n_pic,
+ priv->shadow_e_pic,
+ priv->shadow_s_pic,
+ priv->shadow_w_pic,
+ priv->shadow_ne_pic,
+ priv->shadow_nw_pic,
+ priv->shadow_se_pic,
+ priv->shadow_sw_pic,
+ priv->shadow_pic };
+
+ for (i=0; i < (sizeof(pics_to_free)/sizeof(Picture)); i++)
+ if (pics_to_free[i] != None)
+ XRenderFreePicture (wm->xdpy, pics_to_free[i]);
+ }
+
+ if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_GAUSSIAN)
+ mb_wm_comp_mgr_xrender_shadow_setup (mgr);
+
+ pa.subwindow_mode = IncludeInferiors;
+ pa.repeat = True;
+
+ transPixmap = XCreatePixmap (wm->xdpy, rwin, 1, 1, 8);
+
+ priv->trans_picture
+ = XRenderCreatePicture (wm->xdpy, transPixmap,
+ XRenderFindStandardFormat (wm->xdpy,
+ PictStandardA8),
+ CPRepeat,
+ &pa);
+
+ c.red = c.green = c.blue = 0;
+ c.alpha = 0xddff;
+
+ XRenderFillRectangle (wm->xdpy, PictOpSrc, priv->trans_picture,
+ &c, 0, 0, 1, 1);
+
+ /* black pixmap used for shadows */
+
+ blackPixmap = XCreatePixmap (wm->xdpy, rwin, 1, 1, 32);
+
+ priv->black_picture
+ = XRenderCreatePicture (wm->xdpy, blackPixmap,
+ XRenderFindStandardFormat (wm->xdpy,
+ PictStandardARGB32),
+ CPRepeat,
+ &pa);
+
+ c.red = priv->shadow_color[0];
+ c.green = priv->shadow_color[1];
+ c.blue = priv->shadow_color[2];
+
+ if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_GAUSSIAN)
+ c.alpha = 0xffff;
+ else
+ c.alpha = priv->shadow_color[3];
+
+ XRenderFillRectangle (wm->xdpy, PictOpSrc, priv->black_picture,
+ &c, 0, 0, 1, 1);
+
+ /* Used for lowlights */
+ lowlightPixmap = XCreatePixmap (wm->xdpy, rwin, 1, 1, 32);
+ priv->lowlight_picture
+ = XRenderCreatePicture (wm->xdpy, lowlightPixmap,
+ XRenderFindStandardFormat (wm->xdpy,
+ PictStandardARGB32),
+ CPRepeat,
+ &pa);
+
+ c.red = priv->lowlight_params[0];
+ c.green = priv->lowlight_params[1];
+ c.blue = priv->lowlight_params[2];
+ c.alpha = priv->lowlight_params[3];
+
+ XRenderFillRectangle (wm->xdpy, PictOpSrc, priv->lowlight_picture,
+ &c, 0, 0, 1, 1);
+
+
+ pa.repeat = False;
+
+ priv->root_picture
+ = XRenderCreatePicture (wm->xdpy, rwin,
+ XRenderFindVisualFormat (wm->xdpy,
+ DefaultVisual (wm->xdpy,
+ wm->xscreen)),
+ CPSubwindowMode,
+ &pa);
+
+ priv->all_damage = None;
+}
+
+/* Shuts the compositing down */
+static void
+mb_wm_comp_mgr_xrender_turn_off_real (MBWMCompMgr *mgr)
+{
+ MBWindowManager * wm;
+ Window rwin;
+ MBWMCompMgrDefaultPrivate * priv;
+ MBWMList * l;
+
+ if (!mgr)
+ return;
+
+ priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+
+ if (mgr->disabled)
+ return;
+
+ wm = mgr->wm;
+ rwin = wm->root_win->xwindow;
+
+ /*
+ * really shut down the composite manager.
+ */
+ XCompositeUnredirectSubwindows (wm->xdpy, rwin, CompositeRedirectManual);
+
+ if (priv->root_picture)
+ {
+ XRenderFreePicture (wm->xdpy, priv->root_picture);
+ priv->root_picture = None;
+ }
+
+ if (priv->root_buffer)
+ {
+ XRenderFreePicture (wm->xdpy, priv->root_buffer);
+ priv->root_buffer = None;
+ }
+
+ if (priv->all_damage)
+ {
+ XDamageDestroy (wm->xdpy, priv->all_damage);
+ priv->all_damage = None;
+ }
+
+ /* Free up any client composite resources */
+ l = wm->clients;
+
+ while (l)
+ {
+ MBWindowManagerClient * wmc = l->data;
+ MBWMCompMgrClient * c = wmc->cm_client;
+
+ if (c)
+ {
+ mb_wm_object_unref (MB_WM_OBJECT (c));
+ wmc->cm_client = NULL;
+ }
+
+ l = l->next;
+ }
+
+ mgr->disabled = True;
+}
+
+static void
+mb_wm_comp_mgr_xrender_render_region (MBWMCompMgr *mgr, XserverRegion region);
+
+static void
+mb_wm_comp_mgr_xrender_turn_on_real (MBWMCompMgr *mgr)
+{
+ MBWindowManager * wm;
+ Window rwin;
+ MBWMCompMgrDefaultPrivate * priv;
+ MBWMList * l;
+
+ if (!mgr)
+ return;
+
+ priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+
+ if (!mgr->disabled)
+ return;
+
+ wm = mgr->wm;
+ rwin = wm->root_win->xwindow;
+
+ XCompositeRedirectSubwindows (wm->xdpy, wm->root_win->xwindow,
+ CompositeRedirectManual);
+
+ mb_wm_comp_mgr_xrender_init_pictures (mgr);
+
+ XSync (wm->xdpy, False);
+
+ mgr->disabled = False;
+
+ if (!mb_wm_stack_empty (wm))
+ {
+ MBWindowManagerClient * c;
+
+ mb_wm_stack_enumerate (wm, c)
+ {
+ mb_wm_comp_mgr_xrender_register_client_real (mgr, c);
+ mb_wm_comp_mgr_xrender_client_show_real (c->cm_client);
+ }
+
+ mb_wm_comp_mgr_xrender_render_region (mgr, None);
+ }
+}
+
+static int
+mb_wm_comp_mgr_xrender_client_get_translucency (MBWMCompMgrClient *client)
+{
+ MBWindowManagerClient * wm_client = client->wm_client;
+
+ return wm_client->window->translucency;
+}
+
+static void
+mb_wm_comp_mgr_xrender_add_damage (MBWMCompMgr * mgr, XserverRegion damage)
+{
+ MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+ MBWindowManager * wm = mgr->wm;
+
+ if (priv->all_damage)
+ {
+ XFixesUnionRegion (wm->xdpy, priv->all_damage, priv->all_damage,
+ damage);
+
+ XFixesDestroyRegion (wm->xdpy, damage);
+ }
+ else
+ priv->all_damage = damage;
+
+ mb_wm_display_sync_queue (wm, MBWMSyncVisibility);
+}
+
+static void
+mb_wm_comp_mgr_xrender_client_repair_real (MBWMCompMgrClient * client)
+{
+ MBWindowManagerClient * wm_client = client->wm_client;
+ MBWindowManager * wm = client->wm;
+ MBWMCompMgr * mgr = wm->comp_mgr;
+ XserverRegion parts;
+ MBGeometry geom;
+
+ parts = XFixesCreateRegion (wm->xdpy, 0, 0);
+
+ /* translate region */
+ XDamageSubtract (wm->xdpy, MB_WM_COMP_MGR_DEFAULT_CLIENT (client)->damage,
+ None, parts);
+
+ mb_wm_client_get_coverage (wm_client, &geom);
+
+ XFixesTranslateRegion (wm->xdpy, parts, geom.x, geom.y);
+ mb_wm_comp_mgr_xrender_add_damage (mgr, parts);
+}
+
+static void
+mb_wm_comp_mgr_xrender_client_configure_real (MBWMCompMgrClient * client)
+{
+ MBWMCompMgrDefaultClient * dclient = MB_WM_COMP_MGR_DEFAULT_CLIENT (client);
+ MBWindowManagerClient * wm_client = client->wm_client;
+ MBWindowManager * wm = client->wm;
+ MBWMCompMgr * mgr = wm->comp_mgr;
+ XserverRegion damage = None;
+ XserverRegion extents;
+
+ extents = mb_wm_comp_mgr_xrender_client_extents (client);
+
+ if (dclient->picture)
+ {
+ XRenderFreePicture (wm->xdpy, dclient->picture);
+ dclient->picture = None;
+ }
+
+ damage = XFixesCreateRegion (wm->xdpy, 0, 0);
+
+ if (dclient->extents)
+ {
+ XFixesCopyRegion (wm->xdpy, damage, dclient->extents);
+ XFixesDestroyRegion (wm->xdpy, dclient->extents);
+ }
+
+ XFixesUnionRegion (wm->xdpy, damage, damage, extents);
+
+ dclient->extents = extents;
+
+ mb_wm_comp_mgr_xrender_add_damage (mgr, damage);
+}
+
+static Bool
+mb_wm_comp_mgr_xrender_handle_damage (XDamageNotifyEvent * de,
+ MBWMCompMgr * mgr)
+{
+ MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+ MBWindowManager * wm = mgr->wm;
+ MBWindowManagerClient * c;
+
+ c = mb_wm_managed_client_from_frame (wm, de->drawable);
+
+ if (c && c->cm_client)
+ {
+ MBWM_NOTE (COMPOSITOR,
+ "Reparing window %x, a %d,%d;%dx%d, g %d,%d;%dx%d\n",
+ de->drawable,
+ de->area.x,
+ de->area.y,
+ de->area.width,
+ de->area.height,
+ de->geometry.x,
+ de->geometry.y,
+ de->geometry.width,
+ de->geometry.height);
+
+ mb_wm_comp_mgr_xrender_client_repair_real (c->cm_client);
+ }
+ else
+ {
+ MBWM_NOTE (COMPOSITOR, "Failed to find client for window %x\n",
+ de->drawable);
+ }
+
+ return False;
+}
+
+static void
+_render_a_client (MBWMCompMgrClient * client,
+ XserverRegion region,
+ int lowlight_type) /*0 none, 1 app, 2 full*/
+{
+ MBWMCompMgrDefaultClient * dclient = MB_WM_COMP_MGR_DEFAULT_CLIENT (client);
+ MBWindowManagerClient * wm_client = client->wm_client;
+ MBWindowManager * wm = client->wm;
+ MBWMCompMgr * mgr = wm->comp_mgr;
+ MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+ MBWMClientType ctype = MB_WM_CLIENT_CLIENT_TYPE (wm_client);
+ MBGeometry geom;
+
+ if (!dclient->picture)
+ return;
+
+ mb_wm_client_get_coverage (wm_client, &geom);
+
+ /* Translucency only done for dialogs and overides */
+ if ( !client->is_argb32 &&
+ (ctype == MBWMClientTypeApp ||
+ ctype == MBWMClientTypeDesktop ||
+ ctype == MBWMClientTypeInput ||
+ ctype == MBWMClientTypePanel ||
+ mb_wm_comp_mgr_xrender_client_get_translucency (client) == -1))
+ {
+ XserverRegion winborder;
+
+ winborder = mb_wm_comp_mgr_xrender_client_border_size (client,
+ geom.x, geom.y);
+
+ XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, region);
+
+ XFixesSubtractRegion (wm->xdpy, region, region, winborder);
+
+ XRenderComposite (wm->xdpy, PictOpSrc,
+ dclient->picture,
+ None, priv->root_buffer,
+ 0, 0, 0, 0,
+ geom.x, geom.y, geom.width, geom.height);
+
+ XFixesDestroyRegion (wm->xdpy, winborder);
+ }
+ else if (client->is_argb32 ||
+ mb_wm_comp_mgr_xrender_client_get_translucency (client) != -1)
+ {
+ /*
+ * If the client is translucent, paint the decors only (solid).
+ */
+ MBWMList * l = wm_client->decor;
+
+ while (l)
+ {
+ MBWMDecor * d = l->data;
+ MBGeometry * g = & d->geom;
+ XserverRegion r;
+
+ r = mb_wm_comp_mgr_xrender_client_window_region (client, d->xwin,
+ g->x, g->y);
+
+ XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, r);
+ XFixesSubtractRegion (wm->xdpy, region, region, r);
+
+ XRenderComposite (wm->xdpy, PictOpSrc,
+ dclient->picture,
+ None, priv->root_buffer,
+ 0, 0, 0, 0,
+ geom.x + g->x, geom.y + g->y,
+ g->width, g->height);
+
+ XFixesDestroyRegion (wm->xdpy, r);
+
+ l = l->next;
+ }
+ }
+
+
+ /* Render lowlight dialog modal for app */
+ if (lowlight_type == 1 &&
+ (ctype & (MBWMClientTypeApp | MBWMClientTypeDesktop)))
+ {
+ int title_offset = 0;
+
+ if (ctype == MBWMClientTypeApp)
+ title_offset = mb_wm_client_title_height (wm_client);
+
+ XRenderComposite (wm->xdpy, PictOpOver, priv->lowlight_picture, None,
+ priv->root_buffer,
+ 0, 0, 0, 0, geom.x, geom.y + title_offset,
+ geom.width, geom.height - title_offset);
+ }
+ else if (lowlight_type == 2 /* && client->win_modal_blocker == None */)
+ {
+ /* Render lowlight dialog modal for root - e.g lowlight everything */
+ XRenderComposite (wm->xdpy, PictOpOver, priv->lowlight_picture, None,
+ priv->root_buffer,
+ 0, 0, 0, 0, geom.x, geom.y,
+ geom.width, geom.height);
+ }
+
+ if (dclient->border_clip)
+ {
+ XFixesDestroyRegion (wm->xdpy, dclient->border_clip);
+ dclient->border_clip = None;
+ }
+
+ dclient->border_clip = XFixesCreateRegion (wm->xdpy, 0, 0);
+ XFixesCopyRegion (wm->xdpy, dclient->border_clip, region);
+}
+
+static void
+mb_wm_comp_mgr_xrender_render_real (MBWMCompMgr *mgr)
+{
+ MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+
+ mb_wm_comp_mgr_xrender_render_region (mgr, priv->all_damage);
+
+ if (priv->all_damage)
+ {
+ XDamageDestroy (mgr->wm->xdpy, priv->all_damage);
+ priv->all_damage = None;
+ }
+}
+
+static void
+mb_wm_comp_mgr_xrender_render_region (MBWMCompMgr *mgr, XserverRegion region)
+{
+ MBWindowManager * wm = mgr->wm;
+ MBWMCompMgrDefaultPrivate * priv = MB_WM_COMP_MGR_DEFAULT (mgr)->priv;
+ MBWindowManagerClient * wmc_top, * wmc_temp, * wmc_solid = NULL;
+ int lowlight = 0;
+ int destroy_region = 0;
+ Bool done;
+ Bool top_translucent = False;
+
+ if (mgr->disabled)
+ return;
+
+ if (!region)
+ {
+ /*
+ * Fullscreen render
+ */
+ XRectangle r;
+
+ r.x = 0;
+ r.y = 0;
+ r.width = wm->xdpy_width;
+ r.height = wm->xdpy_height;
+
+ region = XFixesCreateRegion (wm->xdpy, &r, 1);
+ destroy_region = 1;
+ }
+
+ wmc_top = mb_wm_get_visible_main_client (wm);
+
+ if (wmc_top)
+ top_translucent =
+ (mb_wm_comp_mgr_xrender_client_get_translucency(wmc_top->cm_client) == -1);
+
+ if (!priv->root_buffer)
+ {
+ Pixmap rootPixmap =
+ XCreatePixmap (wm->xdpy, wm->root_win->xwindow,
+ wm->xdpy_width, wm->xdpy_height,
+ DefaultDepth (wm->xdpy, wm->xscreen));
+
+ priv->root_buffer =
+ XRenderCreatePicture (wm->xdpy, rootPixmap,
+ XRenderFindVisualFormat (wm->xdpy,
+ DefaultVisual (wm->xdpy,
+ wm->xscreen)),
+ 0, 0);
+
+ XFreePixmap (wm->xdpy, rootPixmap);
+ }
+
+ XFixesSetPictureClipRegion (wm->xdpy, priv->root_picture, 0, 0, region);
+ XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, region);
+
+ XRenderComposite (wm->xdpy, PictOpSrc, priv->black_picture,
+ None, priv->root_buffer, 0, 0, 0, 0, 0, 0,
+ wm->xdpy_width, wm->xdpy_height);
+
+ /*
+ * Check initially to see what kind of lowlight todo ( if any )
+ */
+ mb_wm_stack_enumerate_reverse (wm, wmc_temp)
+ {
+ MBWMClientType type = MB_WM_CLIENT_CLIENT_TYPE (wmc_temp);
+ Bool is_modal = mb_wm_client_is_modal (wmc_temp);
+
+ if (type == MBWMClientTypeDialog && is_modal)
+ {
+ MBWMModality modality = mb_wm_get_modality_type (wm);
+ switch (modality)
+ {
+ case MBWMModalityNormal:
+ default:
+ lowlight = 1;
+ break;
+ case MBWMModalitySystem:
+ lowlight = 2;
+ break;
+ case MBWMModalityNone:
+ lowlight = 0;
+ break;
+ }
+ }
+
+ if (wmc_temp == wmc_top)
+ break;
+ }
+
+ /* Render top -> bottom */
+ done = False;
+ mb_wm_stack_enumerate_reverse (wm, wmc_temp)
+ {
+ _render_a_client(wmc_temp->cm_client, region, lowlight);
+
+ /*
+ * Render clients until we reach first client on/below the top
+ * which is not translucent and is either and application or desktop
+ * (to have adequate coverage).
+ */
+ if (wmc_temp == wmc_top)
+ {
+ done = True;
+ }
+
+ if (done &&
+ (MB_WM_CLIENT_CLIENT_TYPE (wmc_temp) &
+ (MBWMClientTypeApp | MBWMClientTypeDesktop)) &&
+ !wmc_temp->cm_client->is_argb32 &&
+ mb_wm_comp_mgr_xrender_client_get_translucency (wmc_temp->cm_client)
+ == -1)
+ {
+ wmc_solid = wmc_temp;
+ break;
+ }
+ }
+
+ if (!wmc_top)
+ {
+ /* Render block of boring black in case of no top app or desktop */
+ XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, region);
+
+ XRenderComposite (wm->xdpy, PictOpSrc, priv->black_picture,
+ None, priv->root_buffer, 0, 0, 0, 0, 0, 0,
+ wm->xdpy_width, wm->xdpy_height);
+
+ XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, None);
+
+ wmc_top = wm->stack_bottom;
+ }
+
+
+ XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, None);
+
+ /*
+ * Now render shadows and any translucent clients but bottom -> top this
+ * time
+ *
+ * We start from the first solid client on the stack, so that any
+ * translucent windows on the top of the stack get correctly rendered.
+ */
+ for (wmc_temp = wmc_solid ? wmc_solid : wmc_top;
+ wmc_temp; wmc_temp=wmc_temp->stacked_above)
+ {
+ MBWMClientType type = MB_WM_CLIENT_CLIENT_TYPE (wmc_temp);
+ MBWMCompMgrClient * c = wmc_temp->cm_client;
+ MBWMCompMgrDefaultClient * dc = MB_WM_COMP_MGR_DEFAULT_CLIENT (c);
+ Bool is_translucent;
+
+ if (!dc || !dc->picture)
+ continue;
+
+ /*
+ * We have to process all dialogs and, if the top client is translucent,
+ * any translucent windows as well.
+ */
+ is_translucent = (c->is_argb32 ||
+ mb_wm_comp_mgr_xrender_client_get_translucency (c)
+ != -1);
+
+ if (mb_wm_client_is_mapped (wmc_temp) &&
+ (type == MBWMClientTypeDialog ||
+ type == MBWMClientTypeMenu ||
+ type == MBWMClientTypeOverride ||
+ (top_translucent && is_translucent)))
+ {
+ if (priv->shadow_style)
+ {
+ Picture shadow_pic;
+ MBGeometry geom;
+
+ mb_wm_client_get_coverage (wmc_temp, &geom);
+
+ if (priv->shadow_style == MBWM_COMP_MGR_SHADOW_SIMPLE)
+ {
+ XserverRegion shadow_region;
+
+ /* Grab 'shape' region of window */
+ shadow_region =
+ mb_wm_comp_mgr_xrender_client_border_size (c,
+ geom.x, geom.y);
+
+ /* Offset it. */
+ XFixesTranslateRegion (wm->xdpy, shadow_region,
+ priv->shadow_dx,
+ priv->shadow_dy);
+
+ /* Intersect it, so only border remains */
+ XFixesIntersectRegion (wm->xdpy, shadow_region,
+ dc->border_clip,
+ shadow_region );
+
+ XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer,
+ 0, 0, shadow_region);
+
+ /* now paint them */
+ if (wmc_temp->cm_client->is_argb32)
+ {
+ XRenderComposite (wm->xdpy, PictOpOver,
+ priv->black_picture,
+ dc->picture,
+ priv->root_buffer,
+ 0, 0, 0, 0,
+ geom.x + priv->shadow_dx,
+ geom.y + priv->shadow_dy,
+ geom.width +
+ priv->shadow_padding_width,
+ geom.height +
+ priv->shadow_padding_height);
+ }
+ else
+ {
+ XRenderComposite (wm->xdpy, PictOpOver,
+ priv->black_picture,
+ None,
+ priv->root_buffer,
+ 0, 0, 0, 0,
+ geom.x + priv->shadow_dx,
+ geom.y + priv->shadow_dy,
+ geom.width +
+ priv->shadow_padding_width,
+ geom.height +
+ priv->shadow_padding_height);
+ }
+
+ /* Paint any translucent window contents, but no the
+ * decors.
+ */
+ if (is_translucent)
+ {
+ MBGeometry * win_geom = & wmc_temp->window->geometry;
+
+ XFixesDestroyRegion (wm->xdpy, shadow_region);
+
+ shadow_region =
+ mb_wm_comp_mgr_xrender_client_border_size (c,
+ geom.x, geom.y);
+
+ XFixesIntersectRegion (wm->xdpy, shadow_region,
+ dc->border_clip, shadow_region );
+
+ XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer,
+ 0, 0, shadow_region);
+
+ if (c->is_argb32)
+ XRenderComposite (wm->xdpy, PictOpOver,
+ dc->picture, None,
+ priv->root_buffer,
+ win_geom->x, win_geom->y, 0, 0,
+ win_geom->x + geom.x,
+ win_geom->y + geom.y,
+ win_geom->width, win_geom->height);
+ else
+ XRenderComposite (wm->xdpy, PictOpOver,
+ dc->picture, priv->trans_picture,
+ priv->root_buffer,
+ win_geom->x, win_geom->y, 0, 0,
+ win_geom->x + geom.x,
+ win_geom->y + geom.y,
+ win_geom->width, win_geom->height);
+ }
+
+ XFixesDestroyRegion (wm->xdpy, shadow_region);
+ }
+ else /* GAUSSIAN */
+ {
+ MBGeometry * win_geom = & wmc_temp->window->geometry;
+
+ XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer,
+ 0, 0, dc->border_clip);
+
+ if (is_translucent)
+ {
+ /* No shadows currently for transparent windows */
+ XRenderComposite (wm->xdpy, PictOpOver,
+ dc->picture, priv->trans_picture,
+ priv->root_buffer,
+ win_geom->x, win_geom->y, 0, 0,
+ win_geom->x + geom.x,
+ win_geom->y + geom.y,
+ win_geom->width, win_geom->height);
+ }
+ else
+ {
+ /* Combine pregenerated shadow tiles */
+ shadow_pic =
+ mb_wm_comp_mgr_xrender_shadow_gaussian_make_picture (mgr,
+ geom.width + priv->shadow_padding_width,
+ geom.height + priv->shadow_padding_height);
+
+ XRenderComposite (wm->xdpy, PictOpOver,
+ priv->black_picture,
+ shadow_pic,
+ priv->root_buffer,
+ win_geom->x, win_geom->y, 0, 0,
+ geom.x + priv->shadow_dx,
+ geom.y + priv->shadow_dy,
+ geom.width +
+ priv->shadow_padding_width,
+ geom.height +
+ priv->shadow_padding_height);
+
+ XRenderFreePicture (wm->xdpy, shadow_pic);
+ }
+ }
+ }
+ }
+ }
+
+ XFixesSetPictureClipRegion (wm->xdpy, priv->root_buffer, 0, 0, None);
+
+ XRenderComposite (wm->xdpy, PictOpSrc, priv->root_buffer, None,
+ priv->root_picture,
+ 0, 0, 0, 0, 0, 0, wm->xdpy_width, wm->xdpy_height);
+
+ if (destroy_region)
+ XDamageDestroy (wm->xdpy, region);
+}
+
+MBWMCompMgr *
+mb_wm_comp_mgr_xrender_new (MBWindowManager *wm)
+{
+ MBWMObject *mgr;
+
+ mgr = mb_wm_object_new (MB_WM_TYPE_COMP_MGR_DEFAULT, MBWMObjectPropWm, wm, NULL);
+
+ return MB_WM_COMP_MGR (mgr);
+}
+
diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.h b/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.h
new file mode 100644
index 0000000..0a36bbc
--- /dev/null
+++ b/matchbox2/comp-mgr/mb-wm-comp-mgr-xrender.h
@@ -0,0 +1,60 @@
+/*
+ * Matchbox Window Manager - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ * Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2002, 2004, 2007 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _HAVE_MB_WM_COMP_MGR_DEFAULT_H
+#define _HAVE_MB_WM_COMP_MGR_DEFAULT_H
+
+#include <matchbox2/mb-wm-config.h>
+
+#define MB_WM_COMP_MGR_DEFAULT(c) ((MBWMCompMgrDefault*)(c))
+#define MB_WM_COMP_MGR_DEFAULT_CLASS(c) ((MBWMCompMgrDefaultClass*)(c))
+#define MB_WM_TYPE_COMP_MGR_DEFAULT (mb_wm_comp_mgr_xrender_class_type ())
+
+#define MB_WM_COMP_MGR_DEFAULT_CLIENT(c) ((MBWMCompMgrDefaultClient*)(c))
+#define MB_WM_COMP_MGR_DEFAULT_CLIENT_CLASS(c) ((MBWMCompMgrDefaultClientClass*)(c))
+#define MB_WM_TYPE_COMP_MGR_DEFAULT_CLIENT (mb_wm_comp_mgr_xrender_client_class_type ())
+
+struct MBWMCompMgrDefault
+{
+ MBWMCompMgr parent;
+ MBWMCompMgrDefaultPrivate *priv;
+};
+
+struct MBWMCompMgrDefaultClass
+{
+ MBWMCompMgrClass parent;
+};
+
+int
+mb_wm_comp_mgr_xrender_class_type ();
+
+MBWMCompMgr*
+mb_wm_comp_mgr_xrender_new (MBWindowManager *wm);
+
+struct MBWMCompMgrDefaultClientClass
+{
+ MBWMCompMgrClientClass parent;
+};
+
+int
+mb_wm_comp_mgr_xrender_client_class_type ();
+
+#endif
diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr.c b/matchbox2/comp-mgr/mb-wm-comp-mgr.c
new file mode 100644
index 0000000..68063c3
--- /dev/null
+++ b/matchbox2/comp-mgr/mb-wm-comp-mgr.c
@@ -0,0 +1,482 @@
+/*
+ * Matchbox Window Manager - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2002, 2004, 2007 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mb-wm.h"
+#include "mb-wm-client.h"
+#include "mb-wm-comp-mgr.h"
+#include "mb-wm-theme.h"
+
+#include <X11/Xresource.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xrender.h>
+#include <X11/extensions/Xcomposite.h>
+
+static void
+mb_wm_comp_mgr_client_class_init (MBWMObjectClass *klass)
+{
+ MBWMCompMgrClientClass *c_klass = MB_WM_COMP_MGR_CLIENT_CLASS (klass);
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMCompMgrClient";
+#endif
+}
+
+static int
+mb_wm_comp_mgr_client_init (MBWMObject *obj, va_list vap)
+{
+ MBWMCompMgrClient *client = MB_WM_COMP_MGR_CLIENT (obj);
+ MBWindowManagerClient *wm_client = NULL;
+ MBWMObjectProp prop;
+ XRenderPictFormat *format;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropClient:
+ wm_client = va_arg(vap, MBWindowManagerClient *);
+ break;
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ if (!wm_client)
+ return 0;
+
+ client->wm_client = wm_client;
+ client->wm = wm_client->wmref;
+
+ /* Check visual */
+ format = XRenderFindVisualFormat (client->wm->xdpy,
+ wm_client->window->visual);
+
+ if (format && format->type == PictTypeDirect && format->direct.alphaMask)
+ client->is_argb32 = True;
+
+ return 1;
+}
+
+static void
+mb_wm_comp_mgr_client_destroy (MBWMObject* obj)
+{
+ MBWMCompMgrClient *client = MB_WM_COMP_MGR_CLIENT (obj);
+ MBWindowManagerClient *wm_client = client->wm_client;
+}
+
+int
+mb_wm_comp_mgr_client_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMCompMgrClientClass),
+ sizeof (MBWMCompMgrClient),
+ mb_wm_comp_mgr_client_init,
+ mb_wm_comp_mgr_client_destroy,
+ mb_wm_comp_mgr_client_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+void
+mb_wm_comp_mgr_client_hide (MBWMCompMgrClient * client)
+{
+ MBWMCompMgrClientClass *klass;
+
+ if (!client)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLIENT_CLASS (MB_WM_OBJECT_GET_CLASS (client));
+
+ MBWM_ASSERT (klass->hide != NULL);
+ klass->hide (client);
+}
+
+void
+mb_wm_comp_mgr_client_show (MBWMCompMgrClient * client)
+{
+ MBWMCompMgrClientClass *klass;
+
+ if (!client)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLIENT_CLASS (MB_WM_OBJECT_GET_CLASS (client));
+
+ MBWM_ASSERT (klass->show != NULL);
+ klass->show (client);
+}
+
+void
+mb_wm_comp_mgr_client_configure (MBWMCompMgrClient * client)
+{
+ MBWMCompMgrClientClass *klass;
+
+ if (!client)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLIENT_CLASS (MB_WM_OBJECT_GET_CLASS (client));
+
+ MBWM_ASSERT (klass->configure != NULL);
+ klass->configure (client);
+}
+
+void
+mb_wm_comp_mgr_client_repair (MBWMCompMgrClient * client)
+{
+ MBWMCompMgrClientClass *klass;
+
+ if (!client)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLIENT_CLASS (MB_WM_OBJECT_GET_CLASS (client));
+
+ MBWM_ASSERT (klass->repair != NULL);
+ klass->repair (client);
+}
+
+
+/*
+ * MBWMCompMgr object
+ *
+ * Base class for the composite manager, providing the common interface
+ * through which the manager is access by the MBWindowManager object.
+ */
+static void
+mb_wm_comp_mgr_class_init (MBWMObjectClass *klass)
+{
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMCompMgr";
+#endif
+}
+
+static int
+mb_wm_comp_mgr_init (MBWMObject *obj, va_list vap)
+{
+ MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj);
+ MBWindowManager * wm = NULL;
+ MBWMObjectProp prop;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropWm:
+ wm = va_arg(vap, MBWindowManager *);
+ break;
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ if (!wm)
+ return 0;
+
+ mgr->wm = wm;
+ mgr->disabled = True;
+
+ return 1;
+}
+
+static void
+mb_wm_comp_mgr_destroy (MBWMObject* obj)
+{
+ MBWMCompMgr * mgr = MB_WM_COMP_MGR (obj);
+
+ mb_wm_comp_mgr_turn_off (mgr);
+}
+
+int
+mb_wm_comp_mgr_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMCompMgrClass),
+ sizeof (MBWMCompMgr),
+ mb_wm_comp_mgr_init,
+ mb_wm_comp_mgr_destroy,
+ mb_wm_comp_mgr_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+
+Bool
+mb_wm_comp_mgr_enabled (MBWMCompMgr *mgr)
+{
+ if (!mgr || mgr->disabled)
+ return False;
+
+ return True;
+}
+
+/*
+ * Registers new client with the manager (i.e., when a window is created).
+ */
+void
+mb_wm_comp_mgr_register_client (MBWMCompMgr * mgr,
+ MBWindowManagerClient * client)
+{
+ MBWMCompMgrClass *klass;
+
+ if (!client)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ MBWM_ASSERT (klass->register_client != NULL);
+ klass->register_client (mgr, client);
+}
+
+/*
+ * Unregisters existing client (e.g., when window unmaps or is destroyed
+ */
+void
+mb_wm_comp_mgr_unregister_client (MBWMCompMgr * mgr,
+ MBWindowManagerClient * client)
+{
+ MBWMCompMgrClass *klass;
+
+ if (!client)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (!client->cm_client)
+ return;
+
+ if (klass->unregister_client)
+ klass->unregister_client (mgr, client);
+
+ mb_wm_object_unref (MB_WM_OBJECT (client->cm_client));
+ client->cm_client = NULL;
+}
+
+/*
+ * Called to render the entire composited scene on screen.
+ */
+void
+mb_wm_comp_mgr_render (MBWMCompMgr *mgr)
+{
+ MBWMCompMgrClass *klass;
+
+ if (!mgr)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (klass->render)
+ klass->render (mgr);
+}
+
+void
+mb_wm_comp_mgr_restack (MBWMCompMgr *mgr)
+{
+ MBWMCompMgrClass *klass;
+
+ if (!mgr)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (klass->restack)
+ klass->restack (mgr);
+}
+
+/*
+ * Called when a window we are interested in maps.
+ */
+void
+mb_wm_comp_mgr_map_notify (MBWMCompMgr *mgr, MBWindowManagerClient *c)
+{
+ MBWMCompMgrClass *klass;
+
+ if (!mgr || !c || !c->cm_client)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (klass->map_notify)
+ klass->map_notify (mgr, c);
+
+ /*
+ * Run map event effect *before* we call show() on the actor
+ * (the effect will take care of showing the actor, and if not, show() gets
+ * called by mb_wm_comp_mgr_map_notify()).
+ */
+ if (!mb_wm_client_is_hiding_from_desktop (c))
+ mb_wm_comp_mgr_do_effect (mgr, c, MBWMCompMgrClientEventMap);
+
+ if (c->cm_client)
+ mb_wm_comp_mgr_client_show (c->cm_client);
+}
+
+void
+mb_wm_comp_mgr_unmap_notify (MBWMCompMgr *mgr, MBWindowManagerClient *c)
+{
+ MBWMCompMgrClass *klass;
+
+ if (!mgr || !c || !c->cm_client)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (!mb_wm_client_is_hiding_from_desktop (c))
+ mb_wm_comp_mgr_do_effect (mgr, c, MBWMCompMgrClientEventUnmap);
+
+ if (klass->unmap_notify)
+ klass->unmap_notify (mgr, c);
+
+ /*
+ * NB: cannot call hide() here, as at this point an effect could be running
+ * -- the subclass needs to take care of this from the effect and/or
+ * unmap_notify() function.
+ */
+}
+
+/*
+ * Runs a transition-effect from client c1 to client c2; the reverse argument
+ * indicates notional direction of the transition
+ */
+void
+mb_wm_comp_mgr_do_transition (MBWMCompMgr * mgr,
+ MBWindowManagerClient *c1,
+ MBWindowManagerClient *c2,
+ Bool reverse)
+{
+ MBWMCompMgrClass *klass;
+
+ /*
+ * Transitions can only be done for clients of the same type, so
+ * check the types here.
+ */
+ if (!mgr || !c1 || !c2 ||
+ MB_WM_CLIENT_CLIENT_TYPE (c1) != MB_WM_CLIENT_CLIENT_TYPE (c1))
+ return;
+
+ klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (klass->client_transition)
+ klass->client_transition (mgr, c1, c2, reverse);
+}
+
+void
+mb_wm_comp_mgr_do_effect (MBWMCompMgr * mgr,
+ MBWindowManagerClient * client,
+ MBWMCompMgrClientEvent event)
+{
+ MBWMCompMgrClass *klass;
+
+ /*
+ * Transitions can only be done for clients of the same type, so
+ * check the types here.
+ */
+ if (!mgr || !client)
+ return;
+
+ klass = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (klass->client_event)
+ klass->client_event (mgr, client, event);
+}
+
+void
+mb_wm_comp_mgr_select_desktop (MBWMCompMgr * mgr,
+ int desktop,
+ int old_desktop)
+{
+ MBWMCompMgrClass *klass
+ = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (klass->select_desktop)
+ klass->select_desktop (mgr, desktop, old_desktop);
+}
+
+void
+mb_wm_comp_mgr_turn_on (MBWMCompMgr *mgr)
+{
+ MBWindowManager *wm = mgr->wm;
+ MBWMCompMgrClass *klass
+ = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ MBWM_ASSERT (klass->turn_on != NULL);
+ klass->turn_on (mgr);
+
+ mgr->damage_cb_id =
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ None,
+ wm->damage_event_base + XDamageNotify,
+ (MBWMXEventFunc)klass->handle_damage,
+ mgr);
+}
+
+void
+mb_wm_comp_mgr_turn_off (MBWMCompMgr *mgr)
+{
+ MBWindowManager *wm = mgr->wm;
+ MBWMCompMgrClass *klass
+ = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ MBWM_ASSERT (klass->turn_off != NULL);
+ klass->turn_off (mgr);
+
+ mb_wm_main_context_x_event_handler_remove (wm->main_ctx,
+ wm->damage_event_base + XDamageNotify,
+ mgr->damage_cb_id);
+
+ mgr->damage_cb_id = 0;
+}
+
+/*
+ * Returns true if the window identified by id xwin is a special window
+ * that belongs to the compositing manager and should, therefore, be left
+ * alone by MBWMWindow manager (e.g., the overalay window).
+ */
+Bool
+mb_wm_comp_mgr_is_my_window (MBWMCompMgr * mgr, Window xwin)
+{
+ MBWMCompMgrClass *klass
+ = MB_WM_COMP_MGR_CLASS (MB_WM_OBJECT_GET_CLASS (mgr));
+
+ if (klass->my_window)
+ return klass->my_window (mgr, xwin);
+
+ return False;
+}
+
diff --git a/matchbox2/comp-mgr/mb-wm-comp-mgr.h b/matchbox2/comp-mgr/mb-wm-comp-mgr.h
new file mode 100644
index 0000000..98e9cbd
--- /dev/null
+++ b/matchbox2/comp-mgr/mb-wm-comp-mgr.h
@@ -0,0 +1,159 @@
+/*
+ * Matchbox Window Manager - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2002, 2004, 2007 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _HAVE_MB_WM_COMP_MGR_H
+#define _HAVE_MB_WM_COMP_MGR_H
+
+#include <X11/extensions/Xdamage.h>
+
+#define MB_WM_COMP_MGR(c) ((MBWMCompMgr*)(c))
+#define MB_WM_COMP_MGR_CLASS(c) ((MBWMCompMgrClass*)(c))
+#define MB_WM_TYPE_COMP_MGR (mb_wm_comp_mgr_class_type ())
+
+#define MB_WM_COMP_MGR_CLIENT(c) ((MBWMCompMgrClient*)(c))
+#define MB_WM_COMP_MGR_CLIENT_CLASS(c) ((MBWMCompMgrClientClass*)(c))
+#define MB_WM_TYPE_COMP_MGR_CLIENT (mb_wm_comp_mgr_client_class_type ())
+
+struct MBWMCompMgr
+{
+ MBWMObject parent;
+
+ MBWindowManager *wm;
+ Bool disabled;
+ unsigned long damage_cb_id;
+};
+
+struct MBWMCompMgrClass
+{
+ MBWMObjectClass parent;
+
+ void (*register_client) (MBWMCompMgr * mgr, MBWindowManagerClient *c);
+ void (*unregister_client) (MBWMCompMgr * mgr, MBWindowManagerClient *c);
+ void (*turn_on) (MBWMCompMgr * mgr);
+ void (*turn_off) (MBWMCompMgr * mgr);
+ void (*render) (MBWMCompMgr * mgr);
+ void (*restack) (MBWMCompMgr * mgr);
+ void (*map_notify) (MBWMCompMgr * mgr, MBWindowManagerClient *c);
+ void (*unmap_notify) (MBWMCompMgr * mgr, MBWindowManagerClient *c);
+ Bool (*handle_damage) (XDamageNotifyEvent * xev, MBWMCompMgr * mgr);
+ Bool (*my_window) (MBWMCompMgr * mgr, Window xwin);
+ void (*client_event) (MBWMCompMgr * mgr,
+ MBWindowManagerClient *c1,
+ MBWMCompMgrClientEvent event);
+ void (*client_transition) (MBWMCompMgr * mgr,
+ MBWindowManagerClient *c1,
+ MBWindowManagerClient *c2,
+ Bool reverse);
+
+ void (*select_desktop) (MBWMCompMgr * mgr,
+ int desktop, int old_desktop);
+};
+
+int
+mb_wm_comp_mgr_class_type ();
+
+void
+mb_wm_comp_mgr_register_client (MBWMCompMgr * mgr, MBWindowManagerClient *c);
+
+void
+mb_wm_comp_mgr_unregister_client (MBWMCompMgr * mgr,
+ MBWindowManagerClient *client);
+
+void
+mb_wm_comp_mgr_turn_off (MBWMCompMgr *mgr);
+
+void
+mb_wm_comp_mgr_turn_on (MBWMCompMgr *mgr);
+
+void
+mb_wm_comp_mgr_render (MBWMCompMgr *mgr);
+
+void
+mb_wm_comp_mgr_restack (MBWMCompMgr *mgr);
+
+void
+mb_wm_comp_mgr_map_notify (MBWMCompMgr *mgr, MBWindowManagerClient *c);
+
+void
+mb_wm_comp_mgr_unmap_notify (MBWMCompMgr *mgr, MBWindowManagerClient *c);
+
+Bool
+mb_wm_comp_mgr_enabled (MBWMCompMgr *mgr);
+
+Bool
+mb_wm_comp_mgr_handle_events (MBWMCompMgr * mgr, XEvent *ev);
+
+Bool
+mb_wm_comp_mgr_is_my_window (MBWMCompMgr * mgr, Window xwin);
+
+void
+mb_wm_comp_mgr_do_transition (MBWMCompMgr * mgr,
+ MBWindowManagerClient * c1,
+ MBWindowManagerClient * c2,
+ Bool reverse);
+
+void
+mb_wm_comp_mgr_do_effect (MBWMCompMgr * mgr,
+ MBWindowManagerClient * client,
+ MBWMCompMgrClientEvent event);
+
+void
+mb_wm_comp_mgr_select_desktop (MBWMCompMgr * mgr,
+ int desktop,
+ int old_desktop);
+
+struct MBWMCompMgrClient
+{
+ MBWMObject parent;
+
+ MBWindowManager * wm;
+ MBWindowManagerClient * wm_client;
+
+ /* Make private ? */
+ Bool is_argb32;
+};
+
+struct MBWMCompMgrClientClass
+{
+ MBWMObjectClass parent;
+
+ void (*show) (MBWMCompMgrClient * client);
+ void (*hide) (MBWMCompMgrClient * client);
+ void (*repair) (MBWMCompMgrClient * client);
+ void (*configure) (MBWMCompMgrClient * client);
+};
+
+int
+mb_wm_comp_mgr_client_class_type ();
+
+void
+mb_wm_comp_mgr_client_show (MBWMCompMgrClient * client);
+
+void
+mb_wm_comp_mgr_client_hide (MBWMCompMgrClient * client);
+
+void
+mb_wm_comp_mgr_client_repair (MBWMCompMgrClient * client);
+
+void
+mb_wm_comp_mgr_client_configure (MBWMCompMgrClient * client);
+
+
+#endif
diff --git a/matchbox2/core/Makefile.am b/matchbox2/core/Makefile.am
new file mode 100644
index 0000000..ba4774b
--- /dev/null
+++ b/matchbox2/core/Makefile.am
@@ -0,0 +1,49 @@
+
+core_h = mb-wm.h \
+ mb-wm-macros.h \
+ mb-wm-debug.h \
+ mb-wm-object.h \
+ mb-wm-object-props.h \
+ mb-wm-client.h \
+ mb-wm-client-base.h \
+ mb-wm-client-window.h \
+ mb-wm-root-window.h \
+ mb-wm-stack.h \
+ mb-wm-util.h \
+ mb-wm-types.h \
+ mb-wm-atoms.h \
+ mb-wm-layout.h \
+ mb-wm-props.h \
+ mb-wm-keys.h \
+ mb-wm-decor.h \
+ mb-window-manager.h \
+ mb-wm-main-context.h \
+ xas.h
+
+core_c = mb-wm-object.c \
+ mb-wm-debug.c \
+ mb-wm-client.c \
+ mb-wm-client-base.c \
+ mb-wm-client-window.c \
+ mb-wm-root-window.c \
+ mb-wm-stack.c \
+ mb-wm-props.c \
+ mb-wm-util.c \
+ mb-wm-atoms.c \
+ mb-wm-layout.c \
+ mb-wm-keys.c \
+ mb-wm-decor.c \
+ mb-window-manager.c \
+ mb-wm-main-context.c \
+ xas.c
+
+pkgincludedir = $(includedir)/$(MBWM2_INCDIR)/core
+
+if ENABLE_LIBMATCHBOX
+pkginclude_HEADERS = $(core_h)
+endif
+noinst_LTLIBRARIES = libmatchbox-window-manager-2-core.la
+libmatchbox_window_manager_2_core_la_SOURCES = $(core_h) $(core_c)
+libmatchbox_window_manager_2_core_la_CFLAGS = $(MBWM_INCS) $(MBWM_CFLAGS)
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/matchbox2/core/mb-window-manager.c b/matchbox2/core/mb-window-manager.c
new file mode 100644
index 0000000..c1a19f2
--- /dev/null
+++ b/matchbox2/core/mb-window-manager.c
@@ -0,0 +1,2252 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ * Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2005, 2007, 2008 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "mb-wm.h"
+#include "../client-types/mb-wm-client-app.h"
+#include "../client-types/mb-wm-client-panel.h"
+#include "../client-types/mb-wm-client-dialog.h"
+#include "../client-types/mb-wm-client-desktop.h"
+#include "../client-types/mb-wm-client-input.h"
+#include "../client-types/mb-wm-client-note.h"
+#include "../client-types/mb-wm-client-menu.h"
+#include "../theme-engines/mb-wm-theme.h"
+
+#if ENABLE_COMPOSITE
+# include "mb-wm-comp-mgr.h"
+# if ENABLE_CLUTTER_COMPOSITE_MANAGER
+# include <clutter/x11/clutter-x11.h>
+# include "mb-wm-comp-mgr-clutter.h"
+# else
+# include "mb-wm-comp-mgr-xrender.h"
+# endif
+# include "../client-types/mb-wm-client-override.h"
+# include <X11/extensions/Xdamage.h>
+# include <X11/extensions/Xrender.h>
+# include <X11/extensions/Xcomposite.h>
+#endif
+
+#if USE_GTK
+# include <gdk/gdk.h>
+#endif
+
+#include <stdarg.h>
+
+#include <X11/Xmd.h>
+
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h> /* Used to *really* hide cursor */
+#endif
+
+#ifdef HAVE_XCURSOR
+#include <X11/Xcursor/Xcursor.h>
+#endif
+
+#include <X11/cursorfont.h>
+
+static void
+mb_wm_process_cmdline (MBWindowManager *wm);
+
+static void
+mb_wm_focus_client (MBWindowManager *wm, MBWindowManagerClient *client);
+
+static Bool
+mb_wm_activate_client_real (MBWindowManager * wm, MBWindowManagerClient *c);
+
+static void
+mb_wm_update_root_win_rectangles (MBWindowManager *wm);
+
+static Bool
+mb_wm_is_my_window (MBWindowManager *wm, Window xwin,
+ MBWindowManagerClient **client);
+
+static void
+mb_wm_real_get_desktop_geometry (MBWindowManager *wm, MBGeometry *geom);
+
+static MBWindowManagerClient*
+mb_wm_client_new_func (MBWindowManager *wm, MBWMClientWindow *win)
+{
+ if (win->override_redirect)
+ {
+ MBWM_DBG ("### override-redirect window ###\n");
+#if ENABLE_COMPOSITE
+ return mb_wm_client_override_new (wm, win);
+#else
+ return NULL;
+#endif
+ }
+
+ if (win->net_type == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DOCK])
+ {
+ MBWM_DBG ("### is panel ###\n");
+ return mb_wm_client_panel_new(wm, win);
+ }
+ else if (win->net_type == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DIALOG])
+ {
+ MBWM_DBG ("### is dialog ###\n");
+ return mb_wm_client_dialog_new(wm, win);
+ }
+ else if (win->net_type == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION])
+ {
+ MBWM_DBG ("### is notification ###\n");
+ return mb_wm_client_note_new (wm, win);
+ }
+ else if (win->net_type ==wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_MENU] ||
+ win->net_type ==wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU]||
+ win->net_type ==wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU])
+ {
+ MBWM_DBG ("### is menu ###\n");
+ return mb_wm_client_menu_new (wm, win);
+ }
+ else if (win->net_type == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DESKTOP])
+ {
+ MBWM_DBG ("### is desktop ###\n");
+ /* Only one desktop allowed */
+ if (wm->desktop)
+ return NULL;
+
+ return mb_wm_client_desktop_new (wm, win);
+ }
+ else if (win->net_type == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR] ||
+ win->net_type == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_INPUT])
+ {
+ MBWM_DBG ("### is input ###\n");
+ return mb_wm_client_input_new (wm, win);
+ }
+ else if (win->net_type == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_NORMAL])
+ {
+ MBWM_DBG ("### is application ###\n");
+ return mb_wm_client_app_new (wm, win);
+ }
+ else
+ {
+#if MBWM_WANT_DEBUG
+ char * name = XGetAtomName (wm->xdpy, win->net_type);
+ printf("### unhandled window type %s (%x) ###\n", name, win->xwindow);
+ XFree (name);
+#endif
+ return mb_wm_client_app_new (wm, win);
+ }
+
+ return NULL;
+}
+
+static MBWMTheme *
+mb_wm_real_theme_new (MBWindowManager * wm, const char * path)
+{
+ /*
+ * FIXME -- load the selected theme from some configuration
+ */
+ return mb_wm_theme_new (wm, path);
+}
+
+#if ENABLE_COMPOSITE && COMP_MGR_BACKEND
+static MBWMCompMgr *
+mb_wm_real_comp_mgr_new (MBWindowManager *wm)
+{
+#if ENABLE_CLUTTER_COMPOSITE_MANAGER
+ return mb_wm_comp_mgr_clutter_new (wm);
+#else
+ return mb_wm_comp_mgr_xrender_new (wm);
+#endif
+}
+#endif
+
+static MBWMLayout *
+mb_wm_layout_new_real (MBWindowManager *wm)
+{
+ MBWMLayout * layout = mb_wm_layout_new (wm);
+
+ if (!layout)
+ mb_wm_util_fatal_error("OOM?");
+
+ return layout;
+}
+
+#if USE_GTK
+static GdkFilterReturn
+mb_wm_gdk_xevent_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
+{
+ MBWindowManager * wm = data;
+ XEvent * xev = (XEvent*) xevent;
+
+ mb_wm_main_context_handle_x_event (xev, wm->main_ctx);
+
+ if (wm->sync_type)
+ mb_wm_sync (wm);
+
+ return GDK_FILTER_CONTINUE;
+}
+#endif
+
+#if ENABLE_CLUTTER_COMPOSITE_MANAGER
+#if USE_GTK
+static GdkFilterReturn
+mb_wm_clutter_gdk_xevent_filter (GdkXEvent *xevent, GdkEvent *event,
+ gpointer data)
+{
+ switch (clutter_x11_handle_event ((XEvent*)xevent))
+ {
+ default:
+ case CLUTTER_X11_FILTER_CONTINUE:
+ return GDK_FILTER_CONTINUE;
+ case CLUTTER_X11_FILTER_TRANSLATE:
+ return GDK_FILTER_TRANSLATE;
+ case CLUTTER_X11_FILTER_REMOVE:
+ return GDK_FILTER_REMOVE;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+#else
+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;
+}
+#endif
+#endif
+
+#if ENABLE_CLUTTER_COMPOSITE_MANAGER || USE_GTK
+static void
+mb_wm_main_real (MBWindowManager *wm)
+{
+
+#if USE_GTK
+ gdk_window_add_filter (NULL, mb_wm_gdk_xevent_filter, wm);
+#if ENABLE_CLUTTER_COMPOSITE_MANAGER
+ gdk_window_add_filter (NULL, mb_wm_clutter_gdk_xevent_filter, NULL);
+#endif
+ gtk_main ();
+#else
+ clutter_x11_add_filter (mb_wm_clutter_xevent_filter, wm);
+ clutter_main ();
+#endif
+}
+#endif
+
+static void
+mb_wm_class_init (MBWMObjectClass *klass)
+{
+ MBWindowManagerClass *wm_class;
+
+ MBWM_MARK();
+
+ wm_class = (MBWindowManagerClass *)klass;
+
+ wm_class->process_cmdline = mb_wm_process_cmdline;
+ wm_class->client_new = mb_wm_client_new_func;
+ wm_class->theme_new = mb_wm_real_theme_new;
+ wm_class->client_activate = mb_wm_activate_client_real;
+ wm_class->layout_new = mb_wm_layout_new_real;
+ wm_class->get_desktop_geometry = mb_wm_real_get_desktop_geometry;
+
+#if ENABLE_CLUTTER_COMPOSITE_MANAGER
+ wm_class->main = mb_wm_main_real;
+#endif
+
+#if ENABLE_COMPOSITE && COMP_MGR_BACKEND
+ wm_class->comp_mgr_new = mb_wm_real_comp_mgr_new;
+#endif
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWindowManager";
+#endif
+}
+
+static void
+mb_wm_destroy (MBWMObject *this)
+{
+ MBWindowManager * wm = MB_WINDOW_MANAGER (this);
+ MBWMList *l = wm->clients;
+
+ while (l)
+ {
+ MBWMList * old = l;
+ mb_wm_object_unref (l->data);
+
+ l = l->next;
+
+ free (old);
+ }
+
+ mb_wm_object_unref (MB_WM_OBJECT (wm->root_win));
+ mb_wm_object_unref (MB_WM_OBJECT (wm->theme));
+ mb_wm_object_unref (MB_WM_OBJECT (wm->layout));
+ mb_wm_object_unref (MB_WM_OBJECT (wm->main_ctx));
+}
+
+static int
+mb_window_manager_init (MBWMObject *this, va_list vap);
+
+int
+mb_wm_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWindowManagerClass),
+ sizeof (MBWindowManager),
+ mb_window_manager_init,
+ mb_wm_destroy,
+ mb_wm_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+MBWindowManager*
+mb_wm_new (int argc, char **argv)
+{
+ MBWindowManager *wm = NULL;
+
+ wm = MB_WINDOW_MANAGER (mb_wm_object_new (MB_TYPE_WINDOW_MANAGER,
+ MBWMObjectPropArgc, argc,
+ MBWMObjectPropArgv, argv,
+ NULL));
+
+ if (!wm)
+ return wm;
+
+ 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;
+}
+
+static Bool
+mb_wm_handle_key_press (XKeyEvent *xev,
+ void *userdata)
+{
+ MBWindowManager *wm = (MBWindowManager*)userdata;
+
+ mb_wm_keys_press (wm,
+ XKeycodeToKeysym(wm->xdpy, xev->keycode, 0),
+ xev->state);
+
+ return True;
+}
+
+static Bool
+mb_wm_handle_button_press (XButtonEvent *xev, void *userdata)
+{
+ MBWindowManager *wm = (MBWindowManager*)userdata;
+ MBWindowManagerClient *client = NULL;
+
+ if (xev->button != 1)
+ return True;
+
+ mb_wm_is_my_window (wm, xev->window, &client);
+
+ if (!client)
+ return True;
+
+ /*
+ * If the client is not application, we make sure it has focus.
+ * If the client is an application, we top it if it is currently not the top
+ * application; otherwise, we ensure it has focus.
+ */
+ if (MB_WM_CLIENT_CLIENT_TYPE (client) == MBWMClientTypeApp)
+ {
+ MBWindowManagerClient * top = mb_wm_get_visible_main_client(wm);
+
+ if (top == client)
+ mb_wm_focus_client (wm, client);
+ else
+ mb_wm_activate_client (wm, client);
+ }
+ else
+ {
+ mb_wm_focus_client (wm, client);
+ }
+
+ XAllowEvents (wm->xdpy, ReplayPointer, CurrentTime);
+
+ return True;
+}
+
+static Bool
+mb_wm_handle_destroy_notify (XDestroyWindowEvent *xev,
+ void *userdata)
+{
+ MBWindowManager *wm = (MBWindowManager*)userdata;
+ MBWindowManagerClient *client = NULL;
+
+ MBWM_MARK();
+
+ client = mb_wm_managed_client_from_xwindow(wm, xev->window);
+
+ if (client)
+ {
+ if (mb_wm_client_window_is_state_set (client->window,
+ MBWMClientWindowEWMHStateHidden))
+ {
+ if (mb_wm_client_is_hiding_from_desktop (client))
+ {
+ /*
+ * If the destroyed hidden window is hidden because it was
+ * on a different desktop than current, we have to unmanage
+ * it, as it is still considered managed.
+ */
+ mb_wm_unmanage_client (wm, client, True);
+ }
+ else
+ {
+ /*
+ * Otherwise, this is regular minimized window, in which case
+ * the window is no longer managed, only the resources are
+ * kept in the clients list; so we only remove it and free.
+ */
+ wm->clients = mb_wm_util_list_remove (wm->clients, client);
+ mb_wm_object_unref (MB_WM_OBJECT (client));
+ }
+ }
+ else
+ mb_wm_unmanage_client (wm, client, True);
+ }
+
+ return True;
+}
+
+static Bool
+mb_wm_handle_unmap_notify (XUnmapEvent *xev,
+ void *userdata)
+{
+ MBWindowManager *wm = (MBWindowManager*)userdata;
+ MBWindowManagerClient *client = NULL;
+
+ MBWM_MARK();
+
+ client = mb_wm_managed_client_from_xwindow(wm, xev->window);
+
+ if (client)
+ {
+ if (client->skip_unmaps)
+ {
+ MBWM_DBG ("skipping unmap for %p (skip count %d)\n",
+ client, client->skip_unmaps);
+
+ client->skip_unmaps--;
+ }
+ else
+ {
+ /*
+ * If the iconizing flag is set, we unmanage the client, but keep
+ * the resources around; we reset the iconizing flag to indicate
+ * that the iconizing has completed (and the client window is now in
+ * hidden state).
+ *
+ * If the client is not iconizing and is not alreadly in a hidden
+ * state, we unmange it and destroy all the associated resources.
+ */
+ if (mb_wm_client_is_iconizing (client))
+ {
+ MBWM_DBG ("iconizing client %p\n", client);
+
+ mb_wm_unmanage_client (wm, client, False);
+ mb_wm_client_reset_iconizing (client);
+ }
+ else if (!mb_wm_client_window_is_state_set (client->window,
+ MBWMClientWindowEWMHStateHidden))
+ {
+#if ENABLE_COMPOSITE
+ if (mb_wm_compositing_enabled (wm))
+ mb_wm_comp_mgr_unmap_notify (wm->comp_mgr, client);
+#endif
+ MBWM_DBG ("removing client %p\n", client);
+ mb_wm_unmanage_client (wm, client, True);
+ }
+ }
+ }
+
+ return True;
+}
+
+static Bool
+mb_wm_handle_property_notify (XPropertyEvent *xev,
+ void *userdata)
+{
+ MBWindowManager *wm = (MBWindowManager*)userdata;
+ MBWindowManagerClient *client;
+ int flag = 0;
+
+ if (xev->window == wm->root_win->xwindow)
+ {
+ if (xev->atom == wm->atoms[MBWM_ATOM_MB_THEME])
+ {
+ Atom type;
+ int format;
+ unsigned long items;
+ unsigned long left;
+ char *theme_path;
+
+ XGetWindowProperty (wm->xdpy, wm->root_win->xwindow,
+ xev->atom, 0, 8192, False,
+ XA_STRING, &type, &format,
+ &items, &left,
+ (unsigned char **)&theme_path);
+
+ if (!type || !items)
+ return True;
+
+ mb_wm_set_theme_from_path (wm, theme_path);
+
+ XFree (theme_path);
+ }
+
+ return True;
+ }
+
+ client = mb_wm_managed_client_from_xwindow(wm, xev->window);
+
+ if (!client)
+ return True;
+
+ if (xev->atom == wm->atoms[MBWM_ATOM_NET_WM_USER_TIME])
+ flag = MBWM_WINDOW_PROP_NET_USER_TIME;
+ else if (xev->atom == wm->atoms[MBWM_ATOM_WM_NAME] ||
+ xev->atom == wm->atoms[MBWM_ATOM_NET_WM_NAME])
+ flag = MBWM_WINDOW_PROP_NAME;
+ else if (xev->atom == wm->atoms[MBWM_ATOM_WM_HINTS])
+ flag = MBWM_WINDOW_PROP_WM_HINTS;
+ else if (xev->atom == wm->atoms[MBWM_ATOM_WM_NORMAL_HINTS])
+ flag = MBWM_WINDOW_PROP_WM_NORMAL_HINTS;
+ else if (xev->atom == wm->atoms[MBWM_ATOM_NET_WM_ICON])
+ flag = MBWM_WINDOW_PROP_NET_ICON;
+ else if (xev->atom == wm->atoms[MBWM_ATOM_WM_PROTOCOLS])
+ flag = MBWM_WINDOW_PROP_PROTOS;
+ else if (xev->atom == wm->atoms[MBWM_ATOM_WM_TRANSIENT_FOR])
+ flag = MBWM_WINDOW_PROP_TRANSIENCY;
+ else if (xev->atom == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE])
+ flag = MBWM_WINDOW_PROP_WIN_TYPE;
+ else if (xev->atom == wm->atoms[MBWM_ATOM_WM_CLIENT_MACHINE])
+ flag = MBWM_WINDOW_PROP_CLIENT_MACHINE;
+ else if (xev->atom == wm->atoms[MBWM_ATOM_NET_WM_PID])
+ flag = MBWM_WINDOW_PROP_NET_PID;
+
+ if (flag)
+ mb_wm_client_window_sync_properties (client->window, flag);
+
+ return True;
+}
+
+#if ENABLE_COMPOSITE
+static Bool
+mb_wm_handle_composite_config_notify (XConfigureEvent *xev,
+ void *userdata)
+{
+ MBWindowManager * wm = (MBWindowManager*)userdata;
+
+ if (mb_wm_comp_mgr_enabled (wm->comp_mgr))
+ {
+ MBWindowManagerClient *client;
+
+ client = mb_wm_managed_client_from_frame (wm, xev->window);
+
+ if (client)
+ mb_wm_comp_mgr_client_configure (client->cm_client);
+ }
+ return True;
+}
+#endif
+
+/*
+ * This is called if the root window resizes itself, which happens when RANDR is
+ * used to resize or rotate the display.
+ */
+static Bool
+mb_wm_handle_root_config_notify (XConfigureEvent *xev,
+ void *userdata)
+{
+ MBWindowManager * wm = (MBWindowManager*)userdata;
+
+ wm->xdpy_width = xev->width;
+ wm->xdpy_height = xev->height;
+
+ mb_wm_update_root_win_rectangles (wm);
+
+ mb_wm_display_sync_queue (wm, MBWMSyncGeometry);
+}
+
+static Bool
+mb_wm_handle_config_request (XConfigureRequestEvent *xev,
+ void *userdata)
+{
+ MBWindowManager *wm = (MBWindowManager*)userdata;
+ MBWindowManagerClient *client;
+ unsigned long value_mask;
+ int req_x = xev->x;
+ int req_y = xev->y;
+ int req_w = xev->width;
+ int req_h = xev->height;
+ MBGeometry req_geom, *win_geom;
+ Bool no_size_change;
+
+ client = mb_wm_managed_client_from_xwindow(wm, xev->window);
+
+ if (!client)
+ {
+ XWindowChanges xwc;
+ MBWM_DBG ("### No client found for configure event ###\n");
+ /*
+ * We have to allow this window to configure; things like gtk menus
+ * and hildon banners all request configuration before mapping, so
+ * if we did not allow this, things break down.
+ */
+ xwc.x = req_x;
+ xwc.y = req_y;
+ xwc.width = req_w;
+ xwc.height = req_h;
+ xwc.sibling = xev->above;
+ xwc.stack_mode = xev->detail;
+
+ XConfigureWindow (wm->xdpy, xev->window, xev->value_mask, &xwc);
+
+ return True;
+ }
+
+ value_mask = xev->value_mask;
+ win_geom = &client->window->geometry;
+
+ req_geom.x = (value_mask & CWX) ? req_x : win_geom->x;
+ req_geom.y = (value_mask & CWY) ? req_y : win_geom->y;
+ req_geom.width = (value_mask & CWWidth) ? req_w : win_geom->width;
+ req_geom.height = (value_mask & CWHeight) ? req_h : win_geom->height;
+
+ /* We can't determine at this point what the right response
+ * to this configure request is since layout management might
+ * also want to tweak the window geometry.
+ *
+ * We make a note that the configure request needs a response
+ * and when we reach mb_wm_sync - but after all layout decisions
+ * have been made - then we can determine if the request
+ * has been accepted or not and send any synthetic events as
+ * needed.
+ */
+ mb_wm_client_configure_request_ack_queue (client);
+
+ mb_wm_client_request_geometry (client,
+ &req_geom,
+ MBWMClientReqGeomIsViaConfigureReq);
+
+ return True;
+}
+
+/*
+ * 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;
+
+#if 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))
+ {
+ if (client)
+ *client = c;
+
+ return True;
+ }
+
+ return False;
+}
+
+#if ENABLE_COMPOSITE
+
+/* For the compositing engine we need to track overide redirect
+ * windows so the compositor can paint them.
+ */
+static Bool
+mb_wm_handle_map_notify (XMapEvent *xev,
+ void *userdata)
+{
+ MBWindowManager *wm = (MBWindowManager*)userdata;
+ MBWindowManagerClient *client = NULL;
+ MBWindowManagerClass *wm_class =
+ MB_WINDOW_MANAGER_CLASS (MB_WM_OBJECT_GET_CLASS (wm));
+ MBWMClientWindow *win = NULL;
+
+ MBWM_NOTE (COMPOSITOR, "@@@@ Map Notify for %x @@@@\n", xev->window);
+
+ if (!wm_class->client_new)
+ {
+ MBWM_DBG("### No new client hook exists ###");
+ return True;
+ }
+
+ if (mb_wm_is_my_window (wm, xev->window, &client))
+ {
+ if (client)
+ {
+ Window xwin_top =
+ client->xwin_frame ? client->xwin_frame : client->window->xwindow;
+
+ /*
+ * Only notify the CM when the top-level window maps, not for the
+ * decors, etc.
+ */
+ if (xev->window == xwin_top && wm->comp_mgr)
+ {
+ MBWM_NOTE (COMPOSITOR, "@@@@ client %p @@@@\n", client);
+ mb_wm_comp_mgr_map_notify (wm->comp_mgr, client);
+
+ /*
+ * If the hiding_from_deskotp flag is set, reset it
+ */
+ mb_wm_client_reset_hiding_from_desktop (client);
+ }
+ }
+
+ return True;
+ }
+
+ win = mb_wm_client_window_new (wm, xev->window);
+
+ if (!win || win->window_class == InputOnly)
+ {
+ mb_wm_object_unref (MB_WM_OBJECT (win));
+ return True;
+ }
+
+ client = wm_class->client_new (wm, win);
+
+ if (!client)
+ {
+ mb_wm_object_unref (MB_WM_OBJECT (win));
+ return True;
+ }
+
+ mb_wm_manage_client (wm, client, True);
+ mb_wm_comp_mgr_map_notify (wm->comp_mgr, client);
+
+ return True;
+}
+#endif
+
+static Bool
+mb_wm_handle_map_request (XMapRequestEvent *xev,
+ void *userdata)
+{
+ MBWindowManager *wm = (MBWindowManager*)userdata;
+ MBWindowManagerClient *client = NULL;
+ MBWindowManagerClass *wm_class =
+ MB_WINDOW_MANAGER_CLASS (MB_WM_OBJECT_GET_CLASS (wm));
+ MBWMClientWindow *win = NULL;
+
+ MBWM_MARK();
+
+ MBWM_NOTE (COMPOSITOR, "@@@@ Map Request for %x @@@@\n", xev->window);
+
+ if (mb_wm_is_my_window (wm, xev->window, &client))
+ {
+ if (client)
+ mb_wm_activate_client (wm, client);
+
+ return True;
+ }
+
+ if (!wm_class->client_new)
+ {
+ MBWM_DBG("### No new client hook exists ###");
+ return True;
+ }
+
+ win = mb_wm_client_window_new (wm, xev->window);
+
+ if (!win)
+ return True;
+
+ client = wm_class->client_new (wm, win);
+
+ if (!client)
+ {
+ mb_wm_object_unref (MB_WM_OBJECT (win));
+ return True;
+ }
+
+ mb_wm_manage_client (wm, client, True);
+
+ return True;
+}
+
+
+static void
+stack_get_window_list (MBWindowManager *wm, Window * win_list, int * count)
+{
+ MBWindowManagerClient *client;
+ int i = 0;
+
+ if (!wm->stack_n_clients)
+ return;
+
+ mb_wm_stack_enumerate_reverse(wm, client)
+ {
+ if (client->xwin_frame &&
+ !(client->window->ewmh_state & MBWMClientWindowEWMHStateFullscreen))
+ win_list[i++] = client->xwin_frame;
+ else
+ win_list[i++] = MB_WM_CLIENT_XWIN(client);
+
+ if (client->xwin_modal_blocker)
+ win_list[i++] = client->xwin_modal_blocker;
+ }
+
+ *count = i;
+}
+
+static void
+stack_sync_to_display (MBWindowManager *wm)
+{
+ Window *win_list = NULL;
+ int count;
+
+ if (!wm->stack_n_clients)
+ return;
+
+ /*
+ * Allocate two slots for each client; this guarantees us enough space for
+ * both client windows and any modal blockers without having to keep track
+ * of how many of the blocker windows we have (the memory overhead for this
+ * is negligeable and very short lived)
+ */
+ win_list = alloca (sizeof(Window) * (wm->stack_n_clients * 2));
+
+ stack_get_window_list(wm, win_list, &count);
+
+ mb_wm_util_trap_x_errors();
+ XRestackWindows(wm->xdpy, win_list, count);
+ mb_wm_util_untrap_x_errors();
+}
+
+void
+mb_wm_sync (MBWindowManager *wm)
+{
+ /* Sync all changes to display */
+ MBWindowManagerClient *client = NULL;
+
+ MBWM_MARK();
+ MBWM_TRACE ();
+
+ XGrabServer(wm->xdpy);
+
+ /* First of all, make sure stack is correct */
+ if (wm->sync_type & MBWMSyncStacking)
+ {
+ mb_wm_stack_ensure (wm);
+
+#if ENABLE_COMPOSITE
+ if (wm->comp_mgr && mb_wm_comp_mgr_enabled (wm->comp_mgr))
+ mb_wm_comp_mgr_restack (wm->comp_mgr);
+#endif
+ }
+
+ /* Size stuff first assume newly managed windows unmapped ?
+ *
+ */
+ if (wm->layout && (wm->sync_type & MBWMSyncGeometry))
+ mb_wm_layout_update (wm->layout);
+
+ /* Create the actual windows */
+ mb_wm_stack_enumerate(wm, client)
+ if (!mb_wm_client_is_realized (client))
+ mb_wm_client_realize (client);
+
+ /*
+ * Now do updates per individual client - maps, paints etc, main work here
+ *
+ * If an item in the stack needs visibilty sync, then we have to force it
+ * for all items that are above it on the stack.
+ */
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_needs_sync (client))
+ mb_wm_client_display_sync (client);
+
+#if ENABLE_COMPOSITE
+ if (mb_wm_comp_mgr_enabled (wm->comp_mgr))
+ mb_wm_comp_mgr_render (wm->comp_mgr);
+#endif
+
+ /* FIXME: optimise wm sync flags so know if this needs calling */
+ /* FIXME: Can we restack an unmapped window ? - problem of new
+ * clients mapping below existing ones.
+ */
+ if (wm->sync_type & MBWMSyncStacking)
+ stack_sync_to_display (wm);
+
+ /* FIXME: New clients now managed will likely need some propertys
+ * synced up here.
+ */
+
+ XUngrabServer(wm->xdpy);
+
+ wm->sync_type = 0;
+}
+
+static void
+mb_wm_update_root_win_lists (MBWindowManager *wm)
+{
+ Window root_win = wm->root_win->xwindow;
+
+ if (!mb_wm_stack_empty(wm))
+ {
+ Window *wins = NULL;
+ Window *app_wins = NULL;
+ int app_win_cnt = 0;
+ int cnt = 0;
+ int list_size;
+ MBWindowManagerClient *c;
+ MBWMList *l;
+
+ list_size = mb_wm_util_list_length (wm->clients);
+
+ wins = alloca (sizeof(Window) * list_size);
+ app_wins = alloca (sizeof(Window) * list_size);
+
+ if ((wm->flags & MBWindowManagerFlagDesktop) && wm->desktop)
+ {
+ wins[cnt++] = MB_WM_CLIENT_XWIN(wm->desktop);
+ }
+
+ mb_wm_stack_enumerate (wm,c)
+ {
+ if (!(wm->flags & MBWindowManagerFlagDesktop) || c != wm->desktop)
+ wins[cnt++] = c->window->xwindow;
+ }
+
+ /* The MB_APP_WINDOW_LIST_STACKING list is used to construct
+ * application switching menus -- we append anything we have
+ * in client list (some of which might be hidden).
+ * apps)
+ */
+ l = wm->clients;
+ while (l)
+ {
+ c = l->data;
+
+ if (MB_WM_IS_CLIENT_APP (c))
+ app_wins[app_win_cnt++] = c->window->xwindow;
+
+ l = l->next;
+ }
+
+ XChangeProperty(wm->xdpy, root_win,
+ wm->atoms[MBWM_ATOM_NET_CLIENT_LIST_STACKING],
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)wins, cnt);
+
+ XChangeProperty(wm->xdpy, root_win,
+ wm->atoms[MBWM_ATOM_MB_APP_WINDOW_LIST_STACKING],
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)app_wins, app_win_cnt);
+
+ /* Update _NET_CLIENT_LIST but with 'age' order rather than stacking */
+ cnt = 0;
+ l = wm->clients;
+ while (l)
+ {
+ c = l->data;
+ wins[cnt++] = c->window->xwindow;
+
+ l = l->next;
+ }
+
+ XChangeProperty(wm->xdpy, root_win,
+ wm->atoms[MBWM_ATOM_NET_CLIENT_LIST] ,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)wins, cnt);
+ }
+ else
+ {
+ /* No managed windows */
+ XChangeProperty(wm->xdpy, root_win,
+ wm->atoms[MBWM_ATOM_NET_CLIENT_LIST_STACKING] ,
+ XA_WINDOW, 32, PropModeReplace,
+ NULL, 0);
+
+ XChangeProperty(wm->xdpy, root_win,
+ wm->atoms[MBWM_ATOM_MB_APP_WINDOW_LIST_STACKING],
+ XA_WINDOW, 32, PropModeReplace,
+ NULL, 0);
+
+ XChangeProperty(wm->xdpy, root_win,
+ wm->atoms[MBWM_ATOM_NET_CLIENT_LIST] ,
+ XA_WINDOW, 32, PropModeReplace,
+ NULL, 0);
+ }
+}
+
+void
+mb_wm_manage_client (MBWindowManager *wm,
+ MBWindowManagerClient *client,
+ Bool activate)
+{
+ /* Add to our list of managed clients */
+ MBWMSyncType sync_flags = MBWMSyncVisibility | MBWMSyncGeometry;
+
+ if (client == NULL)
+ return;
+
+ wm->clients = mb_wm_util_list_append(wm->clients, (void*)client);
+
+ /* add to stack and move to position in stack */
+ mb_wm_stack_append_top (client);
+ mb_wm_client_stack(client, 0);
+ mb_wm_update_root_win_lists (wm);
+
+ if (MB_WM_CLIENT_CLIENT_TYPE (client) == MBWMClientTypePanel)
+ {
+ mb_wm_update_root_win_rectangles (wm);
+ mb_wm_client_set_desktop (client, -1);
+ }
+ else if (MB_WM_CLIENT_CLIENT_TYPE (client) == MBWMClientTypeDesktop)
+ {
+ wm->desktop = client;
+ mb_wm_client_set_desktop (client, -1);
+ }
+ else if (client->transient_for)
+ {
+ /*
+ * For transient clients, set the desktop to that of the top level
+ * parent; if this does not match the active desktop, hide the client.
+ */
+ MBWindowManagerClient * parent = client->transient_for;
+ int desktop;
+
+ while (parent->transient_for)
+ parent = parent->transient_for;
+
+ desktop = mb_wm_client_get_desktop (parent);
+
+ mb_wm_client_set_desktop (client, desktop);
+
+ if (desktop != wm->active_desktop)
+ mb_wm_client_desktop_change (client, wm->active_desktop);
+ }
+ else
+ mb_wm_client_set_desktop (client, wm->active_desktop);
+
+ /*
+ * Must not mess with stacking if the client if is of the override type
+ */
+ if (MB_WM_CLIENT_CLIENT_TYPE (client) != MBWMClientTypeOverride)
+ sync_flags |= MBWMSyncStacking;
+
+#if ENABLE_COMPOSITE
+ if (mb_wm_comp_mgr_enabled (wm->comp_mgr))
+ mb_wm_comp_mgr_register_client (wm->comp_mgr, client);
+#endif
+
+ if (activate && MB_WM_CLIENT_CLIENT_TYPE (client) != MBWMClientTypeDesktop)
+ mb_wm_activate_client (wm, client);
+ else
+ mb_wm_client_show (client);
+
+ mb_wm_display_sync_queue (client->wmref, sync_flags);
+}
+
+/*
+ * destroy indicates whether the client, if it is an application,
+ * should be destroyed or moved into the iconized category.
+ */
+void
+mb_wm_unmanage_client (MBWindowManager *wm,
+ MBWindowManagerClient *client,
+ Bool destroy)
+{
+ /* FIXME: set a managed flag in client object ? */
+ MBWindowManagerClient *c;
+ MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+ MBWMSyncType sync_flags = 0;
+ MBWindowManagerClient * next_focused;
+
+ /*
+ * Must not mess with stacking if the client if is of the override type
+ */
+ if (c_type != MBWMClientTypeOverride)
+ sync_flags |= MBWMSyncStacking;
+
+ if (c_type & (MBWMClientTypePanel | MBWMClientTypeInput))
+ sync_flags |= MBWMSyncGeometry;
+
+ if (destroy)
+ wm->clients = mb_wm_util_list_remove (wm->clients, (void*)client);
+
+ mb_wm_stack_remove (client);
+ mb_wm_update_root_win_lists (wm);
+
+ if (MB_WM_CLIENT_CLIENT_TYPE (client) == MBWMClientTypePanel)
+ mb_wm_update_root_win_rectangles (wm);
+
+ /*
+ * Must remove client from any transient list, otherwise when we call
+ * _stack_enumerate() everything will go pearshape
+ */
+ mb_wm_client_detransitise (client);
+
+ next_focused = client->next_focused_client;
+ mb_wm_stack_enumerate (wm, c)
+ {
+ /*
+ * Must avoid circular dependcy here
+ */
+ if (c->next_focused_client == client)
+ {
+ if (c != next_focused)
+ c->next_focused_client = next_focused;
+ else
+ c->next_focused_client = NULL;
+ }
+ }
+
+#if ENABLE_COMPOSITE
+ if (mb_wm_comp_mgr_enabled (wm->comp_mgr))
+ {
+ /*
+ * If destroy == False, this unmap was triggered by iconizing the
+ * client; in that case, we do not destory the CM client data, only
+ * make sure the client is hidden (note that any 'minimize' effect
+ * has already completed by the time we get here).
+ */
+ if (destroy)
+ mb_wm_comp_mgr_unregister_client (wm->comp_mgr, client);
+ else
+ mb_wm_comp_mgr_client_hide (client->cm_client);
+ }
+#endif
+
+ if (wm->focused_client == client)
+ mb_wm_unfocus_client (wm, client);
+
+ if (client == wm->desktop)
+ wm->desktop = NULL;
+
+ if (destroy)
+ mb_wm_object_unref (MB_WM_OBJECT(client));
+
+ mb_wm_display_sync_queue (wm, sync_flags);
+}
+
+MBWindowManagerClient*
+mb_wm_managed_client_from_xwindow(MBWindowManager *wm, Window win)
+{
+ MBWindowManagerClient *client = NULL;
+ MBWMList *l;
+
+ if (win == wm->root_win->xwindow)
+ return NULL;
+
+ l = wm->clients;
+ while (l)
+ {
+ client = l->data;
+
+ if (client->window && client->window->xwindow == win)
+ return client;
+
+ l = l->next;
+ }
+
+ return NULL;
+}
+
+MBWindowManagerClient*
+mb_wm_managed_client_from_frame (MBWindowManager *wm, Window frame)
+{
+ MBWindowManagerClient *client = NULL;
+ MBWMList *l;
+
+ if (frame == wm->root_win->xwindow)
+ return NULL;
+
+ l = wm->clients;
+ while (l)
+ {
+ client = l->data;
+
+ if (mb_wm_client_owns_xwindow (client, frame))
+ return client;
+
+ l = l->next;
+ }
+
+ 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)
+{
+#if !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 !ENABLE_CLUTTER_COMPOSITE_MANAGER
+ if (!wm_class->main)
+ {
+ GMainLoop * loop = g_main_loop_new (NULL, FALSE);
+
+ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+ mb_wm_main_context_gloop_xevent, wm->main_ctx, NULL);
+
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+ }
+ else
+#endif
+ {
+ wm_class->main (wm);
+ }
+#endif
+}
+
+void
+mb_wm_get_display_geometry (MBWindowManager *wm,
+ MBGeometry *geometry)
+{
+ geometry->x = 0;
+ geometry->y = 0;
+ geometry->width = wm->xdpy_width;
+ geometry->height = wm->xdpy_height;
+}
+
+void
+mb_wm_display_sync_queue (MBWindowManager* wm, MBWMSyncType sync)
+{
+ wm->sync_type |= sync;
+}
+
+static void
+mb_wm_manage_preexistsing_wins (MBWindowManager* wm)
+{
+ unsigned int nwins, i;
+ Window foowin1, foowin2, *wins;
+ XWindowAttributes attr;
+ MBWindowManagerClass * wm_class =
+ MB_WINDOW_MANAGER_CLASS (MB_WM_OBJECT_GET_CLASS (wm));
+
+ if (!wm_class->client_new)
+ return;
+
+ XQueryTree(wm->xdpy, wm->root_win->xwindow,
+ &foowin1, &foowin2, &wins, &nwins);
+
+ for (i = 0; i < nwins; i++)
+ {
+ XGetWindowAttributes(wm->xdpy, wins[i], &attr);
+
+ if (
+#if ! ENABLE_COMPOSITE
+ !attr.override_redirect &&
+#endif
+ attr.map_state == IsViewable)
+ {
+ MBWMClientWindow *win = NULL;
+ MBWindowManagerClient *client = NULL;
+
+ win = mb_wm_client_window_new (wm, wins[i]);
+
+ if (!win)
+ continue;
+
+ client = wm_class->client_new (wm, win);
+
+ if (client)
+ {
+ /*
+ * When we realize the client, we reparent the application
+ * window to the new frame, which generates an unmap event.
+ * We need to skip it.
+ */
+ client->skip_unmaps++;
+
+#if ENABLE_COMPOSITE
+ /*
+ * Register the new client with the composite manager before
+ * we call mb_wm_manage_client() -- this is necessary so that
+ * we can process map notification on the frame.
+ */
+ if (wm->comp_mgr && mb_wm_comp_mgr_enabled (wm->comp_mgr))
+ mb_wm_comp_mgr_register_client (wm->comp_mgr, client);
+#endif
+ mb_wm_manage_client(wm, client, False);
+ }
+ else
+ mb_wm_object_unref (MB_WM_OBJECT (win));
+ }
+ }
+
+ XFree(wins);
+}
+
+static void
+mb_wm_real_get_desktop_geometry (MBWindowManager *wm, MBGeometry * geom)
+{
+ MBWindowManagerClient *c;
+ MBGeometry p_geom;
+ MBWMClientLayoutHints hints;
+
+ geom->x = 0;
+ geom->y = 0;
+ geom->width = wm->xdpy_width;
+ geom->height = wm->xdpy_height;
+
+ if (mb_wm_stack_empty(wm))
+ return;
+
+ mb_wm_stack_enumerate(wm, c)
+ {
+ if (MB_WM_CLIENT_CLIENT_TYPE (c) != MBWMClientTypePanel ||
+ ((hints = mb_wm_client_get_layout_hints (c)) & LayoutPrefOverlaps))
+ continue;
+
+ mb_wm_client_get_coverage (c, & p_geom);
+
+ if (LayoutPrefReserveEdgeNorth & hints)
+ geom->y += p_geom.height;
+
+ if (LayoutPrefReserveEdgeSouth & hints)
+ geom->height -= p_geom.height;
+
+ if (LayoutPrefReserveEdgeWest & hints)
+ geom->x += p_geom.width;
+
+ if (LayoutPrefReserveEdgeEast & hints)
+ geom->width -= p_geom.width;
+ }
+}
+
+static void
+mb_wm_get_desktop_geometry (MBWindowManager *wm, MBGeometry * geom)
+{
+ MBWindowManagerClass *wm_class;
+
+ wm_class = (MBWindowManagerClass *) MB_WM_OBJECT_GET_CLASS (wm);
+
+ MBWM_ASSERT (wm_class->get_desktop_geometry);
+
+ wm_class->get_desktop_geometry (wm, geom);
+}
+
+static void
+mb_wm_update_root_win_rectangles (MBWindowManager *wm)
+{
+ Display * dpy = wm->xdpy;
+ Window root = wm->root_win->xwindow;
+ MBGeometry d_geom;
+ CARD32 val[4];
+
+ mb_wm_get_desktop_geometry (wm, &d_geom);
+
+ val[0] = d_geom.x;
+ val[1] = d_geom.y;
+ val[2] = d_geom.width;
+ val[3] = d_geom.height;
+
+ /* FIXME -- handle decorated desktops */
+
+ XChangeProperty(dpy, root, wm->atoms[MBWM_ATOM_NET_WORKAREA],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)val, 4);
+
+ val[2] = wm->xdpy_width;
+ val[3] = wm->xdpy_height;
+
+ XChangeProperty(dpy, root, wm->atoms[MBWM_ATOM_NET_DESKTOP_GEOMETRY],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)&val[2], 2);
+
+}
+
+int
+mb_wm_register_client_type (void)
+{
+ static int type_cnt = 0;
+ return ++type_cnt;
+}
+
+static int
+mb_wm_init_xdpy (MBWindowManager * wm, const char * display)
+{
+ if (!wm->xdpy)
+ {
+ wm->xdpy = XOpenDisplay(display ? display : getenv("DISPLAY"));
+
+ if (!wm->xdpy)
+ {
+ /* FIXME: Error codes */
+ 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);
+
+ return 1;
+}
+
+static void
+mb_wm_init_cursors (MBWindowManager * wm)
+{
+ XColor col;
+ Pixmap pix = XCreatePixmap (wm->xdpy, wm->root_win->xwindow, 1, 1, 1);
+
+ memset (&col, 0, sizeof (col));
+
+ wm->cursors[MBWindowManagerCursorNone] =
+ XCreatePixmapCursor (wm->xdpy, pix, pix, &col, &col, 1, 1);
+
+ XFreePixmap (wm->xdpy, pix);
+
+ wm->cursors[MBWindowManagerCursorLeftPtr] =
+ XCreateFontCursor(wm->xdpy, XC_left_ptr);
+
+ MBWM_ASSERT (wm->cursors[_MBWindowManagerCursorLast - 1] != 0);
+
+ mb_wm_set_cursor (wm, MBWindowManagerCursorLeftPtr);
+}
+
+#if ENABLE_COMPOSITE
+static Bool
+mb_wm_init_comp_extensions (MBWindowManager *wm)
+{
+ 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,
+ &wm->damage_event_base, &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;
+ }
+
+ return True;
+}
+#endif
+
+/*
+ * This function must be called before the MBWindowManager object can be
+ * used.
+ */
+void
+mb_wm_init (MBWindowManager * wm)
+{
+ MBWindowManagerClass *wm_class;
+
+ wm_class = (MBWindowManagerClass *) MB_WM_OBJECT_GET_CLASS (wm);
+
+ mb_wm_set_theme_from_path (wm, wm->theme_path);
+
+ MBWM_ASSERT (wm_class->layout_new);
+
+ mb_wm_set_layout (wm, wm_class->layout_new (wm));
+
+#if ENABLE_COMPOSITE
+ if (wm_class->comp_mgr_new && mb_wm_theme_use_compositing_mgr (wm->theme))
+ mb_wm_compositing_on (wm);
+#endif
+
+ mb_wm_manage_preexistsing_wins (wm);
+
+ /*
+ * Force an initial stack sync even when there are no managed windows (when
+ * using compositor, this triggers call to MBWMCompMgr::restack(), allowing
+ * the CM to set its house into order (i.e., a clutter-based compositor
+ * might want to reorganize any auxiliar actors that it might have, depending
+ * on whether the initial stack is empty or not.
+ */
+ wm->sync_type |= MBWMSyncStacking;
+}
+
+
+static int
+mb_window_manager_init (MBWMObject *this, va_list vap)
+{
+ MBWindowManager *wm = MB_WINDOW_MANAGER (this);
+ MBWindowManagerClass *wm_class;
+ MBWMObjectProp prop;
+ int argc = 0;
+ char **argv = NULL;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropArgc:
+ argc = va_arg(vap, int);
+ break;
+ case MBWMObjectPropArgv:
+ argv = va_arg(vap, char **);
+ break;
+ case MBWMObjectPropDpy:
+ wm->xdpy = va_arg(vap, Display *);
+ break;
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ 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);
+
+ if (!mb_wm_init_xdpy (wm, NULL))
+ return 0;
+
+ if (getenv("MB_SYNC"))
+ XSynchronize (wm->xdpy, True);
+
+ mb_wm_debug_init (getenv("MB_DEBUG"));
+
+ /* FIXME: Multiple screen handling */
+
+ wm->xas_context = xas_context_new(wm->xdpy);
+
+ mb_wm_atoms_init(wm);
+
+#if ENABLE_COMPOSITE
+ if (!mb_wm_init_comp_extensions (wm))
+ return 0;
+#endif
+
+ wm->root_win = mb_wm_root_window_get (wm);
+
+ mb_wm_update_root_win_rectangles (wm);
+
+ wm->main_ctx = mb_wm_main_context_new (wm);
+
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ None,
+ MapRequest,
+ (MBWMXEventFunc)mb_wm_handle_map_request,
+ wm);
+
+#if ENABLE_COMPOSITE
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ None,
+ MapNotify,
+ (MBWMXEventFunc)mb_wm_handle_map_notify,
+ wm);
+
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ None,
+ ConfigureNotify,
+ (MBWMXEventFunc)mb_wm_handle_composite_config_notify,
+ wm);
+#endif
+
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ wm->root_win->xwindow,
+ ConfigureNotify,
+ (MBWMXEventFunc)mb_wm_handle_root_config_notify,
+ wm);
+
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ None,
+ ConfigureRequest,
+ (MBWMXEventFunc)mb_wm_handle_config_request,
+ wm);
+
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ None,
+ PropertyNotify,
+ (MBWMXEventFunc)mb_wm_handle_property_notify,
+ wm);
+
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ None,
+ DestroyNotify,
+ (MBWMXEventFunc)mb_wm_handle_destroy_notify,
+ wm);
+
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ None,
+ UnmapNotify,
+ (MBWMXEventFunc)mb_wm_handle_unmap_notify,
+ wm);
+
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ None,
+ KeyPress,
+ (MBWMXEventFunc)mb_wm_handle_key_press,
+ wm);
+
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ None,
+ ButtonPress,
+ (MBWMXEventFunc)mb_wm_handle_button_press,
+ wm);
+
+ mb_wm_keys_init(wm);
+
+ mb_wm_init_cursors (wm);
+
+ base_foo ();
+
+ return 1;
+}
+
+static void
+mb_wm_cmdline_help (const char *arg0, Bool quit)
+{
+ FILE * f = stdout;
+ const char * name;
+ char * p = strrchr (arg0, '/');
+
+ if (p)
+ name = p+1;
+ else
+ name = arg0;
+
+ fprintf (f, "\nThis is Matchbox Window Manager 2.\n");
+
+ fprintf (f, "\nUsage: %s [options]\n\n", name);
+ fprintf (f, "Options:\n");
+ fprintf (f, " -display display : X display to connect to (alternatively, display\n"
+ " can be specified using the DISPLAY environment\n"
+ " variable).\n");
+ fprintf (f, " -sm-client-id id : Session id.\n");
+ fprintf (f, " -theme-always-reload : Reload theme even if it matches the currently\n"
+ " loaded theme.\n");
+ fprintf (f, " -theme theme : Load the specified theme\n");
+
+ if (quit)
+ exit (0);
+}
+
+static void
+mb_wm_process_cmdline (MBWindowManager *wm)
+{
+ int i;
+ char ** argv = wm->argv;
+ int argc = wm->argc;
+
+ for (i = 0; i < argc; ++i)
+ {
+ if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "--help"))
+ {
+ mb_wm_cmdline_help (argv[0], True);
+ }
+ else if (!strcmp(argv[i], "-theme-always-reload"))
+ {
+ wm->flags |= MBWindowManagerFlagAlwaysReloadTheme;
+ }
+ else if (i < argc - 1)
+ {
+ /* These need to have a value after the name parameter */
+ if (!strcmp(argv[i], "-display"))
+ {
+ mb_wm_init_xdpy (wm, argv[++i]);
+ }
+ else if (!strcmp ("-sm-client-id", argv[i]))
+ {
+ wm->sm_client_id = argv[++i];
+ }
+ else if (!strcmp ("-theme", argv[i]))
+ {
+ wm->theme_path = argv[++i];
+ }
+ }
+ }
+
+ /*
+ * Anything below here needs a display conection
+ */
+ if (!wm->xdpy && !mb_wm_init_xdpy (wm, NULL))
+ return;
+}
+
+void
+mb_wm_activate_client (MBWindowManager * wm, MBWindowManagerClient *c)
+{
+ MBWindowManagerClass *wm_klass;
+ wm_klass = MB_WINDOW_MANAGER_CLASS (MB_WM_OBJECT_GET_CLASS (wm));
+
+ MBWM_ASSERT (wm_klass->client_activate);
+
+ wm_klass->client_activate (wm, c);
+}
+
+
+static Bool
+mb_wm_activate_client_real (MBWindowManager * wm, MBWindowManagerClient *c)
+{
+ MBWMClientType c_type;
+ Bool was_desktop;
+ Bool is_desktop;
+ MBWindowManagerClient * c_focus = c;
+ MBWindowManagerClient * trans;
+
+ if (c == NULL)
+ return False;
+
+ c_type = MB_WM_CLIENT_CLIENT_TYPE (c);
+
+ /*
+ * Under no circumtances attempt to activate override windows; only call
+ * show on them.
+ */
+ if (c_type == MBWMClientTypeOverride)
+ {
+ mb_wm_client_show (c);
+ return True;
+ }
+
+ was_desktop = (wm->flags & MBWindowManagerFlagDesktop);
+
+ /*
+ * We are showing desktop if either the client is desktop, it is transient
+ * for the desktop, or the last client was desktop, and the current is a
+ * dialog or menu transiet for root.
+ */
+ is_desktop = ((MB_WM_CLIENT_CLIENT_TYPE (c) == MBWMClientTypeDesktop) ||
+ ((trans = mb_wm_client_get_transient_for (c)) == c) ||
+ (was_desktop &&
+ !trans &&
+ (c_type & (MBWMClientTypeDialog|
+ MBWMClientTypeMenu|
+ MBWMClientTypeNote|
+ MBWMClientTypeOverride))));
+
+ if (is_desktop)
+ wm->flags |= MBWindowManagerFlagDesktop;
+ else
+ wm->flags &= ~MBWindowManagerFlagDesktop;
+
+ mb_wm_client_show (c);
+
+ /* If the next focused client after this one is transient for it,
+ * activate it instead
+ */
+ if (c->last_focused_transient &&
+ c->last_focused_transient->transient_for == c)
+ {
+ c_focus = c->last_focused_transient;
+ }
+
+ mb_wm_focus_client (wm, c_focus);
+ mb_wm_client_stack (c, 0);
+
+ if (is_desktop != was_desktop)
+ {
+ CARD32 card = is_desktop ? 1 : 0;
+
+ XChangeProperty(wm->xdpy, wm->root_win->xwindow,
+ wm->atoms[MBWM_ATOM_NET_SHOWING_DESKTOP],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)&card, 1);
+ }
+
+ if (is_desktop || c_type == MBWMClientTypeApp)
+ {
+ XChangeProperty(wm->xdpy, wm->root_win->xwindow,
+ wm->atoms[MBWM_ATOM_MB_CURRENT_APP_WINDOW],
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)&c->window->xwindow, 1);
+ }
+
+ mb_wm_display_sync_queue (wm, MBWMSyncStacking | MBWMSyncVisibility);
+
+ return True;
+}
+
+MBWindowManagerClient*
+mb_wm_get_visible_main_client(MBWindowManager *wm)
+{
+ if ((wm->flags & MBWindowManagerFlagDesktop) && wm->desktop)
+ return wm->desktop;
+
+ return mb_wm_stack_get_highest_by_type (wm, MBWMClientTypeApp);
+}
+
+void
+mb_wm_handle_ping_reply (MBWindowManager * wm, MBWindowManagerClient *c)
+{
+ if (c == NULL)
+ return;
+
+ if (mb_wm_client_ping_in_progress (c))
+ {
+ MBWindowManagerClass *wm_klass;
+
+ mb_wm_client_ping_stop (c);
+
+ wm_klass = MB_WINDOW_MANAGER_CLASS (MB_WM_OBJECT_GET_CLASS (wm));
+
+ if (wm_klass->client_responding)
+ wm_klass->client_responding (wm, c);
+ }
+}
+
+void
+mb_wm_handle_hang_client (MBWindowManager * wm, MBWindowManagerClient *c)
+{
+ MBWindowManagerClass *wm_klass;
+
+ if (c == NULL)
+ return;
+
+ wm_klass = MB_WINDOW_MANAGER_CLASS (MB_WM_OBJECT_GET_CLASS (wm));
+
+ if (!wm_klass->client_hang || !wm_klass->client_hang (wm, c))
+ {
+ mb_wm_client_shutdown (c);
+ }
+}
+
+void
+mb_wm_toggle_desktop (MBWindowManager * wm)
+{
+ Bool show = !(wm->flags & MBWindowManagerFlagDesktop);
+ mb_wm_handle_show_desktop (wm, show);
+}
+
+void
+mb_wm_handle_show_desktop (MBWindowManager * wm, Bool show)
+{
+ if (!wm->desktop)
+ return;
+
+ if (show)
+ mb_wm_activate_client (wm, wm->desktop);
+ else
+ {
+ MBWindowManagerClient * c =
+ mb_wm_stack_get_highest_by_type (wm, MBWMClientTypeApp);
+
+ if (c)
+ mb_wm_activate_client (wm, c);
+ }
+}
+
+void
+mb_wm_set_layout (MBWindowManager *wm, MBWMLayout *layout)
+{
+ wm->layout = layout;
+ wm->sync_type |= (MBWMSyncGeometry | MBWMSyncVisibility);
+}
+
+static void
+mb_wm_focus_client (MBWindowManager *wm, MBWindowManagerClient *c)
+{
+ MBWindowManagerClient * client = c;
+
+ /*
+ * The last focused transient for this client is modal, we try to focus
+ * the transient rather than the client itself
+ */
+ if (c->last_focused_transient &&
+ mb_wm_client_is_modal (c->last_focused_transient))
+ {
+ client = c->last_focused_transient;
+ }
+
+ /*
+ * If the client is currently focused, it does not want focus, it is a
+ * parent of a currently focused modal client, or is system-modal,
+ * do nothing.
+ */
+ if (wm->focused_client == client ||
+ !mb_wm_client_want_focus (client) ||
+ ((wm->focused_client && mb_wm_client_is_modal (wm->focused_client) &&
+ (client == mb_wm_client_get_transient_for (wm->focused_client) ||
+ (wm->modality_type == MBWMModalitySystem &&
+ !mb_wm_client_get_transient_for (wm->focused_client))))))
+ return;
+
+ if (!mb_wm_client_is_realized (client))
+ {
+ /* We need the window mapped before we can focus it, but do not
+ * want to do a full-scale mb_wm_sync ():
+ *
+ * First We need to update layout, othewise the window will get frame
+ * size of 0x0; then we can realize it, and do a display sync (i.e.,
+ * map).
+ */
+ if (wm->layout)
+ mb_wm_layout_update (wm->layout);
+
+ mb_wm_client_realize (client);
+ mb_wm_client_display_sync (client);
+ }
+
+ if (mb_wm_client_focus (client))
+ {
+ if (wm->focused_client)
+ {
+ MBWindowManagerClient *trans_old = wm->focused_client;
+ MBWindowManagerClient *trans_new = client;
+
+ while (trans_old->transient_for)
+ trans_old = trans_old->transient_for;
+
+ while (trans_new->transient_for)
+ trans_new = trans_new->transient_for;
+
+ client->next_focused_client = NULL;
+
+ /*
+ * Are we both transient for the same thing ?
+ */
+ if (trans_new && trans_new == trans_old)
+ client->next_focused_client = wm->focused_client;
+
+ /* From regular dialog to transient for root dialogs */
+ if (MB_WM_IS_CLIENT_DIALOG (client) &&
+ !client->transient_for &&
+ MB_WM_IS_CLIENT_DIALOG (wm->focused_client))
+ client->next_focused_client = wm->focused_client;
+ }
+
+ wm->focused_client = client;
+ }
+}
+
+void
+mb_wm_unfocus_client (MBWindowManager *wm, MBWindowManagerClient *client)
+{
+ MBWindowManagerClient *next = NULL;
+
+ if (client != wm->focused_client)
+ return;
+
+ /*
+ * Remove this client from any other's next_focused_client
+ */
+ next = client->next_focused_client;
+
+ if (!next && wm->stack_top)
+ {
+ MBWindowManagerClient *c;
+
+ mb_wm_stack_enumerate_reverse (wm, c)
+ {
+ if (c != client && mb_wm_client_want_focus (c))
+ {
+ next = c;
+ break;
+ }
+ }
+ }
+
+ wm->focused_client = NULL;
+
+ if (next)
+ mb_wm_activate_client (wm, next);
+}
+
+void
+mb_wm_cycle_apps (MBWindowManager *wm, Bool reverse)
+{
+ MBWindowManagerClient *old_top, *new_top;
+
+ if (wm->flags & MBWindowManagerFlagDesktop)
+ {
+ mb_wm_handle_show_desktop (wm, False);
+ return;
+ }
+
+ old_top = mb_wm_stack_get_highest_by_type (wm, MBWMClientTypeApp);
+
+ new_top = mb_wm_stack_cycle_by_type(wm, MBWMClientTypeApp, reverse);
+
+ if (new_top && old_top != new_top)
+ {
+#if ENABLE_COMPOSITE
+ if (wm->comp_mgr && mb_wm_comp_mgr_enabled (wm->comp_mgr))
+ mb_wm_comp_mgr_do_transition (wm->comp_mgr, old_top, new_top, reverse);
+#endif
+ mb_wm_activate_client (wm, new_top);
+ }
+}
+
+void
+mb_wm_set_theme (MBWindowManager *wm, MBWMTheme * theme)
+{
+ if (!theme)
+ return;
+
+ XGrabServer(wm->xdpy);
+
+ if (wm->theme)
+ mb_wm_object_unref (MB_WM_OBJECT (wm->theme));
+
+ wm->theme = theme;
+ wm->sync_type |= (MBWMSyncGeometry | MBWMSyncVisibility | MBWMSyncDecor);
+
+ /* When initializing the MBWindowManager object, the theme gets created
+ * before the root window, so that the root window can interogate it,
+ * so we can get here before the window is in place
+ */
+ if (wm->root_win)
+ mb_wm_root_window_update_supported_props (wm->root_win);
+
+ mb_wm_object_signal_emit (MB_WM_OBJECT (wm),
+ MBWindowManagerSignalThemeChange);
+
+
+ XUngrabServer(wm->xdpy);
+}
+
+void
+mb_wm_set_theme_from_path (MBWindowManager *wm, const char *theme_path)
+{
+ MBWMTheme *theme;
+ MBWindowManagerClass *wm_class;
+
+ wm_class = MB_WINDOW_MANAGER_CLASS (MB_WM_OBJECT_GET_CLASS (wm));
+
+ if (wm->theme)
+ {
+ if (!(wm->flags & MBWindowManagerFlagAlwaysReloadTheme) &&
+ (wm->theme->path && theme_path &&
+ !strcmp (theme_path, wm->theme->path)))
+ return;
+
+ if (!wm->theme->path && !theme_path)
+ return;
+ }
+
+ theme = wm_class->theme_new (wm, theme_path);
+
+ mb_wm_set_theme (wm, theme);
+}
+
+void
+mb_wm_set_cursor (MBWindowManager * wm, MBWindowManagerCursor cursor)
+{
+ static int major = 0, minor = 0, ev_base, err_base;
+ Display * dpy;
+ Window rwin;
+
+ if (wm->cursor == cursor)
+ return;
+
+ dpy = wm->xdpy;
+ rwin = wm->root_win->xwindow;
+
+ mb_wm_util_trap_x_errors();
+
+#ifdef HAVE_XFIXES
+ if (!major)
+ {
+ if (XFixesQueryExtension (dpy, &ev_base, &err_base))
+ XFixesQueryVersion (dpy, &major, &minor);
+ else
+ major = -1;
+ }
+
+ if (major >= 4)
+ {
+ if (cursor == MBWindowManagerCursorNone)
+ {
+ XFixesHideCursor (dpy, rwin);
+ }
+ else
+ {
+ XDefineCursor(dpy, rwin, wm->cursors[cursor]);
+ XFixesShowCursor (dpy, rwin);
+ mb_wm_util_trap_x_errors();
+ }
+ }
+ else
+#endif
+ {
+ XDefineCursor(dpy, rwin, wm->cursors[cursor]);
+ }
+
+ XSync (dpy, False);
+
+ if (!mb_wm_util_untrap_x_errors())
+ wm->cursor = cursor;
+}
+
+void
+mb_wm_compositing_on (MBWindowManager * wm)
+{
+#if ENABLE_COMPOSITE
+ MBWindowManagerClass *wm_class =
+ MB_WINDOW_MANAGER_CLASS (MB_WM_OBJECT_GET_CLASS (wm));
+
+ if (!wm->comp_mgr && wm_class->comp_mgr_new)
+ 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);
+ XSync (wm->xdpy, False);
+ }
+#endif
+}
+
+
+void
+mb_wm_compositing_off (MBWindowManager * wm)
+{
+#if ENABLE_COMPOSITE
+ if (wm->comp_mgr && mb_wm_comp_mgr_enabled (wm->comp_mgr))
+ mb_wm_comp_mgr_turn_off (wm->comp_mgr);
+#endif
+}
+
+Bool
+mb_wm_compositing_enabled (MBWindowManager * wm)
+{
+#if ENABLE_COMPOSITE
+ return mb_wm_comp_mgr_enabled (wm->comp_mgr);
+#else
+ return False;
+#endif
+}
+
+MBWMModality
+mb_wm_get_modality_type (MBWindowManager * wm)
+{
+ return wm->modality_type;
+}
+
+void
+mb_wm_set_n_desktops (MBWindowManager *wm, int n_desktops)
+{
+ CARD32 card32 = n_desktops;
+
+ wm->n_desktops = n_desktops;
+
+ XChangeProperty(wm->xdpy, wm->root_win->xwindow,
+ wm->atoms[MBWM_ATOM_NET_NUMBER_OF_DESKTOPS],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)&card32, 1);
+
+ /* FIXME -- deal with the case where the number is shrinking */
+}
+
+
+void
+mb_wm_select_desktop (MBWindowManager *wm, int desktop)
+{
+ CARD32 card32 = desktop;
+ MBWindowManagerClient *c;
+ int old_desktop;
+
+ if (desktop == wm->active_desktop)
+ return;
+
+ old_desktop = wm->active_desktop;
+
+ wm->active_desktop = desktop;
+
+ if (desktop >= wm->n_desktops)
+ {
+ mb_wm_set_n_desktops (wm, desktop + 1);
+ }
+
+ mb_wm_stack_enumerate (wm, c)
+ mb_wm_client_desktop_change (c, desktop);
+
+ XChangeProperty(wm->xdpy, wm->root_win->xwindow,
+ wm->atoms[MBWM_ATOM_NET_CURRENT_DESKTOP],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)&card32, 1);
+
+#if ENABLE_COMPOSITE
+ if (mb_wm_compositing_enabled (wm))
+ mb_wm_comp_mgr_select_desktop (wm->comp_mgr, desktop, old_desktop);
+#endif
+}
+
diff --git a/matchbox2/core/mb-window-manager.h b/matchbox2/core/mb-window-manager.h
new file mode 100644
index 0000000..e82b931
--- /dev/null
+++ b/matchbox2/core/mb-window-manager.h
@@ -0,0 +1,231 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005, 2007 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _HAVE_MB_WM_WINDOW_MANAGER_H
+#define _HAVE_MB_WM_WINDOW_MANAGER_H
+
+#include <matchbox2/mb-wm-config.h>
+#include <matchbox2/core/mb-wm-object.h>
+#include <matchbox2/core/mb-wm-root-window.h>
+#include <matchbox2/core/xas.h>
+
+typedef struct MBWindowManagerClass MBWindowManagerClass;
+typedef struct MBWindowManagerPriv MBWindowManagerPriv;
+
+#define MB_WINDOW_MANAGER(c) ((MBWindowManager*)(c))
+#define MB_WINDOW_MANAGER_CLASS(c) ((MBWindowManagerClass*)(c))
+#define MB_TYPE_WINDOW_MANAGER (mb_wm_class_type ())
+
+typedef enum MBWindowManagerFlag
+{
+ MBWindowManagerFlagDesktop = (1<<0),
+ MBWindowManagerFlagAlwaysReloadTheme = (1<<1),
+} MBWindowManagerFlag;
+
+typedef enum
+{
+ MBWindowManagerSignalThemeChange = 1,
+} MBWindowManagerSingal;
+
+typedef enum
+{
+ MBWindowManagerCursorNone = 0,
+ MBWindowManagerCursorLeftPtr,
+
+ _MBWindowManagerCursorLast
+} MBWindowManagerCursor;
+
+
+struct MBWindowManager
+{
+ MBWMObject parent;
+
+ Display *xdpy;
+ unsigned int xdpy_width, xdpy_height;
+ int xscreen;
+
+ MBWindowManagerClient *stack_top, *stack_bottom;
+ MBWMList *clients;
+ MBWindowManagerClient *desktop;
+ MBWindowManagerClient *focused_client;
+
+ int n_desktops;
+ int active_desktop;
+
+ Atom atoms[MBWM_ATOM_COUNT];
+
+ MBWMKeys *keys; /* Keybindings etc */
+
+ XasContext *xas_context;
+
+ /* ### Private ### */
+ MBWMSyncType sync_type;
+ int client_type_cnt;
+ int stack_n_clients;
+ MBWMRootWindow *root_win;
+
+ const char *sm_client_id;
+
+ MBWMTheme *theme;
+ MBWMLayout *layout;
+ MBWMMainContext *main_ctx;
+ MBWindowManagerFlag flags;
+#if ENABLE_COMPOSITE
+ MBWMCompMgr *comp_mgr;
+ int damage_event_base;
+#endif
+
+ MBWindowManagerCursor cursor;
+ Cursor cursors[_MBWindowManagerCursorLast];
+
+ /* Temporary stuff, only valid during object initialization */
+ const char *theme_path;
+
+ MBWMModality modality_type;
+
+ char **argv;
+ int argc;
+};
+
+struct MBWindowManagerClass
+{
+ MBWMObjectClass parent;
+
+ 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);
+ Bool (*client_hang) (MBWindowManager *wm, MBWindowManagerClient *c);
+
+ MBWMTheme * (*theme_new) (MBWindowManager *wm, const char * path);
+
+#if ENABLE_COMPOSITE
+ MBWMCompMgr * (*comp_mgr_new) (MBWindowManager *wm);
+#endif
+
+ void (*get_desktop_geometry) (MBWindowManager *wm, MBGeometry *geom);
+
+ 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_init (MBWindowManager * wm);
+
+void
+mb_wm_set_layout (MBWindowManager *wm, MBWMLayout *layout);
+
+int
+mb_wm_class_type ();
+
+void
+mb_wm_main_loop(MBWindowManager *wm);
+
+MBWindowManagerClient*
+mb_wm_managed_client_from_xwindow(MBWindowManager *wm, Window win);
+
+MBWindowManagerClient*
+mb_wm_managed_client_from_frame (MBWindowManager *wm, Window frame);
+
+int
+mb_wm_register_client_type (void);
+
+void
+mb_wm_manage_client (MBWindowManager *wm,
+ MBWindowManagerClient *client,
+ Bool activate);
+
+void
+mb_wm_unmanage_client (MBWindowManager *wm,
+ MBWindowManagerClient *client,
+ Bool destroy);
+
+void
+mb_wm_display_sync_queue (MBWindowManager* wm, MBWMSyncType sync);
+
+void
+mb_wm_get_display_geometry (MBWindowManager *wm,
+ MBGeometry *geometry);
+
+void
+mb_wm_activate_client(MBWindowManager * wm, MBWindowManagerClient *c);
+
+void
+mb_wm_handle_ping_reply (MBWindowManager * wm, MBWindowManagerClient *c);
+
+void
+mb_wm_handle_hang_client (MBWindowManager * wm, MBWindowManagerClient *c);
+
+void
+mb_wm_handle_show_desktop (MBWindowManager * wm, Bool show);
+
+void
+mb_wm_toggle_desktop (MBWindowManager * wm);
+
+MBWindowManagerClient*
+mb_wm_get_visible_main_client(MBWindowManager *wm);
+
+void
+mb_wm_unfocus_client (MBWindowManager *wm, MBWindowManagerClient *client);
+
+void
+mb_wm_cycle_apps (MBWindowManager *wm, Bool reverse);
+
+void
+mb_wm_set_theme (MBWindowManager *wm, MBWMTheme * theme);
+
+void
+mb_wm_set_theme_from_path (MBWindowManager *wm, const char *theme_path);
+
+void
+mb_wm_set_cursor (MBWindowManager * wm, MBWindowManagerCursor cursor);
+
+void
+mb_wm_compositing_on (MBWindowManager * wm);
+
+void
+mb_wm_compositing_off (MBWindowManager * wm);
+
+Bool
+mb_wm_compositing_enabled (MBWindowManager * wm);
+
+MBWMModality
+mb_wm_get_modality_type (MBWindowManager * wm);
+
+void
+mb_wm_sync (MBWindowManager *wm);
+
+void
+mb_wm_set_n_desktops (MBWindowManager *wm, int n_desktops);
+
+void
+mb_wm_select_desktop (MBWindowManager *wm, int desktop);
+
+#endif
diff --git a/matchbox2/core/mb-wm-atoms.c b/matchbox2/core/mb-wm-atoms.c
new file mode 100644
index 0000000..5d7e805
--- /dev/null
+++ b/matchbox2/core/mb-wm-atoms.c
@@ -0,0 +1,116 @@
+#include "mb-wm.h"
+
+void
+mb_wm_atoms_init(MBWindowManager *wm)
+{
+ /*
+ * The list below *MUST* be kept in the same order as the corresponding
+ * emun in structs.h or *everything* will break.
+ * Doing it like this avoids a mass of round trips on startup.
+ */
+
+ char *atom_names[] = {
+
+ "WM_NAME",
+ "WM_STATE",
+ "WM_HINTS",
+ "WM_NORMAL_HINTS",
+ "WM_CHANGE_STATE",
+ "WM_PROTOCOLS",
+ "WM_DELETE_WINDOW",
+ "WM_COLORMAP_WINDOWS",
+ "WM_CLIENT_MACHINE",
+ "WM_TRANSIENT_FOR",
+ "WM_TAKE_FOCUS",
+
+ "_NET_WM_WINDOW_TYPE",
+ "_NET_WM_WINDOW_TYPE_NORMAL",
+ "_NET_WM_WINDOW_TYPE_TOOLBAR",
+ "_NET_WM_WINDOW_TYPE_INPUT",
+ "_NET_WM_WINDOW_TYPE_DOCK",
+ "_NET_WM_WINDOW_TYPE_MENU",
+ "_NET_WM_WINDOW_TYPE_POPUP_MENU",
+ "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU",
+ "_NET_WM_WINDOW_TYPE_DIALOG",
+ "_NET_WM_WINDOW_TYPE_SPLASH",
+ "_NET_WM_WINDOW_TYPE_DESKTOP",
+ "_NET_WM_WINDOW_TYPE_NOTIFICATION",
+
+ "_NET_WM_STATE",
+ "_NET_WM_STATE_FULLSCREEN",
+ "_NET_WM_STATE_MODAL",
+ "_NET_WM_STATE_ABOVE",
+ "_NET_WM_STATE_STICKY",
+ "_NET_WM_STATE_MAXIMIZED_VERT",
+ "_NET_WM_STATE_MAXIMIZED_HORZ",
+ "_NET_WM_STATE_SHADED",
+ "_NET_WM_STATE_SKIP_TASKBAR",
+ "_NET_WM_STATE_SKIP_PAGER",
+ "_NET_WM_STATE_HIDDEN",
+ "_NET_WM_STATE_BELOW",
+ "_NET_WM_STATE_DEMANDS_ATTENTION",
+
+ "_NET_SUPPORTED",
+ "_NET_CLIENT_LIST",
+ "_NET_NUMBER_OF_DESKTOPS",
+ "_NET_ACTIVE_WINDOW",
+ "_NET_SUPPORTING_WM_CHECK",
+ "_NET_CLOSE_WINDOW",
+ "_NET_WM_NAME",
+ "_NET_WM_USER_TIME",
+
+ "_NET_CLIENT_LIST_STACKING",
+ "_NET_CURRENT_DESKTOP",
+ "_NET_WM_DESKTOP",
+ "_NET_WM_ICON",
+ "_NET_DESKTOP_GEOMETRY",
+ "_NET_WORKAREA",
+ "_NET_SHOWING_DESKTOP",
+ "_NET_DESKTOP_VIEWPORT",
+ "_NET_FRAME_EXTENTS",
+ "_NET_WM_FULL_PLACEMENT",
+
+ "_NET_WM_ALLOWED_ACTIONS",
+ "_NET_WM_ACTION_MOVE",
+ "_NET_WM_ACTION_RESIZE",
+ "_NET_WM_ACTION_MINIMIZE",
+ "_NET_WM_ACTION_SHADE",
+ "_NET_WM_ACTION_STICK",
+ "_NET_WM_ACTION_MAXIMIZE_HORZ",
+ "_NET_WM_ACTION_MAXIMIZE_VERT",
+ "_NET_WM_ACTION_FULLSCREEN",
+ "_NET_WM_ACTION_CHANGE_DESKTOP",
+ "_NET_WM_ACTION_CLOSE",
+
+ "_NET_WM_PING",
+ "_NET_WM_PID",
+
+ "_NET_STARTUP_ID",
+
+ "UTF8_STRING",
+ "_MOTIF_WM_HINTS",
+ "WIN_SUPPORTING_WM_CHECK",
+
+ "_NET_WM_CONTEXT_HELP",
+ "_NET_WM_CONTEXT_ACCEPT",
+ "_NET_WM_CONTEXT_CUSTOM",
+ "_NET_WM_SYNC_REQUEST",
+ "CM_TRANSLUCENCY",
+ "_MB_APP_WINDOW_LIST_STACKING",
+ "_MB_THEME",
+ "_MB_THEME_NAME",
+ "_MB_COMMAND",
+ "_MB_GRAB_TRANSFER",
+ "_MB_CURRENT_APP_WINDOW",
+ };
+
+ /* FIXME: Error Traps */
+
+ MBWM_ASSERT (MBWM_ATOM_COUNT == sizeof (atom_names) / sizeof (char*));
+
+ XInternAtoms (wm->xdpy,
+ atom_names,
+ MBWM_ATOM_COUNT,
+ False,
+ wm->atoms);
+}
diff --git a/matchbox2/core/mb-wm-atoms.h b/matchbox2/core/mb-wm-atoms.h
new file mode 100644
index 0000000..ef06083
--- /dev/null
+++ b/matchbox2/core/mb-wm-atoms.h
@@ -0,0 +1,27 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_ATOMS_H
+#define _HAVE_MB_WM_ATOMS_H
+
+void
+mb_wm_atoms_init(MBWindowManager *wm);
+
+#endif
diff --git a/matchbox2/core/mb-wm-client-base.c b/matchbox2/core/mb-wm-client-base.c
new file mode 100644
index 0000000..daa679d
--- /dev/null
+++ b/matchbox2/core/mb-wm-client-base.c
@@ -0,0 +1,742 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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-theme.h"
+
+#include <X11/Xmd.h>
+
+#if ENABLE_COMPOSITE
+#include <X11/extensions/Xrender.h>
+#endif
+
+#ifdef HAVE_XEXT
+#include <X11/extensions/shape.h>
+#endif
+
+static void
+mb_wm_client_base_realize (MBWindowManagerClient *client);
+
+static void
+mb_wm_client_base_stack (MBWindowManagerClient *client,
+ int flags);
+static void
+mb_wm_client_base_show (MBWindowManagerClient *client);
+
+static void
+mb_wm_client_base_hide (MBWindowManagerClient *client);
+
+
+static void
+mb_wm_client_base_display_sync (MBWindowManagerClient *client);
+
+static Bool
+mb_wm_client_base_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags);
+
+static Bool
+mb_wm_client_base_focus (MBWindowManagerClient *client);
+
+static void
+mb_wm_client_base_class_init (MBWMObjectClass *klass)
+{
+ MBWindowManagerClientClass *client;
+
+ MBWM_MARK();
+
+ client = (MBWindowManagerClientClass *)klass;
+
+ client->realize = mb_wm_client_base_realize;
+ client->geometry = mb_wm_client_base_request_geometry;
+ client->stack = mb_wm_client_base_stack;
+ client->show = mb_wm_client_base_show;
+ client->hide = mb_wm_client_base_hide;
+ client->sync = mb_wm_client_base_display_sync;
+ client->focus = mb_wm_client_base_focus;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMClientBase";
+#endif
+}
+
+static void
+mb_wm_client_base_destroy (MBWMObject *this)
+{
+ MBWindowManagerClient *parent;
+ MBWindowManagerClient *client;
+ MBWindowManager *wm;
+
+ MBWM_MARK();
+
+ client = MB_WM_CLIENT(this);
+
+ wm = client->wmref;
+
+ mb_wm_util_trap_x_errors();
+
+ if (client->xwin_frame)
+ {
+ XReparentWindow (wm->xdpy, MB_WM_CLIENT_XWIN(client),
+ wm->root_win->xwindow, 0, 0);
+
+ XDestroyWindow (wm->xdpy, client->xwin_frame);
+ client->xwin_frame = None;
+
+
+ if (client->xwin_modal_blocker)
+ {
+ XDestroyWindow (wm->xdpy, client->xwin_modal_blocker);
+ client->xwin_modal_blocker = None;
+ }
+ }
+
+ XSync(wm->xdpy, False);
+ mb_wm_util_untrap_x_errors();
+
+ parent = mb_wm_client_get_transient_for (MB_WM_CLIENT(this));
+
+ if (parent)
+ mb_wm_client_remove_transient (parent, MB_WM_CLIENT(this));
+}
+
+static int
+mb_wm_client_base_init (MBWMObject *this, va_list vap)
+{
+ return 1;
+}
+
+int
+mb_wm_client_base_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMClientBaseClass),
+ sizeof (MBWMClientBase),
+ mb_wm_client_base_init,
+ mb_wm_client_base_destroy,
+ mb_wm_client_base_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_CLIENT, 0);
+ }
+
+ return type;
+}
+
+static void
+mb_wm_client_base_realize (MBWindowManagerClient *client)
+{
+ MBWindowManager *wm = client->wmref;
+
+ XSetWindowAttributes attr;
+
+ MBWM_ASSERT(client->window != NULL);
+
+ /* create the frame window */
+
+ attr.override_redirect = True;
+ attr.background_pixel = BlackPixel(wm->xdpy, wm->xscreen);
+ attr.event_mask = MBWMChildMask|MBWMButtonMask|ExposureMask;
+
+ /* This should probably be called via rather than on new clien sync() ...? */
+ /*
+ * We only create a frame window if the client is decorated (decors are
+ * constructed in the _init functions, so we can easily test if the frame
+ * is needed or not).
+ */
+ if (client->decor)
+ {
+ if (client->xwin_frame == None)
+ {
+#if ENABLE_COMPOSITE
+ if (mb_wm_client_is_argb32 (client))
+ {
+ attr.colormap = client->window->colormap;
+
+ client->xwin_frame
+ = XCreateWindow(wm->xdpy, wm->root_win->xwindow,
+ client->frame_geometry.x,
+ client->frame_geometry.y,
+ client->frame_geometry.width,
+ client->frame_geometry.height,
+ 0,
+ 32,
+ InputOutput,
+ client->window->visual,
+ CWOverrideRedirect|CWEventMask|CWBackPixel|
+ CWBorderPixel|CWColormap,
+ &attr);
+ }
+ else
+#endif
+ {
+ client->xwin_frame
+ = XCreateWindow(wm->xdpy, wm->root_win->xwindow,
+ client->frame_geometry.x,
+ client->frame_geometry.y,
+ client->frame_geometry.width,
+ client->frame_geometry.height,
+ 0,
+ CopyFromParent,
+ CopyFromParent,
+ CopyFromParent,
+ CWOverrideRedirect|CWEventMask|CWBackPixel,
+ &attr);
+ }
+
+ /*
+ * Assume geometry sync will fix this up correctly togeather with
+ * any decoration creation. Layout manager will call this
+ */
+ XReparentWindow(wm->xdpy,
+ MB_WM_CLIENT_XWIN(client),
+ client->xwin_frame,
+ 0, 0);
+ }
+ else
+ {
+ /*
+ * This is an undecorated client; we Must reparent the window to our
+ * root, otherwise we restacking of pre-existing windows might fail.
+ */
+ XReparentWindow(client->wmref->xdpy, MB_WM_CLIENT_XWIN(client),
+ client->wmref->root_win->xwindow, 0, 0);
+ }
+
+ /*
+ * If this is a system-modal client and the global setting is to support
+ * system modal windows, we create a fullscreen, input-only window that
+ * gets stacked immediately bellow it, catching any input events that
+ * fall outside of the system-modal client.
+ */
+ if (mb_wm_client_is_modal (client) &&
+ !mb_wm_client_get_transient_for (client) &&
+ mb_wm_get_modality_type (wm) == MBWMModalitySystem)
+ {
+ XSetWindowAttributes attr;
+ attr.override_redirect = True;
+ attr.event_mask = MBWMChildMask|ButtonPressMask|ExposureMask;
+
+ client->xwin_modal_blocker =
+ XCreateWindow (wm->xdpy,
+ wm->root_win->xwindow,
+ 0, 0,
+ wm->xdpy_width,
+ wm->xdpy_height,
+ 0,
+ CopyFromParent,
+ InputOnly,
+ CopyFromParent,
+ CWOverrideRedirect|CWEventMask,
+ &attr);
+ }
+ }
+
+ XSetWindowBorderWidth(wm->xdpy, MB_WM_CLIENT_XWIN(client), 0);
+
+ XAddToSaveSet(wm->xdpy, MB_WM_CLIENT_XWIN(client));
+
+ XSelectInput(wm->xdpy,
+ MB_WM_CLIENT_XWIN(client),
+ PropertyChangeMask);
+}
+
+static void
+mb_wm_client_base_stack (MBWindowManagerClient *client,
+ int flags)
+{
+ /* Stack to highest/lowest possible possition in stack */
+ MBWMList * t = mb_wm_client_get_transients (client);
+
+ mb_wm_stack_move_top(client);
+
+ mb_wm_util_list_foreach (t, (MBWMListForEachCB)mb_wm_client_stack,
+ (void*)flags);
+
+ mb_wm_util_list_free (t);
+}
+
+static void
+mb_wm_client_base_show (MBWindowManagerClient *client)
+{
+ /* mark dirty somehow */
+
+}
+
+static void
+mb_wm_client_base_hide (MBWindowManagerClient *client)
+{
+
+ /* mark dirty somehow */
+
+}
+
+static void
+mb_wm_client_base_set_state_props (MBWindowManagerClient *c)
+{
+ unsigned long flags = c->window->ewmh_state;
+ Window xwin = c->window->xwindow;
+ MBWindowManager *wm = c->wmref;
+ Display *xdpy = wm->xdpy;
+ CARD32 card32[2];
+ Atom ewmh_state [MBWMClientWindowEWHMStatesCount];
+ int ewmh_i = 0;
+
+ card32[1] = None;
+
+ if (mb_wm_client_is_mapped (c))
+ card32[0] = NormalState;
+ else
+ card32[0] = IconicState;
+
+ if (flags & MBWMClientWindowEWMHStateFullscreen)
+ ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_FULLSCREEN];
+
+ if (flags & MBWMClientWindowEWMHStateModal)
+ ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_MODAL];
+
+ if (flags & MBWMClientWindowEWMHStateSticky)
+ ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_STICKY];
+
+ if (flags & MBWMClientWindowEWMHStateMaximisedVert)
+ ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_MAXIMIZED_VERT];
+ if (flags & MBWMClientWindowEWMHStateMaximisedHorz)
+ ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_MAXIMIZED_HORZ];
+ if (flags & MBWMClientWindowEWMHStateShaded)
+ ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_SHADED];
+
+ if (flags & MBWMClientWindowEWMHStateSkipTaskbar)
+ ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_SKIP_TASKBAR];
+
+ if (flags & MBWMClientWindowEWMHStateSkipPager)
+ ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_SKIP_PAGER];
+
+ if (flags & MBWMClientWindowEWMHStateAbove)
+ ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_BELOW];
+
+ if (flags & MBWMClientWindowEWMHStateDemandsAttention)
+ ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_DEMANDS_ATTENTION];
+ if (flags & MBWMClientWindowEWMHStateHidden)
+ ewmh_state[ewmh_i++] = wm->atoms[MBWM_ATOM_NET_WM_STATE_HIDDEN];
+
+
+ XChangeProperty(xdpy, xwin, wm->atoms[MBWM_ATOM_WM_STATE],
+ wm->atoms[MBWM_ATOM_WM_STATE], 32, PropModeReplace,
+ (void *)&card32[0], 2);
+
+ if (ewmh_i)
+ XChangeProperty (xdpy, xwin, wm->atoms[MBWM_ATOM_NET_WM_STATE],
+ XA_ATOM, 32, PropModeReplace,
+ (void*) &ewmh_state[0], ewmh_i);
+ else
+ XDeleteProperty (xdpy, xwin, wm->atoms[MBWM_ATOM_NET_WM_STATE]);
+}
+
+static void
+send_synthetic_configure_notify (MBWindowManagerClient *client)
+{
+ MBWindowManager *wm = client->wmref;
+ XConfigureEvent ce;
+
+ ce.type = ConfigureNotify;
+ ce.event = MB_WM_CLIENT_XWIN(client);
+ ce.window = MB_WM_CLIENT_XWIN(client);
+ ce.x = client->window->geometry.x;
+ ce.y = client->window->geometry.y;
+ ce.width = client->window->geometry.width;
+ ce.height = client->window->geometry.height;
+ ce.border_width = 0;
+ ce.above = None;
+ ce.override_redirect = 0;
+
+ XSendEvent(wm->xdpy, MB_WM_CLIENT_XWIN(client), False,
+ StructureNotifyMask, (XEvent *)&ce);
+}
+
+static void
+move_resize_client_xwin (MBWindowManagerClient *client, int x, int y, int w, int h)
+{
+ MBWindowManager *wm = client->wmref;
+
+ /* ICCCM says if you ignore a configure request or you respond
+ * by only moving/re-stacking the window - without a size change,
+ * then the WM must send a synthetic ConfigureNotify.
+ *
+ * NB: the above description assumes that a move/re-stack may be
+ * done by the WM by moving the frame (whereby a regular
+ * ConfigureNotify wouldn't be sent in direct response to the
+ * request which I think is the real point)
+ *
+ * NB: It's assumed that no cleverness is going elsewhere
+ * to optimise out calls to this function when the move/resize
+ * is obviously not needed (e.g. when just moving the frame
+ * of a client)
+ */
+ if (mb_wm_client_needs_configure_request_ack (client)
+ && x == client->window->x_geometry.x
+ && y == client->window->x_geometry.y
+ && w == client->window->x_geometry.width
+ && h == client->window->x_geometry.height)
+ {
+ send_synthetic_configure_notify (client);
+ }
+ else
+ {
+ XMoveResizeWindow(wm->xdpy, MB_WM_CLIENT_XWIN(client),
+ x, y, w, h);
+ client->window->x_geometry.x = x;
+ client->window->x_geometry.y = y;
+ client->window->x_geometry.width = w;
+ client->window->x_geometry.height = h;
+
+#if ENABLE_COMPOSITE
+ if (mb_wm_comp_mgr_enabled (wm->comp_mgr))
+ {
+ mb_wm_comp_mgr_client_configure (client->cm_client);
+ }
+#endif
+ }
+}
+
+static void
+mb_wm_client_base_display_sync (MBWindowManagerClient *client)
+{
+ MBWindowManager *wm = client->wmref;
+ MBWMClientWindow * win = client->window;
+ Bool fullscreen = (win->ewmh_state & MBWMClientWindowEWMHStateFullscreen);
+
+ MBWM_MARK();
+
+ /*
+ * If we need to sync due to change in fullscreen state, we have reparent
+ * the client window to the frame/root window
+ */
+ if (mb_wm_client_needs_fullscreen_sync (client))
+ {
+ if (mb_wm_client_is_mapped (client))
+ {
+ if (client->xwin_frame)
+ {
+ if (!fullscreen)
+ {
+ client->skip_unmaps++;
+ XReparentWindow(wm->xdpy, MB_WM_CLIENT_XWIN(client),
+ client->xwin_frame, 0, 0);
+ XMapWindow(wm->xdpy, client->xwin_frame);
+ XMapSubwindows(wm->xdpy, client->xwin_frame);
+
+ /* The frame is very likely the correct dimensions (since the
+ * app geometry is pretty static), but the client window is
+ * not (it was fullscreened) -- we need to force
+ * recalculation of the window frame dimensions, so that it
+ * is correct when we apply it below.
+ */
+ mb_wm_client_request_geometry (client,
+ &client->frame_geometry,
+ MBWMClientReqGeomForced);
+ }
+ else
+ {
+ client->skip_unmaps++;
+ XReparentWindow(wm->xdpy, MB_WM_CLIENT_XWIN(client),
+ wm->root_win->xwindow, 0, 0);
+ XUnmapWindow(wm->xdpy, client->xwin_frame);
+ XMapWindow(wm->xdpy, MB_WM_CLIENT_XWIN(client));
+ }
+ }
+ else
+ {
+ client->skip_unmaps++;
+ XReparentWindow(wm->xdpy, MB_WM_CLIENT_XWIN(client),
+ wm->root_win->xwindow,
+ client->window->geometry.x,
+ client->window->geometry.y);
+ }
+ }
+
+ if (wm->focused_client == client)
+ {
+ /*
+ * If we are the currently focused client,
+ * we need to reset the focus to RevertToPointerRoot, since the
+ * focus was lost during the implicit unmap.
+ */
+ XSetInputFocus (wm->xdpy, client->window->xwindow,
+ RevertToPointerRoot, CurrentTime);
+
+ }
+ }
+
+ /* Sync up any geometry */
+
+ if (mb_wm_client_needs_geometry_sync (client))
+ {
+ int x, y, w, h;
+ CARD32 wgeom[4];
+
+ mb_wm_util_trap_x_errors();
+
+ if (fullscreen || !client->xwin_frame)
+ {
+
+ x = client->window->geometry.x;
+ y = client->window->geometry.y;
+ w = client->window->geometry.width;
+ h = client->window->geometry.height;
+
+ move_resize_client_xwin (client, x, y, w, h);
+
+ wgeom[0] = 0;
+ wgeom[1] = 0;
+ wgeom[2] = 0;
+ wgeom[3] = 0;
+ }
+ else
+ {
+ XMoveResizeWindow(wm->xdpy,
+ client->xwin_frame,
+ client->frame_geometry.x,
+ client->frame_geometry.y,
+ client->frame_geometry.width,
+ client->frame_geometry.height);
+
+ /* FIXME: Call XConfigureWindow(w->dpy, e->window,
+ * value_mask,&xwc); here instead as can set border
+ * width = 0.
+ */
+ x = client->window->geometry.x - client->frame_geometry.x;
+ y = client->window->geometry.y - client->frame_geometry.y;
+ w = client->window->geometry.width;
+ h = client->window->geometry.height;
+
+ move_resize_client_xwin (client, x, y, w, h);
+
+ wgeom[0] = x;
+ wgeom[1] = client->frame_geometry.width - w - x;
+ wgeom[2] = y;
+ wgeom[3] = client->frame_geometry.height - h - y;
+ }
+
+ XChangeProperty(wm->xdpy,
+ MB_WM_CLIENT_XWIN(client),
+ wm->atoms[MBWM_ATOM_NET_FRAME_EXTENTS],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)&wgeom[0], 4);
+
+ /* FIXME: need flags to handle other stuff like configure events etc */
+
+ /* Resize any decor */
+ mb_wm_util_list_foreach(client->decor,
+ (MBWMListForEachCB)mb_wm_decor_handle_resize,
+ NULL);
+
+ mb_wm_util_untrap_x_errors();
+ }
+ else if (mb_wm_client_needs_configure_request_ack (client))
+ send_synthetic_configure_notify (client);
+
+
+ /* Handle any mapping - should be visible state ? */
+
+ if (mb_wm_client_needs_visibility_sync (client))
+ {
+ mb_wm_util_trap_x_errors();
+
+ if (mb_wm_client_is_mapped (client))
+ {
+ if (client->xwin_frame)
+ {
+ if (!fullscreen)
+ {
+ XMapWindow (wm->xdpy, client->xwin_frame);
+ XMapSubwindows (wm->xdpy, client->xwin_frame);
+ }
+ else
+ {
+ XUnmapWindow (wm->xdpy, client->xwin_frame);
+ XMapWindow (wm->xdpy, MB_WM_CLIENT_XWIN(client));
+ }
+ }
+ else
+ {
+ XMapWindow (wm->xdpy, MB_WM_CLIENT_XWIN(client));
+ }
+
+ if (client->xwin_modal_blocker)
+ XMapWindow (wm->xdpy, client->xwin_modal_blocker);
+ }
+ else
+ {
+ if (client->xwin_frame)
+ {
+ XUnmapWindow (wm->xdpy, client->xwin_frame);
+ XUnmapSubwindows (wm->xdpy, client->xwin_frame);
+ }
+ else
+ XUnmapWindow (wm->xdpy, MB_WM_CLIENT_XWIN(client));
+
+
+ if (client->xwin_modal_blocker)
+ XUnmapWindow (wm->xdpy, client->xwin_modal_blocker);
+
+ }
+
+ mb_wm_client_base_set_state_props (client);
+ mb_wm_util_untrap_x_errors();
+ }
+
+ /* Paint any decor */
+
+ mb_wm_util_trap_x_errors();
+
+ if (mb_wm_client_needs_decor_sync (client))
+ {
+ /*
+ * First, we set the base shape mask, if needed, so that individual
+ * decors can add themselves to it.
+ */
+#ifdef HAVE_XEXT
+ if (mb_wm_theme_is_client_shaped (wm->theme, client))
+ {
+ XRectangle rects[1];
+
+ rects[0].x = client->window->geometry.x - client->frame_geometry.x;
+ rects[0].y = client->window->geometry.y - client->frame_geometry.y;
+ rects[0].width = client->window->geometry.width;
+ rects[0].height = client->window->geometry.height;
+
+ XShapeCombineRectangles (wm->xdpy, client->xwin_frame,
+ ShapeBounding,
+ 0, 0, rects, 1, ShapeSet, 0 );
+ }
+#endif
+
+ if (fullscreen)
+ {
+ if (client->xwin_frame)
+ XUnmapWindow(wm->xdpy, client->xwin_frame);
+ }
+ else
+ {
+ if (client->xwin_frame)
+ XMapWindow(wm->xdpy, client->xwin_frame);
+ }
+
+ mb_wm_util_list_foreach(client->decor,
+ (MBWMListForEachCB)mb_wm_decor_handle_repaint,
+ NULL);
+
+
+ }
+
+ mb_wm_util_untrap_x_errors();
+
+ mb_wm_util_trap_x_errors();
+ XSync(wm->xdpy, False);
+ mb_wm_util_untrap_x_errors();
+}
+
+/* Note request geometry always called by layout manager */
+static Bool
+mb_wm_client_base_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags)
+{
+ /*
+ * flags are
+ *
+ * MBReqGeomDontCommit
+ * MBReqGeomIsViaConfigureReq
+ * MBReqGeomIsViaUserAction
+ * MBReqGeomIsViaLayoutManager
+ * MBReqGeomForced
+ *
+ */
+
+ /* Dont actually change anything - mb_wm_core_sync() should do that
+ * but mark dirty and 'queue any extra info like configure req'.
+ */
+
+ if (flags & MBWMClientReqGeomIsViaLayoutManager)
+ {
+ MBWM_DBG("called with 'MBWMClientReqGeomIsViaLayoutManager' %ix%i+%i+%i",
+ new_geometry->width,
+ new_geometry->height,
+ new_geometry->x,
+ new_geometry->y);
+
+ client->frame_geometry.x = new_geometry->x;
+ client->frame_geometry.y = new_geometry->y;
+ client->frame_geometry.width = new_geometry->width;
+ client->frame_geometry.height = new_geometry->height;
+
+ client->window->geometry.x = client->frame_geometry.x + 4;
+ client->window->geometry.y = client->frame_geometry.y + 4;
+ client->window->geometry.width = client->frame_geometry.width - 8;
+ client->window->geometry.height = client->frame_geometry.height - 8;
+
+ mb_wm_client_geometry_mark_dirty (client);
+
+ return True; /* Geometry accepted */
+ }
+
+ return True;
+}
+
+static Bool
+mb_wm_client_base_focus (MBWindowManagerClient *client)
+{
+ static Window last_focused = None;
+ MBWindowManager *wm = client->wmref;
+ Window xwin = client->window->xwindow;
+
+ if (!mb_wm_client_want_focus (client))
+ return False;
+
+ if (xwin == last_focused)
+ return False;
+
+ mb_wm_util_trap_x_errors ();
+
+ XSetInputFocus(wm->xdpy, xwin, RevertToPointerRoot, CurrentTime);
+
+ XChangeProperty(wm->xdpy, wm->root_win->xwindow,
+ wm->atoms[MBWM_ATOM_NET_ACTIVE_WINDOW],
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)&xwin, 1);
+
+ if (mb_wm_util_untrap_x_errors())
+ return False;
+
+ last_focused = xwin;
+
+ return True;
+}
+
+void base_foo(void)
+{
+ ; /* nasty hack to workaround linking issues WTF...
+ * use .la's rather than .a's ??
+ */
+}
diff --git a/matchbox2/core/mb-wm-client-base.h b/matchbox2/core/mb-wm-client-base.h
new file mode 100644
index 0000000..edc8008
--- /dev/null
+++ b/matchbox2/core/mb-wm-client-base.h
@@ -0,0 +1,46 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_CLIENT_BASE_H
+#define _HAVE_MB_WM_CLIENT_BASE_H
+
+#define MB_WM_CLIENT_BASE(c) ((MBWMClientBase*)(c))
+#define MB_WM_CLIENT_BASE_CLASS(c) ((MBWMClientBaseClass*)(c))
+#define MB_WM_TYPE_CLIENT_BASE (mb_wm_client_base_class_type ())
+
+typedef struct MBWMClientBase
+{
+ MBWindowManagerClient parent;
+}
+MBWMClientBase;
+
+typedef struct MBWMClientBaseClass
+{
+ MBWindowManagerClientClass parent;
+
+}
+MBWMClientBaseClass;
+
+int
+mb_wm_client_base_class_type ();
+
+void base_foo(void);
+
+#endif
diff --git a/matchbox2/core/mb-wm-client-window.c b/matchbox2/core/mb-wm-client-window.c
new file mode 100644
index 0000000..f2dbc74
--- /dev/null
+++ b/matchbox2/core/mb-wm-client-window.c
@@ -0,0 +1,1013 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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"
+
+/* Via Xatomtype.h */
+#define NumPropWMHintsElements 9 /* number of elements in this structure */
+#define NumPropWMSizeHintsElements 18
+
+enum {
+ COOKIE_WIN_TYPE = 0,
+ COOKIE_WIN_ATTR,
+ COOKIE_WIN_GEOM,
+ COOKIE_WIN_NAME,
+ COOKIE_WIN_NAME_UTF8,
+ COOKIE_WIN_WM_HINTS,
+ COOKIE_WIN_WM_NORMAL_HINTS,
+ COOKIE_WIN_TRANSIENCY,
+ COOKIE_WIN_PROTOS,
+ COOKIE_WIN_MACHINE,
+ COOKIE_WIN_PID,
+ COOKIE_WIN_ICON,
+ COOKIE_WIN_ACTIONS,
+ COOKIE_WIN_USER_TIME,
+ COOKIE_WIN_CM_TRANSLUCENCY,
+ COOKIE_WIN_NET_STATE,
+ COOKIE_WIN_MWM_HINTS,
+
+ N_COOKIES
+};
+
+#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
+#define MWM_HINTS_DECORATIONS (1L << 1)
+
+#define MWM_DECOR_BORDER (1L << 1)
+#define MWM_DECOR_RESIZEH (1L << 2)
+#define MWM_DECOR_TITLE (1L << 3)
+#define MWM_DECOR_MENU (1L << 4)
+#define MWM_DECOR_MINIMIZE (1L << 5)
+#define MWM_DECOR_MAXIMIZE (1L << 6)
+
+static void
+mb_wm_client_window_class_init (MBWMObjectClass *klass)
+{
+ MBWMClientWindowClass *rw_class;
+
+ MBWM_MARK();
+
+ rw_class = (MBWMClientWindowClass *)klass;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMClientWindow";
+#endif
+}
+
+static void
+mb_wm_client_window_destroy (MBWMObject *this)
+{
+ MBWMClientWindow * win = MB_WM_CLIENT_WINDOW (this);
+ MBWMList * l = win->icons;
+
+ if (win->name)
+ XFree (win->name);
+
+ if (win->machine)
+ XFree (win->machine);
+
+ if (win->net_type_full)
+ XFree (win->net_type_full);
+
+ while (l)
+ {
+ mb_wm_rgba_icon_free ((MBWMRgbaIcon *)l->data);
+ l = l->next;
+ }
+}
+
+static int
+mb_wm_client_window_init (MBWMObject *this, va_list vap)
+{
+ MBWMClientWindow *win = MB_WM_CLIENT_WINDOW (this);
+ MBWMObjectProp prop;
+ MBWindowManager *wm = NULL;
+ Window xwin = None;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropWm:
+ wm = va_arg(vap, MBWindowManager *);
+ break;
+ case MBWMObjectPropXwindow:
+ xwin = va_arg(vap, Window);
+ break;
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ if (!wm || !xwin)
+ {
+ fprintf (stderr, "--- error, no wm or xwin ---\n");
+ return 0;
+ }
+
+ win->xwindow = xwin;
+ win->wm = wm;
+
+ mb_wm_client_window_sync_properties (win, MBWM_WINDOW_PROP_ALL);
+
+ return 1;
+}
+
+int
+mb_wm_client_window_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMClientWindowClass),
+ sizeof (MBWMClientWindow),
+ mb_wm_client_window_init,
+ mb_wm_client_window_destroy,
+ mb_wm_client_window_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+MBWMClientWindow*
+mb_wm_client_window_new (MBWindowManager *wm, Window xwin)
+{
+ MBWMClientWindow *win;
+
+ win = MB_WM_CLIENT_WINDOW (mb_wm_object_new (MB_WM_TYPE_CLIENT_WINDOW,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropXwindow, xwin,
+ NULL));
+ return win;
+}
+
+/*
+ * Creates MBWMIcon from raw _NET_WM_ICON property data, returning
+ * pointer to where the next icon might be in the data
+ */
+static unsigned long *
+icon_from_net_wm_icon (unsigned long * data, MBWMRgbaIcon ** mb_icon)
+{
+ MBWMRgbaIcon * icon = mb_wm_rgba_icon_new ();
+ size_t byte_len;
+
+ *mb_icon = icon;
+
+ if (!icon)
+ return data;
+
+ icon->width = *data++;
+ icon->height = *data++;
+
+ byte_len = sizeof (unsigned long) * icon->width * icon->height;
+
+ icon->pixels = malloc (byte_len);
+
+ if (!icon->pixels)
+ {
+ mb_wm_rgba_icon_free (icon);
+ *mb_icon = NULL;
+ return (data - 2);
+ }
+
+ memcpy (icon->pixels, data, byte_len);
+
+ MBWM_DBG("@@@ Icon %d x %d @@@", icon->width, icon->height);
+
+ return (data + icon->width * icon->height);
+}
+
+Bool
+mb_wm_client_window_sync_properties ( MBWMClientWindow *win,
+ unsigned long props_req)
+{
+ MBWMCookie cookies[N_COOKIES];
+ MBWindowManager *wm = win->wm;
+ Atom actual_type_return, *result_atom = NULL;
+ int actual_format_return;
+ unsigned long nitems_return;
+ unsigned long bytes_after_return;
+ unsigned int foo;
+ int x_error_code;
+ Window xwin;
+ int changes = 0;
+
+ MBWMClientWindowAttributes *xwin_attr = NULL;
+
+ xwin = win->xwindow;
+
+ if (props_req & MBWM_WINDOW_PROP_WIN_TYPE)
+ cookies[COOKIE_WIN_TYPE]
+ = mb_wm_property_atom_req(wm, xwin,
+ wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE]);
+
+ if (props_req & MBWM_WINDOW_PROP_NET_STATE)
+ cookies[COOKIE_WIN_NET_STATE]
+ = mb_wm_property_atom_req(wm, xwin,
+ wm->atoms[MBWM_ATOM_NET_WM_STATE]);
+
+ if (props_req & MBWM_WINDOW_PROP_ATTR)
+ cookies[COOKIE_WIN_ATTR]
+ = mb_wm_xwin_get_attributes (wm, xwin);
+
+ if (props_req & MBWM_WINDOW_PROP_GEOMETRY)
+ cookies[COOKIE_WIN_GEOM]
+ = mb_wm_xwin_get_geometry (wm, (Drawable)xwin);
+
+ if (props_req & MBWM_WINDOW_PROP_NAME)
+ {
+ cookies[COOKIE_WIN_NAME]
+ = mb_wm_property_req (wm,
+ xwin,
+ wm->atoms[MBWM_ATOM_WM_NAME],
+ 0,
+ 2048L,
+ False,
+ XA_STRING);
+
+ cookies[COOKIE_WIN_NAME_UTF8] =
+ mb_wm_property_utf8_req(wm, xwin,
+ wm->atoms[MBWM_ATOM_NET_WM_NAME]);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_WM_HINTS)
+ {
+ cookies[COOKIE_WIN_WM_HINTS]
+ = mb_wm_property_req (wm,
+ xwin,
+ wm->atoms[MBWM_ATOM_WM_HINTS],
+ 0,
+ 1024L,
+ False,
+ XA_WM_HINTS);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_WM_NORMAL_HINTS)
+ {
+ cookies[COOKIE_WIN_WM_NORMAL_HINTS]
+ = mb_wm_property_req (wm,
+ xwin,
+ wm->atoms[MBWM_ATOM_WM_NORMAL_HINTS],
+ 0,
+ 1024L,
+ False,
+ XA_WM_SIZE_HINTS);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_MWM_HINTS)
+ {
+ cookies[COOKIE_WIN_MWM_HINTS]
+ = mb_wm_property_req (wm,
+ xwin,
+ wm->atoms[MBWM_ATOM_MOTIF_WM_HINTS],
+ 0,
+ PROP_MOTIF_WM_HINTS_ELEMENTS,
+ False,
+ wm->atoms[MBWM_ATOM_MOTIF_WM_HINTS]);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_TRANSIENCY)
+ {
+ cookies[COOKIE_WIN_TRANSIENCY]
+ = mb_wm_property_req (wm,
+ xwin,
+ wm->atoms[MBWM_ATOM_WM_TRANSIENT_FOR],
+ 0,
+ 1L,
+ False,
+ XA_WINDOW);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_PROTOS)
+ {
+ cookies[COOKIE_WIN_PROTOS]
+ = mb_wm_property_atom_req(wm, xwin,
+ wm->atoms[MBWM_ATOM_WM_PROTOCOLS]);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_CLIENT_MACHINE)
+ {
+ cookies[COOKIE_WIN_MACHINE]
+ = mb_wm_property_req (wm,
+ xwin,
+ wm->atoms[MBWM_ATOM_WM_CLIENT_MACHINE],
+ 0,
+ 2048L,
+ False,
+ XA_STRING);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_NET_PID)
+ {
+ cookies[COOKIE_WIN_PID]
+ = mb_wm_property_cardinal_req (wm,
+ xwin,
+ wm->atoms[MBWM_ATOM_NET_WM_PID]);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_NET_ICON)
+ {
+ cookies[COOKIE_WIN_ICON]
+ = mb_wm_property_cardinal_req (wm,
+ xwin,
+ wm->atoms[MBWM_ATOM_NET_WM_ICON]);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_NET_USER_TIME)
+ {
+ cookies[COOKIE_WIN_USER_TIME]
+ = mb_wm_property_cardinal_req (wm,
+ xwin,
+ wm->atoms[MBWM_ATOM_NET_WM_USER_TIME]);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_CM_TRANSLUCENCY)
+ {
+ cookies[COOKIE_WIN_CM_TRANSLUCENCY]
+ = mb_wm_property_cardinal_req (wm,
+ xwin,
+ wm->atoms[MBWM_ATOM_CM_TRANSLUCENCY]);
+ }
+
+ /* bundle all pending requests to server and wait for replys */
+ XSync(wm->xdpy, False);
+
+ if (props_req & MBWM_WINDOW_PROP_WIN_TYPE)
+ {
+ mb_wm_property_reply (wm,
+ cookies[COOKIE_WIN_TYPE],
+ &actual_type_return,
+ &actual_format_return,
+ &nitems_return,
+ &bytes_after_return,
+ (unsigned char **)&result_atom,
+ &x_error_code);
+
+ if (x_error_code
+ || actual_type_return != XA_ATOM
+ || actual_format_return != 32
+ || result_atom == NULL
+ )
+ {
+ MBWM_DBG("### Warning net type prop failed ###");
+
+ if (result_atom)
+ XFree(result_atom);
+ }
+ else
+ {
+ int i;
+ Atom type = None;
+
+ for (i = 0; i < nitems_return; ++i)
+ {
+ Atom t = result_atom[i];
+
+ if (t == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_NORMAL] ||
+ t == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR] ||
+ t == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_INPUT] ||
+ t == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DOCK] ||
+ t == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_MENU] ||
+ t == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU] ||
+ t == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU] ||
+ t == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DIALOG] ||
+ t == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_SPLASH] ||
+ t == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DESKTOP] ||
+ t == wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION])
+ {
+ type = t;
+ break;
+ }
+ }
+
+ if (type != None)
+ {
+ if (win->net_type != type)
+ changes |= MBWM_WINDOW_PROP_WIN_TYPE;
+
+ win->net_type = type;
+ }
+
+ if (win->net_type_full)
+ XFree (win->net_type_full);
+
+ win->net_type_full = result_atom;
+ win->net_type_full_size = nitems_return;
+ }
+
+ result_atom = NULL;
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_NET_STATE)
+ {
+ mb_wm_property_reply (wm,
+ cookies[COOKIE_WIN_NET_STATE],
+ &actual_type_return,
+ &actual_format_return,
+ &nitems_return,
+ &bytes_after_return,
+ (unsigned char **)&result_atom,
+ &x_error_code);
+
+ if (x_error_code
+ || actual_type_return != XA_ATOM
+ || actual_format_return != 32
+ || nitems_return <= 0
+ || result_atom == NULL
+ )
+ {
+ MBWM_DBG("### Warning net type state failed ###");
+ }
+ else
+ {
+ int i;
+ win->ewmh_state = 0;
+
+ for (i = 0; i < nitems_return; ++i)
+ {
+ if (result_atom[i] == wm->atoms[MBWM_ATOM_NET_WM_STATE_MODAL])
+ win->ewmh_state |= MBWMClientWindowEWMHStateModal;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_STICKY])
+ win->ewmh_state |= MBWMClientWindowEWMHStateSticky;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_MAXIMIZED_VERT])
+ win->ewmh_state |= MBWMClientWindowEWMHStateMaximisedVert;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_MAXIMIZED_HORZ])
+ win->ewmh_state |= MBWMClientWindowEWMHStateMaximisedHorz;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_SHADED])
+ win->ewmh_state |= MBWMClientWindowEWMHStateShaded;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_SKIP_TASKBAR])
+ win->ewmh_state |= MBWMClientWindowEWMHStateSkipTaskbar;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_SKIP_PAGER])
+ win->ewmh_state |= MBWMClientWindowEWMHStateSkipPager;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_HIDDEN])
+ win->ewmh_state |= MBWMClientWindowEWMHStateHidden;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_FULLSCREEN])
+ win->ewmh_state |= MBWMClientWindowEWMHStateFullscreen;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_ABOVE])
+ win->ewmh_state |= MBWMClientWindowEWMHStateAbove;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_BELOW])
+ win->ewmh_state |= MBWMClientWindowEWMHStateBelow;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_DEMANDS_ATTENTION])
+ win->ewmh_state |= MBWMClientWindowEWMHStateDemandsAttention;
+ }
+ }
+
+ changes |= MBWM_WINDOW_PROP_NET_STATE;
+
+ if (result_atom)
+ XFree(result_atom);
+
+ result_atom = NULL;
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_GEOMETRY)
+ {
+ if (!mb_wm_xwin_get_geometry_reply (wm,
+ cookies[COOKIE_WIN_GEOM],
+ &win->x_geometry,
+ &foo,
+ &win->depth,
+ &x_error_code))
+ {
+ MBWM_DBG("### Warning Get Geometry Failed ( %i ) ###",
+ x_error_code);
+ MBWM_DBG("### Cookie ID was %li ###",
+ cookies[COOKIE_WIN_GEOM]);
+ goto abort;
+ }
+
+ MBWM_DBG("@@@ New Window Obj @@@");
+ MBWM_DBG("Win: %lx", win->xwindow);
+ MBWM_DBG("Type: %lx",win->net_type);
+ MBWM_DBG("Geom: +%i+%i,%ix%i",
+ win->x_geometry.x,
+ win->x_geometry.y,
+ win->x_geometry.width,
+ win->x_geometry.height);
+
+ /* FIXME is it right that we directly/immeditaly update
+ * win->geometry here, perhaps that should be left as a
+ * responsability for a signal handler? */
+ win->geometry = win->x_geometry;
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_ATTR)
+ {
+ xwin_attr = mb_wm_xwin_get_attributes_reply (wm,
+ cookies[COOKIE_WIN_ATTR],
+ &x_error_code);
+
+ if (!xwin_attr || x_error_code)
+ {
+ MBWM_DBG("### Warning Get Attr Failed ( %i ) ###", x_error_code);
+ goto abort;
+ }
+
+ win->visual = xwin_attr->visual;
+ win->colormap = xwin_attr->colormap;
+
+ /* Window gravity should not be set from the window attribute
+ * but using the WM_NORMAL_HINTS atom
+ */
+
+ /* win->gravity = xwin_attr->win_gravity;*/
+ win->override_redirect = xwin_attr->override_redirect;
+ win->window_class = xwin_attr->class;
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_NAME)
+ {
+ if (win->name)
+ XFree(win->name);
+
+ /* Prefer UTF8 Naming... */
+ win->name
+ = mb_wm_property_get_reply_and_validate (wm,
+ cookies[COOKIE_WIN_NAME_UTF8],
+ wm->atoms[MBWM_ATOM_UTF8_STRING],
+ 8,
+ 0,
+ NULL,
+ &x_error_code);
+
+ /* FIXME: Validate the UTF8 */
+
+ if (!win->name)
+ {
+ /* FIXME: Should flag up name could be in some wacko encoding ? */
+ win->name
+ = mb_wm_property_get_reply_and_validate (wm,
+ cookies[COOKIE_WIN_NAME],
+ XA_STRING,
+ 8,
+ 0,
+ NULL,
+ &x_error_code);
+ }
+
+ if (win->name == NULL)
+ win->name = strdup("unknown");
+
+ MBWM_DBG("@@@ New Window Name: '%s' @@@", win->name);
+
+ changes |= MBWM_WINDOW_PROP_NAME;
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_WM_HINTS)
+ {
+ XWMHints *wmhints = NULL;
+
+ /* NOTE: pre-R3 X strips group element so will faill for that */
+ wmhints = mb_wm_property_get_reply_and_validate (wm,
+ cookies[COOKIE_WIN_WM_HINTS],
+ XA_WM_HINTS,
+ 32,
+ NumPropWMHintsElements,
+ NULL,
+ &x_error_code);
+
+ if (wmhints)
+ {
+ MBWM_DBG("@@@ New Window WM Hints @@@");
+
+ if (wmhints->flags & InputHint)
+ {
+ win->want_key_input = wmhints->input;
+ MBWM_DBG("Want key input: %s", wmhints->input ? "yes" : "no" );
+ }
+
+ if (wmhints->flags & StateHint)
+ {
+ win->initial_state = wmhints->initial_state;
+ MBWM_DBG("Initial State : %i", wmhints->initial_state );
+ }
+
+ if (wmhints->flags & IconPixmapHint)
+ {
+ win->icon_pixmap = wmhints->icon_pixmap;
+ MBWM_DBG("Icon Pixmap : %lx", wmhints->icon_pixmap );
+ }
+
+ if (wmhints->flags & IconMaskHint)
+ {
+ win->icon_pixmap_mask = wmhints->icon_mask;
+ MBWM_DBG("Icon Mask : %lx", wmhints->icon_mask );
+ }
+
+ if (wmhints->flags & WindowGroupHint)
+ {
+ win->xwin_group = wmhints->window_group;
+ MBWM_DBG("Window Group : %lx", wmhints->window_group );
+ }
+
+ /* NOTE: we ignore icon window stuff */
+
+ XFree(wmhints);
+
+ /* FIXME: should track better if thus has changed or not */
+ changes |= MBWM_WINDOW_PROP_WM_HINTS;
+ }
+ }
+ if (props_req & MBWM_WINDOW_PROP_WM_NORMAL_HINTS)
+ {
+ XSizeHints *sizehints = NULL;
+
+ sizehints = mb_wm_property_get_reply_and_validate (wm,
+ cookies[COOKIE_WIN_WM_NORMAL_HINTS],
+ XA_WM_SIZE_HINTS,
+ 32,
+ NumPropWMSizeHintsElements,
+ NULL,
+ &x_error_code);
+ if (sizehints)
+ {
+ MBWM_DBG("@@@ New Window WM Normal Hints @@@");
+
+ if (sizehints->flags & PWinGravity)
+ {
+ win->gravity = sizehints->win_gravity;
+ MBWM_DBG("Window Gravity : %i", sizehints->win_gravity);
+ }
+
+ win->user_pos = (sizehints->flags & USPosition) ? True : False;
+ MBWM_DBG ("User positioning : %s", win->user_pos ? "yes" : "no");
+
+ /* May be used to recover other information */
+
+ XFree (sizehints);
+
+ changes |= MBWM_WINDOW_PROP_WM_NORMAL_HINTS;
+ }
+
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_MWM_HINTS)
+ {
+ /*
+ * Handle the Motif decoration hint (Gtk uses it).
+ *
+ * We currently only differentiate between decorated and undecorated
+ * windows, but do not allow finer customisation of the decor.
+ */
+ typedef struct
+ {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long status;
+ } MotifWmHints;
+
+ MotifWmHints *mwmhints = NULL;
+
+ mwmhints =
+ mb_wm_property_get_reply_and_validate (wm,
+ cookies[COOKIE_WIN_MWM_HINTS],
+ wm->atoms[MBWM_ATOM_MOTIF_WM_HINTS],
+ 32,
+ PROP_MOTIF_WM_HINTS_ELEMENTS,
+ NULL,
+ &x_error_code);
+
+ if (mwmhints)
+ {
+ MBWM_DBG("@@@ New Window Motif WM Hints @@@");
+
+ if (mwmhints->flags & MWM_HINTS_DECORATIONS)
+ {
+ if (mwmhints->decorations == 0)
+ {
+ win->undecorated = TRUE;
+ }
+ }
+
+ XFree(mwmhints);
+
+ /* FIXME: should track better if thus has changed or not */
+ changes |= MBWM_WINDOW_PROP_MWM_HINTS;
+ }
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_TRANSIENCY)
+ {
+ Window *trans_win = NULL;
+
+ trans_win
+ = mb_wm_property_get_reply_and_validate (wm,
+ cookies[COOKIE_WIN_TRANSIENCY],
+ MBWM_ATOM_WM_TRANSIENT_FOR,
+ 32,
+ 1,
+ NULL,
+ &x_error_code);
+
+ if (trans_win)
+ {
+ MBWM_DBG("@@@ Window transient for %lx @@@", *trans_win);
+
+ if (*trans_win != win->xwin_transient_for)
+ changes |= MBWM_WINDOW_PROP_TRANSIENCY;
+
+ win->xwin_transient_for = *trans_win;
+ XFree(trans_win);
+ }
+ else MBWM_DBG("@@@ Window transient for nothing @@@");
+
+ changes |= MBWM_WINDOW_PROP_TRANSIENCY;
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_PROTOS)
+ {
+ mb_wm_property_reply (wm,
+ cookies[COOKIE_WIN_PROTOS],
+ &actual_type_return,
+ &actual_format_return,
+ &nitems_return,
+ &bytes_after_return,
+ (unsigned char **)&result_atom,
+ &x_error_code);
+
+ if (x_error_code
+ || actual_type_return != XA_ATOM
+ || actual_format_return != 32
+ || result_atom == NULL
+ )
+ {
+ MBWM_DBG("### Warning wm protocols prop failed ###");
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < nitems_return; ++i)
+ {
+ if (result_atom[i] == wm->atoms[MBWM_ATOM_WM_TAKE_FOCUS])
+ win->protos |= MBWMClientWindowProtosFocus;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_WM_DELETE_WINDOW])
+ win->protos |= MBWMClientWindowProtosDelete;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_HELP])
+ win->protos |= MBWMClientWindowProtosContextHelp;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_ACCEPT])
+ win->protos |= MBWMClientWindowProtosContextAccept;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_CUSTOM])
+ win->protos |= MBWMClientWindowProtosContextCustom;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_PING])
+ win->protos |= MBWMClientWindowProtosPing;
+ else if (result_atom[i] ==
+ wm->atoms[MBWM_ATOM_NET_WM_SYNC_REQUEST])
+ win->protos |= MBWMClientWindowProtosSyncRequest;
+ else
+ MBWM_DBG("Unhandled WM Protocol %d", result_atom[i]);
+ }
+ }
+
+ if (result_atom)
+ XFree(result_atom);
+
+ changes |= MBWM_WINDOW_PROP_PROTOS;
+
+ result_atom = NULL;
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_CLIENT_MACHINE)
+ {
+ if (win->machine)
+ XFree(win->machine);
+
+ win->machine
+ = mb_wm_property_get_reply_and_validate (wm,
+ cookies[COOKIE_WIN_MACHINE],
+ XA_STRING,
+ 8,
+ 0,
+ NULL,
+ &x_error_code);
+
+ if (!win->machine)
+ {
+ MBWM_DBG("### Warning wm client machine prop failed ###");
+ }
+ else
+ {
+ MBWM_DBG("@@@ Client machine %s @@@", win->machine);
+ }
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_NET_PID)
+ {
+ unsigned int *pid = NULL;
+
+ mb_wm_property_reply (wm,
+ cookies[COOKIE_WIN_PID],
+ &actual_type_return,
+ &actual_format_return,
+ &nitems_return,
+ &bytes_after_return,
+ (unsigned char **)&pid,
+ &x_error_code);
+
+ if (x_error_code
+ || actual_type_return != XA_CARDINAL
+ || actual_format_return != 32
+ || pid == NULL
+ )
+ {
+ MBWM_DBG("### Warning net pid prop failed ###");
+ }
+ else
+ {
+ win->pid = (pid_t) *pid;
+ MBWM_DBG("@@@ pid %d @@@", win->pid);
+ }
+
+ if (pid)
+ XFree(pid);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_CM_TRANSLUCENCY)
+ {
+ int *translucency = NULL;
+
+ mb_wm_property_reply (wm,
+ cookies[COOKIE_WIN_CM_TRANSLUCENCY],
+ &actual_type_return,
+ &actual_format_return,
+ &nitems_return,
+ &bytes_after_return,
+ (unsigned char **)&translucency,
+ &x_error_code);
+
+ if (x_error_code
+ || actual_type_return != XA_CARDINAL
+ || actual_format_return != 32
+ || translucency == NULL
+ )
+ {
+ MBWM_DBG("### no CM_TRANSLUCENCY prop ###");
+ win->translucency = -1;
+ }
+ else
+ {
+ win->translucency = *translucency;
+ MBWM_DBG("@@@ translucency %d @@@", win->translucency);
+ }
+
+ changes |= MBWM_WINDOW_PROP_CM_TRANSLUCENCY;
+
+ if (translucency)
+ XFree (translucency);
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_NET_ICON)
+ {
+ unsigned long *icons = NULL;
+
+ mb_wm_property_reply (wm,
+ cookies[COOKIE_WIN_ICON],
+ &actual_type_return,
+ &actual_format_return,
+ &nitems_return,
+ &bytes_after_return,
+ (unsigned char **)&icons,
+ &x_error_code);
+
+ if (x_error_code
+ || actual_type_return != XA_CARDINAL
+ || actual_format_return != 32
+ || icons == NULL
+ )
+ {
+ MBWM_DBG("### Warning net icon prop failed ###");
+ }
+ else
+ {
+ MBWMList *l = win->icons;
+ MBWMList *list_end = NULL;
+ unsigned long *p = icons;
+ unsigned long *p_end = icons + nitems_return;
+
+ while (l)
+ {
+ MBWMRgbaIcon * ic = l->data;
+
+ mb_wm_rgba_icon_free (ic);
+
+ l = l->next;
+ }
+
+ while (p < p_end)
+ {
+ l = mb_wm_util_malloc0 (sizeof (MBWMList));
+ p = icon_from_net_wm_icon (p, (MBWMRgbaIcon **)&l->data);
+
+ if (list_end)
+ {
+ l->prev = list_end;
+ list_end->next = l;
+ }
+ else
+ {
+ win->icons = l;
+ }
+
+ list_end = l;
+ }
+ }
+
+ if (icons)
+ XFree(icons);
+
+ changes |= MBWM_WINDOW_PROP_NET_ICON;
+
+ }
+
+ if (props_req & MBWM_WINDOW_PROP_NET_USER_TIME)
+ {
+ unsigned long *user_time = NULL;
+
+ mb_wm_property_reply (wm,
+ cookies[COOKIE_WIN_USER_TIME],
+ &actual_type_return,
+ &actual_format_return,
+ &nitems_return,
+ &bytes_after_return,
+ (unsigned char **)&user_time,
+ &x_error_code);
+
+ if (x_error_code
+ || actual_type_return != XA_CARDINAL
+ || actual_format_return != 32
+ || user_time == NULL
+ )
+ {
+ MBWM_DBG("### Warning _NET_WM_USER_TIME failed ###");
+ }
+ else
+ {
+ win->user_time = *user_time;
+ MBWM_DBG("@@@ user time %d @@@", win->user_time);
+ }
+
+ if (user_time)
+ XFree(user_time);
+ }
+
+
+ if (changes)
+ mb_wm_object_signal_emit (MB_WM_OBJECT (win), changes);
+
+ abort:
+
+ if (xwin_attr)
+ XFree(xwin_attr);
+
+ return True;
+}
+
+Bool
+mb_wm_client_window_is_state_set (MBWMClientWindow *win,
+ MBWMClientWindowEWMHState state)
+{
+ return (win->ewmh_state & state) ? True : False;
+}
+
diff --git a/matchbox2/core/mb-wm-client-window.h b/matchbox2/core/mb-wm-client-window.h
new file mode 100644
index 0000000..a898b6e
--- /dev/null
+++ b/matchbox2/core/mb-wm-client-window.h
@@ -0,0 +1,177 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_CLIENT_WINDOW_H
+#define _HAVE_MB_WM_CLIENT_WINDOW_H
+
+/* FIXME: below limits to 32 props */
+
+/* When a property changes
+ * - window updates its internal values
+ * - somehow signals client object to process with what changed.
+ */
+
+#define MBWM_WINDOW_PROP_WIN_TYPE (1<<0)
+#define MBWM_WINDOW_PROP_GEOMETRY (1<<1)
+#define MBWM_WINDOW_PROP_ATTR (1<<2)
+#define MBWM_WINDOW_PROP_NAME (1<<3)
+#define MBWM_WINDOW_PROP_WM_HINTS (1<<4)
+#define MBWM_WINDOW_PROP_WM_NORMAL_HINTS (1<<5)
+#define MBWM_WINDOW_PROP_NET_ICON (1<<6)
+#define MBWM_WINDOW_PROP_NET_PID (1<<7)
+#define MBWM_WINDOW_PROP_PROTOS (1<<8)
+#define MBWM_WINDOW_PROP_TRANSIENCY (1<<9)
+#define MBWM_WINDOW_PROP_STATE (1<<10)
+#define MBWM_WINDOW_PROP_NET_STATE (1<<11)
+#define MBWM_WINDOW_PROP_STARTUP_ID (1<<12)
+#define MBWM_WINDOW_PROP_CLIENT_MACHINE (1<<13)
+#define MBWM_WINDOW_PROP_ALLOWED_ACTIONS (1<<14)
+#define MBWM_WINDOW_PROP_NET_USER_TIME (1<<15)
+#define MBWM_WINDOW_PROP_CM_TRANSLUCENCY (1<<17)
+#define MBWM_WINDOW_PROP_MWM_HINTS (1<<18)
+
+#define MBWM_WINDOW_PROP_ALL (0xffffffff)
+
+typedef enum MBWMClientWindowEWMHState
+ {
+ MBWMClientWindowEWMHStateModal = (1<<0),
+ MBWMClientWindowEWMHStateSticky = (1<<1),
+ MBWMClientWindowEWMHStateMaximisedVert = (1<<2),
+ MBWMClientWindowEWMHStateMaximisedHorz = (1<<3),
+ MBWMClientWindowEWMHStateShaded = (1<<4),
+ MBWMClientWindowEWMHStateSkipTaskbar = (1<<5),
+ MBWMClientWindowEWMHStateSkipPager = (1<<6),
+ MBWMClientWindowEWMHStateHidden = (1<<7),
+ MBWMClientWindowEWMHStateFullscreen = (1<<8),
+ MBWMClientWindowEWMHStateAbove = (1<<9),
+ MBWMClientWindowEWMHStateBelow = (1<<10),
+ MBWMClientWindowEWMHStateDemandsAttention = (1<<11),
+ /*
+ * Keep in sync with the MBWMClientWindowEWHMStatesCount define below !!!
+ */
+ }
+MBWMClientWindowEWMHState;
+
+#define MBWMClientWindowEWHMStatesCount 12
+
+typedef enum MBWMClientWindowStateChange
+ {
+ MBWMClientWindowStateChangeRemove = (1<<0),
+ MBWMClientWindowStateChangeAdd = (1<<1),
+ MBWMClientWindowStateChangeToggle = (1<<2),
+ }
+MBWMClientWindowStateChange;
+
+typedef enum MBWMClientWindowProtos
+ {
+ MBWMClientWindowProtosFocus = (1<<0),
+ MBWMClientWindowProtosDelete = (1<<1),
+ MBWMClientWindowProtosContextHelp = (1<<2),
+ MBWMClientWindowProtosContextAccept = (1<<3),
+ MBWMClientWindowProtosContextCustom = (1<<4),
+ MBWMClientWindowProtosPing = (1<<5),
+ MBWMClientWindowProtosSyncRequest = (1<<6),
+ }
+MBWMClientWindowProtos;
+
+typedef enum MBWMClientWindowAllowedActions
+ {
+ MBWMClientWindowActionMove = (1<<0),
+ MBWMClientWindowActionResize = (1<<1),
+ MBWMClientWindowActionMinimize = (1<<2),
+ MBWMClientWindowActionShade = (1<<3),
+ MBWMClientWindowActionStick = (1<<4),
+ MBWMClientWindowActionMaximizeHorz = (1<<5),
+ MBWMClientWindowActionMaximizeVert = (1<<6),
+ MBWMClientWindowActionFullscreen = (1<<7),
+ MBWMClientWindowActionChangeDesktop = (1<<8),
+ MBWMClientWindowActionClose = (1<<9),
+ }
+MBWMClientWindowAllowedActions;
+
+#define MB_WM_CLIENT_WINDOW(c) ((MBWMClientWindow*)(c))
+#define MB_WM_CLIENT_WINDOW_CLASS(c) ((MBWMClientWindowClass*)(c))
+#define MB_WM_TYPE_CLIENT_WINDOW (mb_wm_client_window_class_type ())
+
+struct MBWMClientWindow
+{
+ MBWMObject parent;
+
+ MBGeometry geometry;
+ MBGeometry x_geometry;
+ unsigned int depth;
+ char *name;
+ Window xwindow;
+ Visual *visual;
+ Colormap colormap;
+ MBWindowManager *wm;
+
+ Atom net_type;
+ Atom *net_type_full;
+ int net_type_full_size;
+ Bool want_key_input;
+ Window xwin_group;
+ Pixmap icon_pixmap, icon_pixmap_mask;
+
+ /* WithdrawnState 0, NormalState 1, IconicState 3 */
+ int initial_state ;
+
+ MBWMClientWindowEWMHState ewmh_state;
+ Window xwin_transient_for;
+
+ MBWMClientWindowProtos protos;
+ pid_t pid;
+ int translucency;
+ char *machine;
+
+ MBWMList *icons;
+
+ MBWMClientWindowAllowedActions allowed_actions;
+
+ unsigned long user_time;
+
+ int gravity;
+ int window_class;
+ Bool override_redirect;
+ Bool undecorated;
+
+ Bool user_pos;
+};
+
+struct MBWMClientWindowClass
+{
+ MBWMObjectClass parent;
+};
+
+int
+mb_wm_client_window_class_type ();
+
+MBWMClientWindow*
+mb_wm_client_window_new (MBWindowManager *wm, Window xwin);
+
+Bool
+mb_wm_client_window_sync_properties (MBWMClientWindow *win,
+ unsigned long props_req);
+
+Bool
+mb_wm_client_window_is_state_set (MBWMClientWindow *win,
+ MBWMClientWindowEWMHState state);
+
+#endif
diff --git a/matchbox2/core/mb-wm-client.c b/matchbox2/core/mb-wm-client.c
new file mode 100644
index 0000000..f88a8d8
--- /dev/null
+++ b/matchbox2/core/mb-wm-client.c
@@ -0,0 +1,1120 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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-theme.h"
+
+#include <unistd.h>
+#include <signal.h>
+
+#if ENABLE_COMPOSITE
+#include <X11/extensions/Xrender.h>
+#endif
+
+struct MBWindowManagerClientPriv
+{
+ Bool realized;
+ Bool mapped;
+ Bool iconizing;
+ Bool hiding_from_desktop;
+ MBWMSyncType sync_state;
+};
+
+static void
+mb_wm_client_destroy (MBWMObject *obj)
+{
+ MBWindowManagerClient * client = MB_WM_CLIENT(obj);
+ MBWindowManager * wm = client->wmref;
+ MBWMList * l = client->decor;
+
+ if (client->sig_theme_change_id)
+ mb_wm_object_signal_disconnect (MB_WM_OBJECT (wm),
+ client->sig_theme_change_id);
+ client->sig_theme_change_id = 0;
+
+ if (client->sig_prop_change_id)
+ mb_wm_object_signal_disconnect (MB_WM_OBJECT (client->window),
+ client->sig_prop_change_id);
+
+ client->sig_prop_change_id = 0;
+
+ /* Must call mb_wm_client_ping_stop rather than
+ * mb_wm_main_context_timeout_handler_remove() to prevent a race condition
+ * segfault in the timeout list manipulation
+ */
+ mb_wm_client_ping_stop (client);
+
+#if ENABLE_COMPOSITE
+ if (mb_wm_compositing_enabled (wm))
+ {
+ mb_wm_comp_mgr_unregister_client (wm->comp_mgr, client);
+ }
+#endif
+
+ mb_wm_object_unref (MB_WM_OBJECT (client->window));
+
+ while (l)
+ {
+ mb_wm_object_unref (l->data);
+ l = l->next;
+ }
+
+ if (client->transient_for)
+ mb_wm_client_remove_transient (client->transient_for, client);
+
+ /* If we have transient windows, we need to make sure they are unmapped; for
+ * application dialogs this will happen automatically, but not for external
+ * transients, such as input windows.
+ *
+ * We also have to make sure that the transients no longer refer to this
+ * client, which is about the be destroyed.
+ */
+ l = client->transients;
+ while (l)
+ {
+ MBWindowManagerClient * c = l->data;
+ MBWMList * l2 = l;
+
+ c->transient_for = NULL;
+ XUnmapWindow (wm->xdpy, c->window->xwindow);
+
+ l = l->next;
+
+ free (l2);
+ }
+}
+
+static Bool
+mb_wm_client_on_property_change (MBWMClientWindow *window,
+ int property,
+ void *userdata);
+
+static Bool
+mb_wm_client_on_theme_change (MBWindowManager * wm, int signal,
+ MBWindowManagerClient * client)
+{
+ mb_wm_client_theme_change (client);
+ return False;
+}
+
+
+static int
+mb_wm_client_init (MBWMObject *obj, va_list vap)
+{
+ MBWindowManagerClient *client;
+ MBWindowManager *wm = NULL;
+ MBWMClientWindow *win = NULL;
+ MBWMObjectProp prop;
+ int status;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropWm:
+ wm = va_arg(vap, MBWindowManager *);
+ break;
+ case MBWMObjectPropClientWindow:
+ win = va_arg(vap, MBWMClientWindow *);
+ break;
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ MBWM_MARK();
+
+ client = MB_WM_CLIENT(obj);
+ client->priv = mb_wm_util_malloc0(sizeof(MBWindowManagerClientPriv));
+
+ client->window = win;
+ client->wmref = wm;
+ client->ping_timeout = 1000;
+
+ if (wm->theme)
+ {
+ client->layout_hints =
+ mb_wm_theme_get_client_layout_hints (wm->theme, client);
+ }
+
+ /* sync with client window */
+ mb_wm_client_on_property_change (win, MBWM_WINDOW_PROP_ALL, client);
+
+ /* Handle underlying property changes */
+ client->sig_prop_change_id =
+ mb_wm_object_signal_connect (MB_WM_OBJECT (win),
+ MBWM_WINDOW_PROP_ALL,
+ (MBWMObjectCallbackFunc)mb_wm_client_on_property_change,
+ client);
+
+ client->sig_theme_change_id =
+ mb_wm_object_signal_connect (MB_WM_OBJECT (wm),
+ MBWindowManagerSignalThemeChange,
+ (MBWMObjectCallbackFunc)mb_wm_client_on_theme_change,
+ client);
+
+ status = XGrabButton(wm->xdpy, Button1, 0, win->xwindow, True,
+ ButtonPressMask,
+ GrabModeSync, GrabModeSync, None, None);
+
+ MBWM_NOTE (CLIENT, "XGrabButton() returned status %d for client window %x",
+ status,
+ win->xwindow);
+
+#if ENABLE_COMPOSITE
+ {
+ XRenderPictFormat *format;
+
+ format = XRenderFindVisualFormat (wm->xdpy, win->visual);
+
+ if (format && format->type == PictTypeDirect &&
+ format->direct.alphaMask)
+ {
+ client->is_argb32 = True;
+ }
+ }
+#endif
+
+ return 1;
+}
+
+int
+mb_wm_client_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWindowManagerClientClass),
+ sizeof (MBWindowManagerClient),
+ mb_wm_client_init,
+ mb_wm_client_destroy,
+ NULL
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+void
+mb_wm_client_fullscreen_mark_dirty (MBWindowManagerClient *client)
+{
+ /* fullscreen implies geometry and visibility sync */
+ mb_wm_display_sync_queue (client->wmref,
+ MBWMSyncFullscreen |
+ MBWMSyncVisibility | MBWMSyncGeometry);
+
+ client->priv->sync_state |= (MBWMSyncFullscreen |
+ MBWMSyncGeometry |
+ MBWMSyncVisibility);
+}
+
+void
+mb_wm_client_stacking_mark_dirty (MBWindowManagerClient *client)
+{
+ mb_wm_display_sync_queue (client->wmref, MBWMSyncStacking);
+ client->priv->sync_state |= MBWMSyncStacking;
+}
+
+void
+mb_wm_client_geometry_mark_dirty (MBWindowManagerClient *client)
+{
+ mb_wm_display_sync_queue (client->wmref, MBWMSyncGeometry);
+
+ client->priv->sync_state |= MBWMSyncGeometry;
+}
+
+void
+mb_wm_client_visibility_mark_dirty (MBWindowManagerClient *client)
+{
+ mb_wm_display_sync_queue (client->wmref, MBWMSyncVisibility);
+
+ client->priv->sync_state |= MBWMSyncVisibility;
+
+ MBWM_DBG(" sync state: %i", client->priv->sync_state);
+}
+
+void
+mb_wm_client_configure_request_ack_queue (MBWindowManagerClient *client)
+{
+ mb_wm_display_sync_queue (client->wmref, MBWMSyncConfigRequestAck);
+
+ client->priv->sync_state |= MBWMSyncConfigRequestAck;
+
+ MBWM_DBG(" sync state: %i", client->priv->sync_state);
+}
+
+Bool
+mb_wm_client_needs_configure_request_ack (MBWindowManagerClient *client)
+{
+ return (client->priv->sync_state & MBWMSyncConfigRequestAck);
+}
+
+void
+mb_wm_client_decor_mark_dirty (MBWindowManagerClient *client)
+{
+ mb_wm_display_sync_queue (client->wmref, MBWMSyncDecor);
+
+ client->priv->sync_state |= MBWMSyncDecor;
+
+ MBWM_DBG(" sync state: %i", client->priv->sync_state);
+}
+
+Bool
+mb_wm_client_needs_fullscreen_sync (MBWindowManagerClient *client)
+{
+ return (client->priv->sync_state & MBWMSyncFullscreen);
+}
+
+static Bool
+mb_wm_client_on_property_change (MBWMClientWindow *window,
+ int property,
+ void *userdata)
+{
+ MBWindowManagerClient * client = MB_WM_CLIENT (userdata);
+
+ if (property & MBWM_WINDOW_PROP_NAME)
+ {
+ MBWMList * l = client->decor;
+ while (l)
+ {
+ MBWMDecor * decor = l->data;
+
+ if (mb_wm_decor_get_type (decor) == MBWMDecorTypeNorth)
+ {
+ mb_wm_decor_mark_title_dirty (decor);
+ break;
+ }
+
+ l = l->next;
+ }
+ }
+
+ if (property & MBWM_WINDOW_PROP_GEOMETRY)
+ mb_wm_client_geometry_mark_dirty (client);
+
+#if ENABLE_COMPOSITE
+ if ((property & MBWM_WINDOW_PROP_CM_TRANSLUCENCY) &&
+ client->cm_client && mb_wm_comp_mgr_enabled (client->wmref->comp_mgr))
+ {
+ mb_wm_comp_mgr_client_repair (client->cm_client);
+ }
+#endif
+
+ return False;
+}
+
+MBWindowManagerClient* /* FIXME: rename to mb_wm_client_base/class_new ? */
+mb_wm_client_new (MBWindowManager *wm, MBWMClientWindow *win)
+{
+ MBWindowManagerClient *client = NULL;
+
+ client = MB_WM_CLIENT(mb_wm_object_new (MB_WM_TYPE_CLIENT,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropClientWindow, win,
+ NULL));
+
+ return client;
+}
+
+void
+mb_wm_client_realize (MBWindowManagerClient *client)
+{
+ MBWindowManagerClientClass *klass;
+
+ if (client->priv->realized)
+ return;
+
+ klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
+
+ if (klass->realize)
+ klass->realize(client);
+
+ client->priv->realized = True;
+}
+
+Bool
+mb_wm_client_is_realized (MBWindowManagerClient *client)
+{
+ return client->priv->realized;
+}
+
+
+/* ## Stacking ## */
+
+
+void
+mb_wm_client_stack (MBWindowManagerClient *client,
+ int flags)
+{
+ MBWindowManagerClientClass *klass;
+
+ klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
+
+ if (klass->stack)
+ {
+ klass->stack(client, flags);
+
+ /* Schedule stack sync, but not if the client is of override type */
+ if (MB_WM_CLIENT_CLIENT_TYPE (client) != MBWMClientTypeOverride)
+ mb_wm_client_stacking_mark_dirty (client);
+ }
+}
+
+Bool
+mb_wm_client_needs_stack_sync (MBWindowManagerClient *client)
+{
+ return (client->priv->sync_state & MBWMSyncStacking);
+}
+
+void
+mb_wm_client_show (MBWindowManagerClient *client)
+{
+ MBWindowManagerClientClass *klass;
+
+ klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
+
+ if (klass->show)
+ klass->show (client);
+
+ client->priv->mapped = True;
+
+ /* Make sure any Hidden state flag is cleared */
+ mb_wm_client_set_state (client,
+ MBWM_ATOM_NET_WM_STATE_HIDDEN,
+ MBWMClientWindowStateChangeRemove);
+
+ mb_wm_client_visibility_mark_dirty (client);
+}
+
+void
+mb_wm_client_hide (MBWindowManagerClient *client)
+{
+ MBWindowManagerClientClass *klass;
+
+ klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
+
+ if (klass->hide)
+ {
+ klass->hide (client);
+
+ client->priv->mapped = False;
+
+ mb_wm_unfocus_client (client->wmref, client);
+ mb_wm_client_visibility_mark_dirty (client);
+ }
+}
+
+/*
+ * The focus processing is split into two stages, client and WM
+ *
+ * The client stage is handled by this function, with the return value
+ * of True indicating that the focus has changed.
+ *
+ * NB: This function should be considered protected and only called by the
+ * MBWindowManager object code.
+ */
+Bool
+mb_wm_client_focus (MBWindowManagerClient *client)
+{
+ MBWindowManagerClientClass *klass;
+ Bool ret = False;
+
+ klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
+
+ if (klass->focus)
+ ret = klass->focus(client);
+
+ if (ret)
+ {
+ /*
+ * If this client is transient, store it with the parent; if it is not
+ * transient, reset the last transient field
+ */
+ if (client->transient_for)
+ client->transient_for->last_focused_transient = client;
+ else
+ client->last_focused_transient = NULL;
+ }
+
+ return ret;
+}
+
+Bool
+mb_wm_client_want_focus (MBWindowManagerClient *client)
+{
+ return (client->window->want_key_input != False);
+}
+
+Bool
+mb_wm_client_needs_visibility_sync (MBWindowManagerClient *client)
+{
+ return (client->priv->sync_state & MBWMSyncVisibility);
+}
+
+Bool
+mb_wm_client_needs_geometry_sync (MBWindowManagerClient *client)
+{
+ return (client->priv->sync_state & MBWMSyncGeometry);
+}
+
+Bool
+mb_wm_client_needs_decor_sync (MBWindowManagerClient *client)
+{
+ return (client->priv->sync_state & MBWMSyncDecor);
+}
+
+Bool
+mb_wm_client_needs_sync (MBWindowManagerClient *client)
+{
+ MBWM_DBG("sync_state: %i", client->priv->sync_state);
+
+ return client->priv->sync_state;
+}
+
+Bool
+mb_wm_client_is_mapped (MBWindowManagerClient *client)
+{
+ return client->priv->mapped;
+}
+
+void
+mb_wm_client_display_sync (MBWindowManagerClient *client)
+{
+ MBWindowManagerClientClass *klass;
+
+ klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
+
+ if (klass->sync)
+ klass->sync (client);
+
+ client->priv->sync_state = 0;
+}
+
+
+Bool
+mb_wm_client_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags)
+{
+ MBWindowManagerClientClass *klass;
+
+ klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
+
+ if (klass->geometry)
+ return klass->geometry(client, new_geometry, flags);
+
+ return False;
+}
+
+MBWMClientLayoutHints
+mb_wm_client_get_layout_hints (MBWindowManagerClient *client)
+{
+ if ((client->window->ewmh_state & MBWMClientWindowEWMHStateFullscreen))
+ {
+ if (client->layout_hints & LayoutPrefVisible)
+ return (LayoutPrefFullscreen | LayoutPrefVisible);
+ else
+ return LayoutPrefFullscreen;
+ }
+
+ return client->layout_hints;
+}
+
+void
+mb_wm_client_set_layout_hints (MBWindowManagerClient *client,
+ MBWMClientLayoutHints hints)
+{
+ client->layout_hints = hints;
+}
+
+void
+mb_wm_client_set_layout_hint (MBWindowManagerClient *client,
+ MBWMClientLayoutHints hint,
+ Bool state)
+{
+ if (state)
+ client->layout_hints |= hint;
+ else
+ client->layout_hints &= ~hint;
+}
+
+void /* needs to be boolean, client may not have any coverage */
+mb_wm_client_get_coverage (MBWindowManagerClient *client,
+ MBGeometry *coverage)
+{
+ MBGeometry *geometry;
+
+ if (!client->xwin_frame)
+ geometry = &client->window->geometry;
+ else
+ geometry = &client->frame_geometry;
+
+ coverage->x = geometry->x;
+ coverage->y = geometry->y;
+ coverage->width = geometry->width;
+ coverage->height = geometry->height;
+}
+
+void
+mb_wm_client_add_transient (MBWindowManagerClient *client,
+ MBWindowManagerClient *transient)
+{
+ MBWMList *l;
+
+ if (transient == NULL || client == NULL)
+ return;
+
+ transient->transient_for = client;
+
+ /*
+ * Make sure that each transient is only added once (theoretically it should
+ * be, but it is very easy for a derived class to call this function without
+ * realizing the parent has dones so).
+ */
+ l = client->transients;
+ while (l)
+ {
+ if (l->data == transient)
+ return;
+
+ l = l->next;
+ }
+
+ client->transients = mb_wm_util_list_append(client->transients, transient);
+}
+
+void
+mb_wm_client_remove_transient (MBWindowManagerClient *client,
+ MBWindowManagerClient *transient)
+{
+ if (!transient || !client || !client->transients)
+ return;
+
+ transient->transient_for = NULL;
+
+ client->transients = mb_wm_util_list_remove(client->transients, transient);
+
+ if (client->last_focused_transient == transient)
+ client->last_focused_transient = transient->next_focused_client;
+}
+
+MBWMList*
+mb_wm_client_get_transients (MBWindowManagerClient *client)
+{
+ MBWMList *trans = NULL;
+ MBWMList *l = client->transients;
+ Window xgroup = client->window->xwin_group;
+ MBWindowManagerClient *c;
+ MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+
+ while (l)
+ {
+ trans = mb_wm_util_list_prepend (trans, l->data);
+ l = l->next;
+ }
+
+ /* If this is an application or desktop that are part of an group,
+ * we add any other transients that are part of the group to the list.
+ */
+ if (xgroup &&
+ (c_type == MBWMClientTypeApp || c_type == MBWMClientTypeDesktop))
+ {
+ mb_wm_stack_enumerate (client->wmref, c)
+ if (c != client &&
+ c->transient_for && c->window->xwin_group == xgroup)
+ {
+ MBWindowManagerClient * t = c->transient_for;
+
+ /* Only add it if it is not directly transiet for our client (in
+ * which case it is already in the list
+ *
+ * Find the bottom level transient
+ */
+ while (t && t->transient_for)
+ t = t->transient_for;
+
+ if (!t || (MB_WM_CLIENT_CLIENT_TYPE (t) == MBWMClientTypeApp ||
+ MB_WM_CLIENT_CLIENT_TYPE (t) == MBWMClientTypeDesktop))
+ {
+ trans = mb_wm_util_list_prepend (trans, c);
+ }
+ }
+ }
+
+ return trans;
+}
+
+MBWindowManagerClient*
+mb_wm_client_get_transient_for (MBWindowManagerClient *client)
+{
+ return client->transient_for;
+}
+
+
+const char*
+mb_wm_client_get_name (MBWindowManagerClient *client)
+{
+ if (!client->window)
+ return NULL;
+
+ return client->window->name;
+}
+
+void
+mb_wm_client_deliver_message (MBWindowManagerClient *client,
+ Atom delivery_atom,
+ unsigned long data0,
+ unsigned long data1,
+ unsigned long data2,
+ unsigned long data3,
+ unsigned long data4)
+{
+ MBWindowManager *wm = client->wmref;
+ Window xwin = client->window->xwindow;
+ XEvent ev;
+
+ memset(&ev, 0, sizeof(ev));
+
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = xwin;
+ ev.xclient.message_type = delivery_atom;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = data0;
+ ev.xclient.data.l[1] = data1;
+ ev.xclient.data.l[2] = data2;
+ ev.xclient.data.l[3] = data3;
+ ev.xclient.data.l[4] = data4;
+
+ XSendEvent(wm->xdpy, xwin, False, NoEventMask, &ev);
+
+ XSync(wm->xdpy, False);
+}
+
+void
+mb_wm_client_deliver_wm_protocol (MBWindowManagerClient *client,
+ Atom protocol)
+{
+ MBWindowManager *wm = client->wmref;
+
+ mb_wm_client_deliver_message (client, wm->atoms[MBWM_ATOM_WM_PROTOCOLS],
+ protocol, CurrentTime, 0, 0, 0);
+}
+
+static void
+mb_wm_client_deliver_ping_protocol (MBWindowManagerClient *client)
+{
+ MBWindowManager *wm = client->wmref;
+
+ mb_wm_client_deliver_message (client,
+ wm->atoms[MBWM_ATOM_WM_PROTOCOLS],
+ wm->atoms[MBWM_ATOM_NET_WM_PING],
+ CurrentTime,
+ client->window->xwindow,
+ 0, 0);
+}
+
+static Bool
+mb_wm_client_ping_timeout_cb (void * userdata)
+{
+ MBWindowManagerClient * client = userdata;
+
+ mb_wm_handle_hang_client (client->wmref, client);
+
+ mb_wm_client_ping_stop (client);
+ return False;
+}
+
+void
+mb_wm_client_ping_start (MBWindowManagerClient *client)
+{
+ MBWindowManager * wm = client->wmref;
+ MBWMMainContext * ctx = wm->main_ctx;
+ MBWMClientWindowProtos protos = client->window->protos;
+
+ if (!(protos & MBWMClientWindowProtosPing))
+ return;
+
+ if (client->ping_cb_id)
+ return;
+
+ client->ping_cb_id =
+ mb_wm_main_context_timeout_handler_add (ctx, client->ping_timeout,
+ mb_wm_client_ping_timeout_cb,
+ client);
+
+ mb_wm_client_deliver_ping_protocol (client);
+}
+
+void
+mb_wm_client_ping_stop (MBWindowManagerClient *client)
+{
+ MBWMMainContext * ctx = client->wmref->main_ctx;
+
+ if (!client->ping_cb_id)
+ return;
+
+ mb_wm_main_context_timeout_handler_remove (ctx, client->ping_cb_id);
+ client->ping_cb_id = 0;
+}
+
+void
+mb_wm_client_shutdown (MBWindowManagerClient *client)
+{
+ char buf[257];
+ int sig = 9;
+ MBWindowManager *wm = client->wmref;
+ MBWMClientWindow *win = client->window;
+ Window xwin = client->window->xwindow;
+ const char *machine = win->machine;
+ pid_t pid = win->pid;
+
+ if (machine && pid && (gethostname (buf, sizeof(buf)-1) == 0))
+ {
+ if (!strcmp (buf, machine))
+ {
+ if (kill (pid, sig) >= 0)
+ return;
+ }
+ }
+
+ XKillClient(wm->xdpy, xwin);
+}
+
+void
+mb_wm_client_deliver_delete (MBWindowManagerClient *client)
+{
+ MBWindowManager *wm = client->wmref;
+ MBWMClientWindowProtos protos = client->window->protos;
+
+ if ((protos & MBWMClientWindowProtosDelete))
+ {
+ mb_wm_client_deliver_wm_protocol (client,
+ wm->atoms[MBWM_ATOM_WM_DELETE_WINDOW]);
+
+ /* NB: It is not appropriate (or even possible) to try and
+ * determine a failure to respond to a WM_DELETE, since it
+ * would be reasonable for a client to put up a confirmation
+ * dialog in response to a WM_DELETE and do nothing if the
+ * user cancels the operation (because it was an accident)
+ *
+ * The NET_WM_PING protocol is the right way to determine an
+ * unresponsive client and we always send a ping (if the
+ * client supports the protocol) when issuing a WM_DELETE.
+ */
+
+ mb_wm_client_ping_start (client);
+ }
+ else
+ mb_wm_client_shutdown (client);
+}
+
+void
+mb_wm_client_set_state (MBWindowManagerClient *client,
+ MBWMAtom state,
+ MBWMClientWindowStateChange state_op)
+{
+ MBWindowManager *wm = client->wmref;
+ MBWMClientWindow *win = client->window;
+ Bool old_state;
+ Bool new_state;
+ Bool activate = True;
+ MBWMClientWindowEWMHState state_flag;
+
+ switch (state)
+ {
+ case MBWM_ATOM_NET_WM_STATE_FULLSCREEN:
+ state_flag = MBWMClientWindowEWMHStateFullscreen;
+ break;
+ case MBWM_ATOM_NET_WM_STATE_ABOVE:
+ state_flag = MBWMClientWindowEWMHStateAbove;
+ break;
+ case MBWM_ATOM_NET_WM_STATE_HIDDEN:
+ state_flag = MBWMClientWindowEWMHStateHidden;
+ break;
+ case MBWM_ATOM_NET_WM_STATE_MODAL:
+ case MBWM_ATOM_NET_WM_STATE_STICKY:
+ case MBWM_ATOM_NET_WM_STATE_MAXIMIZED_VERT:
+ case MBWM_ATOM_NET_WM_STATE_MAXIMIZED_HORZ:
+ case MBWM_ATOM_NET_WM_STATE_SHADED:
+ case MBWM_ATOM_NET_WM_STATE_SKIP_TASKBAR:
+ case MBWM_ATOM_NET_WM_STATE_SKIP_PAGER:
+ case MBWM_ATOM_NET_WM_STATE_BELOW:
+ case MBWM_ATOM_NET_WM_STATE_DEMANDS_ATTENTION:
+ default:
+ return; /* not handled yet */
+ }
+
+ old_state = (win->ewmh_state & state_flag);
+
+ switch (state_op)
+ {
+ case MBWMClientWindowStateChangeRemove:
+ new_state = False;
+ break;
+ case MBWMClientWindowStateChangeAdd:
+ new_state = True;
+ break;
+ case MBWMClientWindowStateChangeToggle:
+ new_state = !old_state;
+ break;
+ }
+
+ if (new_state == old_state)
+ return;
+
+ if (new_state)
+ {
+ win->ewmh_state |= state_flag;
+ }
+ else
+ {
+ win->ewmh_state &= ~state_flag;
+ }
+
+ if (state_flag & MBWMClientWindowEWMHStateHidden)
+ {
+ if (new_state)
+ mb_wm_client_hide (client);
+ else
+ mb_wm_client_show (client);
+
+ return;
+ }
+
+ if ((state_flag & MBWMClientWindowEWMHStateFullscreen))
+ {
+ mb_wm_client_fullscreen_mark_dirty (client);
+ }
+
+ /*
+ * FIXME -- resize && move, possibly redraw decors when returning from
+ * fullscreen
+ */
+ if (activate)
+ mb_wm_activate_client(wm, client);
+}
+
+Bool
+mb_wm_client_ping_in_progress (MBWindowManagerClient * client)
+{
+ return (client->ping_cb_id != 0);
+}
+
+void
+mb_wm_client_theme_change (MBWindowManagerClient *client)
+{
+ MBWindowManagerClientClass *klass;
+
+ klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
+
+ if (klass->theme_change)
+ klass->theme_change (client);
+}
+
+/*
+ * Cleanup any transient relationships this client might have
+ * (we need to do this when the client window unmaps to ensure correct
+ * functioning of the stack).
+ */
+void
+mb_wm_client_detransitise (MBWindowManagerClient *client)
+{
+ MBWindowManagerClientClass *klass;
+
+ if (!client->transient_for)
+ return;
+
+ klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
+
+ if (klass->detransitise)
+ klass->detransitise (client);
+
+ mb_wm_client_remove_transient (client->transient_for, client);
+}
+
+Bool
+mb_wm_client_is_iconizing (MBWindowManagerClient *client)
+{
+ return client->priv->iconizing;
+}
+
+void
+mb_wm_client_reset_iconizing (MBWindowManagerClient *client)
+{
+ client->priv->iconizing = False;
+}
+
+void
+mb_wm_client_iconize (MBWindowManagerClient *client)
+{
+ /*
+ * Set the iconizing flag and put the window into hidden state
+ * This triggers an umap event, at which point the client gets unmanaged
+ * by the window manager.
+ */
+#if 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_do_effect (client->wmref->comp_mgr, client,
+ MBWMCompMgrClientEventMinimize);
+ }
+#endif
+
+ client->priv->iconizing = True;
+
+
+ mb_wm_client_set_state (client,
+ MBWM_ATOM_NET_WM_STATE_HIDDEN,
+ MBWMClientWindowStateChangeAdd);
+}
+
+int
+mb_wm_client_title_height (MBWindowManagerClient *client)
+{
+ MBWMClientWindow * win = client->window;
+ MBWindowManager * wm = client->wmref;
+ int north;
+
+ if (!wm->theme ||
+ mb_wm_client_window_is_state_set (win,
+ MBWMClientWindowEWMHStateFullscreen))
+ {
+ return 0;
+ }
+
+
+ mb_wm_theme_get_decor_dimensions (wm->theme, client,
+ &north, NULL, NULL, NULL);
+
+ return north;
+}
+
+Bool
+mb_wm_client_is_modal (MBWindowManagerClient *client)
+{
+ return mb_wm_client_window_is_state_set (client->window,
+ MBWMClientWindowEWMHStateModal);
+}
+
+Bool
+mb_wm_client_owns_xwindow (MBWindowManagerClient *client, Window xwin)
+{
+ MBWMList * l;
+
+ if (client->xwin_frame == xwin || client->window->xwindow == xwin)
+ return True;
+
+ l = client->decor;
+ while (l)
+ {
+ MBWMDecor * d = l->data;
+
+ if (d->xwin == xwin)
+ return True;
+
+ l = l->next;
+ }
+
+ return False;
+}
+
+MBWMStackLayerType
+mb_wm_client_get_stacking_layer (MBWindowManagerClient *client)
+{
+ MBWindowManagerClientClass *klass;
+
+ klass = MB_WM_CLIENT_CLASS(mb_wm_object_get_class (MB_WM_OBJECT(client)));
+
+ if (klass->stacking_layer)
+ return klass->stacking_layer (client);
+
+ return client->stacking_layer;
+}
+
+Bool
+mb_wm_client_is_argb32 (MBWindowManagerClient *client)
+{
+ return client->is_argb32;
+}
+
+void
+mb_wm_client_set_desktop (MBWindowManagerClient * client, int desktop)
+{
+ client->desktop = desktop;
+}
+
+int
+mb_wm_client_get_desktop (MBWindowManagerClient * client)
+{
+ return client->desktop;
+}
+
+void
+mb_wm_client_desktop_change (MBWindowManagerClient * client, int desktop)
+{
+ if (client->desktop < 0)
+ return;
+
+ if (client->desktop == desktop)
+ {
+ mb_wm_client_set_state (client,
+ MBWM_ATOM_NET_WM_STATE_HIDDEN,
+ MBWMClientWindowStateChangeRemove);
+
+ /*
+ * NB -- we do not reset the hiding_from_desktop flag here
+ * since it is there to indicate to the WM that the window is
+ * mapping because of the desktop change; the WM resets it when
+ * it get the map-notify for it.
+ */
+ }
+ else
+ {
+ client->priv->hiding_from_desktop = True;
+
+ mb_wm_client_set_state (client,
+ MBWM_ATOM_NET_WM_STATE_HIDDEN,
+ MBWMClientWindowStateChangeAdd);
+ }
+}
+
+Bool
+mb_wm_client_is_hiding_from_desktop (MBWindowManagerClient * client)
+{
+ return client->priv->hiding_from_desktop;
+}
+
+void
+mb_wm_client_reset_hiding_from_desktop (MBWindowManagerClient * client)
+{
+ client->priv->hiding_from_desktop = False;
+}
+
diff --git a/matchbox2/core/mb-wm-client.h b/matchbox2/core/mb-wm-client.h
new file mode 100644
index 0000000..6b63c8e
--- /dev/null
+++ b/matchbox2/core/mb-wm-client.h
@@ -0,0 +1,384 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_CLIENT_H
+#define _HAVE_MB_CLIENT_H
+
+#include <matchbox2/mb-wm-config.h>
+
+#define MB_WM_CLIENT(c) ((MBWindowManagerClient*)(c))
+#define MB_WM_CLIENT_CLASS(c) ((MBWindowManagerClientClass*)(c))
+#define MB_WM_TYPE_CLIENT (mb_wm_client_class_type ())
+#define MB_WM_CLIENT_XWIN(w) (w)->window->xwindow
+#define MB_WM_CLIENT_CLIENT_TYPE(c) \
+ (MB_WM_CLIENT_CLASS(MB_WM_OBJECT_GET_CLASS(c))->client_type)
+
+typedef void (*MBWindowManagerClientInitMethod) (MBWindowManagerClient *client);
+
+/* Clients hint to what stacking layer they exist in. By default all
+ * transients to that client will also be stacked there.
+ */
+typedef enum MBWMStackLayerType
+{
+ MBWMStackLayerUnknown = 0, /* Transients */
+ MBWMStackLayerBottom , /* Desktop window */
+ MBWMStackLayerBottomMid , /* Panels */
+ MBWMStackLayerMid , /* Apps */
+ MBWMStackLayerTopMid , /* Trans for root dialogs */
+ MBWMStackLayerTop , /* Something else ? */
+ N_MBWMStackLayerTypes
+}
+MBWMStackLayerType;
+
+/* Clients can also hint to as how they would like to be managed by the
+ * layout manager.
+ */
+typedef enum MBWMClientLayoutHints
+ {
+ LayoutPrefReserveEdgeNorth = (1<< 0), /* panels */
+ LayoutPrefReserveEdgeSouth = (1<< 1),
+ LayoutPrefReserveEdgeEast = (1<< 2),
+ LayoutPrefReserveEdgeWest = (1<< 3),
+ LayoutPrefReserveNorth = (1<< 4), /* Input wins */
+ LayoutPrefReserveSouth = (1<< 5),
+ LayoutPrefReserveEast = (1<< 6),
+ LayoutPrefReserveWest = (1<< 7),
+ LayoutPrefGrowToFreeSpace = (1<< 8), /* Free space left by above */
+ LayoutPrefFullscreen = (1<< 9), /* Fullscreen and desktop wins */
+ LayoutPrefPositionFree = (1<<10), /* Dialog */
+ LayoutPrefVisible = (1<<11), /* Flag is toggled by stacking */
+ LayoutPrefFixedX = (1<<12), /* X and width are fixed*/
+ LayoutPrefFixedY = (1<<13),
+ LayoutPrefOverlaps = (1<<14), /* stacked over other windows */
+ LayoutPrefMovable = (1<<15),
+ LayoutPrefResizable = (1<<16),
+ }
+MBWMClientLayoutHints;
+
+typedef enum MBWMClientReqGeomType
+ {
+ MBWMClientReqGeomDontCommit = (1 << 1),
+ MBWMClientReqGeomIsViaConfigureReq = (1 << 2),
+ MBWMClientReqGeomIsViaUserAction = (1 << 3),
+ MBWMClientReqGeomIsViaLayoutManager = (1 << 4),
+ MBWMClientReqGeomForced = (1 << 5)
+ }
+MBWMClientReqGeomType;
+
+/* Methods */
+
+typedef void (*MBWMClientNewMethod) (MBWindowManager *wm,
+ MBWMClientWindow *win);
+
+typedef void (*MBWMClientInitMethod) (MBWindowManager *wm,
+ MBWindowManagerClient *client,
+ MBWMClientWindow *win);
+
+typedef void (*MBWMClientRealizeMethod) (MBWindowManagerClient *client);
+
+typedef void (*MBWMClientDestroyMethod) (MBWindowManagerClient *client);
+
+typedef Bool (*MBWMClientGeometryMethod) (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags);
+
+typedef void (*MBWMClientStackMethod) (MBWindowManagerClient *client,
+ int flags);
+
+typedef void (*MBWMClientShowMethod) (MBWindowManagerClient *client);
+
+typedef void (*MBWMClientHideMethod) (MBWindowManagerClient *client);
+
+typedef void (*MBWMClientSyncMethod) (MBWindowManagerClient *client);
+
+typedef Bool (*MBWMClientFocusMethod)(MBWindowManagerClient *client);
+
+typedef void (*MBWMClientThemeChangeMethod) (MBWindowManagerClient *client);
+
+typedef void (*MBWMClientDetransitise) (MBWindowManagerClient *client);
+
+typedef MBWMStackLayerType (*MBWMClientStackingLayer)(MBWindowManagerClient*);
+
+struct MBWindowManagerClientClass
+{
+ MBWMObjectClass parent;
+
+ MBWMClientType client_type;
+
+ MBWMClientRealizeMethod realize; /* create dpy resources / reparent */
+ MBWMClientGeometryMethod geometry; /* requests a gemetry change */
+ MBWMClientStackMethod stack; /* positions win in stack */
+ MBWMClientShowMethod show;
+ MBWMClientHideMethod hide;
+ MBWMClientSyncMethod sync; /* sync internal changes to display */
+ MBWMClientFocusMethod focus;
+ MBWMClientThemeChangeMethod theme_change;
+ MBWMClientDetransitise detransitise;
+ MBWMClientStackingLayer stacking_layer;
+};
+
+struct MBWindowManagerClient
+{
+ MBWMObject parent;
+ /* ### public ### */
+
+ MBWindowManager *wmref;
+ char *name;
+ MBWMClientWindow *window;
+ Window xwin_frame;
+ Window xwin_modal_blocker;
+ MBWMStackLayerType stacking_layer;
+ unsigned long stacking_hints;
+
+ MBWMClientLayoutHints layout_hints;
+
+ MBWindowManagerClient *stacked_above, *stacked_below;
+ MBWindowManagerClient *next_focused_client;
+
+ MBGeometry frame_geometry; /* FIXME: in ->priv ? */
+ MBWMList *decor;
+ MBWMList *transients;
+ MBWindowManagerClient *transient_for;
+ MBWindowManagerClient *last_focused_transient;
+
+ int skip_unmaps;
+
+ /* ### Private ### */
+
+ MBWindowManagerClientPriv *priv;
+ unsigned long sig_prop_change_id;
+ unsigned long ping_cb_id;
+ unsigned long sig_theme_change_id;
+ int ping_timeout;
+
+ Bool is_argb32;
+
+ int desktop;
+
+#if ENABLE_COMPOSITE
+ MBWMCompMgrClient *cm_client;
+#endif
+};
+
+#define mb_wm_client_frame_west_width(c) \
+ ((c)->window->geometry.x - (c)->frame_geometry.x)
+#define mb_wm_client_frame_east_width(c) \
+ (((c)->frame_geometry.x + (c)->frame_geometry.width) \
+ - ((c)->window->geometry.x + (c)->window->geometry.width))
+#define mb_wm_client_frame_east_x(c) \
+ ((c)->window->geometry.x + (c)->window->geometry.width)
+#define mb_wm_client_frame_north_height(c) \
+ ((c)->window->geometry.y - (c)->frame_geometry.y)
+#define mb_wm_client_frame_south_y(c) \
+ ((c)->window->geometry.y + (c)->window->geometry.height)
+#define mb_wm_client_frame_south_height(c) \
+ ( ((c)->frame_geometry.y + (c)->frame_geometry.height) \
+ - ((c)->window->geometry.y + (c)->window->geometry.height) )
+
+int
+mb_wm_client_class_type ();
+
+MBWMClientWindow*
+mb_wm_client_window_new (MBWindowManager *wm, Window window);
+
+MBWindowManagerClient*
+mb_wm_client_new (MBWindowManager *wm, MBWMClientWindow *win);
+
+void
+mb_wm_client_realize (MBWindowManagerClient *client);
+
+void
+mb_wm_client_stack (MBWindowManagerClient *client,
+ int flags);
+void
+mb_wm_client_show (MBWindowManagerClient *client);
+
+void
+mb_wm_client_hide (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_focus (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_want_focus (MBWindowManagerClient *client);
+
+void
+mb_wm_client_display_sync (MBWindowManagerClient *client);
+
+
+Bool
+mb_wm_client_is_realized (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_request_geometry (MBWindowManagerClient *client,
+ MBGeometry *new_geometry,
+ MBWMClientReqGeomType flags);
+
+Bool
+mb_wm_client_needs_geometry_sync (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_needs_visibility_sync (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_needs_fullscreen_sync (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_needs_decor_sync (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_needs_configure_request_ack (MBWindowManagerClient *client);
+
+void
+mb_wm_client_configure_request_ack_queue (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_needs_sync (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_is_mapped (MBWindowManagerClient *client);
+
+void
+mb_wm_client_get_coverage (MBWindowManagerClient *client,
+ MBGeometry *coverage);
+
+MBWMClientLayoutHints
+mb_wm_client_get_layout_hints (MBWindowManagerClient *client);
+
+void
+mb_wm_client_set_layout_hints (MBWindowManagerClient *client,
+ MBWMClientLayoutHints hints);
+
+void
+mb_wm_client_set_layout_hint (MBWindowManagerClient *client,
+ MBWMClientLayoutHints hint,
+ Bool state);
+
+void
+mb_wm_client_stacking_mark_dirty (MBWindowManagerClient *client);
+
+void
+mb_wm_client_fullscreen_mark_dirty (MBWindowManagerClient *client);
+
+void
+mb_wm_client_geometry_mark_dirty (MBWindowManagerClient *client);
+
+void
+mb_wm_client_visibility_mark_dirty (MBWindowManagerClient *client);
+
+void
+mb_wm_client_decor_mark_dirty (MBWindowManagerClient *client);
+
+void
+mb_wm_client_add_transient (MBWindowManagerClient *client,
+ MBWindowManagerClient *transient);
+
+void
+mb_wm_client_remove_transient (MBWindowManagerClient *client,
+ MBWindowManagerClient *transient);
+
+MBWMList*
+mb_wm_client_get_transients (MBWindowManagerClient *client);
+
+MBWindowManagerClient*
+mb_wm_client_get_transient_for (MBWindowManagerClient *client);
+
+const char*
+mb_wm_client_get_name (MBWindowManagerClient *client);
+
+void
+mb_wm_client_deliver_delete (MBWindowManagerClient *client);
+
+void
+mb_wm_client_deliver_message (MBWindowManagerClient *client,
+ Atom delivery_atom,
+ unsigned long data0,
+ unsigned long data1,
+ unsigned long data2,
+ unsigned long data3,
+ unsigned long data4);
+
+void
+mb_wm_client_deliver_wm_protocol (MBWindowManagerClient *client,
+ Atom protocol);
+
+void
+mb_wm_client_shutdown (MBWindowManagerClient *client);
+
+void
+mb_wm_client_set_state (MBWindowManagerClient *client,
+ MBWMAtom state,
+ MBWMClientWindowStateChange state_op);
+
+Bool
+mb_wm_client_ping_in_progress (MBWindowManagerClient * client);
+
+void
+mb_wm_client_ping_stop (MBWindowManagerClient *client);
+
+void
+mb_wm_client_theme_change (MBWindowManagerClient *client);
+
+void
+mb_wm_client_detransitise (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_is_iconizing (MBWindowManagerClient *client);
+
+void
+mb_wm_client_reset_iconizing (MBWindowManagerClient *client);
+
+void
+mb_wm_client_iconize (MBWindowManagerClient *client);
+
+int
+mb_wm_client_title_height (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_is_modal (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_owns_xwindow (MBWindowManagerClient *client, Window xwin);
+
+MBWMStackLayerType
+mb_wm_client_get_stacking_layer (MBWindowManagerClient *client);
+
+void
+mb_wm_client_ping_start (MBWindowManagerClient *client);
+
+Bool
+mb_wm_client_is_argb32 (MBWindowManagerClient *client);
+
+void
+mb_wm_client_set_desktop (MBWindowManagerClient * client, int desktop);
+
+int
+mb_wm_client_get_desktop (MBWindowManagerClient * client);
+
+void
+mb_wm_client_desktop_change (MBWindowManagerClient * client, int desktop);
+
+Bool
+mb_wm_client_is_hiding_from_desktop (MBWindowManagerClient * client);
+
+void
+mb_wm_client_reset_hiding_from_desktop (MBWindowManagerClient * client);
+
+#endif
diff --git a/matchbox2/core/mb-wm-debug.c b/matchbox2/core/mb-wm-debug.c
new file mode 100644
index 0000000..75d6e63
--- /dev/null
+++ b/matchbox2/core/mb-wm-debug.c
@@ -0,0 +1,77 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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-debug.h"
+
+#if MBWM_WANT_DEBUG
+int mbwm_debug_flags = 0;
+
+static const struct { const char *key; MBWMDebugFlag flag; } debug_keys[] = {
+ { "misc", MBWM_DEBUG_MISC },
+ { "client", MBWM_DEBUG_CLIENT },
+ { "texture", MBWM_DEBUG_PROP },
+ { "event", MBWM_DEBUG_EVENT },
+ { "paint", MBWM_DEBUG_PAINT },
+ { "trace", MBWM_DEBUG_TRACE },
+ { "obj-ref", MBWM_DEBUG_OBJ_REF },
+ { "obj-unref", MBWM_DEBUG_OBJ_UNREF },
+ { "xas", MBWM_DEBUG_XAS },
+ { "compositor",MBWM_DEBUG_COMPOSITOR },
+ { "damage", MBWM_DEBUG_DAMAGE },
+};
+#endif
+
+void
+mb_wm_debug_init (const char *debug_string)
+{
+#if MBWM_WANT_DEBUG
+ char *end;
+ int n, i;
+
+ if (debug_string == NULL)
+ return;
+
+ if (streq(debug_string,"all"))
+ {
+ mbwm_debug_flags = 0xffff;
+ return;
+ }
+
+ end = (char*)(debug_string + strlen(debug_string));
+
+ while (debug_string < end)
+ {
+ n = strcspn(debug_string, ",");
+
+ for (i=0; i<(sizeof(debug_keys)/sizeof(debug_keys[0])); i++)
+ if (!strncmp(debug_string, debug_keys[i].key, n))
+ mbwm_debug_flags |= debug_keys[i].flag;
+
+ debug_string += (n + 1);
+ }
+#else
+ if (debug_string != NULL)
+ mb_wm_util_warn ("You have requested debug messages and this matchbox "
+ "build doesn't have any!");
+#endif
+}
+
diff --git a/matchbox2/core/mb-wm-debug.h b/matchbox2/core/mb-wm-debug.h
new file mode 100644
index 0000000..4c10be4
--- /dev/null
+++ b/matchbox2/core/mb-wm-debug.h
@@ -0,0 +1,48 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_DEBUG_H
+#define _HAVE_MB_DEBUG_H
+
+#if MBWM_WANT_DEBUG
+
+typedef enum {
+ MBWM_DEBUG_MISC = 1 << 0,
+ MBWM_DEBUG_CLIENT = 1 << 1,
+ MBWM_DEBUG_PROP = 1 << 2,
+ MBWM_DEBUG_EVENT = 1 << 3,
+ MBWM_DEBUG_PAINT = 1 << 4,
+ MBWM_DEBUG_TRACE = 1 << 5,
+ MBWM_DEBUG_OBJ_REF = 1 << 6,
+ MBWM_DEBUG_OBJ_UNREF = 1 << 7,
+ MBWM_DEBUG_OBJ = MBWM_DEBUG_OBJ_REF | MBWM_DEBUG_OBJ_UNREF,
+ MBWM_DEBUG_XAS = 1 << 8,
+ MBWM_DEBUG_COMPOSITOR = 1 << 9,
+ MBWM_DEBUG_DAMAGE = 1 << 10,
+} MBWMDebugFlag;
+
+extern int mbwm_debug_flags;
+
+#endif /* MBWM_WANT_DEBUG */
+
+void
+mb_wm_debug_init (const char *debug_string);
+
+#endif
diff --git a/matchbox2/core/mb-wm-decor.c b/matchbox2/core/mb-wm-decor.c
new file mode 100644
index 0000000..f4f171b
--- /dev/null
+++ b/matchbox2/core/mb-wm-decor.c
@@ -0,0 +1,1190 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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-theme.h"
+
+static void
+mb_wm_decor_destroy (MBWMObject *obj);
+
+static void
+mb_wm_decor_button_sync_window (MBWMDecorButton *button);
+
+static void
+mb_wm_decor_class_init (MBWMObjectClass *klass)
+{
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMDecor";
+#endif
+}
+
+static int
+mb_wm_decor_init (MBWMObject *obj, va_list vap)
+{
+ MBWMDecor *decor = MB_WM_DECOR (obj);
+ MBWindowManager *wm = NULL;
+ MBWMDecorType type = 0;
+ MBWMObjectProp prop;
+ int abs_packing = 0;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropWm:
+ wm = va_arg(vap, MBWindowManager *);
+ break;
+ case MBWMObjectPropDecorType:
+ type = va_arg(vap, MBWMDecorType);
+ break;
+ case MBWMObjectPropDecorAbsolutePacking:
+ abs_packing = va_arg(vap, int);
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ if (!wm)
+ return 0;
+
+ decor->type = type;
+ decor->dirty = MBWMDecorDirtyFull; /* Needs painting */
+ decor->absolute_packing = abs_packing;
+
+ return 1;
+}
+
+int
+mb_wm_decor_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMDecorClass),
+ sizeof (MBWMDecor),
+ mb_wm_decor_init,
+ mb_wm_decor_destroy,
+ mb_wm_decor_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+static void
+mb_wm_decor_repaint (MBWMDecor *decor)
+{
+ MBWMTheme *theme = decor->parent_client->wmref->theme;
+
+ mb_wm_theme_paint_decor (theme, decor);
+}
+
+static void
+mb_wm_decor_resize (MBWMDecor *decor)
+{
+ const MBGeometry *geom;
+ MBWMTheme *theme = decor->parent_client->wmref->theme;
+ MBWMList *l;
+ int btn_x_start, btn_x_end;
+ int abs_packing = decor->absolute_packing;
+
+ geom = mb_wm_decor_get_geometry (decor);
+
+ btn_x_end = geom->width;
+ btn_x_start = 0;
+
+ l = decor->buttons;
+
+ /*
+ * Notify theme of resize
+ */
+ mb_wm_theme_resize_decor (theme, decor);
+
+ if (abs_packing)
+ {
+ int width = btn_x_end;
+
+ width /= 2;
+
+ while (l)
+ {
+ int off_x, off_y, bw, bh;
+
+ MBWMDecorButton *btn = (MBWMDecorButton *)l->data;
+ mb_wm_theme_get_button_position (theme, decor, btn->type,
+ &off_x, &off_y);
+ mb_wm_theme_get_button_size (theme, decor, btn->type,
+ &bw, &bh);
+
+ mb_wm_decor_button_move_to (btn, off_x, off_y);
+
+ /*
+ * We need to simulate packing when placing buttons at absolute
+ * positions (e.g., in png-based theme) so that we know the size
+ * of the area into which we can place the document title
+ */
+ if (off_x + bw < width)
+ {
+ int x = off_x + bw;
+
+ if (x > btn_x_start)
+ btn_x_start = x + 2;
+ }
+ else
+ {
+ if (off_x < btn_x_end)
+ btn_x_end = off_x - 2;
+ }
+
+ l = l->next;
+ }
+ }
+ else
+ {
+ while (l)
+ {
+ int off_x, off_y;
+
+ MBWMDecorButton *btn = (MBWMDecorButton *)l->data;
+ mb_wm_theme_get_button_position (theme, decor, btn->type,
+ &off_x, &off_y);
+
+ if (btn->pack == MBWMDecorButtonPackEnd)
+ {
+ btn_x_end -= (btn->geom.width + off_x);
+ mb_wm_decor_button_move_to (btn, btn_x_end, off_y);
+ }
+ else
+ {
+ mb_wm_decor_button_move_to (btn, btn_x_start + off_x, off_y);
+ btn_x_start += btn->geom.width;
+ }
+
+ l = l->next;
+ }
+ }
+
+ decor->pack_start_x = btn_x_start;
+ decor->pack_end_x = btn_x_end;
+}
+
+static Bool
+mb_wm_decor_reparent (MBWMDecor *decor);
+
+static Bool
+mb_wm_decor_release_handler (XButtonEvent *xev,
+ void *userdata)
+{
+ MBWMDecor *decor = userdata;
+ MBWindowManager *wm = decor->parent_client->wmref;
+
+ mb_wm_main_context_x_event_handler_remove (wm->main_ctx, ButtonRelease,
+ decor->release_cb_id);
+
+ decor->release_cb_id = 0;
+
+ XUngrabPointer (wm->xdpy, CurrentTime);
+
+ return False;
+}
+
+static Bool
+mb_wm_decor_press_handler (XButtonEvent *xev,
+ void *userdata)
+{
+ MBWMDecor *decor = userdata;
+ MBWindowManager *wm = decor->parent_client->wmref;
+ Bool retval = True;
+
+ if (xev->window == decor->xwin)
+ {
+ XEvent ev;
+ MBGeometry geom;
+ int orig_x, orig_y;
+ int orig_p_x, orig_p_y;
+
+ mb_wm_client_get_coverage (decor->parent_client, &geom);
+
+ orig_x = geom.x;
+ orig_y = geom.y;
+ orig_p_x = xev->x_root;
+ orig_p_y = xev->y_root;
+
+ /*
+ * This is bit tricky: we do a normal pointer drag and pull out any
+ * pointer events out of the queue; when we get a MotionEvent, we
+ * move the client window. However, for the move to propagete on screen
+ * (particularly with a compositor) we need to spin the main loop so
+ * that any queued up ConfigureNotify events get processed;
+ * unfortunately, this invariably results in the ButtonRelease event
+ * landing in the main loop and not in our sub-loop here. So, on the
+ * ButtonPress we install a ButtonRelease callback into the main loop
+ * and use that to release the grab.
+ */
+ if (XGrabPointer(wm->xdpy, xev->subwindow, False,
+ ButtonPressMask|ButtonReleaseMask|
+ PointerMotionMask|EnterWindowMask|LeaveWindowMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None, None, CurrentTime) == GrabSuccess)
+ {
+
+ decor->release_cb_id = mb_wm_main_context_x_event_handler_add (
+ wm->main_ctx,
+ decor->xwin,
+ ButtonRelease,
+ (MBWMXEventFunc)mb_wm_decor_release_handler,
+ decor);
+
+ for (;;)
+ {
+ /*
+ * If we have no release_cb installed, i.e., the ButtonRelease
+ * has already happened, quit this loop.
+ */
+ if (!decor->release_cb_id)
+ break;
+
+ XMaskEvent(wm->xdpy,
+ ButtonPressMask|ButtonReleaseMask|
+ PointerMotionMask|EnterWindowMask|
+ LeaveWindowMask,
+ &ev);
+
+ switch (ev.type)
+ {
+ case MotionNotify:
+ {
+ Bool events_pending;
+ int event_count = 5; /*Limit how much we spin the loop*/
+ XMotionEvent *pev = (XMotionEvent*)&ev;
+ int diff_x = pev->x_root - orig_p_x;
+ int diff_y = pev->y_root - orig_p_y;
+
+ geom.x = orig_x + diff_x;
+ geom.y = orig_y + diff_y;
+
+ mb_wm_client_request_geometry (decor->parent_client,
+ &geom,
+ MBWMClientReqGeomIsViaUserAction);
+
+ do
+ {
+ events_pending =
+ mb_wm_main_context_spin_loop (wm->main_ctx);
+
+ --event_count;
+ } while (events_pending && event_count);
+ }
+ break;
+ case ButtonRelease:
+ {
+ XUngrabPointer (wm->xdpy, CurrentTime);
+ return False;
+ }
+ default:
+ ;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+static Bool
+mb_wm_decor_sync_window (MBWMDecor *decor)
+{
+ MBWindowManager *wm;
+ XSetWindowAttributes attr;
+
+ if (decor->parent_client == NULL)
+ return False;
+
+ wm = decor->parent_client->wmref;
+
+
+ if (decor->xwin == None)
+ {
+ attr.override_redirect = True;
+ attr.background_pixel = BlackPixel(wm->xdpy, wm->xscreen);
+ attr.event_mask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask;
+
+ mb_wm_util_trap_x_errors();
+
+ decor->xwin
+ = XCreateWindow(wm->xdpy,
+ wm->root_win->xwindow,
+ decor->geom.x,
+ decor->geom.y,
+ decor->geom.width,
+ decor->geom.height,
+ 0,
+ CopyFromParent,
+ CopyFromParent,
+ CopyFromParent,
+ CWOverrideRedirect|CWBackPixel|CWEventMask,
+ &attr);
+
+ MBWM_DBG("g is +%i+%i %ix%i",
+ decor->geom.x,
+ decor->geom.y,
+ decor->geom.width,
+ decor->geom.height);
+
+ if (mb_wm_util_untrap_x_errors())
+ return False;
+
+ mb_wm_decor_resize(decor);
+
+ mb_wm_util_list_foreach(decor->buttons,
+ (MBWMListForEachCB)mb_wm_decor_button_sync_window,
+ NULL);
+
+ /*
+ * If this is a decor with buttons, then we install button press handler
+ * so we can drag the window, if it is movable.
+ */
+ if (decor->type == MBWMDecorTypeNorth &&
+ decor->parent_client->layout_hints & LayoutPrefMovable)
+ {
+ decor->press_cb_id =
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ decor->xwin,
+ ButtonPress,
+ (MBWMXEventFunc)mb_wm_decor_press_handler,
+ decor);
+ }
+
+ return mb_wm_decor_reparent (decor);
+ }
+ else
+ {
+ /* Resize */
+ mb_wm_util_trap_x_errors();
+
+ XMoveResizeWindow(wm->xdpy,
+ decor->xwin,
+ decor->geom.x,
+ decor->geom.y,
+ decor->geom.width,
+ decor->geom.height);
+
+ /* Next up sort buttons */
+
+ mb_wm_util_list_foreach(decor->buttons,
+ (MBWMListForEachCB)mb_wm_decor_button_sync_window,
+ NULL);
+
+ if (mb_wm_util_untrap_x_errors())
+ return False;
+ }
+
+ return True;
+}
+
+static Bool
+mb_wm_decor_reparent (MBWMDecor *decor)
+{
+ MBWindowManager *wm;
+
+ if (decor->parent_client == NULL)
+ return False;
+
+ MBWM_MARK();
+
+ wm = decor->parent_client->wmref;
+
+ /* FIXME: Check if we already have a parent here */
+
+ mb_wm_util_trap_x_errors();
+
+ XReparentWindow (wm->xdpy,
+ decor->xwin,
+ decor->parent_client->xwin_frame,
+ decor->geom.x,
+ decor->geom.y);
+
+ if (mb_wm_util_untrap_x_errors())
+ return False;
+
+ return True;
+}
+
+static void
+mb_wm_decor_calc_geometry (MBWMDecor *decor)
+{
+ MBWindowManager *wm;
+ MBWindowManagerClient *client;
+ int n, s, w, e;
+
+ if (decor->parent_client == NULL)
+ return;
+
+ client = decor->parent_client;
+ wm = client->wmref;
+
+ mb_wm_theme_get_decor_dimensions (wm->theme, client,
+ &n, &s, &w, &e);
+
+ switch (decor->type)
+ {
+ case MBWMDecorTypeNorth:
+ decor->geom.x = 0;
+ decor->geom.y = 0;
+ decor->geom.height = n;
+ decor->geom.width = client->frame_geometry.width;
+ break;
+ case MBWMDecorTypeSouth:
+ decor->geom.x = 0;
+ decor->geom.y = client->window->geometry.height + n;
+ decor->geom.height = s;
+ decor->geom.width = client->frame_geometry.width;
+ break;
+ case MBWMDecorTypeWest:
+ decor->geom.x = 0;
+ decor->geom.y = n;
+ decor->geom.height = client->window->geometry.height;
+ decor->geom.width = w;
+ break;
+ case MBWMDecorTypeEast:
+ decor->geom.x = client->window->geometry.width + w;
+ decor->geom.y = n;
+ decor->geom.height = client->window->geometry.height;
+ decor->geom.width = e;
+ break;
+ default:
+ /* FIXME: some kind of callback for custom types here ? */
+ break;
+ }
+
+ MBWM_DBG("geom is +%i+%i %ix%i, Type %i",
+ decor->geom.x,
+ decor->geom.y,
+ decor->geom.width,
+ decor->geom.height,
+ decor->type);
+
+ return;
+}
+
+void
+mb_wm_decor_handle_map (MBWMDecor *decor)
+{
+ /* Not needed as XMapSubWindows() is used */
+}
+
+
+void
+mb_wm_decor_handle_repaint (MBWMDecor *decor)
+{
+ MBWMList *l;
+
+ if (decor->parent_client == NULL)
+ return;
+
+ if (decor->dirty)
+ {
+ mb_wm_decor_repaint(decor);
+
+ l = decor->buttons;
+ while (l)
+ {
+ MBWMDecorButton * button = l->data;
+ mb_wm_decor_button_handle_repaint (button);
+
+ l = l->next;
+ }
+
+ decor->dirty = MBWMDecorDirtyNot;
+ }
+}
+
+void
+mb_wm_decor_handle_resize (MBWMDecor *decor)
+{
+ if (decor->parent_client == NULL)
+ return;
+
+ mb_wm_decor_calc_geometry (decor);
+
+ mb_wm_decor_sync_window (decor);
+
+ /* Fire resize callback */
+ mb_wm_decor_resize(decor);
+
+ /* Fire repaint callback */
+ mb_wm_decor_mark_dirty (decor);
+}
+
+MBWMDecor*
+mb_wm_decor_new (MBWindowManager *wm,
+ MBWMDecorType type)
+{
+ MBWMObject *decor;
+
+ decor = mb_wm_object_new (MB_WM_TYPE_DECOR,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropDecorType, type,
+ NULL);
+
+ return MB_WM_DECOR(decor);
+}
+
+Window
+mb_wm_decor_get_x_window (MBWMDecor *decor)
+{
+ return decor->xwin;
+}
+
+MBWMDecorType
+mb_wm_decor_get_type (MBWMDecor *decor)
+{
+ return decor->type;
+}
+
+MBWindowManagerClient*
+mb_wm_decor_get_parent (MBWMDecor *decor)
+{
+ return decor->parent_client;
+}
+
+
+const MBGeometry*
+mb_wm_decor_get_geometry (MBWMDecor *decor)
+{
+ return &decor->geom;
+}
+
+int
+mb_wm_decor_get_pack_start_x (MBWMDecor *decor)
+{
+ return decor->pack_start_x;
+}
+
+
+int
+mb_wm_decor_get_pack_end_x (MBWMDecor *decor)
+{
+ return decor->pack_end_x;
+}
+
+
+/* Mark a client in need of a repaint */
+void
+mb_wm_decor_mark_dirty (MBWMDecor *decor)
+{
+ decor->dirty |= MBWMDecorDirtyPaint;
+
+ if (decor->parent_client)
+ mb_wm_client_decor_mark_dirty (decor->parent_client);
+}
+
+void
+mb_wm_decor_mark_title_dirty (MBWMDecor *decor)
+{
+ decor->dirty |= MBWMDecorDirtyTitle;
+
+ if (decor->parent_client)
+ mb_wm_client_decor_mark_dirty (decor->parent_client);
+}
+
+MBWMDecorDirtyState
+mb_wm_decor_get_dirty_state (MBWMDecor *decor)
+{
+ return decor->dirty;
+}
+
+void
+mb_wm_decor_attach (MBWMDecor *decor,
+ MBWindowManagerClient *client)
+{
+ decor->parent_client = client;
+ client->decor = mb_wm_util_list_append(client->decor, decor);
+
+ mb_wm_decor_mark_dirty (decor);
+
+ return;
+}
+
+void
+mb_wm_decor_detach (MBWMDecor *decor)
+{
+}
+
+static void
+mb_wm_decor_destroy (MBWMObject* obj)
+{
+ MBWMDecor * decor = MB_WM_DECOR(obj);
+ MBWMList * l = decor->buttons;
+ MBWMMainContext * ctx = decor->parent_client->wmref->main_ctx;
+
+ if (decor->themedata && decor->destroy_themedata)
+ {
+ decor->destroy_themedata (decor, decor->themedata);
+ decor->themedata = NULL;
+ decor->destroy_themedata = NULL;
+ }
+
+ mb_wm_decor_detach (decor);
+
+ while (l)
+ {
+ MBWMList * old = l;
+ mb_wm_object_unref (MB_WM_OBJECT (l->data));
+ l = l->next;
+ free (old);
+ }
+
+ if (decor->press_cb_id)
+ mb_wm_main_context_x_event_handler_remove (ctx, ButtonPress,
+ decor->press_cb_id);
+}
+
+void
+mb_wm_decor_set_theme_data (MBWMDecor * decor, void *userdata,
+ MBWMDecorDestroyUserData destroy)
+{
+ if (decor->themedata && decor->destroy_themedata)
+ decor->destroy_themedata (decor, decor->themedata);
+
+ decor->themedata = userdata;
+ decor->destroy_themedata = destroy;
+}
+
+void *
+mb_wm_decor_get_theme_data (MBWMDecor * decor)
+{
+ return decor->themedata;
+}
+
+/* Buttons */
+static void
+mb_wm_decor_button_destroy (MBWMObject* obj);
+
+static void
+mb_wm_decor_button_stock_button_action (MBWMDecorButton *button)
+{
+ MBWindowManagerClient *client = button->decor->parent_client;
+ MBWindowManager *wm = client->wmref;
+
+ switch (button->type)
+ {
+ case MBWMDecorButtonClose:
+ mb_wm_client_deliver_delete (client);
+ break;
+ case MBWMDecorButtonMinimize:
+ mb_wm_client_iconize (client);
+ break;
+ case MBWMDecorButtonFullscreen:
+ mb_wm_client_set_state (client,
+ MBWM_ATOM_NET_WM_STATE_FULLSCREEN,
+ MBWMClientWindowStateChangeAdd);
+ break;
+ case MBWMDecorButtonAccept:
+ mb_wm_client_deliver_wm_protocol (client,
+ wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_ACCEPT]);
+ break;
+ case MBWMDecorButtonHelp:
+ mb_wm_client_deliver_wm_protocol (client,
+ wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_HELP]);
+ break;
+ case MBWMDecorButtonMenu:
+ mb_wm_client_deliver_wm_protocol (client,
+ wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_CUSTOM]);
+ default:
+ break;
+ }
+
+ return;
+}
+
+void
+mb_wm_decor_button_set_theme_data (MBWMDecorButton * button, void *themedata,
+ MBWMDecorButtonDestroyUserData destroy)
+{
+ if (button->themedata && button->destroy_themedata)
+ button->destroy_themedata (button, button->themedata);
+
+ button->themedata = themedata;
+ button->destroy_themedata = destroy;
+}
+
+void *
+mb_wm_decor_button_get_theme_data (MBWMDecorButton * button)
+{
+ return button->themedata;
+}
+
+static Bool
+mb_wm_decor_button_press_handler (XButtonEvent *xev,
+ void *userdata)
+{
+ MBWMDecorButton *button = (MBWMDecorButton *)userdata;
+ MBWMDecor *decor = button->decor;
+ MBWindowManager *wm = decor->parent_client->wmref;
+ MBWMList *l = NULL;
+ Bool retval = True;
+
+ if (xev->window == decor->xwin)
+ {
+ int xmin, ymin, xmax, ymax;
+ l = mb_wm_client_get_transients (decor->parent_client);
+
+ /* Ignore events on the main window decor if transients other than
+ * input methods are present
+ */
+ while (l)
+ {
+ MBWindowManagerClient * c = l->data;
+
+ if (MB_WM_CLIENT_CLIENT_TYPE (c) != MBWMClientTypeInput &&
+ mb_wm_client_is_modal (c))
+ {
+ retval = True;
+ goto done;
+ }
+
+ l = l->next;
+ }
+
+ xmin = button->geom.x;
+ ymin = button->geom.y;
+ xmax = button->geom.x + button->geom.width;
+ ymax = button->geom.y + button->geom.height;
+
+ if (xev->x < xmin ||
+ xev->x > xmax ||
+ xev->y < ymin ||
+ xev->y > ymax)
+ {
+ retval = True;
+ goto done;
+ }
+
+ if (button->state != MBWMDecorButtonStatePressed)
+ {
+ button->state = MBWMDecorButtonStatePressed;
+ mb_wm_theme_paint_button (wm->theme, button);
+ }
+
+ if (button->press_activated)
+ {
+ XUngrabPointer(wm->xdpy, CurrentTime);
+
+ mb_wm_client_deliver_message (decor->parent_client,
+ wm->atoms[MBWM_ATOM_MB_GRAB_TRANSFER],
+ xev->time,
+ xev->subwindow,
+ xev->button, 0, 0);
+
+ XSync (wm->xdpy, False); /* Necessary */
+
+ if (button->press)
+ button->press(wm, button, button->userdata);
+ else
+ mb_wm_decor_button_stock_button_action (button);
+ }
+ else
+ {
+ XEvent ev;
+
+ /*
+ * First, call the custom function if any.
+ */
+ if (button->press)
+ button->press(wm, button, button->userdata);
+
+ if (XGrabPointer(wm->xdpy, xev->subwindow, False,
+ ButtonPressMask|ButtonReleaseMask|
+ PointerMotionMask|EnterWindowMask|LeaveWindowMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None, None, CurrentTime) == GrabSuccess)
+ {
+ if (button->state == MBWMDecorButtonStateInactive)
+ {
+ button->state = MBWMDecorButtonStatePressed;
+ mb_wm_theme_paint_button (wm->theme, button);
+ }
+
+ for (;;)
+ {
+ /*
+ * First of all, we make sure that all events are flushed
+ * out (this is necessary to ensure that all the events we
+ * are interested in are actually intercepted here).
+ */
+ XSync (wm->xdpy, False);
+
+ if (XCheckMaskEvent(wm->xdpy,
+ ButtonPressMask|ButtonReleaseMask|
+ PointerMotionMask|EnterWindowMask|
+ LeaveWindowMask,
+ &ev))
+ {
+ switch (ev.type)
+ {
+ case MotionNotify:
+ {
+ XMotionEvent *pev = (XMotionEvent*)&ev;
+
+ if (pev->x < xmin || pev->x > xmax ||
+ pev->y < ymin || pev->y > ymax)
+ {
+ if (button->state ==
+ MBWMDecorButtonStatePressed)
+ {
+ button->state =
+ MBWMDecorButtonStateInactive;
+ mb_wm_theme_paint_button (wm->theme,button);
+ }
+ }
+ else
+ {
+ if (button->state !=
+ MBWMDecorButtonStatePressed)
+ {
+ button->state = MBWMDecorButtonStatePressed;
+ mb_wm_theme_paint_button (wm->theme,button);
+ }
+ }
+ }
+ break;
+ case EnterNotify:
+ if (button->state == MBWMDecorButtonStateInactive)
+ {
+ button->state = MBWMDecorButtonStatePressed;
+ mb_wm_theme_paint_button (wm->theme, button);
+ }
+ break;
+ case LeaveNotify:
+ if (button->state != MBWMDecorButtonStateInactive)
+ {
+ button->state = MBWMDecorButtonStateInactive;
+ mb_wm_theme_paint_button (wm->theme, button);
+ }
+ break;
+ case ButtonRelease:
+ {
+ XButtonEvent *pev = (XButtonEvent*)&ev;
+
+ if (button->state != MBWMDecorButtonStateInactive)
+ {
+ button->state = MBWMDecorButtonStateInactive;
+ mb_wm_theme_paint_button (wm->theme, button);
+ }
+
+ XUngrabPointer (wm->xdpy, CurrentTime);
+ XSync (wm->xdpy, False); /* necessary */
+
+ if (pev->x < xmin || pev->x > xmax ||
+ pev->y < ymin || pev->y > ymax)
+ {
+ retval = False;
+ goto done;
+ }
+
+ if (button->release)
+ button->release(wm, button, button->userdata);
+ else
+ mb_wm_decor_button_stock_button_action (button);
+
+ return False;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * No pending X event, so spin the main loop (this allows
+ * things like timers to work.
+ */
+ mb_wm_main_context_spin_loop (wm->main_ctx);
+ }
+ }
+ }
+ }
+
+ retval = False;
+ }
+
+ done:
+ mb_wm_util_list_free (l);
+ return retval;
+}
+
+static void
+mb_wm_decor_button_class_init (MBWMObjectClass *klass)
+{
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMDecorButton";
+#endif
+}
+
+static int
+mb_wm_decor_button_init (MBWMObject *obj, va_list vap)
+{
+ MBWMDecorButton *button = MB_WM_DECOR_BUTTON (obj);
+ MBWindowManager *wm = NULL;
+ MBWMDecor *decor = NULL;
+ MBWMDecorButtonPressedFunc press = NULL;
+ MBWMDecorButtonReleasedFunc release = NULL;
+ MBWMDecorButtonFlags flags = 0;
+ MBWMDecorButtonType type = 0;
+ MBWMDecorButtonPack pack = MBWMDecorButtonPackEnd;
+ MBWMObjectProp prop;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropWm:
+ wm = va_arg(vap, MBWindowManager *);
+ break;
+ case MBWMObjectPropDecor:
+ decor = va_arg(vap, MBWMDecor*);
+ break;
+ case MBWMObjectPropDecorButtonPressedFunc:
+ press = va_arg(vap, MBWMDecorButtonPressedFunc);
+ break;
+ case MBWMObjectPropDecorButtonReleasedFunc:
+ release = va_arg(vap, MBWMDecorButtonReleasedFunc);
+ break;
+ case MBWMObjectPropDecorButtonFlags:
+ flags = va_arg(vap, MBWMDecorButtonFlags);
+ break;
+ case MBWMObjectPropDecorButtonType:
+ type = va_arg(vap, MBWMDecorButtonType);
+ break;
+ case MBWMObjectPropDecorButtonPack:
+ pack = va_arg(vap, MBWMDecorButtonPack);
+ break;
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ if (!wm || !decor)
+ return 0;
+
+ /*
+ * Decors must be attached before we can start adding buttons to them,
+ * otherwise we cannot work out the button geometry.
+ */
+ MBWM_ASSERT (decor->parent_client);
+
+ button->geom.width = 0;
+ button->geom.height = 0;
+
+ mb_wm_theme_get_button_size (wm->theme,
+ decor,
+ type,
+ &button->geom.width,
+ &button->geom.height);
+
+ button->press = press;
+ button->release = release;
+ button->decor = decor;
+ button->type = type;
+ button->pack = pack;
+ button->press_activated = mb_wm_theme_is_button_press_activated (wm->theme,
+ decor,
+ type);
+
+ decor->buttons = mb_wm_util_list_append (decor->buttons, button);
+
+ /* the decor assumes a reference, so add one for the caller */
+ mb_wm_object_ref (obj);
+
+ return 1;
+}
+
+int
+mb_wm_decor_button_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMDecorButtonClass),
+ sizeof (MBWMDecorButton),
+ mb_wm_decor_button_init,
+ mb_wm_decor_button_destroy,
+ mb_wm_decor_button_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+static void
+mb_wm_decor_button_destroy (MBWMObject* obj)
+{
+ MBWMDecorButton * button = MB_WM_DECOR_BUTTON (obj);
+ MBWMMainContext * ctx = button->decor->parent_client->wmref->main_ctx;
+
+ if (button->userdata && button->destroy_userdata)
+ {
+ button->destroy_userdata (button, button->userdata);
+ button->userdata = NULL;
+ button->destroy_userdata = NULL;
+ }
+
+ if (button->themedata && button->destroy_themedata)
+ {
+ button->destroy_themedata (button, button->themedata);
+ button->themedata = NULL;
+ button->destroy_themedata = NULL;
+ }
+
+ mb_wm_main_context_x_event_handler_remove (ctx, ButtonPress,
+ button->press_cb_id);
+}
+
+static void
+mb_wm_decor_button_realize (MBWMDecorButton *button)
+{
+ MBWMDecor *decor = button->decor;
+ MBWindowManager *wm = decor->parent_client->wmref;
+
+ button->press_cb_id =
+ mb_wm_main_context_x_event_handler_add (wm->main_ctx,
+ decor->xwin,
+ ButtonPress,
+ (MBWMXEventFunc)mb_wm_decor_button_press_handler,
+ button);
+
+ button->realized = True;
+}
+
+static void
+mb_wm_decor_button_sync_window (MBWMDecorButton *button)
+{
+ if (!button->realized)
+ {
+ mb_wm_decor_button_realize (button);
+ }
+}
+
+void
+mb_wm_decor_button_show (MBWMDecorButton *button)
+{
+ button->visible = True;
+}
+
+void
+mb_wm_decor_button_hide (MBWMDecorButton *button)
+{
+ button->visible = False;
+}
+
+void
+mb_wm_decor_button_move_to (MBWMDecorButton *button, int x, int y)
+{
+ /* FIXME: set a sync flag so it know X movewindow is needed */
+ button->geom.x = x;
+ button->geom.y = y;
+
+ MBWM_DBG ("####### moving to %i, %i\n", button->geom.x, button->geom.y);
+}
+
+MBWMDecorButton*
+mb_wm_decor_button_new (MBWindowManager *wm,
+ MBWMDecorButtonType type,
+ MBWMDecorButtonPack pack,
+ MBWMDecor *decor,
+ MBWMDecorButtonPressedFunc press,
+ MBWMDecorButtonReleasedFunc release,
+ MBWMDecorButtonFlags flags)
+{
+ MBWMObject *button;
+
+ button = mb_wm_object_new (MB_WM_TYPE_DECOR_BUTTON,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropDecorButtonType, type,
+ MBWMObjectPropDecorButtonPack, pack,
+ MBWMObjectPropDecor, decor,
+ MBWMObjectPropDecorButtonPressedFunc, press,
+ MBWMObjectPropDecorButtonReleasedFunc, release,
+ MBWMObjectPropDecorButtonFlags, flags,
+ NULL);
+
+ return MB_WM_DECOR_BUTTON(button);
+}
+
+MBWMDecorButton*
+mb_wm_decor_button_stock_new (MBWindowManager *wm,
+ MBWMDecorButtonType type,
+ MBWMDecorButtonPack pack,
+ MBWMDecor *decor,
+ MBWMDecorButtonFlags flags)
+{
+ MBWMObject *button;
+
+ button = mb_wm_object_new (MB_WM_TYPE_DECOR_BUTTON,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropDecorButtonType, type,
+ MBWMObjectPropDecorButtonPack, pack,
+ MBWMObjectPropDecor, decor,
+ MBWMObjectPropDecorButtonFlags, flags,
+ NULL);
+
+ return MB_WM_DECOR_BUTTON(button);
+}
+
+void
+mb_wm_decor_button_handle_repaint (MBWMDecorButton *button)
+{
+ MBWMDecor * decor = button->decor;
+ MBWMTheme * theme = decor->parent_client->wmref->theme;
+
+ if (decor->parent_client == NULL)
+ return;
+
+ mb_wm_theme_paint_button (theme, button);
+}
+
+void
+mb_wm_decor_button_set_user_data (MBWMDecorButton * button, void *userdata,
+ MBWMDecorButtonDestroyUserData destroy)
+{
+ button->userdata = userdata;
+ button->destroy_userdata = destroy;
+}
+
+void *
+mb_wm_decor_button_get_user_data (MBWMDecorButton * button)
+{
+ return button->userdata;
+}
diff --git a/matchbox2/core/mb-wm-decor.h b/matchbox2/core/mb-wm-decor.h
new file mode 100644
index 0000000..6adeadf
--- /dev/null
+++ b/matchbox2/core/mb-wm-decor.h
@@ -0,0 +1,241 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_DECOR_H
+#define _HAVE_MB_WM_DECOR_H
+
+#define MB_WM_DECOR(c) ((MBWMDecor*)(c))
+#define MB_WM_DECOR_CLASS(c) ((MBWMDecorClass*)(c))
+#define MB_WM_TYPE_DECOR (mb_wm_decor_class_type ())
+
+
+#define MB_WM_DECOR_BUTTON(c) ((MBWMDecorButton*)(c))
+#define MB_WM_DECOR_BUTTON_CLASS(c) ((MBWMDecorButtonClass*)(c))
+#define MB_WM_TYPE_DECOR_BUTTON (mb_wm_decor_button_class_type ())
+
+typedef void (*MBWMDecorButtonPressedFunc) (MBWindowManager *wm,
+ MBWMDecorButton *button,
+ void *userdata);
+
+typedef void (*MBWMDecorButtonReleasedFunc) (MBWindowManager *wm,
+ MBWMDecorButton *button,
+ void *userdata);
+
+
+typedef void (*MBWMDecorDestroyUserData) (MBWMDecor *, void *);
+typedef void (*MBWMDecorButtonDestroyUserData) (MBWMDecorButton *, void *);
+
+typedef enum MBWMDecorDirtyState
+{
+ MBWMDecorDirtyNot = 0,
+ MBWMDecorDirtyTitle = (1<<0),
+ MBWMDecorDirtyPaint = (1<<1),
+
+ MBWMDecorDirtyFull = 0xffffffff,
+} MBWMDecorDirtyState;
+
+struct MBWMDecor
+{
+ MBWMObject parent;
+ MBWMDecorType type;
+ Window xwin;
+ MBWindowManagerClient *parent_client;
+ MBGeometry geom;
+ MBWMDecorDirtyState dirty;
+ Bool absolute_packing;
+ MBWMList *buttons;
+ int pack_start_x;
+ int pack_end_x;
+
+ unsigned long press_cb_id;
+ unsigned long release_cb_id;
+
+ void *themedata;
+ MBWMDecorDestroyUserData destroy_themedata;
+};
+
+struct MBWMDecorClass
+{
+ MBWMObjectClass parent;
+};
+
+
+MBWMDecor*
+mb_wm_decor_new (MBWindowManager *wm,
+ MBWMDecorType type);
+
+void
+mb_wm_decor_handle_repaint (MBWMDecor *decor);
+
+void
+mb_wm_decor_handle_resize (MBWMDecor *decor);
+
+Window
+mb_wm_decor_get_x_window (MBWMDecor *decor);
+
+MBWMDecorType
+mb_wm_decor_get_type (MBWMDecor *decor);
+
+int
+mb_wm_decor_get_pack_start_x (MBWMDecor *decor);
+
+int
+mb_wm_decor_get_pack_end_x (MBWMDecor *decor);
+
+const MBGeometry*
+mb_wm_decor_get_geometry (MBWMDecor *decor);
+
+MBWindowManagerClient*
+mb_wm_decor_get_parent (MBWMDecor *decor);
+
+void
+mb_wm_decor_mark_dirty (MBWMDecor *decor);
+
+void
+mb_wm_decor_mark_title_dirty (MBWMDecor *decor);
+
+MBWMDecorDirtyState
+mb_wm_decor_get_dirty_state (MBWMDecor *decor);
+
+void
+mb_wm_decor_attach (MBWMDecor *decor,
+ MBWindowManagerClient *client);
+
+void
+mb_wm_decor_detach (MBWMDecor *decor);
+
+void
+mb_wm_decor_set_theme_data (MBWMDecor * decor, void *userdata,
+ MBWMDecorDestroyUserData destroy);
+
+void *
+mb_wm_decor_get_theme_data (MBWMDecor* decor);
+
+typedef enum MBWMDecorButtonState
+{
+ MBWMDecorButtonStateInactive = 0,
+ MBWMDecorButtonStatePressed
+
+} MBWMDecorButtonState ;
+
+typedef enum MBWMDecorButtonType
+{
+ MBWMDecorButtonCustom = 0,
+ MBWMDecorButtonClose = 1,
+ MBWMDecorButtonMenu = 2,
+ MBWMDecorButtonMinimize = 3,
+ MBWMDecorButtonFullscreen = 4,
+ MBWMDecorButtonAccept = 5,
+ MBWMDecorButtonHelp = 6,
+} MBWMDecorButtonType;
+
+typedef enum MBWMDecorButtonPack
+ {
+ MBWMDecorButtonPackStart = 0,
+ MBWMDecorButtonPackEnd = 1,
+ }
+MBWMDecorButtonPack;
+
+struct MBWMDecorButton
+{
+ MBWMObject parent;
+ MBWMDecorButtonType type;
+ MBWMDecorButtonPack pack;
+ MBWMDecor *decor;
+
+ MBGeometry geom;
+
+ /* in priv ? */
+ Bool visible;
+ Bool needs_sync;
+ Bool realized;
+ Bool press_activated;
+ MBWMDecorButtonState state;
+
+ MBWMDecorButtonPressedFunc press;
+ MBWMDecorButtonReleasedFunc release;
+
+ unsigned long press_cb_id;
+
+ /* Data for any custom button callbacks */
+ void *userdata;
+ MBWMDecorButtonDestroyUserData destroy_userdata;
+
+ /* Data utilized by the theme engine */
+ void *themedata;
+ MBWMDecorButtonDestroyUserData destroy_themedata;
+
+};
+
+struct MBWMDecorButtonClass
+{
+ MBWMObjectClass parent;
+
+ /*
+ show;
+ hide;
+ realize; ??
+ */
+};
+
+void
+mb_wm_decor_button_show (MBWMDecorButton *button);
+
+void
+mb_wm_decor_button_hide (MBWMDecorButton *button);
+
+void
+mb_wm_decor_button_move_to (MBWMDecorButton *button, int x, int y);
+
+void
+mb_wm_decor_button_handle_repaint (MBWMDecorButton *button);
+
+MBWMDecorButton*
+mb_wm_decor_button_new (MBWindowManager *wm,
+ MBWMDecorButtonType type,
+ MBWMDecorButtonPack pack,
+ MBWMDecor *decor,
+ MBWMDecorButtonPressedFunc press,
+ MBWMDecorButtonReleasedFunc release,
+ MBWMDecorButtonFlags flags);
+
+
+MBWMDecorButton*
+mb_wm_decor_button_stock_new (MBWindowManager *wm,
+ MBWMDecorButtonType type,
+ MBWMDecorButtonPack pack,
+ MBWMDecor *decor,
+ MBWMDecorButtonFlags flags);
+
+void
+mb_wm_decor_button_set_user_data (MBWMDecorButton * button, void *userdata,
+ MBWMDecorButtonDestroyUserData destroy);
+
+void *
+mb_wm_decor_button_get_user_data (MBWMDecorButton * button);
+
+void
+mb_wm_decor_button_set_theme_data (MBWMDecorButton * button, void *themedata,
+ MBWMDecorButtonDestroyUserData destroy);
+
+void *
+mb_wm_decor_button_get_theme_data (MBWMDecorButton* button);
+
+#endif
diff --git a/matchbox2/core/mb-wm-keys.c b/matchbox2/core/mb-wm-keys.c
new file mode 100644
index 0000000..7c32105
--- /dev/null
+++ b/matchbox2/core/mb-wm-keys.c
@@ -0,0 +1,379 @@
+#include "mb-wm.h"
+#include <ctype.h> /* isalpha etc */
+
+struct MBWMKeys /* FIXME: Probably do want to hide these here */
+{
+ MBWMList *bindings; /* Always points to first binding */
+
+ int MetaMask;
+ int HyperMask;
+ int SuperMask;
+ int AltMask;
+ int ModeMask;
+ int NumLockMask;
+ int ScrollLockMask;
+ int lock_mask;
+
+};
+
+static Bool
+keysym_needs_shift (MBWindowManager *wm, KeySym keysym)
+{
+ int min_kc, max_kc, keycode, col;
+ KeySym k;
+
+ XDisplayKeycodes(wm->xdpy, &min_kc, &max_kc);
+
+ for (keycode = min_kc; keycode <= max_kc; keycode++)
+ for (col = 0;
+ (k = XKeycodeToKeysym (wm->xdpy, keycode, col)) != NoSymbol;
+ col++)
+ if (k == keysym && col == 1)
+ return True;
+
+ return False;
+}
+
+static Bool
+key_binding_set_grab (MBWindowManager *wm,
+ MBWMKeyBinding *key,
+ Bool ungrab)
+{
+ int ignored_mask = 0;
+
+ MBWM_ASSERT (wm->keys != NULL);
+
+ /* Needed to grab all Locked combo's too */
+ while (ignored_mask < (int) wm->keys->lock_mask)
+ {
+ if (ignored_mask & ~(wm->keys->lock_mask))
+ {
+ ++ignored_mask;
+ continue;
+ }
+
+ if (ungrab)
+ {
+ MBWM_DBG("ungrabbing %i , %i",
+ XKeysymToKeycode(wm->xdpy, key->keysym),
+ key->modifier_mask);
+
+ XUngrabKey(wm->xdpy,
+ XKeysymToKeycode(wm->xdpy, key->keysym),
+ key->modifier_mask | ignored_mask,
+ wm->root_win->xwindow);
+ }
+ else
+ {
+ int result;
+
+ mb_wm_util_trap_x_errors();
+
+ MBWM_DBG ("grabbing keycode: %i, keysym %li, mask: %i",
+ XKeysymToKeycode(wm->xdpy, key->keysym),
+ key->keysym,
+ key->modifier_mask | ignored_mask);
+
+ XGrabKey(wm->xdpy, XKeysymToKeycode(wm->xdpy, key->keysym),
+ key->modifier_mask | ignored_mask,
+ wm->root_win->xwindow, True, GrabModeAsync, GrabModeAsync);
+
+ result = mb_wm_util_untrap_x_errors();
+
+ if (result != Success)
+ {
+ if (result == BadAccess)
+ mb_wm_util_warn ("Some other program is already using the key %s with modifiers %x as a binding\n",
+ (XKeysymToString(key->keysym)) ? XKeysymToString (key->keysym) : "unknown",
+ key->modifier_mask | ignored_mask );
+ else
+ mb_wm_util_warn ("Unable to grab the key %s with modifiers %x as a binding\n",
+ (XKeysymToString(key->keysym)) ? XKeysymToString (key->keysym) : "unknown",
+ key->modifier_mask | ignored_mask );
+ return False;
+ }
+ }
+
+ ++ignored_mask;
+ }
+
+ return True;
+}
+
+void
+mb_wm_keys_binding_remove_all (MBWindowManager *wm)
+{
+
+}
+
+void
+mb_wm_keys_binding_remove (MBWindowManager *wm,
+ MBWMKeyBinding *binding)
+{
+
+ key_binding_set_grab (wm, binding, True);
+}
+
+MBWMKeyBinding*
+mb_wm_keys_binding_add (MBWindowManager *wm,
+ KeySym ks,
+ int mask,
+ MBWMKeyPressedFunc press_func,
+ MBWMKeyDestroyFunc destroy_func,
+ void *userdata)
+{
+ MBWMKeyBinding *binding = NULL;
+ MBWMKeys *keys = wm->keys;
+
+ MBWM_ASSERT (wm->keys != NULL);
+
+ binding = mb_wm_util_malloc0(sizeof(MBWMKeyBinding));
+
+ binding->keysym = ks;
+ binding->modifier_mask = mask;
+ binding->pressed = press_func;
+ binding->destroy = destroy_func;
+ binding->userdata = userdata;
+
+ if (key_binding_set_grab (wm, binding, False))
+ {
+ keys->bindings = mb_wm_util_list_append(keys->bindings, binding);
+ return binding;
+ }
+
+ /* Grab failed */
+ free(binding);
+ return NULL;
+}
+
+MBWMKeyBinding*
+mb_wm_keys_binding_add_with_spec (MBWindowManager *wm,
+ const char *keystr,
+ MBWMKeyPressedFunc press_func,
+ MBWMKeyDestroyFunc destroy_func,
+ void *userdata)
+{
+ char *orig, *p, *q, *keydef = NULL;
+ int i = 0, mask = 0;
+ Bool want_shift = False;
+ KeySym ks;
+ MBWMKeys *keys = wm->keys;
+ MBWMKeyBinding *binding = NULL;
+
+ struct { char *def; int mask; } lookup[] =
+ {
+ { "ctrl", ControlMask },
+ { "alt", keys->AltMask },
+ { "meta", keys->MetaMask },
+ { "super",keys->SuperMask },
+ { "hyper",keys->HyperMask },
+ { "mod1", Mod1Mask },
+ { "mod2", Mod2Mask },
+ { "mod3", Mod3Mask },
+ { "mod4", Mod4Mask },
+ { "mod5", Mod5Mask },
+ { "shift",-1 },
+ { NULL, 0 }
+ };
+
+ orig = p = strdup(keystr);
+
+ /* parse '<mod><mod><mod>key' */
+
+ while (*p != '\0')
+ {
+ Bool found = False;
+
+ if (*p == '<')
+ {
+ q = ++p; i = 0;
+
+ while (*q != '\0' && *q != '>')
+ q++;
+
+ if (*q == '\0')
+ goto out; /* Parse error */
+
+ while (lookup[i].def != NULL && !found)
+ {
+ if (!strncasecmp(p, lookup[i].def, q-p) && lookup[i].mask)
+ {
+ if (lookup[i].mask == -1)
+ want_shift = True;
+ else
+ mask |= lookup[i].mask;
+ found = True;
+ }
+ i++;
+ }
+
+ if (found)
+ p = q;
+ else
+ goto out;
+ }
+ else if (!isspace(*p))
+ {
+ keydef = p;
+ break;
+ }
+
+ p++;
+ }
+
+ if (!keydef)
+ goto out;
+
+ MBWM_DBG("keydefinition is %s, want_shift is %i", keydef, want_shift);
+
+ if ((ks = XStringToKeysym(keydef)) == (KeySym)NULL)
+ {
+ if (islower(keydef[0])) /* Try again, changing case */
+ keydef[0] = toupper(keydef[0]);
+ else
+ keydef[0] = tolower(keydef[0]);
+
+ if ((ks = XStringToKeysym(keydef)) == (KeySym)NULL)
+ {
+ mb_wm_util_warn ("Cant find keysym for %s", keydef);
+ goto out;
+ }
+ }
+
+ if (keysym_needs_shift(wm, ks) || want_shift)
+ mask |= ShiftMask;
+
+ /* If we grab keycode 0, we end up grabbing the entire keyboard.. */
+ if (XKeysymToKeycode(wm->xdpy, ks) == 0 && mask == 0)
+ {
+ MBWM_DBG("Cant find a keycode for keysym %li", ks);
+ goto out;
+ }
+
+ binding = mb_wm_keys_binding_add (wm, ks, mask,
+ press_func, destroy_func, userdata);
+
+ out:
+
+ free (orig);
+ return binding;
+}
+
+void /* FIXME: rename */
+mb_wm_keys_press (MBWindowManager *wm,
+ KeySym keysym,
+ int modifier_mask)
+{
+ MBWMList *iter;
+ MBWMKeyBinding *binding;
+
+ if (!wm->keys)
+ return;
+
+ MBWM_DBG ("Looking up keysym <%li>, ( mask %i )", keysym, modifier_mask);
+
+ iter = wm->keys->bindings;
+
+ while (iter)
+ {
+ int ignored_mask = 0;
+
+ binding = (MBWMKeyBinding*)iter->data;
+
+ MBWM_DBG ("Checking up keysym <%li>, ( mask %i )",
+ binding->keysym,
+ binding->modifier_mask);
+
+ /* FIXME: Assumes multiple bindings per key */
+ while (ignored_mask < (int) wm->keys->lock_mask)
+ {
+ if (ignored_mask & ~(wm->keys->lock_mask))
+ {
+ ++ignored_mask;
+ continue;
+ }
+
+ if (binding->pressed
+ && binding->keysym == keysym
+ && binding->modifier_mask|ignored_mask == modifier_mask)
+ {
+ binding->pressed(wm, binding, binding->userdata);
+ break;
+ }
+
+ ++ignored_mask;
+ }
+
+ iter = mb_wm_util_list_next(iter);
+ }
+}
+
+
+Bool
+mb_wm_keys_init(MBWindowManager *wm)
+{
+ int mod_idx, mod_key, col, kpm;
+ XModifierKeymap *mod_map;
+ MBWMKeys *keys;
+
+ mod_map = XGetModifierMapping(wm->xdpy);
+
+ keys = wm->keys = mb_wm_util_malloc0(sizeof(MBWMKeys));
+
+ /* Figure out modifier masks */
+
+ kpm = mod_map->max_keypermod;
+ for (mod_idx = 0; mod_idx < 8; mod_idx++)
+ for (mod_key = 0; mod_key < kpm; mod_key++)
+ {
+ KeySym last_sym = 0;
+ for (col = 0; col < 4; col += 2)
+ {
+ KeyCode code = mod_map->modifiermap[mod_idx * kpm + mod_key];
+ KeySym sym = (code ? XKeycodeToKeysym(wm->xdpy, code, col) : 0);
+
+ if (sym == last_sym) continue;
+ last_sym = sym;
+
+ switch (sym)
+ {
+ case XK_Mode_switch:
+ /* XXX store_modifier("Mode_switch", mode_bit); */
+ break;
+ case XK_Meta_L:
+ case XK_Meta_R:
+ keys->MetaMask |= (1 << mod_idx);
+ break;
+ case XK_Super_L:
+ case XK_Super_R:
+ keys->SuperMask |= (1 << mod_idx);
+ break;
+ case XK_Hyper_L:
+ case XK_Hyper_R:
+ keys->HyperMask |= (1 << mod_idx);
+ break;
+ case XK_Alt_L:
+ case XK_Alt_R:
+ keys->AltMask |= (1 << mod_idx);
+ break;
+ case XK_Num_Lock:
+ keys->NumLockMask |= (1 << mod_idx);
+ break;
+ case XK_Scroll_Lock:
+ keys->ScrollLockMask |= (1 << mod_idx);
+ break;
+ }
+ }
+ }
+
+ /* XXX check this. assume alt <=> meta if only either set */
+ if (!keys->AltMask) keys->AltMask = keys->MetaMask;
+ if (!keys->MetaMask) keys->MetaMask = keys->AltMask;
+
+ keys->lock_mask = keys->ScrollLockMask | keys->NumLockMask | LockMask;
+
+ if (mod_map) XFreeModifiermap(mod_map);
+
+ return True;
+}
+
diff --git a/matchbox2/core/mb-wm-keys.h b/matchbox2/core/mb-wm-keys.h
new file mode 100644
index 0000000..0269274
--- /dev/null
+++ b/matchbox2/core/mb-wm-keys.h
@@ -0,0 +1,55 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_KEYS_H
+#define _HAVE_MB_WM_KEYS_H
+
+#include <matchbox2/core/mb-wm.h>
+
+void
+mb_wm_keys_binding_remove_all (MBWindowManager *wm);
+
+void
+mb_wm_keys_binding_remove (MBWindowManager *wm,
+ MBWMKeyBinding *binding);
+MBWMKeyBinding*
+mb_wm_keys_binding_add (MBWindowManager *wm,
+ KeySym ks,
+ int mask,
+ MBWMKeyPressedFunc press_func,
+ MBWMKeyDestroyFunc destroy_func,
+ void *userdata);
+
+MBWMKeyBinding*
+mb_wm_keys_binding_add_with_spec (MBWindowManager *wm,
+ const char *keystr,
+ MBWMKeyPressedFunc press_func,
+ MBWMKeyDestroyFunc destroy_func,
+ void *userdata);
+
+void
+mb_wm_keys_press (MBWindowManager *wm,
+ KeySym keysym,
+ int modifier_mask);
+
+Bool
+mb_wm_keys_init (MBWindowManager *wm);
+
+#endif
diff --git a/matchbox2/core/mb-wm-layout.c b/matchbox2/core/mb-wm-layout.c
new file mode 100644
index 0000000..793276c
--- /dev/null
+++ b/matchbox2/core/mb-wm-layout.c
@@ -0,0 +1,753 @@
+#include "mb-wm.h"
+#include "mb-wm-client-input.h"
+
+static void
+mb_wm_layout_real_update (MBWMLayout * layout);
+static void
+mb_wm_layout_real_layout_panels (MBWMLayout *layout, MBGeometry * avail_geom);
+static void
+mb_wm_layout_real_layout_input (MBWMLayout *layout, MBGeometry * avail_geom);
+static void
+mb_wm_layout_real_layout_free (MBWMLayout *layout, MBGeometry * avail_geom);
+static void
+mb_wm_layout_real_layout_fullscreen (MBWMLayout *layout, MBGeometry * avail_geom);
+
+static void
+mb_wm_layout_class_init (MBWMObjectClass *klass)
+{
+ MBWMLayoutClass * layout_class = MB_WM_LAYOUT_CLASS (klass);
+
+ layout_class->update = mb_wm_layout_real_update;
+ layout_class->layout_panels = mb_wm_layout_real_layout_panels;
+ layout_class->layout_input = mb_wm_layout_real_layout_input;
+ layout_class->layout_free = mb_wm_layout_real_layout_free;
+ layout_class->layout_fullscreen = mb_wm_layout_real_layout_fullscreen;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMLayout";
+#endif
+}
+
+static void
+mb_wm_layout_destroy (MBWMObject *this)
+{
+}
+
+static int
+mb_wm_layout_init (MBWMObject *this, va_list vap)
+{
+ MBWMLayout *layout = MB_WM_LAYOUT (this);
+ MBWMObjectProp prop;
+ MBWindowManager *wm = NULL;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropWm:
+ wm = va_arg(vap, MBWindowManager *);
+ break;
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ MBWM_ASSERT (wm);
+
+ layout->wm = wm;
+
+ return 1;
+}
+
+int
+mb_wm_layout_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMLayoutClass),
+ sizeof (MBWMLayout),
+ mb_wm_layout_init,
+ mb_wm_layout_destroy,
+ mb_wm_layout_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+MBWMLayout*
+mb_wm_layout_new (MBWindowManager *wm)
+{
+ MBWMLayout *layout;
+
+ layout = MB_WM_LAYOUT (mb_wm_object_new (MB_WM_TYPE_LAYOUT,
+ MBWMObjectPropWm, wm,
+ NULL));
+ return layout;
+}
+
+Bool
+mb_wm_layout_clip_geometry (MBGeometry *geom,
+ MBGeometry *min,
+ int flags)
+{
+ Bool changed = False;
+
+ if (flags & SET_X)
+ if (geom->x < min->x || geom->x > min->x + min->width)
+ {
+ geom->x = min->x;
+ changed = True;
+ }
+
+ if (flags & SET_Y)
+ if (geom->y < min->y || geom->y > min->y + min->height)
+ {
+ geom->y = min->y;
+ changed = True;
+ }
+
+ if (flags & SET_WIDTH)
+ if (geom->x + geom->width > min->x + min->width)
+ {
+ int old_width = geom->width;
+
+ geom->width = min->x + min->width - geom->x;
+
+ /*
+ * if we are about to reduce the width, and are asked also to set the x
+ * coord, see if we can move the window left so it can be bigger.
+ */
+ if ((flags & SET_X) && old_width > geom->width && geom->x > min->x)
+ {
+ int w_diff = old_width - geom->width;
+ int x = geom->x - w_diff;
+ int x_diff;
+
+ if (x < min->x)
+ x = min->x;
+
+ x_diff = geom->x - x;
+
+ geom->x = x;
+ geom->width += x_diff;
+ }
+
+ changed = True;
+ }
+
+ if (flags & SET_HEIGHT)
+ if (geom->y + geom->height > min->y + min->height)
+ {
+ int old_height = geom->height;
+
+ geom->height = min->y + min->height - geom->y;
+
+ /*
+ * if we are about to reduce the height, and are asked also to set the
+ * y coord, see if we can move the window up so it can be bigger.
+ */
+ if ((flags & SET_Y) && old_height > geom->height && geom->y > min->y)
+ {
+ int h_diff = old_height - geom->height;
+ int y = geom->y - h_diff;
+ int y_diff;
+
+ if (y < min->y)
+ y = min->y;
+
+ y_diff = geom->y - y;
+
+ geom->y = y;
+ geom->height += y_diff;
+ }
+ changed = True;
+ }
+
+ return changed;
+}
+
+Bool
+mb_wm_layout_maximise_geometry (MBGeometry *geom,
+ MBGeometry *max,
+ int flags)
+{
+ Bool changed = False;
+
+ if (flags & SET_X && geom->x != max->x)
+ {
+ geom->x = max->x;
+ changed = True;
+ }
+
+ if (flags & SET_Y && geom->y != max->y)
+ {
+ geom->y = max->y;
+ changed = True;
+ }
+
+ if (flags & SET_WIDTH && geom->width != max->width)
+ {
+ geom->width = max->width;
+ changed = True;
+ }
+
+ if (flags & SET_HEIGHT && geom->height != max->height)
+ {
+ geom->height = max->height;
+ changed = True;
+ }
+
+ return changed;
+}
+
+static void
+mb_wm_layout_real_layout_panels (MBWMLayout *layout, MBGeometry * avail_geom)
+{
+ MBWindowManager *wm = layout->wm;
+ MBWindowManagerClient *client;
+ MBGeometry coverage;
+ Bool need_change;
+
+ /* FIXME: need to enumerate by *age* in case multiple panels ? */
+ mb_wm_stack_enumerate(wm, client)
+ if ((mb_wm_client_get_layout_hints(client) & LayoutPrefReserveEdgeNorth) &&
+ (mb_wm_client_get_layout_hints(client) & LayoutPrefVisible))
+ {
+ int flags = SET_Y;
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefFixedX))
+ flags |= SET_X | SET_WIDTH;
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom, flags);
+ /* Too high */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_HEIGHT);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+ /* FIXME: what if this returns False ? */
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefOverlaps))
+ {
+ avail_geom->y = coverage.y + coverage.height;
+ avail_geom->height = avail_geom->height - coverage.height;
+ }
+ }
+
+ mb_wm_stack_enumerate(wm, client)
+ if ((mb_wm_client_get_layout_hints(client) & LayoutPrefReserveEdgeSouth) &&
+ (mb_wm_client_get_layout_hints(client) & LayoutPrefVisible))
+ {
+ int y;
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefFixedX))
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_X | SET_WIDTH);
+ else
+ need_change = False;
+
+ y = avail_geom->y + avail_geom->height - coverage.height;
+
+ if (y != coverage.y)
+ {
+ coverage.y = y;
+ need_change = True;
+ }
+
+ /* Too high */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_HEIGHT);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefOverlaps))
+ avail_geom->height = avail_geom->height - coverage.height;
+ }
+
+ mb_wm_stack_enumerate(wm, client)
+ if ((mb_wm_client_get_layout_hints(client) & LayoutPrefReserveEdgeWest) &&
+ (mb_wm_client_get_layout_hints(client) & LayoutPrefVisible))
+ {
+ int flags = SET_X;
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefFixedY))
+ flags |= SET_Y | SET_HEIGHT;
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ flags);
+ /* Too wide */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_WIDTH);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefOverlaps))
+ {
+ avail_geom->x = coverage.x + coverage.width;
+ avail_geom->width = avail_geom->width - coverage.width;
+ }
+ }
+
+
+ mb_wm_stack_enumerate(wm, client)
+ if ((mb_wm_client_get_layout_hints(client) & LayoutPrefReserveEdgeEast) &&
+ (mb_wm_client_get_layout_hints(client) & LayoutPrefVisible))
+ {
+ int x;
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefFixedY))
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_Y|SET_HEIGHT);
+ else
+ need_change = False;
+
+ x = avail_geom->x + avail_geom->width - coverage.width;
+
+ if (x != coverage.x)
+ {
+ coverage.x = x;
+ need_change = True;
+ }
+
+ /* Too wide */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_WIDTH);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ if (!(mb_wm_client_get_layout_hints (client) & LayoutPrefOverlaps))
+ avail_geom->width = avail_geom->width - coverage.width;
+ }
+}
+
+static void
+mb_wm_layout_real_layout_input (MBWMLayout *layout, MBGeometry * avail_geom)
+{
+ MBWindowManager *wm = layout->wm;
+ MBWindowManagerClient *client;
+ MBGeometry coverage;
+ Bool need_change;
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefReserveNorth|LayoutPrefVisible))
+ {
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_X|SET_Y|SET_WIDTH);
+
+ if (client->transient_for &&
+ (client->transient_for->window->ewmh_state &
+ MBWMClientWindowEWMHStateFullscreen) &&
+ coverage.width != wm->xdpy_width)
+ {
+ coverage.width = wm->xdpy_width;
+ coverage.x = 0;
+ need_change = True;
+ }
+
+ /* Too high */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_HEIGHT);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+ /* FIXME: what if this returns False ? */
+
+ avail_geom->y = coverage.y + coverage.height;
+ avail_geom->height = avail_geom->height - coverage.height;
+ }
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefReserveSouth|LayoutPrefVisible))
+ {
+ int y;
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* First of all, tweak the y value so that we start with position
+ * that as much as possible respects the request for south edge
+ * for the current geometry. For example, the hildon input method
+ * initially maps with height 1 and y 399; it then requests resize
+ * to some sensible height, but does not adjust the y value.
+ */
+ y = avail_geom->y + avail_geom->height - coverage.height;
+
+ if (y < 0)
+ y = 0;
+
+ if (y != coverage.y)
+ need_change = True;
+
+ coverage.y = y;
+
+ /* set x and width */
+ need_change |= mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_X|SET_WIDTH);
+
+ if (client->transient_for &&
+ (client->transient_for->window->ewmh_state &
+ MBWMClientWindowEWMHStateFullscreen) &&
+ coverage.width != wm->xdpy_width)
+ {
+ coverage.width = wm->xdpy_width;
+ coverage.x = 0;
+ need_change = True;
+ }
+
+ /* Too high */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_HEIGHT);
+
+ if (coverage.y != avail_geom->y + avail_geom->height - coverage.height)
+ {
+ coverage.y = avail_geom->y + avail_geom->height - coverage.height;
+ need_change = True;
+ }
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ avail_geom->height = avail_geom->height - coverage.height;
+ }
+
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefReserveWest|LayoutPrefVisible))
+ {
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_X|SET_Y|SET_HEIGHT);
+
+ if (client->transient_for &&
+ (client->transient_for->window->ewmh_state &
+ MBWMClientWindowEWMHStateFullscreen) &&
+ coverage.height != wm->xdpy_height)
+ {
+ coverage.height = wm->xdpy_height;
+ coverage.y = 0;
+ need_change = True;
+ }
+
+ /* Too wide */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_WIDTH);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ avail_geom->x = coverage.x + coverage.width;
+ avail_geom->width = avail_geom->width - coverage.width;
+ }
+
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefReserveEast|LayoutPrefVisible))
+ {
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* set x,y to avail and max width */
+ need_change = mb_wm_layout_maximise_geometry (&coverage,
+ avail_geom,
+ SET_Y|SET_HEIGHT);
+
+ if (client->transient_for &&
+ (client->transient_for->window->ewmh_state &
+ MBWMClientWindowEWMHStateFullscreen) &&
+ coverage.height != wm->xdpy_height)
+ {
+ coverage.height = wm->xdpy_height;
+ coverage.y = 0;
+ need_change = True;
+ }
+
+ /* Too wide */
+ need_change |= mb_wm_layout_clip_geometry (&coverage,
+ avail_geom, SET_WIDTH);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+
+ if (coverage.x != avail_geom->x + avail_geom->width - coverage.width)
+ {
+ coverage.x = avail_geom->x + avail_geom->width - coverage.width;
+ need_change = True;
+ }
+
+ avail_geom->width = avail_geom->width - coverage.width;
+ }
+}
+
+static void
+mb_wm_layout_real_layout_free (MBWMLayout *layout, MBGeometry * avail_geom)
+{
+ MBWindowManager *wm = layout->wm;
+ MBWindowManagerClient *client;
+ MBGeometry coverage;
+ Bool need_change;
+ int min_x, max_x, min_y, max_y;
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefGrowToFreeSpace|LayoutPrefVisible))
+ {
+ mb_wm_client_get_coverage (client, &coverage);
+
+ if (coverage.x != avail_geom->x
+ || coverage.width != avail_geom->width
+ || coverage.y != avail_geom->y
+ || coverage.height != avail_geom->height)
+ {
+ MBWM_DBG("available geom for free space: %i+%i %ix%i",
+ min_x, min_y, max_x - min_x, max_y - min_y);
+
+ coverage.width = avail_geom->width;
+ coverage.height = avail_geom->height;
+ coverage.x = avail_geom->x;
+ coverage.y = avail_geom->y;
+
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+ }
+ }
+
+ mb_wm_stack_enumerate(wm, client)
+ {
+ MBWMClientLayoutHints hints = mb_wm_client_get_layout_hints (client);
+
+ if ((hints & LayoutPrefPositionFree) && (hints & LayoutPrefVisible) &&
+ !(hints & (LayoutPrefFixedX|LayoutPrefFixedY)))
+ {
+ /* Clip if needed */
+ mb_wm_client_get_coverage (client, &coverage);
+
+ need_change = mb_wm_layout_clip_geometry (&coverage,
+ avail_geom,
+ SET_X | SET_Y |
+ SET_HEIGHT | SET_WIDTH);
+
+ if (need_change)
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+ }
+ }
+
+}
+
+static void
+mb_wm_layout_real_layout_fullscreen (MBWMLayout *layout, MBGeometry * avail_geom)
+{
+ MBWindowManager *wm = layout->wm;
+ MBWindowManagerClient *client;
+ MBGeometry coverage;
+
+ mb_wm_stack_enumerate(wm, client)
+ if (mb_wm_client_get_layout_hints (client) ==
+ (LayoutPrefFullscreen|LayoutPrefVisible))
+ {
+ MBWMList *l = mb_wm_client_get_transients (client);
+
+ mb_wm_client_get_coverage (client, &coverage);
+
+ /* See if this client comes with an input method and if so,
+ * adjust the available geometry accordingly
+ */
+ while (l)
+ {
+ MBWindowManagerClient * c = l->data;
+
+ if (MB_WM_CLIENT_CLIENT_TYPE (c) == MBWMClientTypeInput)
+ {
+ MBGeometry geom;
+ mb_wm_client_get_coverage (c, &geom);
+
+ if (mb_wm_client_get_layout_hints (c) ==
+ (LayoutPrefReserveSouth|LayoutPrefVisible))
+ {
+ if (geom.y < avail_geom->y + avail_geom->height)
+ {
+ avail_geom->height = geom.y - avail_geom->y;
+ }
+ }
+ else if (mb_wm_client_get_layout_hints (c) ==
+ (LayoutPrefReserveNorth|LayoutPrefVisible))
+ {
+ if (geom.height && geom.height + geom.y > avail_geom->y)
+ {
+ int y = avail_geom->y;
+
+ avail_geom->y = geom.y + geom.height;
+ avail_geom->height -= y - avail_geom->y;
+ }
+ }
+ else if (mb_wm_client_get_layout_hints (c) ==
+ (LayoutPrefReserveWest|LayoutPrefVisible))
+ {
+ if (geom.x < avail_geom->x + avail_geom->width)
+ {
+ avail_geom->width = geom.x - avail_geom->x;
+ }
+ }
+ else if (mb_wm_client_get_layout_hints (c) ==
+ (LayoutPrefReserveEast|LayoutPrefVisible))
+ {
+ if (geom.width && geom.width + geom.x > avail_geom->x)
+ {
+ int x = avail_geom->x;
+
+ avail_geom->x = geom.x + geom.width;
+ avail_geom->width -= x - avail_geom->x;
+ }
+ }
+
+ break;
+ }
+
+ l = l->next;
+ }
+
+ if (coverage.x != avail_geom->x
+ || coverage.width != avail_geom->width
+ || coverage.y != avail_geom->y
+ || coverage.height != avail_geom->height)
+ {
+ coverage.width = avail_geom->width;
+ coverage.height = avail_geom->height;
+ coverage.x = avail_geom->x;
+ coverage.y = avail_geom->y;
+
+ mb_wm_client_request_geometry (client,
+ &coverage,
+ MBWMClientReqGeomIsViaLayoutManager);
+ }
+
+ mb_wm_util_list_free (l);
+ }
+}
+
+static void
+mb_wm_layout_real_update (MBWMLayout * layout)
+{
+ MBWMLayoutClass *klass;
+ MBWindowManager *wm = layout->wm;
+ MBGeometry avail_geom;
+
+ klass = MB_WM_LAYOUT_CLASS (MB_WM_OBJECT_GET_CLASS (layout));
+
+ MBWM_ASSERT (klass->layout_panels);
+ MBWM_ASSERT (klass->layout_input);
+ MBWM_ASSERT (klass->layout_free);
+ MBWM_ASSERT (klass->layout_fullscreen);
+
+ mb_wm_get_display_geometry (wm, &avail_geom);
+
+ /*
+ cycle through clients, laying out each in below order.
+ Note they must have LayoutPrefVisible set.
+
+ LayoutPrefReserveEdgeNorth
+ LayoutPrefReserveEdgeSouth
+
+ LayoutPrefReserveEdgeEast
+ LayoutPrefReserveEdgeWest
+
+ LayoutPrefReserveNorth
+ LayoutPrefReserveSouth
+
+ LayoutPrefReserveEast
+ LayoutPrefReserveWest
+
+ LayoutPrefGrowToFreeSpace
+
+ LayoutPrefFullscreen
+
+ XXX need to check they are mapped too
+
+ foreach client with LayoutPrefReserveEdgeNorth & LayoutPrefVisible
+ grab there current geometry
+ does it fit well into current restraints ( min_, max_ )
+ yes leave
+ no resize so it does, mark dirty
+ set min_x, max_y, min_y, max_y to current size
+ repeat for next condition
+
+ mb_wm_client_get_coverage (MBWindowManagerClient *client,
+ MBGeometry *coverage)
+
+ */
+
+ klass->layout_panels (layout, &avail_geom);
+ klass->layout_input (layout, &avail_geom);
+ klass->layout_free (layout, &avail_geom);
+
+ mb_wm_get_display_geometry (wm, &avail_geom);
+ klass->layout_fullscreen (layout, &avail_geom);
+}
+
+void
+mb_wm_layout_update (MBWMLayout * layout)
+{
+ MBWMLayoutClass *klass;
+
+ klass = MB_WM_LAYOUT_CLASS (MB_WM_OBJECT_GET_CLASS (layout));
+
+ MBWM_ASSERT (klass->update);
+
+ klass->update (layout);
+}
diff --git a/matchbox2/core/mb-wm-layout.h b/matchbox2/core/mb-wm-layout.h
new file mode 100644
index 0000000..81db28d
--- /dev/null
+++ b/matchbox2/core/mb-wm-layout.h
@@ -0,0 +1,76 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_LAYOUT_MANAGER_H
+#define _HAVE_MB_WM_LAYOUT_MANAGER_H
+
+#include <matchbox2/core/mb-wm.h>
+
+#define MB_WM_LAYOUT(c) ((MBWMLayout*)(c))
+#define MB_WM_LAYOUT_CLASS(c) ((MBWMLayoutClass*)(c))
+#define MB_WM_TYPE_LAYOUT (mb_wm_layout_class_type ())
+
+struct MBWMLayout
+{
+ MBWMObject parent;
+
+ MBWindowManager *wm;
+};
+
+struct MBWMLayoutClass
+{
+ MBWMObjectClass parent;
+
+ void (*update) (MBWMLayout *layout);
+
+ void (*layout_panels) (MBWMLayout *layout, MBGeometry *avail_geom);
+ void (*layout_input) (MBWMLayout *layout, MBGeometry *avail_geom);
+ void (*layout_free) (MBWMLayout *layout, MBGeometry *avail_geom);
+ void (*layout_fullscreen) (MBWMLayout *layout, MBGeometry *avail_geom);
+};
+
+int
+mb_wm_layout_class_type ();
+
+MBWMLayout*
+mb_wm_layout_new (MBWindowManager *wm);
+
+void
+mb_wm_layout_update (MBWMLayout *layout);
+
+/* These are intended for use by subclasses of MBWMLayout */
+
+#define SET_X (1<<1)
+#define SET_Y (1<<2)
+#define SET_WIDTH (1<<3)
+#define SET_HEIGHT (1<<4)
+#define SET_ALL (SET_X|SET_Y|SET_WIDTH|SET_HEIGHT)
+
+Bool
+mb_wm_layout_maximise_geometry (MBGeometry *geom,
+ MBGeometry *max,
+ int flags);
+
+Bool
+mb_wm_layout_clip_geometry (MBGeometry *geom,
+ MBGeometry *min,
+ int flags);
+
+#endif
diff --git a/matchbox2/core/mb-wm-macros.h b/matchbox2/core/mb-wm-macros.h
new file mode 100644
index 0000000..5c8ab4b
--- /dev/null
+++ b/matchbox2/core/mb-wm-macros.h
@@ -0,0 +1,104 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_MACROS_H
+#define _HAVE_MB_MACROS_H
+
+#if MBWM_WANT_DEBUG
+#define MBWM_NOTE(type,x,a...) do { \
+ if (mbwm_debug_flags & MBWM_DEBUG_##type) \
+ { fprintf (stderr, "[" #type "] " __FILE__ ":%d,%s() " ": " x "\n", __LINE__, __func__, ##a); } \
+ } while (0);
+
+#define MBWM_MARK() MBWM_NOTE(MISC, "== mark ==")
+#define MBWM_DBG(x, a...) MBWM_NOTE(MISC, x, ##a)
+
+#include <execinfo.h>
+
+#define _MBWM_TRACE(type,x,a...) \
+if (mbwm_debug_flags & MBWM_DEBUG_##type) \
+do \
+{ \
+ void *trace[10]; \
+ size_t depth, i; \
+ char **strings; \
+ \
+ fprintf (stderr, __FILE__ ":%d,%s(): " x "\n", \
+ __LINE__, __func__, ##a); \
+ \
+ depth = backtrace (trace, sizeof(trace)/sizeof(void*)); \
+ strings = backtrace_symbols (trace, depth); \
+ \
+ for (i = 1; i < depth; ++i) \
+ { \
+ char * s = strings[i]; \
+ while (s && *s && *s != '(') \
+ s++; \
+ \
+ if (s && *s) \
+ s++; \
+ \
+ fprintf (stderr, " %s\n", s); \
+ } \
+ free (strings); \
+}while (0)
+
+#define MBWM_TRACE() _MBWM_TRACE(TRACE, "### TRACE ###")
+#define MBWM_TRACE_MSG(type,x,a...) _MBWM_TRACE(type, x, ##a)
+
+#else /* !MBWM_ENABLE_DEBUG */
+
+#define MBWM_NOTE(type,x,a...)
+#define MBWM_DBG(x, a...)
+#define MBWM_TRACE()
+#define MBWM_TRACE_MSG(type,x,a...)
+#define MBWM_MARK()
+
+#endif /* MBWM_ENABLE_DEBUG */
+
+#define MBWM_WANT_ASSERT 1
+
+#if (MBWM_WANT_ASSERT)
+#include <assert.h>
+#define MBWM_ASSERT(x) assert(x)
+#else
+#define MBWM_ASSERT(x) do {} while (0)
+#endif
+
+/* FIXME: ifdef this with compile time flag */
+#define mbwm_return_if_fail(expr) do { \
+ if LIKELY(expr) { } else \
+ { \
+ mb_wm_util_warn (__FILE__ ":%d,%s() " ":" #expr "failed" ,\
+ __LINE__, __func__); \
+ return; \
+ } \
+ } while(0);
+
+#define mbwm_return_val_if_fail(expr,val) do { \
+ if LIKELY(expr) { } else \
+ { \
+ mb_wm_util_warn (__FILE__ ":%d,%s() " ":" #expr "failed" ,\
+ __LINE__, __func__); \
+ return val; \
+ } \
+ } while(0);
+
+#endif
diff --git a/matchbox2/core/mb-wm-main-context.c b/matchbox2/core/mb-wm-main-context.c
new file mode 100644
index 0000000..71d5d6c
--- /dev/null
+++ b/matchbox2/core/mb-wm-main-context.c
@@ -0,0 +1,1116 @@
+#include "mb-wm-main-context.h"
+
+#include <sys/time.h>
+#include <poll.h>
+#include <limits.h>
+#include <fcntl.h>
+
+#if ENABLE_COMPOSITE
+#include <X11/extensions/Xdamage.h>
+#endif
+
+#define MBWM_CTX_MAX_TIMEOUT 100
+
+#if MBWM_WANT_DEBUG
+
+static const char *MBWMDEBUGEvents[] = {
+ "error",
+ "reply",
+ "KeyPress",
+ "KeyRelease",
+ "ButtonPress",
+ "ButtonRelease",
+ "MotionNotify",
+ "EnterNotify",
+ "LeaveNotify",
+ "FocusIn",
+ "FocusOut",
+ "KeymapNotify",
+ "Expose",
+ "GraphicsExpose",
+ "NoExpose",
+ "VisibilityNotify",
+ "CreateNotify",
+ "DestroyNotify",
+ "UnmapNotify",
+ "MapNotify",
+ "MapRequest",
+ "ReparentNotify",
+ "ConfigureNotify",
+ "ConfigureRequest",
+ "GravityNotify",
+ "ResizeRequest",
+ "CirculateNotify",
+ "CirculateRequest",
+ "PropertyNotify",
+ "SelectionClear",
+ "SelectionRequest",
+ "SelectionNotify",
+ "ColormapNotify",
+ "ClientMessage",
+ "MappingNotify",
+};
+
+#endif
+
+static Bool
+mb_wm_main_context_check_timeouts (MBWMMainContext *ctx);
+
+static Bool
+mb_wm_main_context_check_fd_watches (MBWMMainContext * ctx);
+
+static Bool
+mb_wm_main_context_spin_xevent (MBWMMainContext *ctx);
+
+struct MBWMTimeOutEventInfo
+{
+ int ms;
+ MBWindowManagerTimeOutFunc func;
+ void *userdata;
+ unsigned long id;
+ struct timeval triggers;
+
+};
+
+struct MBWMFdWatchInfo{
+ MBWMIOChannel *channel;
+ MBWMIOCondition events;
+ MBWindowManagerFdWatchFunc func;
+ void *userdata;
+ unsigned long id;
+};
+
+static void
+mb_wm_main_context_class_init (MBWMObjectClass *klass)
+{
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMMainContext";
+#endif
+}
+
+static void
+mb_wm_main_context_destroy (MBWMObject *this)
+{
+}
+
+#if USE_GLIB_MAINLOOP
+gboolean
+mb_wm_main_context_gloop_xevent (gpointer userdata)
+{
+ MBWMMainContext * ctx = userdata;
+ MBWindowManager * wm = ctx->wm;
+
+ while (mb_wm_main_context_spin_xevent (ctx));
+
+ if (wm->sync_type)
+ mb_wm_sync (wm);
+
+ return TRUE;
+}
+#endif
+
+static int
+mb_wm_main_context_init (MBWMObject *this, va_list vap)
+{
+ MBWMMainContext *ctx = MB_WM_MAIN_CONTEXT (this);
+ MBWindowManager *wm = NULL;
+ MBWMObjectProp prop;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ if (prop == MBWMObjectPropWm)
+ {
+ wm = va_arg(vap, MBWindowManager *);
+ break;
+ }
+ else
+ MBWMO_PROP_EAT (vap, prop);
+
+ prop = va_arg (vap, MBWMObjectProp);
+ }
+
+ ctx->wm = wm;
+
+ return 1;
+}
+
+int
+mb_wm_main_context_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMMainContextClass),
+ sizeof (MBWMMainContext),
+ mb_wm_main_context_init,
+ mb_wm_main_context_destroy,
+ mb_wm_main_context_class_init
+ };
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+MBWMMainContext*
+mb_wm_main_context_new (MBWindowManager *wm)
+{
+ MBWMMainContext *ctx;
+
+ ctx = MB_WM_MAIN_CONTEXT (mb_wm_object_new (MB_WM_TYPE_MAIN_CONTEXT,
+ MBWMObjectPropWm, wm,
+ NULL));
+
+ return ctx;
+}
+
+Bool
+mb_wm_main_context_handle_x_event (XEvent *xev,
+ MBWMMainContext *ctx)
+{
+ MBWindowManager *wm = ctx->wm;
+ MBWMList *iter;
+ Window xwin = xev->xany.window;
+
+#if (MBWM_WANT_DEBUG)
+ {
+ if (mbwm_debug_flags & MBWM_DEBUG_EVENT)
+ {
+ MBWindowManagerClient *ev_client;
+
+ ev_client = mb_wm_managed_client_from_xwindow(wm, xev->xany.window);
+
+ printf (" @ XEvent: '%s:%i' for %lx %s%s\n",
+ xev->type < sizeof (MBWMDEBUGEvents)/sizeof(MBWMDEBUGEvents[0])
+ ? MBWMDEBUGEvents[xev->type] : "unknown",
+ xev->type,
+ xev->xany.window,
+ xev->xany.window == wm->root_win->xwindow ? "(root)" : "",
+ ev_client ? ev_client->name : ""
+ );
+ }
+ }
+#endif
+
+#define XE_ITER_GET_FUNC(i) (((MBWMXEventFuncInfo *)((i)->data))->func)
+#define XE_ITER_GET_DATA(i) ((MBWMXEventFuncInfo *)((i)->data))->userdata
+#define XE_ITER_GET_XWIN(i) ((MBWMXEventFuncInfo *)((i)->data))->xwindow
+
+#if ENABLE_COMPOSITE
+ if (xev->type == wm->damage_event_base + XDamageNotify)
+ {
+ iter = ctx->event_funcs.damage_notify;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWMXEventFunc)XE_ITER_GET_FUNC(iter)
+ (xev, XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ }
+ else
+#endif
+ switch (xev->type)
+ {
+ case ClientMessage:
+ /*
+ * TODO -- perhaps this should not be special-cased.
+ */
+ if (xev->xany.window == wm->root_win->xwindow ||
+ ((XClientMessageEvent *)xev)->message_type ==
+ wm->atoms[MBWM_ATOM_NET_ACTIVE_WINDOW] ||
+ ((XClientMessageEvent *)xev)->message_type ==
+ wm->atoms[MBWM_ATOM_NET_WM_STATE])
+ {
+ mb_wm_root_window_handle_message (wm->root_win,
+ (XClientMessageEvent *)xev);
+ }
+
+ iter = ctx->event_funcs.client_message;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerClientMessageFunc)XE_ITER_GET_FUNC(iter)
+ ((XClientMessageEvent*)&xev->xclient,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ case Expose:
+ break;
+ case MapRequest:
+ iter = ctx->event_funcs.map_request;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerMapRequestFunc)XE_ITER_GET_FUNC(iter)
+ ((XMapRequestEvent*)&xev->xmaprequest,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ case MapNotify:
+ iter = ctx->event_funcs.map_notify;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerMapNotifyFunc)XE_ITER_GET_FUNC(iter)
+ ((XMapEvent*)&xev->xmap,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ case UnmapNotify:
+#if MBWM_WANT_DEBUG
+ if (mbwm_debug_flags & MBWM_DEBUG_EVENT)
+ {
+ XUnmapEvent * uev = & xev->xunmap;
+ printf (" window %x, event %x, %d\n",
+ uev->window,
+ uev->event,
+ uev->from_configure);
+ }
+#endif
+ xwin = xev->xunmap.window;
+ iter = ctx->event_funcs.unmap_notify;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerUnmapNotifyFunc)XE_ITER_GET_FUNC(iter)
+ ((XUnmapEvent*)&xev->xunmap,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ case DestroyNotify:
+ iter = ctx->event_funcs.destroy_notify;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerDestroyNotifyFunc)XE_ITER_GET_FUNC(iter)
+ ((XDestroyWindowEvent*)&xev->xdestroywindow,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ case ConfigureNotify:
+#if MBWM_WANT_DEBUG
+ if (mbwm_debug_flags & MBWM_DEBUG_EVENT)
+ {
+ XConfigureEvent * cev = & xev->xconfigure;
+ printf (" window %x, event %x, [%d,%d;%dx%d]\n",
+ cev->window,
+ cev->event,
+ cev->x,
+ cev->y,
+ cev->width,
+ cev->height);
+ }
+#endif
+ xwin = xev->xconfigure.window;
+ iter = ctx->event_funcs.configure_notify;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerConfigureNotifyFunc)XE_ITER_GET_FUNC(iter)
+ ((XConfigureEvent*)&xev->xconfigure,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ case ConfigureRequest:
+#if MBWM_WANT_DEBUG
+ if (mbwm_debug_flags & MBWM_DEBUG_EVENT)
+ {
+ XConfigureRequestEvent * cev = & xev->xconfigurerequest;
+ printf (" window %x, parent %x, [%d,%d;%dx%d]\n",
+ cev->window,
+ cev->parent,
+ cev->x,
+ cev->y,
+ cev->width,
+ cev->height);
+ }
+#endif
+ xwin = xev->xconfigurerequest.window;
+ iter = ctx->event_funcs.configure_request;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerConfigureRequestFunc)XE_ITER_GET_FUNC(iter)
+ ((XConfigureRequestEvent*)&xev->xconfigurerequest,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ case KeyPress:
+ iter = ctx->event_funcs.key_press;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerKeyPressFunc)XE_ITER_GET_FUNC(iter)
+ ((XKeyEvent*)&xev->xkey,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ case PropertyNotify:
+#if MBWM_WANT_DEBUG
+ if (mbwm_debug_flags & MBWM_DEBUG_EVENT)
+ {
+ XPropertyEvent * pev = & xev->xproperty;
+ char * prop = XGetAtomName (wm->xdpy, pev->atom);
+ printf (" window %x, prop %s, state %d\n",
+ pev->window,
+ prop,
+ pev->state);
+
+ if (prop)
+ XFree (prop);
+ }
+#endif
+ xwin = xev->xproperty.window;
+ iter = ctx->event_funcs.property_notify;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerPropertyNotifyFunc)XE_ITER_GET_FUNC(iter)
+ ((XPropertyEvent*)&xev->xproperty,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ case ButtonPress:
+ iter = ctx->event_funcs.button_press;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerButtonPressFunc)XE_ITER_GET_FUNC(iter)
+ ((XButtonEvent*)&xev->xbutton,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ case ButtonRelease:
+ iter = ctx->event_funcs.button_release;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerButtonReleaseFunc)XE_ITER_GET_FUNC(iter)
+ ((XButtonEvent*)&xev->xbutton,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ case MotionNotify:
+ iter = ctx->event_funcs.motion_notify;
+
+ while (iter)
+ {
+ Window msg_xwin = XE_ITER_GET_XWIN(iter);
+ MBWMList * next = iter->next;
+
+ if (msg_xwin == None || msg_xwin == xwin)
+ {
+ if (!(MBWindowManagerMotionNotifyFunc)XE_ITER_GET_FUNC(iter)
+ ((XMotionEvent*)&xev->xmotion,
+ XE_ITER_GET_DATA(iter)))
+ break;
+ }
+
+ iter = next;
+ }
+ break;
+ }
+
+ return False;
+}
+
+static Bool
+mb_wm_main_context_spin_xevent (MBWMMainContext *ctx)
+{
+ MBWindowManager * wm = ctx->wm;
+ XEvent xev;
+
+ if (!XEventsQueued (wm->xdpy, QueuedAfterFlush))
+ return False;
+
+ XNextEvent(wm->xdpy, &xev);
+
+ mb_wm_main_context_handle_x_event (&xev, ctx);
+
+ return (XEventsQueued (wm->xdpy, QueuedAfterReading) != 0);
+}
+
+static Bool
+mb_wm_main_context_spin_xevent_blocking (MBWMMainContext *ctx)
+{
+ MBWindowManager * wm = ctx->wm;
+ XEvent xev;
+
+ XNextEvent(wm->xdpy, &xev);
+
+ mb_wm_main_context_handle_x_event (&xev, ctx);
+
+ return (XEventsQueued (wm->xdpy, QueuedAfterReading) != 0);
+}
+
+void
+mb_wm_main_context_loop (MBWMMainContext *ctx)
+{
+#if ! USE_GLIB_MAINLOOP
+ MBWindowManager * wm = ctx->wm;
+
+ while (True)
+ {
+ Bool sources;
+
+ sources = mb_wm_main_context_check_timeouts (ctx);
+ sources |= mb_wm_main_context_check_fd_watches (ctx);
+
+ if (!sources)
+ {
+ /* No timeouts, idles, etc. -- wait for next
+ * X event
+ */
+ mb_wm_main_context_spin_xevent_blocking (ctx);
+ }
+ else
+ {
+ /* Process any pending xevents */
+ while (mb_wm_main_context_spin_xevent (ctx));
+ }
+
+ if (wm->sync_type)
+ mb_wm_sync (wm);
+ }
+#endif
+}
+
+Bool
+mb_wm_main_context_spin_loop (MBWMMainContext *ctx)
+{
+#if USE_GLIB_MAINLOOP
+ g_main_context_iteration (NULL, FALSE);
+ return g_main_context_pending (NULL);
+#else
+ return mb_wm_main_context_spin_xevent (ctx);
+#endif
+}
+
+
+unsigned long
+mb_wm_main_context_x_event_handler_add (MBWMMainContext *ctx,
+ Window xwin,
+ int type,
+ MBWMXEventFunc func,
+ void *userdata)
+{
+ static unsigned long ids = 0;
+ MBWMXEventFuncInfo * func_info;
+#if ENABLE_COMPOSITE
+ MBWindowManager * wm = ctx->wm;
+#endif
+
+ ++ids;
+
+ func_info = mb_wm_util_malloc0(sizeof(MBWMXEventFuncInfo));
+ func_info->func = func;
+ func_info->xwindow = xwin;
+ func_info->userdata = userdata;
+ func_info->id = ids;
+
+#if ENABLE_COMPOSITE
+ if (type == wm->damage_event_base + XDamageNotify)
+ {
+ ctx->event_funcs.damage_notify =
+ mb_wm_util_list_append (ctx->event_funcs.damage_notify, func_info);
+ }
+ else
+#endif
+ switch (type)
+ {
+ case Expose:
+ break;
+ case MapRequest:
+ ctx->event_funcs.map_request =
+ mb_wm_util_list_append (ctx->event_funcs.map_request, func_info);
+ break;
+ case MapNotify:
+ ctx->event_funcs.map_notify=
+ mb_wm_util_list_append (ctx->event_funcs.map_notify, func_info);
+ break;
+ case UnmapNotify:
+ ctx->event_funcs.unmap_notify=
+ mb_wm_util_list_append (ctx->event_funcs.unmap_notify, func_info);
+ break;
+ case DestroyNotify:
+ ctx->event_funcs.destroy_notify =
+ mb_wm_util_list_append (ctx->event_funcs.destroy_notify, func_info);
+ break;
+ case ConfigureNotify:
+ ctx->event_funcs.configure_notify =
+ mb_wm_util_list_append (ctx->event_funcs.configure_notify, func_info);
+ break;
+ case ConfigureRequest:
+ ctx->event_funcs.configure_request =
+ mb_wm_util_list_append (ctx->event_funcs.configure_request, func_info);
+ break;
+ case KeyPress:
+ ctx->event_funcs.key_press =
+ mb_wm_util_list_append (ctx->event_funcs.key_press, func_info);
+ break;
+ case PropertyNotify:
+ ctx->event_funcs.property_notify =
+ mb_wm_util_list_append (ctx->event_funcs.property_notify, func_info);
+ break;
+ case ButtonPress:
+ ctx->event_funcs.button_press =
+ mb_wm_util_list_append (ctx->event_funcs.button_press, func_info);
+ break;
+ case ButtonRelease:
+ ctx->event_funcs.button_release =
+ mb_wm_util_list_append (ctx->event_funcs.button_release, func_info);
+ break;
+ case MotionNotify:
+ ctx->event_funcs.motion_notify =
+ mb_wm_util_list_append (ctx->event_funcs.motion_notify, func_info);
+ break;
+ case ClientMessage:
+ ctx->event_funcs.client_message =
+ mb_wm_util_list_append (ctx->event_funcs.client_message, func_info);
+ break;
+
+ default:
+ break;
+ }
+
+ return ids;
+}
+
+void
+mb_wm_main_context_x_event_handler_remove (MBWMMainContext *ctx,
+ int type,
+ unsigned long id)
+{
+ MBWMList * l = NULL;
+ MBWMList **l_start;
+
+#if ENABLE_COMPOSITE
+ MBWindowManager * wm = ctx->wm;
+
+ if (type == wm->damage_event_base + XDamageNotify)
+ {
+ l_start = &ctx->event_funcs.damage_notify;
+ }
+ else
+#endif
+ switch (type)
+ {
+ case Expose:
+ break;
+ case MapRequest:
+ l_start = &ctx->event_funcs.map_request;
+ break;
+ case MapNotify:
+ l_start = &ctx->event_funcs.map_notify;
+ break;
+ case UnmapNotify:
+ l_start = &ctx->event_funcs.unmap_notify;
+ break;
+ case DestroyNotify:
+ l_start = &ctx->event_funcs.destroy_notify;
+ break;
+ case ConfigureNotify:
+ l_start = &ctx->event_funcs.configure_notify;
+ break;
+ case ConfigureRequest:
+ l_start = &ctx->event_funcs.configure_request;
+ break;
+ case KeyPress:
+ l_start = &ctx->event_funcs.key_press;
+ break;
+ case PropertyNotify:
+ l_start = &ctx->event_funcs.property_notify;
+ break;
+ case ButtonPress:
+ l_start = &ctx->event_funcs.button_press;
+ break;
+ case ButtonRelease:
+ l_start = &ctx->event_funcs.button_release;
+ break;
+ case MotionNotify:
+ l_start = &ctx->event_funcs.motion_notify;
+ break;
+ case ClientMessage:
+ l_start = &ctx->event_funcs.client_message;
+ break;
+
+ default:
+ break;
+ }
+
+ l = *l_start;
+
+ while (l)
+ {
+ MBWMXEventFuncInfo * info = l->data;
+
+ if (info->id == id)
+ {
+ MBWMList * prev = l->prev;
+ MBWMList * next = l->next;
+
+ if (prev)
+ prev->next = next;
+ else
+ *l_start = next;
+
+ if (next)
+ next->prev = prev;
+
+ free (info);
+ free (l);
+
+ return;
+ }
+
+ l = l->next;
+ }
+}
+
+#if ! USE_GLIB_MAINLOOP
+static void
+mb_wm_main_context_timeout_setup (MBWMTimeOutEventInfo * tinfo,
+ struct timeval * current_time)
+{
+ int sec = tinfo->ms / 1000;
+ int usec = (tinfo->ms - sec *1000) * 1000;
+
+ sec += current_time->tv_sec;
+ usec += current_time->tv_usec;
+
+ if (usec >= 1000000)
+ {
+ usec -= 1000000;
+ sec++;
+ }
+
+ tinfo->triggers.tv_sec = sec;
+ tinfo->triggers.tv_usec = usec;
+}
+
+static Bool
+mb_wm_main_context_handle_timeout (MBWMTimeOutEventInfo *tinfo,
+ struct timeval *current_time)
+{
+ if (tinfo->triggers.tv_sec < current_time->tv_sec ||
+ (tinfo->triggers.tv_sec == current_time->tv_sec &&
+ tinfo->triggers.tv_usec <= current_time->tv_usec))
+ {
+ if (!tinfo->func (tinfo->userdata))
+ return False;
+
+ mb_wm_main_context_timeout_setup (tinfo, current_time);
+ }
+
+ return True;
+}
+
+/*
+ * Returns false if no timeouts are present
+ */
+static Bool
+mb_wm_main_context_check_timeouts (MBWMMainContext *ctx)
+{
+ MBWMList * l = mb_wm_util_list_get_first(ctx->event_funcs.timeout);
+ struct timeval current_time;
+
+ if (!l)
+ return False;
+
+ gettimeofday (&current_time, NULL);
+
+ while (l)
+ {
+ MBWMTimeOutEventInfo * tinfo = l->data;
+ unsigned long tid = tinfo->id;
+
+ if (!mb_wm_main_context_handle_timeout (tinfo, &current_time))
+ {
+ /* Timeout handler notified it can be removed, do so now */
+ mb_wm_main_context_timeout_handler_remove (ctx,tid);
+ /* To avoid race condition, restart at front of list */
+ l = mb_wm_util_list_get_first(ctx->event_funcs.timeout);
+ }
+ else
+ l = mb_wm_util_list_next(l);
+ }
+ return True;
+}
+#endif /* !USE_GLIB_MAINLOOP */
+
+unsigned long
+mb_wm_main_context_timeout_handler_add (MBWMMainContext *ctx,
+ int ms,
+ MBWindowManagerTimeOutFunc func,
+ void *userdata)
+{
+#if ! USE_GLIB_MAINLOOP
+ static unsigned long ids = 0;
+ MBWMTimeOutEventInfo * tinfo;
+ struct timeval current_time;
+
+ ++ids;
+
+ tinfo = mb_wm_util_malloc0 (sizeof (MBWMTimeOutEventInfo));
+ tinfo->func = func;
+ tinfo->id = ids;
+ tinfo->ms = ms;
+ tinfo->userdata = userdata;
+
+ gettimeofday (&current_time, NULL);
+ mb_wm_main_context_timeout_setup (tinfo, &current_time);
+
+ ctx->event_funcs.timeout =
+ mb_wm_util_list_append (ctx->event_funcs.timeout, tinfo);
+
+ return ids;
+
+#else
+ return g_timeout_add (ms, func, userdata);
+#endif
+}
+
+void
+mb_wm_main_context_timeout_handler_remove (MBWMMainContext *ctx,
+ unsigned long id)
+{
+#if ! USE_GLIB_MAINLOOP
+ MBWMList * l = ctx->event_funcs.timeout;
+
+ while (l)
+ {
+ MBWMTimeOutEventInfo * info = l->data;
+
+ if (info->id == id)
+ {
+ /* Reset list head after entry removal */
+ ctx->event_funcs.timeout =
+ mb_wm_util_list_remove(ctx->event_funcs.timeout, l->data);
+ return;
+ }
+
+ l = mb_wm_util_list_next(l);
+ }
+#else
+ g_source_remove (id);
+#endif
+}
+
+unsigned long
+mb_wm_main_context_fd_watch_add (MBWMMainContext *ctx,
+ MBWMIOChannel *channel,
+ MBWMIOCondition events,
+ MBWindowManagerFdWatchFunc func,
+ void *userdata)
+{
+#if ! USE_GLIB_MAINLOOP
+ static unsigned long ids = 0;
+ MBWMFdWatchInfo * finfo;
+ struct pollfd * fds;
+
+ ++ids;
+
+ finfo = mb_wm_util_malloc0 (sizeof (MBWMFdWatchInfo));
+ finfo->func = func;
+ finfo->id = ids;
+ finfo->channel = channel;
+ finfo->events = events;
+ finfo->userdata = userdata;
+
+ ctx->event_funcs.fd_watch =
+ mb_wm_util_list_append (ctx->event_funcs.fd_watch, finfo);
+
+ ctx->n_poll_fds++;
+ ctx->poll_fds = realloc (ctx->poll_fds, sizeof (struct pollfd));
+
+ fds = ctx->poll_fds + (ctx->n_poll_fds - 1);
+ fds->fd = *channel;
+ fds->events = events;
+
+ return ids;
+
+#else
+ return g_io_add_watch (channel, events, func, userdata);
+#endif
+}
+
+void
+mb_wm_main_context_fd_watch_remove (MBWMMainContext *ctx,
+ unsigned long id)
+{
+#if ! USE_GLIB_MAINLOOP
+ MBWMList * l = ctx->event_funcs.fd_watch;
+
+ while (l)
+ {
+ MBWMFdWatchInfo * info = l->data;
+
+ if (info->id == id)
+ {
+ MBWMList * prev = l->prev;
+ MBWMList * next = l->next;
+
+ if (prev)
+ prev->next = next;
+ else
+ ctx->event_funcs.fd_watch = next;
+
+ if (next)
+ next->prev = prev;
+
+ free (info);
+ free (l);
+
+ return;
+ }
+
+ l = l->next;
+ }
+
+ ctx->n_poll_fds--;
+ ctx->poll_cache_dirty = True;
+#else
+ g_source_remove (id);
+#endif
+}
+
+MBWMIOChannel *
+mb_wm_main_context_io_channel_new (int fd)
+{
+#if ! USE_GLIB_MAINLOOP
+ MBWMIOChannel * c = mb_wm_util_malloc0 (sizeof (MBWMIOChannel));
+ *c = fd;
+ return c;
+#else
+ return g_io_channel_unix_new (fd);
+#endif
+}
+
+
+void
+mb_wm_main_context_io_channel_destroy (MBWMIOChannel * channel)
+{
+#if ! USE_GLIB_MAINLOOP
+ if (channel)
+ free (channel);
+#else
+ g_io_channel_unref (channel);
+#endif
+}
+
+int
+mb_wm_main_context_io_channel_get_fd (MBWMIOChannel * channel)
+{
+#if ! USE_GLIB_MAINLOOP
+ return *channel;
+#else
+ g_io_channel_unix_get_fd (channel);
+#endif
+}
+
+#if ! USE_GLIB_MAINLOOP
+static void
+mb_wm_main_context_setup_poll_cache (MBWMMainContext *ctx)
+{
+ MBWMList *l = ctx->event_funcs.fd_watch;
+ int i = 0;
+
+ if (!ctx->poll_cache_dirty)
+ return;
+
+ ctx->poll_fds = realloc (ctx->poll_fds, ctx->n_poll_fds);
+
+ while (l)
+ {
+ MBWMFdWatchInfo *info = l->data;
+
+ ctx->poll_fds[i].fd = *(info->channel);
+ ctx->poll_fds[i].events = info->events;
+
+ l = l->next;
+ ++i;
+ }
+
+ ctx->poll_cache_dirty = False;
+}
+
+static Bool
+mb_wm_main_context_check_fd_watches (MBWMMainContext * ctx)
+{
+ int ret;
+ int i = 0;
+ MBWMList * l = ctx->event_funcs.fd_watch;
+ Bool removal = False;
+
+ if (!ctx->n_poll_fds)
+ return False;
+
+ mb_wm_main_context_setup_poll_cache (ctx);
+
+ ret = poll (ctx->poll_fds, ctx->n_poll_fds, 0);
+
+ if (ret < 0)
+ {
+ MBWM_DBG ("Poll failed.");
+ return True;
+ }
+
+ if (ret == 0)
+ return True;
+
+ while (l)
+ {
+ MBWMFdWatchInfo *info = l->data;
+
+ if (ctx->poll_fds[i].revents & ctx->poll_fds[i].events)
+ {
+ Bool zap = !info->func (info->channel, ctx->poll_fds[i].revents,
+ info->userdata);
+
+ if (zap)
+ {
+ MBWMList * prev = l->prev;
+ MBWMList * next = l->next;
+
+ if (prev)
+ prev->next = next;
+ else
+ ctx->event_funcs.fd_watch = next;
+
+ if (next)
+ next->prev = prev;
+
+ free (info);
+ free (l);
+
+ ctx->n_poll_fds--;
+
+ removal = True;
+
+ l = next;
+ }
+ else
+ l = l->next;
+ }
+ else
+ l = l->next;
+
+ ++i;
+ }
+
+ ctx->poll_cache_dirty = removal;
+
+ return True;
+}
+#endif
diff --git a/matchbox2/core/mb-wm-main-context.h b/matchbox2/core/mb-wm-main-context.h
new file mode 100644
index 0000000..d9ce7b0
--- /dev/null
+++ b/matchbox2/core/mb-wm-main-context.h
@@ -0,0 +1,141 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_MAIN_CONTEXT_H
+#define _HAVE_MB_MAIN_CONTEXT_H
+
+#include <matchbox2/core/mb-wm.h>
+#include <poll.h>
+
+#define MB_WM_MAIN_CONTEXT(c) ((MBWMMainContext*)(c))
+#define MB_WM_MAIN_CONTEXT_CLASS(c) ((MBWMMainContextClass*)(c))
+#define MB_WM_TYPE_MAIN_CONTEXT (mb_wm_main_context_class_type ())
+#define MB_WM_IS_MAIN_CONTEXT(c) (MB_WM_OBJECT_TYPE(c)==MB_WM_TYPE_MAIN_CONTEXT)
+
+typedef Bool (*MBWMMainContextXEventFunc) (XEvent * xev, void * userdata);
+
+typedef struct MBWMEventFuncs
+{
+ /* FIXME: figure our X wrap / unwrap mechanism */
+ MBWMList *map_notify;
+ MBWMList *unmap_notify;
+ MBWMList *map_request;
+ MBWMList *destroy_notify;
+ MBWMList *configure_request;
+ MBWMList *configure_notify;
+ MBWMList *key_press;
+ MBWMList *property_notify;
+ MBWMList *button_press;
+ MBWMList *button_release;
+ MBWMList *motion_notify;
+ MBWMList *client_message;
+
+#if ENABLE_COMPOSITE
+ MBWMList *damage_notify;
+#endif
+
+#if ! USE_GLIB_MAINLOOP
+ MBWMList *timeout;
+ MBWMList *fd_watch;
+#endif
+}
+MBWMEventFuncs;
+
+struct MBWMMainContext
+{
+ MBWMObject parent;
+
+ MBWindowManager *wm;
+
+ MBWMEventFuncs event_funcs;
+ struct pollfd *poll_fds;
+ int n_poll_fds;
+ Bool poll_cache_dirty;
+};
+
+struct MBWMMainContextClass
+{
+ MBWMObjectClass parent;
+};
+
+int
+mb_wm_main_context_class_type ();
+
+MBWMMainContext*
+mb_wm_main_context_new(MBWindowManager *wm);
+
+unsigned long
+mb_wm_main_context_x_event_handler_add (MBWMMainContext *ctx,
+ Window xwin,
+ int type,
+ MBWMXEventFunc func,
+ void *userdata);
+
+void
+mb_wm_main_context_x_event_handler_remove (MBWMMainContext *ctx,
+ int type,
+ unsigned long id);
+
+unsigned long
+mb_wm_main_context_timeout_handler_add (MBWMMainContext *ctx,
+ int ms,
+ MBWindowManagerTimeOutFunc func,
+ void *userdata);
+
+void
+mb_wm_main_context_timeout_handler_remove (MBWMMainContext *ctx,
+ unsigned long id);
+
+MBWMIOChannel *
+mb_wm_main_context_io_channel_new (int fd);
+
+void
+mb_wm_main_context_io_channel_destroy (MBWMIOChannel * channel);
+
+int
+mb_wm_main_context_io_channel_get_fd (MBWMIOChannel * channel);
+
+unsigned long
+mb_wm_main_context_fd_watch_add (MBWMMainContext *ctx,
+ MBWMIOChannel *channel,
+ MBWMIOCondition events,
+ MBWindowManagerFdWatchFunc func,
+ void *userdata);
+
+void
+mb_wm_main_context_fd_watch_remove (MBWMMainContext *ctx,
+ unsigned long id);
+
+#if USE_GLIB_MAINLOOP
+gboolean
+mb_wm_main_context_gloop_xevent (gpointer userdata);
+#endif
+
+Bool
+mb_wm_main_context_handle_x_event (XEvent *xev,
+ MBWMMainContext *ctx);
+
+void
+mb_wm_main_context_loop (MBWMMainContext *ctx);
+
+Bool
+mb_wm_main_context_spin_loop (MBWMMainContext *ctx);
+
+#endif
diff --git a/matchbox2/core/mb-wm-object-props.h b/matchbox2/core/mb-wm-object-props.h
new file mode 100644
index 0000000..c2d9fb4
--- /dev/null
+++ b/matchbox2/core/mb-wm-object-props.h
@@ -0,0 +1,104 @@
+
+#ifndef _HAVE_MB_OBJECT_PROPS_H
+#define _HAVE_MB_OBJECT_PROPS_H
+
+#include <matchbox2/core/mb-wm-types.h>
+
+/*
+ * MBWMObject construction properties
+ *
+ * NB: the properties are only used at construction time, being passed to
+ * mb_wm_object_new (); they cannot be set or queried subsequently.
+ *
+ * Property ids are numerical; this allows us (a) to avoid excessive use of
+ * strcmp during object creation (passing 6 properties to the constructor
+ * would result in each _init function doing 21 strcmp() call to retrieve it's
+ * values), and (b) handle unknown properties safely.
+ *
+ * Property arguments can only be of the following types:
+ *
+ * int,
+ * long,
+ * long long,
+ * void*,
+ *
+ * plus their unsigned variants.
+ *
+ * The property id is a 32-bit value, constructed as follows:
+ *
+ * Bits 31-4 : numerical id that uniquely identifies this property. Bits 31-24
+ * are reserved for private properties of any objects built out of
+ * tree to avoid clashing with default properties; with default
+ * properties bits 31-24 are always 0 (_MBWMObjectPropLastGlobal
+ * represent the highest numerical id of a default property).
+ *
+ * Bits 3-0 : Size of the property argument, as returned by sizeof().
+ *
+ * Since properties always come in id-value pairs, when an object _init()
+ * function encounters a property it does not know, it needs to eat the
+ * argument, the MBWMO_PROP_EAT() macro is provided for this purpose.
+ */
+#define _MKOPROP(n, type) (((1<<4)+(n<<4))|sizeof(type))
+
+#define MBWMO_PROP_EAT(_ovap, prop) \
+do \
+{ \
+ int size = (prop & 0x0000000f); \
+ \
+ if (size == sizeof (int)) \
+ va_arg (_ovap, int); \
+ else if (size == sizeof (void *)) \
+ va_arg (_ovap, void *); \
+ else if (size == sizeof (long)) \
+ va_arg (_ovap, long); \
+ else if (size == sizeof (long long)) \
+ va_arg (_ovap, long long); \
+}while (0)
+
+typedef enum MBWMObjectProp
+ {
+ MBWMObjectPropWidth = _MKOPROP(0, int),
+ MBWMObjectPropHeight = _MKOPROP(1, int),
+ MBWMObjectPropXwindow = _MKOPROP(2, Window),
+ MBWMObjectPropArgc = _MKOPROP(3, int),
+ MBWMObjectPropArgv = _MKOPROP(4, void*),
+ MBWMObjectPropWm = _MKOPROP(5, void*),
+ MBWMObjectPropClient = _MKOPROP(6, void*),
+ MBWMObjectPropClientWindow = _MKOPROP(7, void*),
+
+ MBWMObjectPropDecor = _MKOPROP(8, void*),
+ MBWMObjectPropDecorType = _MKOPROP(9, MBWMDecorType),
+ MBWMObjectPropDecorUserData = _MKOPROP(10, void*),
+ MBWMObjectPropDecorAbsolutePacking = _MKOPROP(11, int),
+
+ MBWMObjectPropDecorButtonRepaintFunc = _MKOPROP(12, void*),
+ MBWMObjectPropDecorButtonPressedFunc = _MKOPROP(13, void*),
+ MBWMObjectPropDecorButtonReleasedFunc = _MKOPROP(14, void*),
+ MBWMObjectPropDecorButtonFlags = _MKOPROP(15, MBWMDecorButtonFlags),
+ MBWMObjectPropDecorButtonType = _MKOPROP(16, int),
+ MBWMObjectPropDecorButtonPack = _MKOPROP(17, int),
+
+ MBWMObjectPropThemePath = _MKOPROP(18, void*),
+ MBWMObjectPropThemeImg = _MKOPROP(19, void*),
+ MBWMObjectPropThemeXmlClients = _MKOPROP(20, void*),
+ MBWMObjectPropThemeColorLowlight = _MKOPROP(21, void*),
+ MBWMObjectPropThemeColorShadow = _MKOPROP(22, void*),
+ MBWMObjectPropThemeShadowType = _MKOPROP(23, int),
+ MBWMObjectPropThemeCompositing = _MKOPROP(24, int),
+ MBWMObjectPropThemeShaped = _MKOPROP(25, int),
+
+ MBWMObjectPropCompMgrEffectType = _MKOPROP(26, int),
+ MBWMObjectPropCompMgrEffectDuration = _MKOPROP(27, unsigned long),
+ MBWMObjectPropCompMgrEffectGravity = _MKOPROP(28, unsigned long),
+ MBWMObjectPropCompMgrClutterEffectTimeline = _MKOPROP(29, void*),
+ MBWMObjectPropCompMgrClutterEffectBehaviour = _MKOPROP(30, void*),
+
+ MBWMObjectPropDpy = _MKOPROP(31, void*),
+
+ _MBWMObjectPropLastGlobal = 0x00fffff0,
+ }
+MBWMObjectProp;
+
+#undef _MKOPROP
+
+#endif
diff --git a/matchbox2/core/mb-wm-object.c b/matchbox2/core/mb-wm-object.c
new file mode 100644
index 0000000..09a6ad4
--- /dev/null
+++ b/matchbox2/core/mb-wm-object.c
@@ -0,0 +1,477 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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"
+
+#if MBWM_WANT_DEBUG
+#include <execinfo.h>
+#endif
+
+static MBWMObjectClassInfo **ObjectClassesInfo = NULL;
+static MBWMObjectClass **ObjectClasses = NULL;
+static int ObjectClassesAllocated = 0;
+static int NObjectClasses = 0;
+
+#if MBWM_WANT_DEBUG
+#define MBWM_OBJECT_TRACE_DEPTH 3
+/*
+ * Increased for each ref call and decreased for each unref call
+ */
+MBWMList *alloc_objects = NULL;
+
+void
+mb_wm_object_dump ()
+{
+ MBWMList * l = alloc_objects;
+
+ if (!l)
+ {
+ fprintf (stderr, "=== There currently are no allocated objects === \n");
+ return;
+ }
+
+ fprintf (stderr, "=== Currently allocated objects === \n");
+
+ while (l)
+ {
+ int i;
+ MBWMObject * o = l->data;
+ const MBWMObjectClass * k = MB_WM_OBJECT_GET_CLASS (o);
+
+ fprintf (stderr, "Object of type %s, allocated from:\n",
+ k->klass_name);
+
+
+ for (i = 1; i < MBWM_OBJECT_TRACE_DEPTH; ++i)
+ {
+ char * s = o->trace_strings[i];
+ while (s && *s && *s != '(')
+ s++;
+
+ fprintf (stderr, " %s\n", s);
+ }
+
+ l = l->next;
+ }
+
+ fprintf (stderr, "=== Currently allocated objects end === \n");
+
+}
+
+#endif
+
+#define N_CLASSES_PREALLOC 10
+#define N_CLASSES_REALLOC_STEP 5
+
+void
+mb_wm_object_init(void)
+{
+ ObjectClasses = mb_wm_util_malloc0 (sizeof(void*) * N_CLASSES_PREALLOC);
+ ObjectClassesInfo = mb_wm_util_malloc0 (sizeof(void*) * N_CLASSES_PREALLOC);
+
+ if (ObjectClasses && ObjectClassesInfo)
+ ObjectClassesAllocated = N_CLASSES_PREALLOC;
+}
+
+static void
+mb_wm_object_class_init_recurse (MBWMObjectClass *klass,
+ MBWMObjectClass *parent)
+{
+ if (parent->parent)
+ mb_wm_object_class_init_recurse (klass, parent->parent);
+
+ if (parent->class_init)
+ parent->class_init (klass);
+}
+
+static void
+mb_wm_object_class_init (MBWMObjectClass *klass)
+{
+ if (klass->parent)
+ mb_wm_object_class_init_recurse (klass, klass->parent);
+
+ if (klass->class_init)
+ klass->class_init (klass);
+}
+
+int
+mb_wm_object_register_class (MBWMObjectClassInfo *info,
+ int parent_type,
+ int flags)
+{
+ MBWMObjectClass *klass;
+
+ if (NObjectClasses >= ObjectClassesAllocated)
+ {
+ int byte_len;
+ int new_offset;
+ int new_byte_len;
+
+ new_offset = ObjectClassesAllocated;
+ ObjectClassesAllocated += N_CLASSES_REALLOC_STEP;
+
+ byte_len = sizeof(void *) * (ObjectClassesAllocated);
+ new_byte_len = sizeof(void *) * (ObjectClassesAllocated - new_offset);
+
+ ObjectClasses = realloc (ObjectClasses, byte_len);
+ ObjectClassesInfo = realloc (ObjectClassesInfo, byte_len);
+
+ if (!ObjectClasses || !ObjectClassesInfo)
+ return 0;
+
+ memset (ObjectClasses + new_offset , 0, new_byte_len);
+ memset (ObjectClassesInfo + new_offset, 0, new_byte_len);
+ }
+
+ ObjectClassesInfo[NObjectClasses] = info;
+
+ klass = mb_wm_util_malloc0(info->klass_size);
+ klass->init = info->instance_init;
+ klass->destroy = info->instance_destroy;
+ klass->class_init = info->class_init;
+ klass->type = NObjectClasses + 1;
+
+ if (parent_type != 0)
+ klass->parent = ObjectClasses[parent_type-1];
+
+ ObjectClasses[NObjectClasses] = klass;
+
+ mb_wm_object_class_init (klass);
+
+ return 1 + NObjectClasses++;
+}
+
+void *
+mb_wm_object_ref (MBWMObject *this)
+{
+ if (!this)
+ {
+ MBWM_DBG("### Warning: called with NULL ###");
+ return this;
+ }
+
+ this->refcnt++;
+
+ MBWM_TRACE_MSG (OBJ_REF, "### REF ###");
+
+ return this;
+}
+
+static void
+mb_wm_object_destroy_recursive (const MBWMObjectClass * klass,
+ MBWMObject *this)
+{
+ /* Destruction needs to happen top to bottom */
+ MBWMObjectClass *parent_klass = klass->parent;
+
+ if (klass->destroy)
+ klass->destroy (this);
+
+ if (parent_klass)
+ mb_wm_object_destroy_recursive (parent_klass, this);
+}
+
+void
+mb_wm_object_unref (MBWMObject *this)
+{
+ if (!this)
+ {
+ MBWM_DBG("### Warning: called with NULL ###");
+ return;
+ }
+
+
+ this->refcnt--;
+
+ if (this->refcnt == 0)
+ {
+ MBWM_NOTE (OBJ_UNREF, "=== DESTROYING OBJECT type %d ===",
+ this->klass->type);
+
+ mb_wm_object_destroy_recursive (MB_WM_OBJECT_GET_CLASS (this),
+ this);
+
+ free (this);
+
+#if MBWM_WANT_DEBUG
+ alloc_objects = mb_wm_util_list_remove (alloc_objects, this);
+#endif
+ }
+}
+
+static int
+mb_wm_object_init_recurse (MBWMObject *obj, MBWMObjectClass *parent,
+ va_list vap)
+{
+ va_list vap2;
+
+ va_copy (vap2, vap);
+
+ if (parent->parent)
+ if (!mb_wm_object_init_recurse (obj, parent->parent, vap2))
+ return 0;
+
+ if (parent->init)
+ if (!parent->init (obj, vap))
+ return 0;
+
+ va_end (vap2);
+
+ return 1;
+}
+
+static int
+mb_wm_object_init_object (MBWMObject *obj, va_list vap)
+{
+ va_list vap2;
+
+ va_copy(vap2, vap);
+
+ if (obj->klass->parent)
+ if (!mb_wm_object_init_recurse (obj, obj->klass->parent, vap2))
+ return 0;
+
+ if (obj->klass->init)
+ if (!obj->klass->init(obj, vap))
+ return 0;
+
+ va_end(vap2);
+
+ return 1;
+}
+
+
+MBWMObject*
+mb_wm_object_new (int type, ...)
+{
+ MBWMObjectClassInfo *info;
+ MBWMObject *obj;
+ va_list vap;
+
+ va_start(vap, type);
+
+ info = ObjectClassesInfo[type-1];
+
+ obj = mb_wm_util_malloc0 (info->instance_size);
+
+ obj->klass = MB_WM_OBJECT_CLASS(ObjectClasses[type-1]);
+
+ if (!mb_wm_object_init_object (obj, vap))
+ {
+ free (obj);
+ return NULL;
+ }
+
+
+ mb_wm_object_ref (obj);
+
+ va_end(vap);
+
+#if MBWM_WANT_DEBUG
+ {
+ void * trace[MBWM_OBJECT_TRACE_DEPTH];
+
+ alloc_objects = mb_wm_util_list_append (alloc_objects, obj);
+ obj->trace_depth = backtrace (trace, sizeof(trace)/sizeof(void*));
+ obj->trace_strings = backtrace_symbols (trace, obj->trace_depth);
+ }
+#endif
+
+ return obj;
+}
+
+const MBWMObjectClass*
+mb_wm_object_get_class (MBWMObject *this)
+{
+ return this->klass;
+}
+
+unsigned long
+mb_wm_object_signal_connect (MBWMObject *obj,
+ unsigned long signal,
+ MBWMObjectCallbackFunc func,
+ void *userdata)
+{
+ static unsigned long id_counter = 0;
+ MBWMFuncInfo *func_info;
+
+ MBWM_ASSERT(func != NULL);
+
+ func_info = mb_wm_util_malloc0(sizeof(MBWMFuncInfo));
+ func_info->func = (void*)func;
+ func_info->userdata = userdata;
+ func_info->data = mb_wm_object_ref (obj);
+ func_info->signal = signal;
+ func_info->id = id_counter++;
+
+ obj->callbacks =
+ mb_wm_util_list_append (obj->callbacks, func_info);
+
+ return func_info->id;
+}
+
+void
+mb_wm_object_signal_disconnect (MBWMObject *obj,
+ unsigned long id)
+{
+ MBWMList *item = obj->callbacks;
+
+ while (item)
+ {
+ MBWMFuncInfo* info = item->data;
+
+ if (info->id == id)
+ {
+ MBWMList * prev = item->prev;
+ MBWMList * next = item->next;
+
+ if (prev)
+ prev->next = next;
+ else
+ obj->callbacks = next;
+
+ if (next)
+ next->prev = prev;
+
+ mb_wm_object_unref (MB_WM_OBJECT (info->data));
+
+ free (info);
+ free (item);
+
+ return;
+ }
+
+ item = item->next;
+ }
+
+ MBWM_DBG ("### Warning: did not find signal handler %d ###", id);
+}
+
+void
+mb_wm_object_signal_emit (MBWMObject *obj,
+ unsigned long signal)
+{
+ MBWMList *item = obj->callbacks;
+
+ while (item)
+ {
+ MBWMFuncInfo* info = item->data;
+
+ if (info->signal & signal)
+ {
+ if (((MBWMObjectCallbackFunc)info->func) (obj,
+ signal,
+ info->userdata))
+ {
+ break;
+ }
+ }
+
+ item = item->next;
+ }
+}
+
+#if 0
+
+/* ----- Test code -------- */
+
+typedef struct Foo
+{
+ MBWMObject parent;
+
+ int hello;
+}
+Foo;
+
+typedef struct FooClass
+{
+ MBWMObjectClass parent;
+
+}
+FooClass;
+
+void
+mb_wm_foo_init (MBWMObject *obj)
+{
+ printf("%s() called\n", __func__);
+}
+
+void
+mb_wm_foo_destroy (MBWMObject *obj)
+{
+ printf("%s() called\n", __func__);
+}
+
+int
+mb_wm_foo_get_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (FooClass),
+ sizeof (Foo), /* Instance */
+ mb_wm_foo_init,
+ mb_wm_foo_destroy,
+ NULL
+ };
+
+ type = mb_wm_object_register_class (&info);
+
+ printf("type: %i\n", type);
+ }
+
+ return type;
+}
+
+Foo*
+mb_wm_foo_new (int val)
+{
+ Foo *foo;
+
+ foo = (Foo*)mb_wm_object_new (mb_wm_foo_get_class_type ());
+
+ /* call init */
+
+ foo->hello = val;
+
+ return foo;
+}
+
+
+int
+main (int argc, char **argv)
+{
+ Foo *foo, *foo2;
+
+ mb_wm_object_init();
+
+ printf("%s() called init, about to call new\n", __func__);
+
+ foo = mb_wm_foo_new (10);
+ foo2 = mb_wm_foo_new (10);
+
+ printf("%s() foo->hello is %i\n", __func__, foo->hello);
+
+ mb_wm_object_unref (MB_WM_OBJECT(foo));
+}
+
+#endif
diff --git a/matchbox2/core/mb-wm-object.h b/matchbox2/core/mb-wm-object.h
new file mode 100644
index 0000000..62a04ae
--- /dev/null
+++ b/matchbox2/core/mb-wm-object.h
@@ -0,0 +1,130 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_OBJECT_H
+#define _HAVE_MB_OBJECT_H
+
+#include <stdarg.h>
+#include <matchbox2/core/mb-wm-object-props.h>
+
+typedef struct MBWMObject MBWMObject;
+typedef struct MBWMObjectClass MBWMObjectClass;
+
+typedef void (*MBWMObjFunc) (MBWMObject* obj);
+typedef int (*MBWMObjVargFunc) (MBWMObject* obj, va_list vap);
+typedef void (*MBWMClassFunc) (MBWMObjectClass* klass);
+
+#define MB_WM_TYPE_OBJECT 0
+#define MB_WM_OBJECT(x) ((MBWMObject*)(x))
+#define MB_WM_OBJECT_CLASS(x) ((MBWMObjectClass*)(x))
+#define MB_WM_OBJECT_TYPE(x) (((MBWMObject*)(x))->klass->type)
+#define MB_WM_OBJECT_GET_CLASS(x) (mb_wm_object_get_class (MB_WM_OBJECT(x)))
+#define MB_WM_OBJECT_GET_PARENT_CLASS(x) \
+ ((mb_wm_object_get_class (MB_WM_OBJECT(x)))->parent)
+
+typedef enum MBWMObjectClassType
+{
+ MB_WM_OBJECT_TYPE_CLASS = 0,
+ MB_WM_OBJECT_TYPE_ABSTRACT,
+ MB_WM_OBJECT_TYPE_SINGLETON
+}
+MBWMObjectClassType;
+
+typedef struct MBWMObjectClassInfo
+{
+ size_t klass_size;
+ size_t instance_size;
+ MBWMObjVargFunc instance_init;
+ MBWMObjFunc instance_destroy;
+ MBWMClassFunc class_init;
+}
+MBWMObjectClassInfo;
+
+struct MBWMObjectClass
+{
+ int type;
+ MBWMObjectClass *parent;
+ MBWMObjVargFunc init;
+ MBWMObjFunc destroy;
+ MBWMClassFunc class_init;
+
+#if MBWM_WANT_DEBUG
+ const char *klass_name;
+#endif
+};
+
+struct MBWMObject
+{
+ MBWMObjectClass *klass;
+ int refcnt;
+
+ MBWMList *callbacks;
+
+#if MBWM_WANT_DEBUG
+ char **trace_strings;
+ int trace_depth;
+#endif
+};
+
+/* returns True to stop signal emission */
+typedef Bool (*MBWMObjectCallbackFunc) (MBWMObject *obj,
+ int mask,
+ void *userdata);
+
+
+void
+mb_wm_object_init(void);
+
+int
+mb_wm_object_register_class (MBWMObjectClassInfo *info,
+ int parent_type,
+ int flags);
+
+void *
+mb_wm_object_ref (MBWMObject *this);
+
+void
+mb_wm_object_unref (MBWMObject *this);
+
+MBWMObject*
+mb_wm_object_new (int type, ...);
+
+const MBWMObjectClass*
+mb_wm_object_get_class (MBWMObject *this);
+
+unsigned long
+mb_wm_object_signal_connect (MBWMObject *obj,
+ unsigned long signal,
+ MBWMObjectCallbackFunc func,
+ void *userdata);
+
+void
+mb_wm_object_signal_disconnect (MBWMObject *obj,
+ unsigned long id);
+
+void
+mb_wm_object_signal_emit (MBWMObject *obj, unsigned long signal);
+
+#if MBWM_WANT_DEBUG
+void
+mb_wm_object_dump ();
+#endif
+
+#endif
diff --git a/matchbox2/core/mb-wm-props.c b/matchbox2/core/mb-wm-props.c
new file mode 100644
index 0000000..01a74bb
--- /dev/null
+++ b/matchbox2/core/mb-wm-props.c
@@ -0,0 +1,202 @@
+#include "mb-wm.h"
+#include "xas.h"
+
+MBWMCookie
+mb_wm_property_req (MBWindowManager *wm,
+ Window win,
+ Atom property,
+ long offset,
+ long length,
+ Bool delete,
+ Atom req_type)
+{
+ XasCookie cookie;
+
+ cookie = xas_get_property(wm->xas_context,
+ win,
+ property,
+ offset,
+ length,
+ delete,
+ req_type);
+
+ return (MBWMCookie)cookie;
+}
+
+
+Status
+mb_wm_property_reply (MBWindowManager *wm,
+ MBWMCookie cookie,
+ Atom *actual_type_return,
+ int *actual_format_return,
+ unsigned long *nitems_return,
+ unsigned long *bytes_after_return,
+ unsigned char **prop_return,
+ int *x_error_code)
+{
+ return xas_get_property_reply(wm->xas_context,
+ (XasCookie)cookie,
+ actual_type_return,
+ actual_format_return,
+ nitems_return,
+ bytes_after_return,
+ prop_return,
+ x_error_code);
+}
+
+void*
+mb_wm_property_get_reply_and_validate (MBWindowManager *wm,
+ MBWMCookie cookie,
+ Atom expected_type,
+ int expected_format,
+ int expected_n_items,
+ int *n_items_ret,
+ int *x_error_code)
+{
+ Atom actual_type_return;
+ int actual_format_return;
+ unsigned long nitems_return;
+ unsigned long bytes_after_return;
+ unsigned char *prop_data = NULL;
+
+ *x_error_code = 0;
+
+ xas_get_property_reply(wm->xas_context,
+ (XasCookie)cookie,
+ &actual_type_return,
+ &actual_format_return,
+ &nitems_return,
+ &bytes_after_return,
+ &prop_data,
+ x_error_code);
+
+ if (*x_error_code || prop_data == NULL)
+ goto fail;
+
+ if (expected_format && actual_format_return != expected_format)
+ goto fail;
+
+ if (expected_n_items && nitems_return != expected_n_items)
+ goto fail;
+
+ if (n_items_ret)
+ *n_items_ret = nitems_return;
+
+ return prop_data;
+
+ fail:
+
+ if (prop_data)
+ XFree(prop_data);
+
+ return NULL;
+}
+
+
+
+Bool
+mb_wm_property_have_reply (MBWindowManager *wm,
+ MBWMCookie cookie)
+{
+ return xas_have_reply(wm->xas_context, (XasCookie)cookie);
+}
+
+
+MBWMCookie
+mb_wm_xwin_get_attributes (MBWindowManager *wm,
+ Window win)
+{
+ return xas_get_window_attributes(wm->xas_context, win);
+}
+
+MBWMCookie
+mb_wm_xwin_get_geometry (MBWindowManager *wm,
+ Drawable d)
+{
+ return xas_get_geometry(wm->xas_context, d);
+}
+
+MBWMClientWindowAttributes*
+mb_wm_xwin_get_attributes_reply (MBWindowManager *wm,
+ MBWMCookie cookie,
+ int *x_error_code)
+{
+ return (MBWMClientWindowAttributes*)
+ xas_get_window_attributes_reply(wm->xas_context,
+ cookie,
+ x_error_code);
+}
+
+Status
+mb_wm_xwin_get_geometry_reply (MBWindowManager *wm,
+ XasCookie cookie,
+ MBGeometry *geom_return,
+ unsigned int *border_width_return,
+ unsigned int *depth_return,
+ int *x_error_code)
+{
+ return xas_get_geometry_reply (wm->xas_context,
+ cookie,
+ &geom_return->x,
+ &geom_return->y,
+ &geom_return->width,
+ &geom_return->height,
+ border_width_return,
+ depth_return,
+ x_error_code);
+}
+
+
+void
+mb_wm_props_send_x_message (MBWindowManager *wm,
+ Window xwin_src,
+ Window xwin_dest,
+ Atom delivery_atom,
+ unsigned long data0,
+ unsigned long data1,
+ unsigned long data2,
+ unsigned long data3,
+ unsigned long data4,
+ unsigned long mask)
+{
+ XEvent ev;
+
+ memset(&ev, 0, sizeof(ev));
+
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = xwin_src;
+ ev.xclient.message_type = delivery_atom;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = data0;
+ ev.xclient.data.l[1] = data1;
+ ev.xclient.data.l[2] = data2;
+ ev.xclient.data.l[3] = data3;
+ ev.xclient.data.l[4] = data4;
+
+ if (!mask)
+ mask = NoEventMask;
+
+ /* FIXME: traps */
+
+ XSendEvent(wm->xdpy, xwin_dest, False, mask, &ev);
+ XSync(wm->xdpy, False);
+
+}
+
+void
+mb_wm_props_sync_root_props (MBWindowManager *wm)
+{
+
+
+
+
+}
+
+void
+mb_wm_props_root_message (MBWindowManager *wm)
+{
+
+
+
+
+}
diff --git a/matchbox2/core/mb-wm-props.h b/matchbox2/core/mb-wm-props.h
new file mode 100644
index 0000000..07418ca
--- /dev/null
+++ b/matchbox2/core/mb-wm-props.h
@@ -0,0 +1,118 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_PROPS_H
+#define _HAVE_MB_WM_PROPS_H
+
+MBWMCookie
+mb_wm_property_req (MBWindowManager *wm,
+ Window win,
+ Atom property,
+ long offset,
+ long length,
+ Bool delete,
+ Atom req_type);
+
+Status
+mb_wm_property_reply (MBWindowManager *wm,
+ MBWMCookie cookie,
+ Atom *actual_type_return,
+ int *actual_format_return,
+ unsigned long *nitems_return,
+ unsigned long *bytes_after_return,
+ unsigned char **prop_return,
+ int *x_error_code);
+
+void*
+mb_wm_property_get_reply_and_validate (MBWindowManager *wm,
+ MBWMCookie cookie,
+ Atom expected_type,
+ int expected_format,
+ int expected_n_items,
+ int *n_items_ret,
+ int *x_error_code);
+Bool
+mb_wm_property_have_reply (MBWindowManager *wm,
+ MBWMCookie cookie);
+
+/* FIXME: mb_wm_xwin_* calls to go else where */
+
+MBWMCookie
+mb_wm_xwin_get_attributes (MBWindowManager *wm,
+ Window win);
+
+MBWMCookie
+mb_wm_xwin_get_geometry (MBWindowManager *wm,
+ Drawable d);
+
+MBWMClientWindowAttributes*
+mb_wm_xwin_get_attributes_reply (MBWindowManager *wm,
+ MBWMCookie cookie,
+ int *x_error_code);
+Status
+mb_wm_xwin_get_geometry_reply (MBWindowManager *wm,
+ XasCookie cookie,
+ MBGeometry *geom_return,
+ unsigned int *border_width_return,
+ unsigned int *depth_return,
+ int *x_error_code);
+
+void
+mb_wm_props_send_x_message (MBWindowManager *wm,
+ Window xwin_src,
+ Window xwin_dest,
+ Atom delivery_atom,
+ unsigned long data0,
+ unsigned long data1,
+ unsigned long data2,
+ unsigned long data3,
+ unsigned long data4,
+ unsigned long mask);
+
+/* Utils */
+
+#define mb_wm_property_cardinal_req(wm, win, prop) \
+ mb_wm_property_req ((wm), \
+ (win), \
+ (prop), \
+ 0, /* offset */ \
+ 1024L, /* Length, FIXME: Check this */ \
+ False, \
+ XA_CARDINAL);
+
+#define mb_wm_property_atom_req(wm, win, prop) \
+ mb_wm_property_req ((wm), \
+ (win), \
+ (prop), \
+ 0, /* offset */ \
+ 1024L, /* Length, FIXME: Check this */ \
+ False, \
+ XA_ATOM);
+
+#define mb_wm_property_utf8_req(wm, win, prop) \
+ mb_wm_property_req ((wm), \
+ (win), \
+ (prop), \
+ 0, /* offset */ \
+ 1024L, /* Length, FIXME: Check this */ \
+ False, \
+ (wm)->atoms[MBWM_ATOM_UTF8_STRING]);
+
+#endif
diff --git a/matchbox2/core/mb-wm-root-window.c b/matchbox2/core/mb-wm-root-window.c
new file mode 100644
index 0000000..62016bb
--- /dev/null
+++ b/matchbox2/core/mb-wm-root-window.c
@@ -0,0 +1,436 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2007 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mb-wm.h"
+
+#include "../theme-engines/mb-wm-theme.h"
+#include "../client-types/mb-wm-client-dialog.h"
+#include "../client-types/mb-wm-client-app.h"
+
+#include <X11/Xmd.h>
+
+static void
+mb_wm_root_window_class_init (MBWMObjectClass *klass)
+{
+ MBWMRootWindowClass *rw_class;
+
+ MBWM_MARK();
+
+ rw_class = (MBWMRootWindowClass *)klass;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMRootWindow";
+#endif
+}
+
+static void
+mb_wm_root_window_destroy (MBWMObject *this)
+{
+}
+
+static Bool
+mb_wm_root_window_init_attributes (MBWMRootWindow * win);
+
+static void
+mb_wm_root_window_init_properties (MBWMRootWindow * win);
+
+static int
+mb_wm_root_window_init (MBWMObject *this, va_list vap)
+{
+ MBWMRootWindow *root_window = MB_WM_ROOT_WINDOW (this);
+ MBWindowManager *wm;
+ MBWMObjectProp prop;
+ XSetWindowAttributes attr;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ if (prop == MBWMObjectPropWm)
+ {
+ wm = va_arg(vap, MBWindowManager *);
+ break;
+ }
+ else
+ MBWMO_PROP_EAT (vap, prop);
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ root_window->wm = wm;
+ root_window->xwindow = RootWindow(wm->xdpy, wm->xscreen);
+
+ if (!mb_wm_root_window_init_attributes (root_window))
+ {
+ MBWM_DBG ("Failed to initialize root window attributes.");
+ abort ();
+ }
+
+ attr.override_redirect = True;
+ root_window->hidden_window = XCreateWindow(wm->xdpy,
+ root_window->xwindow,
+ -200, -200, 5, 5, 0,
+ CopyFromParent,
+ CopyFromParent,
+ CopyFromParent,
+ CWOverrideRedirect, &attr);
+
+ mb_wm_root_window_init_properties (root_window);
+
+ return 1;
+}
+
+int
+mb_wm_root_window_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMRootWindowClass),
+ sizeof (MBWMRootWindow),
+ mb_wm_root_window_init,
+ mb_wm_root_window_destroy,
+ mb_wm_root_window_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+MBWMRootWindow*
+mb_wm_root_window_get (MBWindowManager *wm)
+{
+ static MBWMRootWindow * root_window = NULL;
+
+ if (!root_window)
+ {
+ root_window
+ = MB_WM_ROOT_WINDOW (mb_wm_object_new (MB_WM_TYPE_ROOT_WINDOW,
+ MBWMObjectPropWm, wm,
+ NULL));
+ }
+ else
+ mb_wm_object_ref (MB_WM_OBJECT (root_window));
+
+ return root_window;
+}
+
+static Bool
+mb_wm_root_window_init_attributes (MBWMRootWindow * win)
+{
+ XSetWindowAttributes sattr;
+ MBWindowManager *wm = win->wm;
+
+ sattr.event_mask = SubstructureRedirectMask
+ |SubstructureNotifyMask
+ |StructureNotifyMask
+ |PropertyChangeMask;
+
+ mb_wm_util_trap_x_errors();
+
+ XChangeWindowAttributes(wm->xdpy, win->xwindow, CWEventMask, &sattr);
+
+ XSync(wm->xdpy, False);
+
+ if (mb_wm_util_untrap_x_errors())
+ {
+ /* FIXME: Error codes */
+ mb_wm_util_fatal_error("Unable to manage display - "
+ "another window manager already active?");
+ return False;
+ }
+
+ XSelectInput(wm->xdpy, win->xwindow, sattr.event_mask);
+
+ return True;
+}
+
+void
+mb_wm_root_window_update_supported_props (MBWMRootWindow *win)
+{
+ MBWindowManager *wm = win->wm;
+ Window rwin = win->xwindow;
+ CARD32 num_supported = 0;
+
+ /*
+ * Supported info
+ */
+ Atom supported[] = {
+ wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR],
+ wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DOCK],
+ wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DIALOG],
+ wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_DESKTOP],
+ wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_SPLASH],
+ wm->atoms[MBWM_ATOM_NET_WM_WINDOW_TYPE_MENU],
+ wm->atoms[MBWM_ATOM_NET_WM_STATE],
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_FULLSCREEN],
+ wm->atoms[MBWM_ATOM_NET_WM_STATE_MODAL],
+ wm->atoms[MBWM_ATOM_NET_SUPPORTED],
+ wm->atoms[MBWM_ATOM_NET_CLIENT_LIST],
+ wm->atoms[MBWM_ATOM_NET_NUMBER_OF_DESKTOPS],
+ wm->atoms[MBWM_ATOM_NET_ACTIVE_WINDOW],
+ wm->atoms[MBWM_ATOM_NET_SUPPORTING_WM_CHECK],
+ wm->atoms[MBWM_ATOM_NET_CLOSE_WINDOW],
+ wm->atoms[MBWM_ATOM_NET_CURRENT_DESKTOP],
+ wm->atoms[MBWM_ATOM_NET_CLIENT_LIST_STACKING],
+ wm->atoms[MBWM_ATOM_NET_SHOWING_DESKTOP],
+ wm->atoms[MBWM_ATOM_NET_WM_NAME],
+ wm->atoms[MBWM_ATOM_NET_WM_ICON],
+ wm->atoms[MBWM_ATOM_NET_WM_ALLOWED_ACTIONS],
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_MOVE],
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_FULLSCREEN],
+ wm->atoms[MBWM_ATOM_NET_WM_ACTION_CLOSE],
+ wm->atoms[MBWM_ATOM_NET_STARTUP_ID],
+ wm->atoms[MBWM_ATOM_NET_WM_PING],
+ wm->atoms[MBWM_ATOM_NET_WORKAREA],
+ wm->atoms[MBWM_ATOM_NET_DESKTOP_GEOMETRY],
+ wm->atoms[MBWM_ATOM_NET_WM_PING],
+ wm->atoms[MBWM_ATOM_NET_WM_PID],
+ wm->atoms[MBWM_ATOM_CM_TRANSLUCENCY],
+ wm->atoms[MBWM_ATOM_NET_WM_FULL_PLACEMENT],
+ wm->atoms[MBWM_ATOM_NET_FRAME_EXTENTS],
+ 0, 0, 0
+ };
+
+ num_supported = sizeof(supported)/sizeof(Atom) - 3;
+
+ /* Check to see if the theme supports help / accept buttons */
+ if (wm->theme)
+ {
+ if (mb_wm_theme_supports (wm->theme,
+ MBWMThemeCapsFrameMainButtonActionAccept))
+ supported[num_supported++]=wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_ACCEPT];
+
+ if (mb_wm_theme_supports (wm->theme,
+ MBWMThemeCapsFrameMainButtonActionHelp))
+ supported[num_supported++] = wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_HELP];
+
+ if (mb_wm_theme_supports (wm->theme,
+ MBWMThemeCapsFrameMainButtonActionCustom))
+ supported[num_supported++]=wm->atoms[MBWM_ATOM_NET_WM_CONTEXT_CUSTOM];
+ }
+
+ XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_NET_SUPPORTED],
+ XA_ATOM, 32, PropModeReplace, (unsigned char *)supported,
+ num_supported);
+
+ if (wm->theme)
+ {
+ if (wm->theme->path)
+ XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_MB_THEME],
+ XA_STRING, 8, PropModeReplace,
+ (unsigned char *)wm->theme->path,
+ strlen (wm->theme->path) + 1);
+ else
+ XDeleteProperty (wm->xdpy, rwin, wm->atoms[MBWM_ATOM_MB_THEME]);
+ }
+}
+
+static void
+mb_wm_root_window_init_properties (MBWMRootWindow * win)
+{
+ MBWindowManager *wm = win->wm;
+ Window rwin = win->xwindow;
+ Window hwin = win->hidden_window;
+
+ CARD32 card32;
+ unsigned long val[2];
+ char *app_name = "matchbox";
+
+ val[0] = hwin;
+
+ /* Window name */
+ XChangeProperty(wm->xdpy, hwin,
+ wm->atoms[MBWM_ATOM_NET_WM_NAME],
+ wm->atoms[MBWM_ATOM_UTF8_STRING],
+ 8, PropModeReplace,
+ (unsigned char *)app_name, strlen(app_name)+1);
+
+ XStoreName(wm->xdpy, hwin, app_name);
+
+ /* Crack Needed to stop gnome session hanging ? */
+ XChangeProperty(wm->xdpy, rwin,
+ wm->atoms[MBWM_ATOM_WIN_SUPPORTING_WM_CHECK],
+ XA_WINDOW, 32, PropModeReplace, (unsigned char *)val,
+ 1);
+
+ XChangeProperty(wm->xdpy, hwin,
+ wm->atoms[MBWM_ATOM_WIN_SUPPORTING_WM_CHECK],
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)val, 1);
+
+ /* Correct way of doing it */
+ XChangeProperty(wm->xdpy, rwin,
+ wm->atoms[MBWM_ATOM_NET_SUPPORTING_WM_CHECK],
+ XA_WINDOW, 32, PropModeReplace, (unsigned char *)val,
+ 1);
+
+ XChangeProperty(wm->xdpy, hwin,
+ wm->atoms[MBWM_ATOM_NET_SUPPORTING_WM_CHECK],
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)val, 1);
+
+ mb_wm_root_window_update_supported_props (win);
+
+ /*
+ * Desktop info
+ */
+ card32 = 1;
+ XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_NET_NUMBER_OF_DESKTOPS],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)&card32, 1);
+
+ --card32;
+ XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_NET_CURRENT_DESKTOP],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)&card32, 1);
+
+ XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_NET_SHOWING_DESKTOP],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)&card32, 1);
+
+ val[0] = 0;
+ val[1] = 0;
+
+ XChangeProperty(wm->xdpy, rwin, wm->atoms[MBWM_ATOM_NET_DESKTOP_VIEWPORT],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)&val[0], 2);
+
+ XSync(wm->xdpy, False);
+}
+
+int
+mb_wm_root_window_handle_message (MBWMRootWindow *win, XClientMessageEvent *e)
+{
+ MBWindowManager *wm = win->wm;
+ MBWindowManagerClient *c = NULL;
+
+ if (e->message_type == wm->atoms[MBWM_ATOM_NET_ACTIVE_WINDOW])
+ {
+ Window xwin = e->window;
+
+ if ((c = mb_wm_managed_client_from_xwindow (wm, xwin)) != NULL)
+ mb_wm_activate_client (wm, c);
+
+ return 1;
+ }
+ else if (e->message_type == wm->atoms[MBWM_ATOM_NET_CLOSE_WINDOW])
+ {
+ if ((c = mb_wm_managed_client_from_xwindow(wm, e->window)) != NULL)
+ mb_wm_client_deliver_delete(c);
+
+ return 1;
+ }
+ else if (e->message_type == wm->atoms[MBWM_ATOM_WM_PROTOCOLS]
+ && e->data.l[0] == wm->atoms[MBWM_ATOM_NET_WM_PING])
+ {
+ if ((c = mb_wm_managed_client_from_xwindow(wm, e->data.l[2])) != NULL)
+ mb_wm_handle_ping_reply (wm, c);
+ return 1;
+ }
+ else if (e->message_type == wm->atoms[MBWM_ATOM_NET_WM_STATE])
+ {
+ MBWMClientWindowStateChange state_op = 0;
+
+ if (e->data.l[0] == 0)
+ state_op = MBWMClientWindowStateChangeRemove;
+ else if (e->data.l[0] == 1)
+ state_op = MBWMClientWindowStateChangeAdd;
+ else if (e->data.l[0] == 2)
+ state_op = MBWMClientWindowStateChangeToggle;
+
+ if (e->data.l[1] == wm->atoms[MBWM_ATOM_NET_WM_STATE_FULLSCREEN]
+ && ((c = mb_wm_managed_client_from_xwindow(wm, e->window)) != NULL)
+ && MB_WM_IS_CLIENT_APP (c))
+ {
+ mb_wm_client_set_state (c,
+ MBWM_ATOM_NET_WM_STATE_FULLSCREEN,
+ state_op);
+ }
+ else if (e->data.l[1] == wm->atoms[MBWM_ATOM_NET_WM_STATE_ABOVE]
+ && ((c = mb_wm_managed_client_from_xwindow(wm, e->window)) !=
+ NULL)
+ && MB_WM_IS_CLIENT_DIALOG (c))
+ {
+ mb_wm_client_set_state (c,
+ MBWM_ATOM_NET_WM_STATE_ABOVE,
+ state_op);
+ }
+ return 1;
+ }
+
+ else if (e->message_type == wm->atoms[MBWM_ATOM_WM_CHANGE_STATE])
+ {
+ switch (e->data.l[0])
+ {
+ case IconicState:
+ if ((c = mb_wm_managed_client_from_xwindow (wm, e->window)))
+ mb_wm_client_iconize (c);
+
+ default:
+ MBWM_DBG ("Unhandled value %d for WM_CHANGE_STATE ClientMessage",
+ e->data.l[0]);
+ }
+ }
+ else if (e->message_type == wm->atoms[MBWM_ATOM_NET_SHOWING_DESKTOP])
+ {
+ mb_wm_handle_show_desktop (wm, e->data.l[0]);
+ return 1;
+ }
+ else if (e->message_type == wm->atoms[MBWM_ATOM_NET_CURRENT_DESKTOP])
+ {
+ mb_wm_select_desktop (wm, e->data.l[0]);
+ return 1;
+ }
+ else if (e->message_type == wm->atoms[MBWM_ATOM_MB_COMMAND])
+ {
+ switch (e->data.l[0])
+ {
+ case MB_CMD_EXIT:
+ exit(0);
+ case MB_CMD_NEXT:
+ mb_wm_cycle_apps (wm, False);
+ break;
+ case MB_CMD_PREV:
+ mb_wm_cycle_apps (wm, True);
+ break;
+ case MB_CMD_DESKTOP:
+ mb_wm_toggle_desktop (wm);
+ break;
+#if ENABLE_COMPOSITE
+ case MB_CMD_COMPOSITE:
+ if (mb_wm_compositing_enabled (wm))
+ mb_wm_compositing_off (wm);
+ else
+ mb_wm_compositing_on (wm);
+ break;
+#endif
+ default:
+ /*FIXME -- not implemented yet */
+ case MB_CMB_KEYS_RELOAD:
+ ;
+ }
+ }
+
+ return 0;
+}
diff --git a/matchbox2/core/mb-wm-root-window.h b/matchbox2/core/mb-wm-root-window.h
new file mode 100644
index 0000000..7d3cdbe
--- /dev/null
+++ b/matchbox2/core/mb-wm-root-window.h
@@ -0,0 +1,57 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2007 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _HAVE_MB_WM_ROOT_WINDOW_H
+#define _HAVE_MB_WM_ROOT_WINDOW_H
+
+typedef struct MBWMRootWindow MBWMRootWindow;
+typedef struct MBWMRootWindowClass MBWMRootWindowClass;
+
+#define MB_WM_ROOT_WINDOW(c) ((MBWMRootWindow*)(c))
+#define MB_WM_ROOT_WINDOW_CLASS(c) ((MBWMRootWindowClass*)(c))
+#define MB_WM_TYPE_ROOT_WINDOW (mb_wm_root_window_class_type ())
+
+struct MBWMRootWindow
+{
+ MBWMObject parent;
+
+ Window xwindow;
+ Window hidden_window;
+ MBWindowManager *wm;
+};
+
+struct MBWMRootWindowClass
+{
+ MBWMObjectClass parent;
+};
+
+MBWMRootWindow *
+mb_wm_root_window_get (MBWindowManager *wm);
+
+int
+mb_wm_root_window_class_type ();
+
+int
+mb_wm_root_window_handle_message(MBWMRootWindow *win, XClientMessageEvent *e);
+
+void
+mb_wm_root_window_update_supported_props (MBWMRootWindow *win);
+
+#endif
diff --git a/matchbox2/core/mb-wm-stack.c b/matchbox2/core/mb-wm-stack.c
new file mode 100644
index 0000000..f75b228
--- /dev/null
+++ b/matchbox2/core/mb-wm-stack.c
@@ -0,0 +1,325 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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"
+
+
+static void
+mb_wm_stack_ensure_trans_foreach (MBWindowManagerClient *client, void *data)
+{
+ MBWMList * t = mb_wm_client_get_transients (client);
+
+ mb_wm_stack_move_top (client);
+
+ mb_wm_util_list_foreach
+ (t, (MBWMListForEachCB) mb_wm_stack_ensure_trans_foreach, NULL);
+
+ mb_wm_util_list_free (t);
+}
+
+void
+mb_wm_stack_dump (MBWindowManager *wm)
+{
+#if (MBWM_WANT_DEBUG)
+ MBWindowManagerClient *client;
+ MBWMStackLayerType stacking_layer;
+
+ fprintf(stderr, "\n==== window stack =====\n");
+
+ mb_wm_stack_enumerate_reverse (wm, client)
+ {
+ MBWindowManagerClient *trans_client = client;
+ int i = 0, j = 0;
+ char prefix[128] = {0};
+
+ while ((trans_client = mb_wm_client_get_transient_for(trans_client)))
+ i++;
+
+ if (i)
+ {
+ for (j=0;j<=i*2;j+=2)
+ { prefix[j] = ' '; prefix[j+1] = ' '; }
+
+ strcpy(&prefix[i*2], " +--");
+ }
+
+ stacking_layer = mb_wm_client_get_stacking_layer (client);
+
+ fprintf(stderr, "%s XID: %lx NAME: %s, type %d, layer %d\n",
+ prefix,
+ MB_WM_CLIENT_XWIN(client),
+ client->window->name ? client->window->name : "unknown",
+ MB_WM_CLIENT_CLIENT_TYPE (client),
+ stacking_layer);
+ }
+
+ fprintf(stderr, "======================\n\n");
+#endif
+}
+
+void
+mb_wm_stack_ensure (MBWindowManager *wm)
+{
+ MBWindowManagerClient *client, *seen, *next;
+ int i;
+ MBWMStackLayerType stacking_layer;
+
+ if (wm->stack_bottom == NULL)
+ return;
+
+ /* Ensure the window stack is corrent;
+ * - with respect to client layer types
+ * - transients are stacked within these layers also
+ *
+ * We need to be careful here as we modify stacking list
+ * in place while enumerating it.
+ *
+ * FIXME: This isn't optimal
+ */
+
+ /* bottom -> top on layer types */
+ for (i=1; i<N_MBWMStackLayerTypes; i++)
+ {
+ /* Push each layer type to top, handling transients */
+ client = wm->stack_bottom;
+ seen = NULL;
+
+ while (client != seen && client != NULL)
+ {
+ /* get the next valid client ( ignore transients ) before
+ * modifying the list
+ */
+ next = client->stacked_above;
+
+ while (next && mb_wm_client_get_transient_for (next))
+ next = next->stacked_above;
+
+ stacking_layer = mb_wm_client_get_stacking_layer (client);
+
+ if (stacking_layer == i
+ && mb_wm_client_get_transient_for (client) == NULL)
+ {
+ /* Keep track of the first client modified so we
+ * know when to stop iterating.
+ */
+ if (seen == NULL)
+ seen = client;
+
+ mb_wm_client_stack (client, 0);
+ }
+ client = next;
+ }
+ }
+
+ mb_wm_stack_dump (wm);
+}
+
+void
+mb_wm_stack_insert_above_client (MBWindowManagerClient *client,
+ MBWindowManagerClient *client_below)
+{
+ MBWindowManager *wm = client->wmref;
+
+ MBWM_ASSERT (client != NULL);
+
+ if (client_below == NULL)
+ {
+ /* NULL so nothing below add at bottom */
+ if (wm->stack_bottom)
+ {
+ client->stacked_above = wm->stack_bottom;
+ wm->stack_bottom->stacked_below = client;
+ }
+
+ wm->stack_bottom = client;
+ }
+ else
+ {
+ client->stacked_below = client_below;
+ client->stacked_above = client_below->stacked_above;
+ if (client->stacked_below) client->stacked_below->stacked_above = client;
+ if (client->stacked_above) client->stacked_above->stacked_below = client;
+ }
+
+ if (client_below == wm->stack_top)
+ wm->stack_top = client;
+
+ wm->stack_n_clients++;
+}
+
+
+void
+mb_wm_stack_append_top (MBWindowManagerClient *client)
+{
+ MBWindowManager *wm = client->wmref;
+
+ mb_wm_stack_insert_above_client(client, wm->stack_top);
+}
+
+void
+mb_wm_stack_prepend_bottom (MBWindowManagerClient *client)
+{
+ mb_wm_stack_insert_above_client(client, NULL);
+}
+
+void
+mb_wm_stack_move_client_above_type (MBWindowManagerClient *client,
+ MBWMClientType type_below)
+{
+ MBWindowManager *wm = client->wmref;
+ MBWindowManagerClient *highest_client = NULL;
+
+ highest_client = mb_wm_stack_get_highest_by_type (wm, type_below);
+
+ if (highest_client)
+ mb_wm_stack_move_above_client(client, highest_client);
+}
+
+
+void
+mb_wm_stack_move_above_client (MBWindowManagerClient *client,
+ MBWindowManagerClient *client_below)
+{
+ if (client == client_below) return;
+
+ MBWM_ASSERT (client != NULL);
+ MBWM_ASSERT (client_below != NULL);
+
+ mb_wm_stack_remove(client);
+ mb_wm_stack_insert_above_client(client, client_below);
+}
+
+MBWindowManagerClient*
+mb_wm_stack_get_highest_by_type (MBWindowManager *wm,
+ MBWMClientType type)
+{
+ MBWindowManagerClient *c = NULL;
+
+ mb_wm_stack_enumerate_reverse (wm,c)
+ if (MB_WM_CLIENT_CLIENT_TYPE(c) & type)
+ return c;
+
+ return NULL;
+}
+
+MBWindowManagerClient*
+mb_wm_stack_get_lowest_by_type(MBWindowManager *w, MBWMClientType wanted_type)
+
+{
+ MBWindowManagerClient *c = NULL;
+
+ mb_wm_stack_enumerate(w,c)
+ if (MB_WM_CLIENT_CLIENT_TYPE(c) & wanted_type)
+ return c;
+
+ return NULL;
+}
+
+MBWindowManagerClient *
+mb_wm_stack_cycle_by_type(MBWindowManager *wm, MBWMClientType type,
+ Bool reverse)
+{
+ if (reverse)
+ {
+ MBWindowManagerClient *prev, *highest;
+
+ highest = mb_wm_stack_get_highest_by_type (wm, type);
+
+ if (!highest)
+ return highest;
+
+ prev = highest->stacked_below;
+
+ while (prev && (!(type & MB_WM_CLIENT_CLIENT_TYPE (prev))))
+ {
+ prev = prev->stacked_below;
+ }
+
+ if (prev && highest && prev != highest)
+ {
+ mb_wm_stack_move_above_client (prev, highest);
+ }
+
+ return prev;
+ }
+ else
+ {
+ MBWindowManagerClient *lowest, *highest;
+
+ lowest = mb_wm_stack_get_lowest_by_type (wm, type);
+ highest = mb_wm_stack_get_highest_by_type (wm, type);
+
+ if (lowest && highest && lowest != highest)
+ {
+ mb_wm_stack_move_above_client (lowest, highest);
+ }
+
+ return lowest;
+ }
+}
+
+void
+mb_wm_stack_remove (MBWindowManagerClient *client)
+{
+ MBWindowManager *wm = client->wmref;
+ Bool change = False;
+
+ if (wm->stack_top == wm->stack_bottom)
+ {
+ if (wm->stack_top != client)
+ {
+ MBWM_DBG("Client stack corruption !!!");
+ }
+ else
+ wm->stack_top = wm->stack_bottom = NULL;
+ }
+ else
+ {
+ if (client == wm->stack_top)
+ {
+ wm->stack_top = client->stacked_below;
+ change = True;
+ }
+
+ if (client == wm->stack_bottom)
+ {
+ wm->stack_bottom = client->stacked_above;
+ change = True;
+ }
+
+ if (client->stacked_below != NULL)
+ {
+ client->stacked_below->stacked_above = client->stacked_above;
+ change = True;
+ }
+ if (client->stacked_above != NULL)
+ {
+ client->stacked_above->stacked_below = client->stacked_below;
+ change = True;
+ }
+ }
+
+ client->stacked_above = client->stacked_below = NULL;
+
+ if (change)
+ wm->stack_n_clients--;
+}
+
+
diff --git a/matchbox2/core/mb-wm-stack.h b/matchbox2/core/mb-wm-stack.h
new file mode 100644
index 0000000..58afc45
--- /dev/null
+++ b/matchbox2/core/mb-wm-stack.h
@@ -0,0 +1,96 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_STACK_H_
+#define _HAVE_MB_WM_STACK_H_
+
+#define mb_wm_stack_enumerate(w,c) \
+ if ((w)->stack_bottom) \
+ for ((c)=(w)->stack_bottom; (c) != NULL; (c)=(c)->stacked_above)
+
+#define mb_wm_stack_enumerate_reverse(w,c) \
+ if ((w)->stack_top) \
+ for ((c)=(w)->stack_top; (c) != NULL; (c)=(c)->stacked_below)
+
+#define mb_wm_stack_enumerate_transients(w,c,t) \
+ if ((w)->stack_bottom) \
+ for ((c)=(w)->stack_bottom; (c) != NULL; (c)=(c)->stacked_above) \
+ if ((c)->trans == (t))
+
+
+#define mb_wm_stack_move_top(c) \
+ mb_wm_stack_move_above_client((c), (c)->wmref->stack_top)
+
+/*
+#define mb_wm_stack_add_bottom(c) \
+ stack_move_below_client((c), (c)->wmref->stack_bottom)
+*/
+
+#define mb_wm_stack_empty(w) \
+ ((w)->stack_bottom == NULL)
+
+#define mb_wm_stack_size(w) \
+ (w)->stack_n_clients
+
+void
+mb_wm_stack_ensure (MBWindowManager *wm);
+
+void
+mb_wm_stack_insert_above_client (MBWindowManagerClient *client,
+ MBWindowManagerClient *client_below);
+
+void
+mb_wm_stack_append_top (MBWindowManagerClient *client);
+
+void
+mb_wm_stack_prepend_bottom (MBWindowManagerClient *client);
+
+void
+mb_wm_stack_move_client_above_type (MBWindowManagerClient *client,
+ MBWMClientType type_below);
+
+void
+mb_wm_stack_move_client_above_type (MBWindowManagerClient *client,
+ MBWMClientType type_below);
+
+MBWindowManagerClient *
+mb_wm_stack_cycle_by_type(MBWindowManager *w, MBWMClientType type,
+ Bool reverse);
+
+void
+mb_wm_stack_move_above_client (MBWindowManagerClient *client,
+ MBWindowManagerClient *client_below);
+
+MBWindowManagerClient*
+mb_wm_stack_get_highest_by_type(MBWindowManager *w,
+ MBWMClientType wanted_type);
+
+
+MBWindowManagerClient*
+mb_wm_stack_get_lowest_by_type(MBWindowManager *w,
+ MBWMClientType wanted_type);
+
+void
+mb_wm_stack_remove (MBWindowManagerClient *client);
+
+void
+mb_wm_stack_dump (MBWindowManager *wm);
+
+#endif
diff --git a/matchbox2/core/mb-wm-types.h b/matchbox2/core/mb-wm-types.h
new file mode 100644
index 0000000..9c1c71a
--- /dev/null
+++ b/matchbox2/core/mb-wm-types.h
@@ -0,0 +1,443 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_TYPES_H
+#define _HAVE_MB_WM_TYPES_H
+
+#include <matchbox2/mb-wm-config.h>
+
+#if USE_GLIB_MAINLOOP
+#include <glib.h>
+#endif
+
+#include <X11/Xlib.h>
+
+typedef struct MBWMFuncInfo
+{
+ void *func;
+ void *data;
+ void *userdata;
+ unsigned long signal;
+ unsigned long id;
+} MBWMFuncInfo;
+
+typedef struct MBGeometry
+{
+ int x,y;
+ int width,height;
+
+} MBGeometry;
+
+typedef struct MBWMList MBWMList;
+
+typedef void (*MBWMListForEachCB) (void *data, void *userdata);
+
+struct MBWMList
+{
+ MBWMList *next, *prev;
+ void *data;
+};
+
+typedef struct MBWMClientWindowAttributes /* Needs to be sorted */
+{
+ Visual *visual;
+ Window root;
+ int class;
+ int bit_gravity;
+ int win_gravity;
+ int backing_store;
+ unsigned long backing_planes;
+ unsigned long backing_pixel;
+ Bool save_under;
+ Colormap colormap;
+ Bool map_installed;
+ int map_state;
+ long all_event_masks;
+ long your_event_mask;
+ long do_not_propagate_mask;
+ Bool override_redirect;
+
+} MBWMClientWindowAttributes ;
+
+typedef struct MBWMRgbaIcon
+{
+ int width;
+ int height;
+ unsigned long *pixels;
+} MBWMRgbaIcon;
+
+typedef struct MBWindowManager MBWindowManager;
+typedef struct MBWindowManagerClient MBWindowManagerClient;
+typedef struct MBWindowManagerClientClass MBWindowManagerClientClass;
+typedef struct MBWindowManagerClientPriv MBWindowManagerClientPriv;
+typedef struct MBWMClientWindow MBWMClientWindow;
+typedef struct MBWMClientWindowClass MBWMClientWindowClass;
+typedef struct MBWMTheme MBWMTheme;
+typedef struct MBWMThemeClass MBWMThemeClass;
+typedef struct MBWMThemePng MBWMThemePng;
+typedef struct MBWMThemePngClass MBWMThemePngClass;
+typedef enum MBWMThemeCaps MBWMThemeCaps;
+typedef struct MBWMDecor MBWMDecor;
+typedef struct MBWMDecorClass MBWMDecorClass;
+typedef struct MBWMDecorButton MBWMDecorButton;
+typedef struct MBWMDecorButtonClass MBWMDecorButtonClass;
+typedef struct MBWMLayout MBWMLayout;
+typedef struct MBWMLayoutClass MBWMLayoutClass;
+typedef struct MBWMMainContext MBWMMainContext;
+typedef struct MBWMMainContextClass MBWMMainContextClass;
+typedef struct MBWMCompMgr MBWMCompMgr;
+typedef struct MBWMCompMgrClass MBWMCompMgrClass;
+typedef struct MBWMCompMgrDefault MBWMCompMgrDefault;
+typedef struct MBWMCompMgrDefaultPrivate MBWMCompMgrDefaultPrivate;
+typedef struct MBWMCompMgrDefaultClass MBWMCompMgrDefaultClass;
+typedef struct MBWMCompMgrClient MBWMCompMgrClient;
+typedef struct MBWMCompMgrClientClass MBWMCompMgrClientClass;
+typedef struct MBWMCompMgrDefaultClient MBWMCompMgrDefaultClient;
+typedef struct MBWMCompMgrDefaultClientClass MBWMCompMgrDefaultClientClass;
+typedef struct MBWMCompMgrDefaultClentPrivate MBWMCompMgrDefaultClientPrivate;
+
+typedef enum MBWMClientType
+{
+ MBWMClientTypeApp = (1 << 0),
+ MBWMClientTypeDialog = (1 << 1),
+ MBWMClientTypePanel = (1 << 2),
+ MBWMClientTypeDesktop = (1 << 3),
+ MBWMClientTypeInput = (1 << 4),
+ MBWMClientTypeMenu = (1 << 5),
+ MBWMClientTypeNote = (1 << 6),
+ MBWMClientTypeOverride = (1 << 7),
+
+ MBWMClientTypeLast = MBWMClientTypeOverride,
+} MBWMClientType;
+
+typedef enum _MBWMCompMgrClientEvent
+{
+ MBWMCompMgrClientEventNone = 0,
+ MBWMCompMgrClientEventMinimize,
+ MBWMCompMgrClientEventMap,
+ MBWMCompMgrClientEventUnmap,
+
+ _MBWMCompMgrClientEventLast,
+} MBWMCompMgrClientEvent;
+
+typedef enum _MBWMGravity
+{
+ MBWMGravityNone = 0,
+ MBWMGravityNorth,
+ MBWMGravityNorthEast,
+ MBWMGravityEast,
+ MBWMGravitySouthEast,
+ MBWMGravitySouth,
+ MBWMGravitySouthWest,
+ MBWMGravityWest,
+ MBWMGravityNorthWest,
+ MBWMGravityCenter,
+} MBWMGravity;
+
+typedef unsigned long MBWMCookie;
+
+typedef enum MBWMAtom
+{
+ /* ICCCM */
+
+ MBWM_ATOM_WM_NAME = 0,
+ MBWM_ATOM_WM_STATE,
+ MBWM_ATOM_WM_HINTS,
+ MBWM_ATOM_WM_NORMAL_HINTS,
+ MBWM_ATOM_WM_CHANGE_STATE,
+ MBWM_ATOM_WM_PROTOCOLS,
+ MBWM_ATOM_WM_DELETE_WINDOW,
+ MBWM_ATOM_WM_COLORMAP_WINDOWS,
+ MBWM_ATOM_WM_CLIENT_MACHINE,
+ MBWM_ATOM_WM_TRANSIENT_FOR,
+ MBWM_ATOM_WM_TAKE_FOCUS,
+
+ /* EWMH */
+
+ MBWM_ATOM_NET_WM_WINDOW_TYPE,
+ MBWM_ATOM_NET_WM_WINDOW_TYPE_NORMAL,
+ MBWM_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR,
+ MBWM_ATOM_NET_WM_WINDOW_TYPE_INPUT,
+ MBWM_ATOM_NET_WM_WINDOW_TYPE_DOCK,
+ MBWM_ATOM_NET_WM_WINDOW_TYPE_MENU,
+ MBWM_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU,
+ MBWM_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
+ MBWM_ATOM_NET_WM_WINDOW_TYPE_DIALOG,
+ MBWM_ATOM_NET_WM_WINDOW_TYPE_SPLASH,
+ MBWM_ATOM_NET_WM_WINDOW_TYPE_DESKTOP,
+ MBWM_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION,
+
+ MBWM_ATOM_NET_WM_STATE,
+ MBWM_ATOM_NET_WM_STATE_FULLSCREEN,
+ MBWM_ATOM_NET_WM_STATE_MODAL,
+ MBWM_ATOM_NET_WM_STATE_ABOVE,
+ MBWM_ATOM_NET_WM_STATE_STICKY,
+ MBWM_ATOM_NET_WM_STATE_MAXIMIZED_VERT,
+ MBWM_ATOM_NET_WM_STATE_MAXIMIZED_HORZ,
+ MBWM_ATOM_NET_WM_STATE_SHADED,
+ MBWM_ATOM_NET_WM_STATE_SKIP_TASKBAR,
+ MBWM_ATOM_NET_WM_STATE_SKIP_PAGER,
+ MBWM_ATOM_NET_WM_STATE_HIDDEN,
+ MBWM_ATOM_NET_WM_STATE_BELOW,
+ MBWM_ATOM_NET_WM_STATE_DEMANDS_ATTENTION,
+
+ MBWM_ATOM_NET_SUPPORTED,
+ MBWM_ATOM_NET_CLIENT_LIST,
+ MBWM_ATOM_NET_NUMBER_OF_DESKTOPS,
+ MBWM_ATOM_NET_ACTIVE_WINDOW,
+ MBWM_ATOM_NET_SUPPORTING_WM_CHECK,
+ MBWM_ATOM_NET_CLOSE_WINDOW,
+ MBWM_ATOM_NET_WM_NAME,
+ MBWM_ATOM_NET_WM_USER_TIME,
+
+ MBWM_ATOM_NET_CLIENT_LIST_STACKING,
+ MBWM_ATOM_NET_CURRENT_DESKTOP,
+ MBWM_ATOM_NET_WM_DESKTOP,
+ MBWM_ATOM_NET_WM_ICON,
+ MBWM_ATOM_NET_DESKTOP_GEOMETRY,
+ MBWM_ATOM_NET_WORKAREA,
+ MBWM_ATOM_NET_SHOWING_DESKTOP,
+ MBWM_ATOM_NET_DESKTOP_VIEWPORT,
+ MBWM_ATOM_NET_FRAME_EXTENTS,
+ MBWM_ATOM_NET_WM_FULL_PLACEMENT,
+
+ MBWM_ATOM_NET_WM_ALLOWED_ACTIONS,
+ MBWM_ATOM_NET_WM_ACTION_MOVE,
+ MBWM_ATOM_NET_WM_ACTION_RESIZE,
+ MBWM_ATOM_NET_WM_ACTION_MINIMIZE,
+ MBWM_ATOM_NET_WM_ACTION_SHADE,
+ MBWM_ATOM_NET_WM_ACTION_STICK,
+ MBWM_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ,
+ MBWM_ATOM_NET_WM_ACTION_MAXIMIZE_VERT,
+ MBWM_ATOM_NET_WM_ACTION_FULLSCREEN,
+ MBWM_ATOM_NET_WM_ACTION_CHANGE_DESKTOP,
+ MBWM_ATOM_NET_WM_ACTION_CLOSE,
+
+ MBWM_ATOM_NET_WM_PING,
+ MBWM_ATOM_NET_WM_PID,
+
+ /* Startup Notification */
+ MBWM_ATOM_NET_STARTUP_ID,
+
+ /* Misc */
+
+ MBWM_ATOM_UTF8_STRING,
+ MBWM_ATOM_MOTIF_WM_HINTS,
+ MBWM_ATOM_WIN_SUPPORTING_WM_CHECK,
+
+ MBWM_ATOM_NET_WM_CONTEXT_HELP,
+ MBWM_ATOM_NET_WM_CONTEXT_ACCEPT,
+ MBWM_ATOM_NET_WM_CONTEXT_CUSTOM,
+ MBWM_ATOM_NET_WM_SYNC_REQUEST,
+
+ MBWM_ATOM_CM_TRANSLUCENCY,
+
+ MBWM_ATOM_MB_APP_WINDOW_LIST_STACKING,
+ MBWM_ATOM_MB_THEME,
+ MBWM_ATOM_MB_THEME_NAME,
+ MBWM_ATOM_MB_COMMAND,
+ MBWM_ATOM_MB_GRAB_TRANSFER,
+ MBWM_ATOM_MB_CURRENT_APP_WINDOW,
+
+ /* FIXME: Custom/Unused to sort out
+ *
+ * MB_WM_STATE_DOCK_TITLEBAR,
+ *
+ * _NET_WM_SYNC_REQUEST_COUNTER,
+ * _NET_WM_SYNC_REQUEST,
+ *
+ * MB_CLIENT_EXEC_MAP,
+ * MB_CLIENT_STARTUP_LIST,
+ * MB_DOCK_TITLEBAR_SHOW_ON_DESKTOP,
+ *
+ * WINDOW_TYPE_MESSAGE,
+ *
+ */
+
+ MBWM_ATOM_COUNT
+
+} MBWMAtom;
+
+/* Keys */
+
+typedef struct MBWMKeyBinding MBWMKeyBinding;
+typedef struct MBWMKeys MBWMKeys;
+
+typedef void (*MBWMKeyPressedFunc) (MBWindowManager *wm,
+ MBWMKeyBinding *binding,
+ void *userdata);
+
+typedef void (*MBWMKeyDestroyFunc) (MBWindowManager *wm,
+ MBWMKeyBinding *binding,
+ void *userdata);
+
+struct MBWMKeyBinding
+{
+ KeySym keysym;
+ int modifier_mask;
+ MBWMKeyPressedFunc pressed;
+ MBWMKeyDestroyFunc destroy;
+ void *userdata;
+ /* FIXME: free func */
+};
+
+/* Event Callbacks */
+
+typedef Bool (*MBWMXEventFunc)
+ (void *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerMapNotifyFunc)
+ (XMapEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerClientMessageFunc)
+ (XClientMessageEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerMapRequestFunc)
+ (XMapRequestEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerUnmapNotifyFunc)
+ (XUnmapEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerDestroyNotifyFunc)
+ (XDestroyWindowEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerConfigureNotifyFunc)
+ (XConfigureEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerConfigureRequestFunc)
+ (XConfigureRequestEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerKeyPressFunc)
+ (XKeyEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerPropertyNotifyFunc)
+ (XPropertyEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerButtonPressFunc)
+ (XButtonEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerButtonReleaseFunc)
+ (XButtonEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerMotionNotifyFunc)
+ (XMotionEvent *xev,
+ void *userdata);
+
+typedef Bool (*MBWindowManagerTimeOutFunc)
+ (void *userdata);
+
+#if USE_GLIB_MAINLOOP
+typedef GIOChannel MBWMIOChannel;
+typedef GIOCondition MBWMIOCondition;
+#else
+typedef int MBWMIOChannel;
+typedef int MBWMIOCondition;
+#endif
+
+typedef Bool (*MBWindowManagerFdWatchFunc)
+ (MBWMIOChannel *channel,
+ MBWMIOCondition events,
+ void *userdata);
+
+typedef struct MBWMXEventFuncInfo
+{
+ MBWMXEventFunc func;
+ Window xwindow;
+ void *userdata;
+ unsigned long id;
+}
+MBWMXEventFuncInfo;
+
+typedef struct MBWMTimeOutEventInfo MBWMTimeOutEventInfo;
+typedef struct MBWMFdWatchInfo MBWMFdWatchInfo;
+
+typedef enum MBWMDecorButtonFlags
+{
+ MB_WM_DECOR_BUTTON_INVISIBLE = (1<<1)
+
+} MBWMDecorButtonFlags;
+
+typedef enum MBWMDecorType
+{
+ MBWMDecorTypeNorth = 1,
+ MBWMDecorTypeSouth,
+ MBWMDecorTypeEast,
+ MBWMDecorTypeWest,
+
+} MBWMDecorType;
+
+typedef enum MBWMSyncType
+{
+ MBWMSyncStacking = (1<<1),
+ MBWMSyncGeometry = (1<<2),
+ MBWMSyncVisibility = (1<<3),
+ MBWMSyncDecor = (1<<4),
+ MBWMSyncConfigRequestAck = (1<<5),
+ MBWMSyncFullscreen = (1<<6),
+} MBWMSyncType;
+
+typedef struct MBWMColor
+{
+ double r;
+ double g;
+ double b;
+ double a;
+
+ Bool set;
+}MBWMColor;
+
+typedef enum MBWMCompMgrShadowType
+{
+ MBWM_COMP_MGR_SHADOW_NONE = 0,
+ MBWM_COMP_MGR_SHADOW_SIMPLE,
+ MBWM_COMP_MGR_SHADOW_GAUSSIAN,
+} MBWMCompMgrShadowType;
+
+typedef enum MBWMModality
+{
+ MBWMModalityNormal = 0, /* Handle modality per EWMH */
+ MBWMModalitySystem, /* Treat all modal dialogs as if system modal */
+ MBWMModalityNone, /* Ignore modality */
+}MBWMModality;
+
+
+/* mb remote commands */
+#define MB_CMD_SET_THEME 1
+#define MB_CMD_EXIT 2
+#define MB_CMD_DESKTOP 3
+#define MB_CMD_NEXT 4
+#define MB_CMD_PREV 5
+#define MB_CMD_MISC 7 /* spare, used for debugging */
+#define MB_CMD_COMPOSITE 8
+#define MB_CMB_KEYS_RELOAD 9
+
+#endif
diff --git a/matchbox2/core/mb-wm-util.c b/matchbox2/core/mb-wm-util.c
new file mode 100644
index 0000000..792cb81
--- /dev/null
+++ b/matchbox2/core/mb-wm-util.c
@@ -0,0 +1,289 @@
+#include "mb-wm.h"
+#include <stdarg.h>
+
+static int TrappedErrorCode = 0;
+static int (*old_error_handler) (Display *, XErrorEvent *);
+
+static int
+error_handler(Display *xdpy,
+ XErrorEvent *error)
+{
+ TrappedErrorCode = error->error_code;
+ return 0;
+}
+
+void
+mb_wm_util_trap_x_errors(void)
+{
+ /* MBWM_DBG("### X Errors Trapped ###"); */
+
+ TrappedErrorCode = 0;
+ old_error_handler = XSetErrorHandler(error_handler);
+}
+
+int
+mb_wm_util_untrap_x_errors(void)
+{
+ /* MBWM_DBG("### X Errors Untrapped (%i) ###", TrappedErrorCode); */
+
+ XSetErrorHandler(old_error_handler);
+ return TrappedErrorCode;
+}
+
+
+void*
+mb_wm_util_malloc0(int size)
+{
+ void *p = NULL;
+
+ p = malloc(size);
+
+ if (p == NULL)
+ {
+ /* hook into some kind of out of memory */
+ }
+ else
+ memset(p, 0, size);
+
+ return p;
+}
+
+Bool /* FIXME: define, inline ? */
+mb_geometry_compare (MBGeometry *g1, MBGeometry *g2)
+{
+ return (g1->x == g2->x
+ && g1->y == g2->y
+ && g1->width == g2->width
+ && g1->height == g2->height);
+}
+
+Bool /* True if overlaps */
+mb_geometry_intersects (MBGeometry *g1, MBGeometry *g2)
+{
+ if ((g1->x > g2->x + g2->width) ||
+ (g1->y > g2->y + g2->height) ||
+ (g2->x > g1->x + g1->width) ||
+ (g2->y > g1->y + g1->height))
+ return False;
+
+ return True;
+}
+
+
+void
+mb_wm_util_fatal_error (char *msg)
+{
+ fprintf(stderr, "matchbox-window-manager: *Error* %s\n", msg);
+ exit(1);
+}
+
+void
+mb_wm_util_warn (const char *format, ...)
+{
+ va_list ap;
+ char *msg = NULL;
+
+ va_start(ap, format);
+ vasprintf(&msg, format, ap);
+ va_end(ap);
+
+ fprintf(stderr, "*MBWM Warning* %s\n", msg);
+
+ if (msg) free(msg);
+}
+
+MBWMList*
+mb_wm_util_list_alloc_item(void)
+{
+ return mb_wm_util_malloc0(sizeof(MBWMList));
+}
+
+int
+mb_wm_util_list_length(MBWMList *list)
+{
+ int result = 1;
+
+ if (!list)
+ return 0;
+
+ list = mb_wm_util_list_get_first(list);
+
+ while ((list = mb_wm_util_list_next(list)) != NULL)
+ result++;
+
+ return result;
+}
+
+MBWMList*
+mb_wm_util_list_get_last(MBWMList *list)
+{
+ if (list == NULL)
+ return NULL;
+
+ while (list->next)
+ list = mb_wm_util_list_next(list);
+ return list;
+}
+
+MBWMList*
+mb_wm_util_list_get_first(MBWMList *list)
+{
+ if (list == NULL)
+ return NULL;
+
+ while (list->prev)
+ list = mb_wm_util_list_prev(list);
+ return list;
+}
+
+void*
+mb_wm_util_list_get_nth_data(MBWMList *list, int n)
+{
+ if (list == NULL)
+ return NULL;
+
+ list = mb_wm_util_list_get_first(list);
+
+ while (list->next && n)
+ {
+ list = mb_wm_util_list_next(list);
+ n--;
+ }
+
+ if (n) return NULL;
+
+ return (void *)list->data;
+}
+
+MBWMList*
+mb_wm_util_list_prepend(MBWMList *list, void *data)
+{
+ MBWMList * l = mb_wm_util_list_alloc_item();
+
+ l->data = data;
+ l->next = list;
+
+ if (list)
+ list->prev = l;
+
+ return l;
+}
+
+MBWMList*
+mb_wm_util_list_append(MBWMList *list, void *data)
+{
+ if (list == NULL)
+ {
+ list = mb_wm_util_list_alloc_item();
+ list->data = data;
+ }
+ else
+ {
+ MBWMList *last;
+
+ last = mb_wm_util_list_get_last(list);
+
+ last->next = mb_wm_util_list_alloc_item();
+ last->next->prev = last;
+ last->next->data = data;
+ }
+
+ return list;
+}
+
+MBWMList*
+mb_wm_util_list_remove(MBWMList *list, void *data)
+{
+ MBWMList *prev, *start;
+
+ prev = NULL;
+ start = list = mb_wm_util_list_get_first(list);
+
+ while (list)
+ {
+ if (list->data == data)
+ {
+ if (list->next)
+ list->next->prev = prev;
+
+ if (prev)
+ prev->next = list->next;
+ else
+ start = list->next;
+
+ free(list);
+
+ return start;
+ }
+
+ prev = list;
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+void
+mb_wm_util_list_foreach (const MBWMList *list,
+ MBWMListForEachCB func,
+ void *userdata)
+{
+ MBWMList *p = (MBWMList *) list;
+
+ while (p)
+ {
+ func(p->data, userdata);
+ p = mb_wm_util_list_next(p);
+ }
+}
+
+void
+mb_wm_util_list_free (MBWMList * list)
+{
+ MBWMList * l = list;
+
+ while (l)
+ {
+ MBWMList * f = l;
+ l = l->next;
+
+ free (f);
+ }
+}
+
+
+MBWMRgbaIcon *
+mb_wm_rgba_icon_new ()
+{
+ return mb_wm_util_malloc0 (sizeof (MBWMRgbaIcon));
+}
+
+
+void
+mb_wm_rgba_icon_free (MBWMRgbaIcon *icon)
+{
+ if (icon->pixels)
+ free (icon->pixels);
+
+ free (icon);
+}
+
+int
+mb_wm_util_pixels_to_points (MBWindowManager *wm, int pixels)
+{
+ static double scale = 0.0; /* Points per pixel */
+ int points;
+
+ if (scale == 0.0)
+ {
+ scale =
+ ((double)DisplayHeightMM (wm->xdpy, wm->xscreen) * 2.8346456693)
+ / (double) DisplayHeight(wm->xdpy, wm->xscreen);
+ }
+
+ /* Scale and round */
+ points = (((int)((double)(pixels << 10) * scale) + 512) >> 10);
+
+ return points;
+}
+
diff --git a/matchbox2/core/mb-wm-util.h b/matchbox2/core/mb-wm-util.h
new file mode 100644
index 0000000..c9bd6b5
--- /dev/null
+++ b/matchbox2/core/mb-wm-util.h
@@ -0,0 +1,118 @@
+#ifndef _MB_HAVE_UTIL_H
+#define _MB_HAVE_UTIL_H
+
+#include <matchbox2/core/mb-wm.h>
+
+/* See http://rlove.org/log/2005102601 */
+#if __GNUC__ >= 3
+#if ! USE_GLIB_MAINLOOP
+# define inline __attribute__ ((always_inline))
+#endif
+# define __pure__attribute__ ((pure))
+# define __const__attribute__ ((const))
+# define __noreturn__attribute__ ((noreturn))
+# define __malloc__attribute__ ((malloc))
+# define __must_check__attribute__ ((warn_unused_result))
+# define __deprecated__attribute__ ((deprecated))
+# define __used__attribute__ ((used))
+# define __unused__attribute__ ((unused))
+# define __packed__attribute__ ((packed))
+# define LIKELY(x)__builtin_expect (!!(x), 1)
+# define UNLIKELY(x)__builtin_expect (!!(x), 0)
+#else
+# define inline/* no inline */
+# define __pure/* no pure */
+# define __const/* no const */
+# define __noreturn/* no noreturn */
+# define __malloc/* no malloc */
+# define __must_check/* no warn_unused_result */
+# define __deprecated/* no deprecated */
+# define __used/* no used */
+# define __unused/* no unused */
+# define __packed/* no packed */
+# define LIKELY(x)(x)
+# define UNLIKELY(x)(x)
+#endif
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strcaseeq(a,b) (strcasecmp(a,b) == 0)
+#define unless(x) if (!(x))
+
+#define MBWMChildMask (SubstructureRedirectMask|SubstructureNotifyMask)
+#define MBWMButtonMask (ButtonPressMask|ButtonReleaseMask)
+#define MBWMMouseMask (ButtonMask|PointerMotionMask)
+#define MBWMKeyMask (KeyPressMask|KeyReleaseMask)
+
+void*
+mb_wm_util_malloc0(int size);
+
+void
+mb_wm_util_fatal_error(char *msg);
+
+void
+mb_wm_util_warn (const char *format, ...);
+
+/* Misc */
+
+Bool /* True if matching */
+mb_geometry_compare (MBGeometry *g1, MBGeometry *g2);
+
+Bool /* True if overlaps */
+mb_geometry_intersects (MBGeometry *g1, MBGeometry *g2);
+
+/* XErrors */
+
+void
+mb_wm_util_trap_x_errors(void);
+
+int
+mb_wm_util_untrap_x_errors(void);
+
+
+/* List */
+
+
+#define mb_wm_util_list_next(list) (list)->next
+#define mb_wm_util_list_prev(list) (list)->prev
+#define mb_wm_util_list_data(data) (list)->data
+
+MBWMList*
+mb_wm_util_list_alloc_item(void);
+
+MBWMList*
+mb_wm_util_list_remove(MBWMList *list, void *data);
+
+int
+mb_wm_util_list_length(MBWMList *list);
+
+MBWMList*
+mb_wm_util_list_get_last(MBWMList *list);
+
+MBWMList*
+mb_wm_util_list_get_first(MBWMList *list);
+
+void*
+mb_wm_util_list_get_nth_data(MBWMList *list, int n);
+
+MBWMList*
+mb_wm_util_list_append(MBWMList *list, void *data);
+
+MBWMList*
+mb_wm_util_list_prepend(MBWMList *list, void *data);
+
+void
+mb_wm_util_list_foreach (const MBWMList *list, MBWMListForEachCB func, void *userdata);
+
+void
+mb_wm_util_list_free (MBWMList * list);
+
+MBWMRgbaIcon *
+mb_wm_rgba_icon_new ();
+
+void
+mb_wm_rgba_icon_free (MBWMRgbaIcon *icon);
+
+int
+mb_wm_util_pixels_to_points (MBWindowManager *wm, int pixels);
+
+#endif
diff --git a/matchbox2/core/mb-wm.h b/matchbox2/core/mb-wm.h
new file mode 100644
index 0000000..0643510
--- /dev/null
+++ b/matchbox2/core/mb-wm.h
@@ -0,0 +1,62 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_H
+#define _HAVE_MB_WM_H
+
+#define _GNU_SOURCE /* For vasprintf */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h> /* for XA_ATOM etc */
+#include <X11/keysym.h> /* key mask defines */
+
+#include <matchbox2/mb-wm-config.h>
+#include <matchbox2/core/xas.h> /* async stuff not needed for xlib on xcb */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#include <matchbox2/core/mb-wm-macros.h>
+#include <matchbox2/core/mb-wm-debug.h>
+#include <matchbox2/core/mb-wm-types.h>
+#include <matchbox2/core/mb-wm-util.h>
+#include <matchbox2/core/mb-wm-object.h>
+#include <matchbox2/core/mb-wm-atoms.h>
+#include <matchbox2/core/mb-wm-props.h>
+#include <matchbox2/core/mb-wm-keys.h>
+#include <matchbox2/core/mb-wm-decor.h>
+#include <matchbox2/core/mb-wm-client-window.h>
+#include <matchbox2/core/mb-wm-root-window.h>
+#include <matchbox2/core/mb-wm-client.h>
+#include <matchbox2/core/mb-wm-client-base.h>
+#include <matchbox2/core/mb-wm-layout.h>
+#include <matchbox2/core/mb-wm-stack.h>
+#include <matchbox2/core/mb-window-manager.h>
+#include <matchbox2/core/mb-wm-main-context.h>
+#endif
diff --git a/matchbox2/core/xas.c b/matchbox2/core/xas.c
new file mode 100644
index 0000000..47329dc
--- /dev/null
+++ b/matchbox2/core/xas.c
@@ -0,0 +1,906 @@
+/* Asynchronous Xlib hack utiltys lib
+ *
+ * Copyright (c) 2005 Matthew Allum
+ *
+ * Contains portions of code from Metacity and Xlib thus;
+ *
+ * Copyright (C) 2002 Havoc Pennington
+ * Copyright (C) 1986, 1998 The Open Group
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation.
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of The Open Group shall not be
+ * used in advertising or otherwise to promote the sale, use or other dealings
+ * in this Software without prior written authorization from The Open Group.
+ */
+
+#include "xas.h"
+
+#if MBWM_WANT_DEBUG
+#include "mb-wm-debug.h"
+#include <stdio.h>
+#define XAS_DBG(x, a...) \
+if (mbwm_debug_flags & MBWM_DEBUG_XAS) \
+ fprintf(stderr, __FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a)
+#else
+#define XAS_DBG(x, a...) do {} while (0)
+#endif
+#define XAS_MARK() XAS_DBG("--mark--");
+
+#ifdef MBWM_WANT_ASSERT
+#include <assert.h>
+#define XAS_ASSERT(x) assert(x)
+#else
+#define XAS_ASSERT(x) do {} while (0)
+#endif
+
+#define XAS_ALIGN_VALUE(this, boundary) \
+ (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
+
+#define NEED_REPLIES
+#include <X11/Xlibint.h>
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+typedef struct XasTask XasTask;
+typedef struct XasTaskGetProperty XasTaskGetProperty;
+typedef struct XasTaskGetWinAttr XasTaskGetWinAttr;
+typedef struct XasTaskGetGeom XasTaskGetGeom;
+
+#define XAS_TASK(t) (XasTask*)(t)
+
+typedef enum XasTaskType
+{
+ XAS_TASK_UNKNOWN,
+ XAS_TASK_GET_PROPERTY,
+ XAS_TASK_GET_WIN_ATTR,
+ XAS_TASK_GET_GEOM,
+
+} XasTaskType;
+
+struct XasContext
+{
+ _XAsyncHandler async;
+ Display *xdpy;
+ XasTask *tasks_pending;
+ int n_tasks_pending;
+ XasTask *tasks_completed;
+ int n_tasks_completed;
+};
+
+struct XasTask
+{
+ XasTask *next;
+ XasTaskType type;
+ XasContext *ctx;
+ unsigned long request_seq;
+ Bool have_reply;
+ int error;
+
+};
+
+struct XasTaskGetProperty
+{
+ XasTask task;
+
+ Window window;
+ Atom property;
+
+ Atom actual_type;
+ int actual_format;
+
+ unsigned long n_items;
+ unsigned long bytes_after;
+ unsigned char *data;
+};
+
+struct XasTaskGetWinAttr
+{
+ XasTask task;
+ Window window;
+ XasWindowAttributes *attr;
+};
+
+struct XasTaskGetGeom
+{
+ XasTask task;
+ Drawable drw;
+ Window root;
+ int x;
+ int y;
+ unsigned int width;
+ unsigned int height;
+ unsigned int border;
+ unsigned int depth;
+};
+
+static XasTask*
+task_list_append(XasTask *tasks, XasTask *task)
+{
+ XasTask *t = NULL;
+
+ /* FIXME: use hash on seq_req key instead ? */
+
+ if (tasks == NULL) return task;
+
+ for (t = tasks; t->next != NULL; t = t->next);
+
+ t->next = task;
+
+ return tasks;
+}
+
+XasTask*
+task_list_remove(XasTask *tasks, XasTask *task)
+{
+ XasTask *t = NULL, *p = NULL;
+
+ if (task == tasks)
+ {
+ t = task->next;
+ tasks->next = NULL;
+ return t;
+ }
+
+ p = tasks;
+ t = tasks->next;
+
+ while (t != NULL)
+ {
+ if (t == task)
+ {
+ p->next = t->next;
+ task->next = NULL;
+ return tasks;
+ }
+ p = t; t = t->next;
+ }
+
+ return tasks;
+}
+
+static void
+task_init(XasContext *ctx, XasTask *task, XasTaskType type)
+{
+ task->ctx = ctx;
+ task->next = NULL;
+ task->type = type;
+ task->request_seq = ctx->xdpy->request;
+ task->have_reply = False;
+}
+
+static void
+task_complete(XasContext *ctx, XasTask *task)
+{
+ ctx->tasks_pending = task_list_remove(ctx->tasks_pending, task);
+ ctx->n_tasks_pending--;
+ ctx->tasks_completed = task_list_append(ctx->tasks_completed, task);
+ ctx->n_tasks_completed++;
+}
+
+static XasTask*
+xas_find_task_for_request_seq(XasContext *ctx,
+ XasTask *task_list,
+ unsigned long request_seq)
+{
+ XasTask *task = NULL;
+
+ task = task_list;
+
+ while (task != NULL)
+ {
+ if (task->request_seq == request_seq)
+ return task;
+ task = task->next;
+ }
+
+ XAS_DBG("Failed to find task\n");
+ return NULL;
+}
+
+static Bool
+xas_async_get_geom_handler (XasContext *ctx,
+ XasTaskGetGeom *task,
+ xReply *rep,
+ char *buf,
+ int len)
+{
+ Display *dpy;
+ xGetGeometryReply *repl;
+ xGetGeometryReply replbuf;
+
+ dpy = ctx->xdpy;
+
+ task->task.have_reply = True;
+
+ task_complete (ctx, XAS_TASK(task));
+
+ if (rep->generic.type == X_Error)
+ {
+ xError errbuf;
+ task->task.error = rep->error.errorCode;
+ _XGetAsyncReply (dpy, (char *)&errbuf, rep, buf, len,
+ (SIZEOF (xError) - SIZEOF (xReply)) >> 2,
+ False);
+ return True;
+ }
+
+ repl = (xGetGeometryReply *)
+ _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
+ (SIZEOF(xGetGeometryReply) - SIZEOF(xReply)) >> 2,
+ True);
+
+ task->root = repl->root;
+ task->x = cvtINT16toInt (repl->x);
+ task->y = cvtINT16toInt (repl->y);
+ task->width = repl->width;
+ task->height = repl->height;
+ task->border = repl->borderWidth;
+ task->depth = repl->depth;
+
+ return True;
+}
+
+
+static Bool
+xas_async_get_win_attr_handler (XasContext *ctx,
+ XasTaskGetWinAttr *task,
+ xReply *rep,
+ char *buf,
+ int len)
+{
+ Display *dpy;
+ xGetWindowAttributesReply replbuf;
+ xGetWindowAttributesReply *repl;
+
+ dpy = ctx->xdpy;
+
+ task->task.have_reply = True;
+
+ task_complete (ctx, XAS_TASK(task));
+
+ if (rep->generic.type == X_Error)
+ {
+ xError errbuf;
+ task->task.error = rep->error.errorCode;
+ _XGetAsyncReply (dpy, (char *)&errbuf, rep, buf, len,
+ (SIZEOF (xError) - SIZEOF (xReply)) >> 2,
+ False);
+ return True;
+ }
+
+ repl = (xGetWindowAttributesReply *)
+ _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
+ (SIZEOF(xGetWindowAttributesReply) - SIZEOF(xReply)) >> 2,
+ True);
+
+ task->attr = (XasWindowAttributes *)Xmalloc(sizeof(XasWindowAttributes));
+
+ if (task->attr == NULL)
+ {
+ task->task.error = BadAlloc;
+ return True;
+ }
+
+ task->attr->class = repl->class;
+ task->attr->bit_gravity = repl->bitGravity;
+ task->attr->win_gravity = repl->winGravity;
+ task->attr->backing_store = repl->backingStore;
+ task->attr->backing_planes = repl->backingBitPlanes;
+ task->attr->backing_pixel = repl->backingPixel;
+ task->attr->save_under = repl->saveUnder;
+ task->attr->colormap = repl->colormap;
+ task->attr->map_installed = repl->mapInstalled;
+ task->attr->map_state = repl->mapState;
+ task->attr->all_event_masks = repl->allEventMasks;
+ task->attr->your_event_mask = repl->yourEventMask;
+ task->attr->do_not_propagate_mask = repl->doNotPropagateMask;
+ task->attr->override_redirect = repl->override;
+ task->attr->visual = _XVIDtoVisual (dpy, repl->visualID);
+
+ return True;
+}
+
+static Bool
+xas_async_get_property_handler (XasContext *ctx,
+ XasTaskGetProperty *task,
+ xReply *rep,
+ char *buf,
+ int len)
+{
+ Display *dpy;
+ xGetPropertyReply replbuf;
+ xGetPropertyReply *reply;
+ int bytes_read;
+
+ /* Code and comments here wripped out of Metacity, Copyright
+ * Havoc Pennington.
+ */
+
+ /* FIXME: Really check this code is really reliable/safe.*/
+
+ dpy = ctx->xdpy;
+
+ XAS_DBG ("seeing request seq %ld buflen %d",
+ dpy->last_request_read, len);
+
+ task_complete (ctx, XAS_TASK(task));
+
+ /* read bytes so far */
+ bytes_read = SIZEOF (xReply);
+
+ if (rep->generic.type == X_Error)
+ {
+ xError errbuf;
+
+ task->task.error = rep->error.errorCode;
+
+ /* We return True (meaning we consumed the reply)
+ * because otherwise it would invoke the X error handler,
+ * and an async API is useless if you have to synchronously
+ * trap X errors. Also GetProperty can always fail, pretty
+ * much, so trapping errors is always what you want.
+ *
+ * We have to eat all the error reply data here.
+ * (kind of a charade as we know sizeof(xError) == sizeof(xReply))
+ *
+ * Passing discard = True seems to break things; I don't understand
+ * why, because there should be no extra data in an error reply,
+ * right?
+ */
+ _XGetAsyncReply (dpy, (char *)&errbuf, rep, buf, len,
+ (SIZEOF (xError) - bytes_read) >> 2, /* 32-bit words */
+ False); /* really seems like it should be True */
+ return True;
+ }
+
+ XAS_DBG ("already read %d bytes reading %d more for total of %d; generic.length = %ld",
+ bytes_read, (SIZEOF (xGetPropertyReply) - bytes_read) >> 2,
+ SIZEOF (xGetPropertyReply), rep->generic.length);
+
+ reply = (xGetPropertyReply *)
+ _XGetAsyncReply (dpy, (char *)&replbuf, rep, buf, len,
+ (SIZEOF (xGetPropertyReply) - bytes_read) >> 2,
+ False); /* False means expecting more data to follow,
+ * don't eat the rest of the reply
+ */
+
+ bytes_read = SIZEOF (xGetPropertyReply);
+
+ XAS_DBG ("have reply propertyType = %ld format = %d n_items = %ld",
+ reply->propertyType, reply->format, reply->nItems);
+
+ /* This is all copied from XGetWindowProperty(). Not sure we should
+ * LockDisplay(). Not sure I'm passing the right args to
+ * XGetAsyncData(). Not sure about a lot of things.
+ */
+
+ /* LockDisplay (dpy); */
+
+ if (reply->propertyType != None)
+ {
+ long nbytes, netbytes;
+
+ /* this alignment macro from orbit2 */
+
+ switch (reply->format)
+ {
+ /*
+ * One extra byte is malloced than is needed to contain the property
+ * data, but this last byte is null terminated and convenient for
+ * returning string properties, so the client doesn't then have to
+ * recopy the string to make it null terminated.
+ */
+ case 8:
+ nbytes = reply->nItems;
+ /* there's padding to word boundary */
+ netbytes = XAS_ALIGN_VALUE (nbytes, 4);
+ if (nbytes + 1 > 0 &&
+ (task->data = (unsigned char *) Xmalloc ((unsigned)nbytes + 1)))
+ {
+
+ XAS_DBG ("already read %d bytes using %ld, more eating %ld more",
+ bytes_read, nbytes, netbytes);
+
+ /* _XReadPad (dpy, (char *) task->data, netbytes); */
+ _XGetAsyncData (dpy, task->data, buf, len,
+ bytes_read, nbytes,
+ netbytes);
+ }
+ break;
+
+ case 16:
+ nbytes = reply->nItems * sizeof (short);
+ netbytes = reply->nItems << 1;
+ netbytes = XAS_ALIGN_VALUE (netbytes, 4); /* to word boundary */
+ if (nbytes + 1 > 0 &&
+ (task->data = (unsigned char *) Xmalloc ((unsigned)nbytes + 1)))
+ {
+ XAS_DBG ("%s: already read %d bytes using %ld more, eating %ld more\n",
+ __FUNCTION__, bytes_read, nbytes, netbytes);
+
+ /* _XRead16Pad (dpy, (short *) task->data, netbytes); */
+ _XGetAsyncData (dpy, task->data, buf, len,
+ bytes_read, nbytes, netbytes);
+ }
+ break;
+
+ case 32:
+ /* NOTE buffer is in longs to match XGetWindowProperty() */
+ nbytes = reply->nItems * sizeof (long);
+ netbytes = reply->nItems << 2; /* wire size always 32 bits though */
+ if (nbytes + 1 > 0 &&
+ (task->data = (unsigned char *) Xmalloc ((unsigned)nbytes + 1)))
+ {
+ XAS_DBG ("already read %d bytes using %ld more, eating %ld more",
+ bytes_read, nbytes, netbytes);
+
+ /* We have to copy the XGetWindowProperty() crackrock
+ * and get format 32 as long even on 64-bit platforms.
+ */
+ if (sizeof (long) == 8)
+ {
+ unsigned char *netdata;
+ unsigned char *lptr;
+ unsigned char *end_lptr;
+
+ /* Store the 32-bit values in the end of the array */
+ netdata = task->data + nbytes / 2;
+
+ _XGetAsyncData (dpy, netdata, buf, len,
+ bytes_read, netbytes,
+ netbytes);
+
+ /* Now move the 32-bit values to the front */
+
+ lptr = task->data;
+ end_lptr = task->data + nbytes;
+ while (lptr != end_lptr)
+ {
+ *(long*) lptr = *(CARD32*) netdata;
+ lptr += sizeof (long);
+ netdata += sizeof (CARD32);
+ }
+ }
+ else
+ {
+ /* Here the wire format matches our actual format */
+ _XGetAsyncData (dpy, task->data, buf, len,
+ bytes_read, netbytes,
+ netbytes);
+ }
+ }
+ break;
+
+ default:
+ /*
+ * This part of the code should never be reached. If it is,
+ * the server sent back a property with an invalid format.
+ * This is a BadImplementation error.
+ *
+ * However this async GetProperty API doesn't report errors
+ * via the standard X mechanism, so don't do anything about
+ * it, other than store it in task->error.
+ */
+ task->task.error = BadImplementation;
+ nbytes = netbytes = 0L;
+ break;
+ }
+
+ if (task->data == NULL)
+ {
+ task->task.error = BadAlloc;
+
+ XAS_DBG ("already read %d bytes eating %ld", bytes_read, netbytes);
+
+ /* _XEatData (dpy, (unsigned long) netbytes); */
+ _XGetAsyncData (dpy, NULL, buf, len, bytes_read, 0, netbytes);
+
+ /* UnlockDisplay (dpy); */
+ return BadAlloc; /* not Success */
+ }
+
+ (task->data)[nbytes] = '\0';
+ }
+
+ XAS_DBG ("have data");
+
+ task->actual_type = reply->propertyType;
+ task->actual_format = reply->format;
+ task->n_items = reply->nItems;
+ task->bytes_after = reply->bytesAfter;
+
+ /* UnlockDisplay (dpy); */
+
+ return True;
+}
+
+static Bool
+xas_async_handler (Display *dpy,
+ xReply *rep,
+ char *buf,
+ int len,
+ XPointer data)
+{
+ XasContext *ctx = (XasContext *)data;
+ XasTask *task;
+
+ XAS_ASSERT(ctx->xdpy == dpy);
+
+ if (!ctx->tasks_pending)
+ return False;
+
+ task = xas_find_task_for_request_seq(ctx,
+ ctx->tasks_pending,
+ dpy->last_request_read);
+ if (!task)
+ return False;
+
+ switch (task->type)
+ {
+ case XAS_TASK_GET_PROPERTY:
+ return xas_async_get_property_handler (ctx,
+ (XasTaskGetProperty*)task,
+ rep, buf, len);
+ case XAS_TASK_GET_WIN_ATTR:
+ return xas_async_get_win_attr_handler (ctx,
+ (XasTaskGetWinAttr*)task,
+ rep, buf, len);
+ case XAS_TASK_GET_GEOM:
+ return xas_async_get_geom_handler (ctx,
+ (XasTaskGetGeom*)task,
+ rep, buf, len);
+ case XAS_TASK_UNKNOWN:
+ default:
+ /* Should never get here */
+ return False;
+ }
+
+ return False;
+}
+
+/* public */
+
+XasContext*
+xas_context_new(Display *xdpy)
+{
+ XasContext *ctx = NULL;
+
+ ctx = (XasContext *)Xmalloc(sizeof(XasContext));
+
+ ctx->xdpy = xdpy;
+ ctx->async.next = xdpy->async_handlers;
+ ctx->async.handler = xas_async_handler;
+ ctx->async.data = (XPointer) ctx;
+ ctx->xdpy->async_handlers = &ctx->async;
+
+ ctx->tasks_pending = NULL;
+ ctx->n_tasks_pending = 0;
+ ctx->tasks_completed = NULL;
+ ctx->n_tasks_completed = 0;
+
+ return ctx;
+}
+
+void
+xas_context_destroy(XasContext *ctx)
+{
+ DeqAsyncHandler (ctx->xdpy, &ctx->async);
+
+ /* FIXME: empty pending and completed lists */
+
+ free(ctx);
+}
+
+XasCookie
+xas_get_property(XasContext *ctx,
+ Window win,
+ Atom property,
+ long offset,
+ long length,
+ Bool delete,
+ Atom req_type)
+{
+ Display *dpy ;
+ XasTaskGetProperty *task;
+ xGetPropertyReq *req;
+
+ LockDisplay (ctx->xdpy);
+
+ dpy = ctx->xdpy; /* GetReq() needs this */
+
+ task = Xcalloc (1, sizeof (XasTaskGetProperty));
+ if (task == NULL)
+ {
+ UnlockDisplay (dpy);
+ return 0;
+ }
+
+ GetReq (GetProperty, req);
+ req->window = win;
+ req->property = property;
+ req->type = req_type;
+ req->delete = delete;
+ req->longOffset = offset;
+ req->longLength = length;
+
+ /* needed ? error.sequenceNumber = ctx->xdpy->request;*/
+
+ task_init(ctx, XAS_TASK(task), XAS_TASK_GET_PROPERTY);
+
+ task->window = win;
+ task->property = property;
+
+ ctx->tasks_pending = task_list_append(ctx->tasks_pending, &task->task);
+
+ ctx->n_tasks_pending ++;
+
+ UnlockDisplay (dpy);
+
+ SyncHandle ();
+
+ return task->task.request_seq;
+}
+
+Bool
+xas_have_reply(XasContext *ctx,
+ XasCookie cookie)
+{
+ return (xas_find_task_for_request_seq(ctx, ctx->tasks_completed, cookie) != NULL);
+}
+
+
+Status
+xas_get_property_reply(XasContext *ctx,
+ XasCookie cookie,
+ Atom *actual_type_return,
+ int *actual_format_return,
+ unsigned long *nitems_return,
+ unsigned long *bytes_after_return,
+ unsigned char **prop_return,
+ int *x_error_code)
+{
+ Display *dpy;
+ XasTaskGetProperty *task = NULL;
+ Bool result = False;
+
+ dpy = ctx->xdpy; /* For SyncHandle (); */
+
+ if (x_error_code) *x_error_code = 0; /* No error as yet */
+
+ task = (XasTaskGetProperty *) xas_find_task_for_request_seq(ctx,
+ ctx->tasks_completed,
+ cookie);
+ if (task == NULL)
+ {
+ XAS_DBG("Failed to find cookie");
+ return False;
+ }
+
+ if (!task->task.error)
+ {
+ *actual_type_return = task->actual_type;
+ *actual_format_return = task->actual_format;
+ *nitems_return = task->n_items;
+ *bytes_after_return = task->bytes_after;
+ *prop_return = task->data;
+
+ result = True;
+ }
+ else
+ {
+ XAS_DBG("is error");
+ if (x_error_code)
+ *x_error_code = task->task.error;
+ result = False;;
+ }
+
+ SyncHandle ();
+
+ ctx->tasks_completed = task_list_remove(ctx->tasks_completed,
+ XAS_TASK(task));
+ ctx->n_tasks_completed--;
+
+ XFree (task);
+
+ return result;
+}
+
+XasCookie
+xas_get_window_attributes(XasContext *ctx,
+ Window win)
+{
+ xResourceReq *req;
+ Display *dpy ;
+ XasTaskGetWinAttr *task;
+
+ LockDisplay (ctx->xdpy);
+
+ dpy = ctx->xdpy; /* GetReq() needs this */
+
+ task = Xcalloc (1, sizeof (XasTaskGetWinAttr));
+ if (task == NULL)
+ {
+ UnlockDisplay (dpy);
+ return 0;
+ }
+
+ GetResReq(GetWindowAttributes, win, req);
+
+ task_init(ctx, XAS_TASK(task), XAS_TASK_GET_WIN_ATTR);
+
+ task->window = win;
+
+ ctx->tasks_pending = task_list_append(ctx->tasks_pending, &task->task);
+ ctx->n_tasks_pending ++;
+
+ UnlockDisplay (dpy);
+
+ SyncHandle ();
+
+ return task->task.request_seq;
+}
+
+XasWindowAttributes*
+xas_get_window_attributes_reply(XasContext *ctx,
+ XasCookie cookie,
+ int *x_error_code)
+{
+ Display *dpy;
+ XasTaskGetWinAttr *task = NULL;
+ XasWindowAttributes *result = NULL;
+
+ dpy = ctx->xdpy; /* For SyncHandle (); */
+
+ if (x_error_code) *x_error_code = 0; /* No error as yet */
+
+ task = (XasTaskGetWinAttr *) xas_find_task_for_request_seq(ctx,
+ ctx->tasks_completed,
+ cookie);
+
+ if (task == NULL)
+ return NULL;
+
+ if (task->task.type != XAS_TASK_GET_WIN_ATTR)
+ return NULL;
+
+ if (!task->task.error)
+ {
+ result = task->attr;
+ }
+ else
+ {
+ XAS_DBG("is error");
+ if (x_error_code)
+ *x_error_code = task->task.error;
+ }
+
+ SyncHandle ();
+
+ ctx->tasks_completed = task_list_remove(ctx->tasks_completed,
+ XAS_TASK(task));
+ ctx->n_tasks_completed--;
+
+ XFree (task);
+
+ return result;
+}
+
+XasCookie
+xas_get_geometry(XasContext *ctx,
+ Drawable d)
+{
+ xResourceReq *req;
+ Display *dpy ;
+ XasTaskGetGeom *task;
+
+ LockDisplay (ctx->xdpy);
+
+ dpy = ctx->xdpy; /* GetReq() needs this */
+
+ task = Xcalloc (1, sizeof (XasTaskGetGeom));
+ if (task == NULL)
+ {
+ UnlockDisplay (dpy);
+ return 0;
+ }
+
+ GetResReq(GetGeometry, d, req);
+
+ task_init(ctx, XAS_TASK(task), XAS_TASK_GET_GEOM);
+
+ task->drw = d;
+
+ ctx->tasks_pending = task_list_append(ctx->tasks_pending, &task->task);
+ ctx->n_tasks_pending ++;
+
+ UnlockDisplay (dpy);
+
+ SyncHandle ();
+
+ return task->task.request_seq;
+}
+
+Status
+xas_get_geometry_reply (XasContext *ctx,
+ XasCookie cookie,
+ int *x_return,
+ int *y_return,
+ unsigned int *width_return,
+ unsigned int *height_return,
+ unsigned int *border_width_return,
+ unsigned int *depth_return,
+ int *x_error_code)
+{
+ Display *dpy;
+ XasTaskGetGeom *task = NULL;
+ Status result = False;
+
+ dpy = ctx->xdpy; /* For SyncHandle (); */
+
+ if (x_error_code) *x_error_code = 0; /* No error as yet */
+
+ task = (XasTaskGetGeom *) xas_find_task_for_request_seq(ctx,
+ ctx->tasks_completed,
+ cookie);
+
+ if (task == NULL)
+ {
+ XAS_DBG("Failed to find task\n");
+ return False;
+ }
+
+ if (task->task.type != XAS_TASK_GET_GEOM)
+ {
+ XAS_DBG("Found task, but type different to expected ( %i vs %i )\n",
+ task->task.type, XAS_TASK_GET_GEOM);
+ return False;
+ }
+
+ if (!task->task.error)
+ {
+ *x_return = task->x;
+ *y_return = task->y;
+ *width_return = task->width;
+ *height_return = task->height;
+ *border_width_return = task->border;
+ *depth_return = task->depth;
+ result = True;
+ }
+ else
+ {
+ XAS_DBG("is error");
+ if (x_error_code)
+ *x_error_code = task->task.error;
+ }
+
+ SyncHandle ();
+
+ ctx->tasks_completed = task_list_remove(ctx->tasks_completed,
+ XAS_TASK(task));
+ ctx->n_tasks_completed--;
+
+ XFree (task);
+
+ return result;
+}
+
+
+
diff --git a/matchbox2/core/xas.h b/matchbox2/core/xas.h
new file mode 100644
index 0000000..e9b7ca8
--- /dev/null
+++ b/matchbox2/core/xas.h
@@ -0,0 +1,114 @@
+/* Asynchronous Xlib hack utiltys lib
+ *
+ * Copyright (c) 2005 Matthew Allum
+ *
+ * Contains portions of code from Metacity and Xlib.
+ *
+ * Copyright (C) 2002 Havoc Pennington
+ * Copyright (C) 1986, 1998 The Open Group
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation.
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of The Open Group shall not be
+ * used in advertising or otherwise to promote the sale, use or other dealings
+ * in this Software without prior written authorization from The Open Group.
+ */
+
+#ifndef _HAVE_XAS_H
+#define _HAVE_XAS_H
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef struct XasContext XasContext;
+typedef unsigned long XasCookie;
+typedef struct XasWindowAttributes XasWindowAttributes;
+
+/* XWindowAttributes without geom info */
+struct XasWindowAttributes {
+ Visual *visual;
+ Window root;
+ int class;
+ int bit_gravity;
+ int win_gravity;
+ int backing_store;
+ unsigned long backing_planes;
+ unsigned long backing_pixel;
+ Bool save_under;
+ Colormap colormap;
+ Bool map_installed;
+ int map_state;
+ long all_event_masks;
+ long your_event_mask;
+ long do_not_propagate_mask;
+ Bool override_redirect;
+};
+
+XasContext*
+xas_context_new(Display *xdpy);
+
+void
+xas_context_destroy(XasContext *ctx);
+
+XasCookie
+xas_get_property(XasContext *ctx,
+ Window win,
+ Atom property,
+ long offset,
+ long length,
+ Bool delete,
+ Atom req_type);
+
+Status
+xas_get_property_reply(XasContext *ctx,
+ XasCookie cookie,
+ Atom *actual_type_return,
+ int *actual_format_return,
+ unsigned long *nitems_return,
+ unsigned long *bytes_after_return,
+ unsigned char **prop_return,
+ int *x_error_code);
+
+XasCookie
+xas_get_window_attributes(XasContext *ctx,
+ Window win);
+
+XasWindowAttributes*
+xas_get_window_attributes_reply(XasContext *ctx,
+ XasCookie cookie,
+ int *x_error_code);
+
+XasCookie
+xas_get_geometry(XasContext *ctx,
+ Drawable d);
+
+Status
+xas_get_geometry_reply (XasContext *ctx,
+ XasCookie cookie,
+ int *x_return,
+ int *y_return,
+ unsigned int *width_return,
+ unsigned int *height_return,
+ unsigned int *border_width_return,
+ unsigned int *depth_return,
+ int *x_error_code);
+Bool
+xas_have_reply(XasContext *ctx,
+ XasCookie cookie);
+
+#endif
diff --git a/matchbox2/mb-wm-config.h.in b/matchbox2/mb-wm-config.h.in
new file mode 100644
index 0000000..8c8de50
--- /dev/null
+++ b/matchbox2/mb-wm-config.h.in
@@ -0,0 +1,35 @@
+
+#ifndef _MB_MW_CONFIG_H
+#define _MB_WM_CONFIG_H
+
+/* Enable composite manager code */
+#define ENABLE_COMPOSITE @ENABLE_COMPOSITE@
+
+/* Build PNG-image based theme engine */
+#define THEME_PNG @THEME_PNG@
+
+/* Use pango for text layout */
+#define USE_PANGO @USE_PANGO@
+
+/* Use pango for text layout */
+#define USE_PANGO @USE_PANGO@
+
+/* Use clutter for compositing */
+#define ENABLE_CLUTTER_COMPOSITE_MANAGER @ENABLE_CLUTTER_COMPOSITE_MANAGER@
+
+/* Use xrender compositing manager backend */
+#define ENABLE_XRENDER_COMPOSITE_MANAGER @ENABLE_XRENDER_COMPOSITE_MANAGER@
+
+/* Include at least one of the default compositing manager backends */
+#define COMP_MGR_BACKEND @COMP_MGR_BACKEND@
+
+/* Use glib main loop */
+#define USE_GLIB_MAINLOOP @USE_GLIB_MAINLOOP@
+
+/* GTK Integration */
+#define USE_GTK @USE_GTK@
+
+/* Debugging stuff */
+#define MBWM_WANT_DEBUG @MBWM_WANT_DEBUG@
+
+#endif
diff --git a/matchbox2/theme-engines/Makefile.am b/matchbox2/theme-engines/Makefile.am
new file mode 100644
index 0000000..ee7f594
--- /dev/null
+++ b/matchbox2/theme-engines/Makefile.am
@@ -0,0 +1,19 @@
+
+if THEME_PNG
+PNG_SRC = mb-wm-theme-png.c mb-wm-theme-png.h
+endif
+
+COMMON_SRC = mb-wm-theme.h mb-wm-theme.c mb-wm-theme-xml.h mb-wm-theme-xml.c
+
+pkgincludedir = $(includedir)/$(MBWM2_INCDIR)/theme-engines
+
+if ENABLE_LIBMATCHBOX
+pkginclude_HEADERS = mb-wm-theme.h mb-wm-theme-png.h mb-wm-theme-xml.h
+endif
+noinst_LTLIBRARIES = libmb-theme.la
+libmb_theme_la_SOURCES = $(COMMON_SRC) $(PNG_SRC)
+libmb_theme_la_CFLAGS =
+
+INCLUDES = $(MBWM_INCS) $(MBWM_CFLAGS) -DDATADIR=\"$(datadir)\"
+
+MAINTAINERCLEANFILES = config.h.in Makefile.in
diff --git a/matchbox2/theme-engines/mb-wm-theme-png.c b/matchbox2/theme-engines/mb-wm-theme-png.c
new file mode 100644
index 0000000..a747691
--- /dev/null
+++ b/matchbox2/theme-engines/mb-wm-theme-png.c
@@ -0,0 +1,1306 @@
+#include <math.h>
+#include <png.h>
+
+#include "mb-wm-theme-png.h"
+#include "mb-wm-theme-xml.h"
+
+#include <X11/Xft/Xft.h>
+
+#ifdef HAVE_XEXT
+#include <X11/extensions/shape.h>
+#endif
+
+static int
+mb_wm_theme_png_ximg (MBWMThemePng * theme, const char * img);
+
+static unsigned char*
+mb_wm_theme_png_load_file (const char *file, int *width, int *height);
+
+static void
+mb_wm_theme_png_paint_decor (MBWMTheme *theme, MBWMDecor *decor);
+
+static void
+mb_wm_theme_png_paint_button (MBWMTheme *theme, MBWMDecorButton *button);
+
+static void
+mb_wm_theme_png_get_decor_dimensions (MBWMTheme *, MBWindowManagerClient *,
+ int*, int*, int*, int*);
+
+static MBWMDecor *
+mb_wm_theme_png_create_decor (MBWMTheme*, MBWindowManagerClient *,
+ MBWMDecorType);
+
+static void
+mb_wm_theme_png_resize_decor (MBWMTheme *theme, MBWMDecor *decor);
+
+static void
+mb_wm_theme_png_get_button_size (MBWMTheme *, MBWMDecor *,
+ MBWMDecorButtonType, int *, int *);
+
+static void
+mb_wm_theme_png_get_button_position (MBWMTheme *, MBWMDecor *,
+ MBWMDecorButtonType,
+ int *, int *);
+
+static void
+mb_wm_theme_png_class_init (MBWMObjectClass *klass)
+{
+ MBWMThemeClass *t_class = MB_WM_THEME_CLASS (klass);
+
+ t_class->paint_decor = mb_wm_theme_png_paint_decor;
+ t_class->paint_button = mb_wm_theme_png_paint_button;
+ t_class->decor_dimensions = mb_wm_theme_png_get_decor_dimensions;
+ t_class->button_size = mb_wm_theme_png_get_button_size;
+ t_class->button_position = mb_wm_theme_png_get_button_position;
+ t_class->create_decor = mb_wm_theme_png_create_decor;
+ t_class->resize_decor = mb_wm_theme_png_resize_decor;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMThemePng";
+#endif
+}
+
+static void
+mb_wm_theme_png_destroy (MBWMObject *obj)
+{
+ MBWMThemePng * theme = MB_WM_THEME_PNG (obj);
+ Display * dpy = MB_WM_THEME (obj)->wm->xdpy;
+
+ XRenderFreePicture (dpy, theme->xpic);
+ XFreePixmap (dpy, theme->xdraw);
+
+ if (theme->shape_mask)
+ XFreePixmap (dpy, theme->shape_mask);
+}
+
+static int
+mb_wm_theme_png_init (MBWMObject *obj, va_list vap)
+{
+ MBWMThemePng *p_theme = MB_WM_THEME_PNG (obj);
+ MBWMTheme *theme = MB_WM_THEME (obj);
+ MBWMObjectProp prop;
+ char *img = NULL;
+#if USE_PANGO
+ Display *xdpy = theme->wm->xdpy;
+ int xscreen = theme->wm->xscreen;
+#endif
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropThemeImg:
+ img = va_arg(vap, char *);
+ break;
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ if (!img || !mb_wm_theme_png_ximg (p_theme, img))
+ return 0;
+
+#if USE_PANGO
+ p_theme->context = pango_xft_get_context (xdpy, xscreen);
+ p_theme->fontmap = pango_xft_get_font_map (xdpy, xscreen);
+#endif
+
+ return 1;
+}
+
+int
+mb_wm_theme_png_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMThemePngClass),
+ sizeof (MBWMThemePng),
+ mb_wm_theme_png_init,
+ mb_wm_theme_png_destroy,
+ mb_wm_theme_png_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_THEME, 0);
+ }
+
+ return type;
+}
+
+struct DecorData
+{
+ Pixmap xpix;
+ Pixmap shape_mask;
+ GC gc_mask;
+ XftDraw *xftdraw;
+ XftColor clr;
+#if USE_PANGO
+ PangoFont *font;
+#else
+ XftFont *font;
+#endif
+};
+
+static void
+decordata_free (MBWMDecor * decor, void *data)
+{
+ struct DecorData * dd = data;
+ Display * xdpy = decor->parent_client->wmref->xdpy;
+
+ XFreePixmap (xdpy, dd->xpix);
+
+ if (dd->shape_mask)
+ XFreePixmap (xdpy, dd->shape_mask);
+
+ if (dd->gc_mask)
+ XFreeGC (xdpy, dd->gc_mask);
+
+ XftDrawDestroy (dd->xftdraw);
+
+#if USE_PANGO
+ if (dd->font)
+ g_object_unref (dd->font);
+#else
+ if (dd->font)
+ XftFontClose (xdpy, dd->font);
+#endif
+
+ free (dd);
+}
+
+struct ButtonData
+{
+ Pixmap xpix_i;
+ XftDraw *xftdraw_i;
+ Pixmap xpix_a;
+ XftDraw *xftdraw_a;
+};
+
+static void
+buttondata_free (MBWMDecorButton * button, void *data)
+{
+ struct ButtonData * bd = data;
+ Display * xdpy = button->decor->parent_client->wmref->xdpy;
+
+ XFreePixmap (xdpy, bd->xpix_i);
+ XftDrawDestroy (bd->xftdraw_i);
+ XFreePixmap (xdpy, bd->xpix_a);
+ XftDrawDestroy (bd->xftdraw_a);
+
+ free (bd);
+}
+
+#if !USE_PANGO
+static XftFont *
+xft_load_font(MBWMDecor * decor, MBWMXmlDecor *d)
+{
+ char desc[512];
+ XftFont *font;
+ Display * xdpy = decor->parent_client->wmref->xdpy;
+ int xscreen = decor->parent_client->wmref->xscreen;
+ int font_size = d->font_size ? d->font_size : 18;
+
+ if (d->font_units == MBWMXmlFontUnitsPixels)
+ {
+ font_size = mb_wm_util_pixels_to_points (decor->parent_client->wmref,
+ font_size);
+ }
+
+ snprintf (desc, sizeof (desc), "%s-%i",
+ d->font_family ? d->font_family : "Sans",
+ font_size);
+
+ font = XftFontOpenName (xdpy, xscreen, desc);
+
+ return font;
+}
+#endif
+
+static void
+mb_wm_theme_png_paint_button (MBWMTheme *theme, MBWMDecorButton *button)
+{
+ MBWMDecor * decor;
+ MBWMThemePng * p_theme = MB_WM_THEME_PNG (theme);
+ MBWindowManagerClient * client;
+ MBWMClientType c_type;;
+ MBWMXmlClient * c;
+ MBWMXmlDecor * d;
+ MBWMXmlButton * b;
+
+ /*
+ * We do not paint inactive buttons, as they get painted with the decor
+ */
+ decor = button->decor;
+ client = mb_wm_decor_get_parent (decor);
+ c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+
+ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) &&
+ (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type)) &&
+ (b = mb_wm_xml_button_find_by_type (d->buttons, button->type)))
+ {
+ Display * xdpy = theme->wm->xdpy;
+ int xscreen = theme->wm->xscreen;
+ struct DecorData * ddata = mb_wm_decor_get_theme_data (decor);
+ struct ButtonData * bdata;
+ int x, y;
+
+ if (!ddata)
+ return;
+
+ bdata = mb_wm_decor_button_get_theme_data (button);
+
+ if (!bdata)
+ {
+ int a_x = b->active_x > -1 ? b->active_x : b->x;
+ int a_y = b->active_y > -1 ? b->active_y : b->y;
+
+ int i_x = b->inactive_x > -1 ? b->inactive_x : b->x;
+ int i_y = b->inactive_y > -1 ? b->inactive_y : b->y;
+
+ bdata = malloc (sizeof (struct ButtonData));
+
+ bdata->xpix_a = XCreatePixmap(xdpy, decor->xwin,
+ button->geom.width, button->geom.height,
+ DefaultDepth(xdpy, xscreen));
+
+ bdata->xftdraw_a = XftDrawCreate (xdpy, bdata->xpix_a,
+ DefaultVisual (xdpy, xscreen),
+ DefaultColormap (xdpy, xscreen));
+
+ bdata->xpix_i = XCreatePixmap(xdpy, decor->xwin,
+ button->geom.width, button->geom.height,
+ DefaultDepth(xdpy, xscreen));
+
+ bdata->xftdraw_i = XftDrawCreate (xdpy, bdata->xpix_i,
+ DefaultVisual (xdpy, xscreen),
+ DefaultColormap (xdpy, xscreen));
+
+ /*
+ * If the background color is set for the parent decor, we do a fill
+ * with the parent color first, then composite the decor image over,
+ * and finally composite the button image. (This way we can paint the
+ * button with a simple PictOpSrc, rather than having to do
+ * composting on each draw).
+ */
+ if (d->clr_bg.set)
+ {
+ XRenderColor rclr2;
+
+ rclr2.red = (int)(d->clr_bg.r * (double)0xffff);
+ rclr2.green = (int)(d->clr_bg.g * (double)0xffff);
+ rclr2.blue = (int)(d->clr_bg.b * (double)0xffff);
+
+ /* Fill the inactive image */
+ XRenderFillRectangle (xdpy, PictOpSrc,
+ XftDrawPicture (bdata->xftdraw_i), &rclr2,
+ 0, 0, b->width, b->height);
+
+ /* Composite the decor over */
+ XRenderComposite (xdpy, PictOpOver,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (bdata->xftdraw_i),
+ b->x, b->y, 0, 0, 0, 0, b->width, b->height);
+
+ /* Copy inactive button to the active one */
+ XRenderComposite (xdpy, PictOpSrc,
+ XftDrawPicture (bdata->xftdraw_i),
+ None,
+ XftDrawPicture (bdata->xftdraw_a),
+ 0, 0, 0, 0, 0, 0, b->width, b->height);
+
+ /* Composite inactive and active image on top */
+ XRenderComposite (xdpy, PictOpOver,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (bdata->xftdraw_i),
+ i_x, i_y, 0, 0, 0, 0, b->width, b->height);
+
+ XRenderComposite (xdpy, PictOpOver,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (bdata->xftdraw_a),
+ a_x, a_y, 0, 0, 0, 0, b->width, b->height);
+ }
+ else
+ {
+ XRenderComposite (xdpy, PictOpSrc,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (bdata->xftdraw_i),
+ i_x, i_y, 0, 0, 0, 0, b->width, b->height);
+
+ XRenderComposite (xdpy, PictOpSrc,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (bdata->xftdraw_a),
+ a_x, a_y, 0, 0, 0, 0, b->width, b->height);
+ }
+
+ mb_wm_decor_button_set_theme_data (button, bdata, buttondata_free);
+ }
+
+ /* Here we automagically determine if the button should be left or
+ * right aligned in the case that a decor is expanded wider than
+ * the template image. If the coordinate comes before the point
+ * where decor padding is added, it's left aligned else it's
+ * right aligned. If no padding hints were given in the theme.xml,
+ * then we assume padding happens in the center.
+ * Note: we look at pad_length because pad_offset could be 0
+ */
+ x = b->x - d->x;
+ if (x > (d->pad_length ? d->pad_offset : d->width/2) )
+ x = decor->geom.width - (d->x + d->width - b->x);
+
+ y = b->y - d->y;
+
+ XRenderComposite (xdpy, PictOpSrc,
+ button->state == MBWMDecorButtonStatePressed ?
+ XftDrawPicture (bdata->xftdraw_a) :
+ XftDrawPicture (bdata->xftdraw_i),
+ None,
+ XftDrawPicture (ddata->xftdraw),
+ 0, 0, 0, 0, x, y, b->width, b->height);
+
+ XClearWindow (xdpy, decor->xwin);
+ }
+}
+
+static void
+mb_wm_theme_png_resize_decor (MBWMTheme *theme, MBWMDecor *decor)
+{
+ /*
+ * Clear any data we have stored with the theme; this will force
+ * resize on the next paint
+ */
+ mb_wm_decor_set_theme_data (decor, NULL, NULL);
+}
+
+static void
+mb_wm_theme_png_paint_decor (MBWMTheme *theme, MBWMDecor *decor)
+{
+ MBWMThemePng * p_theme = MB_WM_THEME_PNG (theme);
+ MBWindowManagerClient * client = decor->parent_client;
+ MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+ MBWMXmlClient * c;
+ MBWMXmlDecor * d;
+ Display * xdpy = theme->wm->xdpy;
+ int xscreen = theme->wm->xscreen;
+ struct DecorData * data = mb_wm_decor_get_theme_data (decor);
+ const char * title;
+ int x, y;
+ int operator = PictOpSrc;
+ Bool shaped;
+
+ if (!((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) &&
+ (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type))))
+ return;
+
+#ifdef HAVE_XEXT
+ shaped = theme->shaped && c->shaped && !mb_wm_client_is_argb32 (client);
+#endif
+
+ if (data && (mb_wm_decor_get_dirty_state (decor) & MBWMDecorDirtyTitle))
+ {
+ /*
+ * If the decor title is dirty, and we already have the data,
+ * free it and recreate (since the old title is already composited
+ * in the cached image).
+ */
+ mb_wm_decor_set_theme_data (decor, NULL, NULL);
+ data = NULL;
+ }
+
+ if (!data)
+ {
+ XRenderColor rclr;
+
+ data = mb_wm_util_malloc0 (sizeof (struct DecorData));
+ data->xpix = XCreatePixmap(xdpy, decor->xwin,
+ decor->geom.width, decor->geom.height,
+ DefaultDepth(xdpy, xscreen));
+
+
+#ifdef HAVE_XEXT
+ if (shaped)
+ {
+ data->shape_mask =
+ XCreatePixmap(xdpy, decor->xwin,
+ decor->geom.width, decor->geom.height, 1);
+
+ data->gc_mask = XCreateGC (xdpy, data->shape_mask, 0, NULL);
+ }
+#endif
+ data->xftdraw = XftDrawCreate (xdpy, data->xpix,
+ DefaultVisual (xdpy, xscreen),
+ DefaultColormap (xdpy, xscreen));
+
+ /*
+ * If the background color is set, we fill the pixmaps with it,
+ * and then overlay the the PNG image over (this allows a theme
+ * to provide a monochromatic PNG that can be toned, e.g., Sato)
+ */
+ if (d->clr_bg.set)
+ {
+ XRenderColor rclr2;
+
+ operator = PictOpOver;
+
+ rclr2.red = (int)(d->clr_bg.r * (double)0xffff);
+ rclr2.green = (int)(d->clr_bg.g * (double)0xffff);
+ rclr2.blue = (int)(d->clr_bg.b * (double)0xffff);
+
+ XRenderFillRectangle (xdpy, PictOpSrc,
+ XftDrawPicture (data->xftdraw), &rclr2,
+ 0, 0,
+ decor->geom.width, decor->geom.height);
+ }
+
+ rclr.red = 0;
+ rclr.green = 0;
+ rclr.blue = 0;
+ rclr.alpha = 0xffff;
+
+ if (d->clr_fg.set)
+ {
+ rclr.red = (int)(d->clr_fg.r * (double)0xffff);
+ rclr.green = (int)(d->clr_fg.g * (double)0xffff);
+ rclr.blue = (int)(d->clr_fg.b * (double)0xffff);
+ }
+
+ XftColorAllocValue (xdpy, DefaultVisual (xdpy, xscreen),
+ DefaultColormap (xdpy, xscreen),
+ &rclr, &data->clr);
+
+#if USE_PANGO
+ {
+ PangoFontDescription * pdesc;
+ char desc[512];
+
+ snprintf (desc, sizeof (desc), "%s %i%s",
+ d->font_family ? d->font_family : "Sans",
+ d->font_size ? d->font_size : 18,
+ d->font_units == MBWMXmlFontUnitsPoints ? "" : "px");
+
+ pdesc = pango_font_description_from_string (desc);
+
+ data->font = pango_font_map_load_font (p_theme->fontmap,
+ p_theme->context,
+ pdesc);
+
+ pango_font_description_free (pdesc);
+ }
+#else
+ data->font = xft_load_font (decor, d);
+#endif
+ XSetWindowBackgroundPixmap(xdpy, decor->xwin, data->xpix);
+
+ mb_wm_decor_set_theme_data (decor, data, decordata_free);
+ }
+
+ /*
+ * Since we want to support things like rounded corners, but still
+ * have the decor resizable, we need to paint it in stages
+ *
+ * We assume that the decor image is exact in it's major axis,
+ * i.e., North and South decors provide image of the exactly correct
+ * height, and West and East of width.
+ */
+ if (decor->type == MBWMDecorTypeNorth ||
+ decor->type == MBWMDecorTypeSouth)
+ {
+ if (decor->geom.width < d->width)
+ {
+ /* The decor is smaller than the template, cut bit from the
+ * midle
+ */
+ int width1 = decor->geom.width / 2;
+ int width2 = decor->geom.width - width1;
+ int x2 = d->x + d->width - width2;
+
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ d->x, d->y, 0, 0, 0, 0,
+ width1, d->height);
+
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ x2 , d->y, 0, 0,
+ width1, 0,
+ width2, d->height);
+
+#ifdef HAVE_XEXT
+ if (shaped)
+ {
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ d->x, d->y, width1, d->height, 0, 0);
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ x2, d->y, width2, d->height, width1, 0);
+ }
+#endif
+ }
+ else if (decor->geom.width == d->width)
+ {
+ /* Exact match */
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ d->x, d->y, 0, 0,
+ 0, 0, d->width, d->height);
+
+#ifdef HAVE_XEXT
+ if (shaped)
+ {
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ d->x, d->y, d->width, d->height, 0, 0);
+ }
+#endif
+ }
+ else
+ {
+ /* The decor is bigger than the template, draw extra bit from
+ * the middle
+ */
+ int pad_offset = d->pad_offset;
+ int pad_length = d->pad_length;
+ int gap_length = decor->geom.width - d->width;
+
+ if (!pad_length)
+ {
+ pad_length =
+ decor->geom.width > 30 ? 10 : decor->geom.width / 4 + 1;
+ pad_offset = (d->width / 2) - (pad_length / 2);
+ }
+
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ d->x, d->y, 0, 0,
+ 0, 0,
+ pad_offset, d->height);
+
+ /* TODO: can we do this as one scaled operation? */
+ for (x = pad_offset; x < pad_offset + gap_length; x += pad_length)
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ d->x + pad_offset, d->y, 0, 0,
+ x, 0,
+ pad_length,
+ d->height);
+
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ d->x + pad_offset, d->y, 0, 0,
+ pad_offset + gap_length, 0,
+ d->width - pad_offset, d->height);
+
+#ifdef HAVE_XEXT
+ if (shaped)
+ {
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ d->x, d->y,
+ pad_offset, d->height,
+ 0, 0);
+
+ for (x = pad_offset; x < pad_offset + gap_length; x += pad_length)
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ d->x + pad_offset, d->y,
+ d->width - pad_offset, d->height,
+ x, 0);
+
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ d->x + pad_offset, d->y,
+ d->width - pad_offset, d->height,
+ pad_offset + gap_length, 0);
+ }
+#endif
+ }
+ }
+ else
+ {
+ if (decor->geom.height < d->height)
+ {
+ /* The decor is smaller than the template, cut bit from the
+ * midle
+ */
+ int height1 = decor->geom.height / 2;
+ int height2 = decor->geom.height - height1;
+ int y2 = d->y + d->height - height2;
+
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ d->x, d->y, 0, 0,
+ 0, 0,
+ d->width, height1);
+
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ d->x , y2, 0, 0,
+ 0, height1,
+ d->width, height2);
+
+#ifdef HAVE_XEXT
+ if (shaped)
+ {
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ d->x, d->y, d->width, height1, 0, 0);
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ d->x, y2, d->width, height2, 0, height1);
+ }
+#endif
+ }
+ else if (decor->geom.height == d->height)
+ {
+ /* Exact match */
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ d->x, d->y, 0, 0,
+ 0, 0,
+ d->width, d->height);
+
+#ifdef HAVE_XEXT
+ if (shaped)
+ {
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ d->x, d->y, d->width, d->height, 0, 0);
+ }
+#endif
+ }
+ else
+ {
+ /* The decor is bigger than the template, draw extra bit from
+ * the middle
+ */
+ int pad_offset = d->pad_offset;
+ int pad_length = d->pad_length;
+ int gap_length = decor->geom.height - d->height;
+
+ if (!pad_length)
+ {
+ pad_length =
+ decor->geom.height > 30 ? 10 : decor->geom.height / 4 + 1;
+ pad_offset = (d->height / 2) - (pad_length / 2);
+ }
+
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ d->x, d->y, 0, 0, 0, 0,
+ d->width, pad_offset);
+
+ /* TODO: can we do this as one scaled operation? */
+ for (y = pad_offset; y < pad_offset + gap_length; y += pad_length)
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ d->x, d->y + pad_offset, 0, 0, 0, y,
+ d->width,
+ pad_length);
+
+ XRenderComposite(xdpy, operator,
+ p_theme->xpic,
+ None,
+ XftDrawPicture (data->xftdraw),
+ d->x , d->y + pad_offset, 0, 0,
+ 0, pad_offset + gap_length,
+ d->width, d->height - pad_offset);
+
+#ifdef HAVE_XEXT
+ if (shaped)
+ {
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ d->x, d->y,
+ d->width, pad_offset,
+ 0, 0);
+
+ for (y = pad_offset; y < pad_offset + gap_length; y += pad_length)
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ d->x, d->y + pad_offset,
+ d->width, pad_length,
+ 0, y);
+
+ XCopyArea (xdpy, p_theme->shape_mask, data->shape_mask,
+ data->gc_mask,
+ d->x, d->y + pad_offset,
+ d->width, d->height - pad_offset,
+ 0, pad_offset + gap_length);
+ }
+#endif
+ }
+ }
+
+ if (d->show_title &&
+ (title = mb_wm_client_get_name (client)) &&
+ data->font)
+ {
+ XRectangle rec;
+
+ int pack_start_x = mb_wm_decor_get_pack_start_x (decor);
+ int pack_end_x = mb_wm_decor_get_pack_end_x (decor);
+ int west_width = mb_wm_client_frame_west_width (client);
+ int y, ascent, descent;
+ int len = strlen (title);
+
+#if USE_PANGO
+ PangoFontMetrics * mtx;
+ PangoGlyphString * glyphs;
+ GList * items, *l;
+ PangoRectangle rect;
+ int xoff = 0;
+
+ mtx = pango_font_get_metrics (data->font, NULL);
+
+ ascent = PANGO_PIXELS (pango_font_metrics_get_ascent (mtx));
+ descent = PANGO_PIXELS (pango_font_metrics_get_descent (mtx));
+
+ pango_font_metrics_unref (mtx);
+#else
+ ascent = data->font->ascent;
+ descent = data->font->descent;
+#endif
+
+ y = (decor->geom.height - (ascent + descent)) / 2 + ascent;
+
+ rec.x = 0;
+ rec.y = 0;
+ rec.width = pack_end_x - 2;
+ rec.height = d->height;
+
+ XftDrawSetClipRectangles (data->xftdraw, 0, 0, &rec, 1);
+
+#if USE_PANGO
+ glyphs = pango_glyph_string_new ();
+
+ /*
+ * Run the pango rendering pipeline on this text and draw with
+ * the xft backend (why Pango does not provide a convenience
+ * API for something as common as drawing a string escapes me).
+ */
+ items = pango_itemize (p_theme->context, title, 0, len, NULL, NULL);
+
+ l = items;
+ while (l)
+ {
+ PangoItem * item = l->data;
+
+ item->analysis.font = data->font;
+
+ pango_shape (title, len, &item->analysis, glyphs);
+
+ pango_xft_render (data->xftdraw,
+ &data->clr,
+ data->font,
+ glyphs,
+ xoff + west_width + pack_start_x, y);
+
+ /* Advance position */
+ pango_glyph_string_extents (glyphs, data->font, NULL, &rect);
+ xoff += PANGO_PIXELS (rect.width);
+
+ l = l->next;
+ }
+
+ if (glyphs)
+ pango_glyph_string_free (glyphs);
+
+ g_list_free (items);
+#else
+ XftDrawStringUtf8(data->xftdraw,
+ &data->clr,
+ data->font,
+ west_width + pack_start_x, y,
+ title, len);
+#endif
+
+ /* Unset the clipping rectangle */
+ rec.width = decor->geom.width;
+ rec.height = decor->geom.height;
+
+ XftDrawSetClipRectangles (data->xftdraw, 0, 0, &rec, 1);
+ }
+
+#ifdef HAVE_XEXT
+ if (shaped)
+ {
+ XShapeCombineMask (xdpy, decor->xwin,
+ ShapeBounding, 0, 0,
+ data->shape_mask, ShapeSet);
+
+ XShapeCombineShape (xdpy,
+ client->xwin_frame,
+ ShapeBounding, decor->geom.x, decor->geom.y,
+ decor->xwin,
+ ShapeBounding, ShapeUnion);
+ }
+#endif
+ XClearWindow (xdpy, decor->xwin);
+}
+
+static void
+construct_buttons (MBWMThemePng * theme, MBWMDecor * decor, MBWMXmlDecor *d)
+{
+ MBWindowManagerClient *client = decor->parent_client;
+ MBWindowManager *wm = client->wmref;
+ MBWMDecorButton *button;
+
+ if (d)
+ {
+ MBWMList * l = d->buttons;
+ while (l)
+ {
+ MBWMXmlButton * b = l->data;
+
+ button = mb_wm_decor_button_stock_new (wm,
+ b->type,
+ b->packing,
+ decor,
+ 0);
+
+ mb_wm_decor_button_show (button);
+ mb_wm_object_unref (MB_WM_OBJECT (button));
+
+ l = l->next;
+ }
+ }
+}
+
+static MBWMDecor *
+mb_wm_theme_png_create_decor (MBWMTheme *theme,
+ MBWindowManagerClient *client,
+ MBWMDecorType type)
+{
+ MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+ MBWMDecor *decor = NULL;
+ MBWindowManager *wm = client->wmref;
+ MBWMXmlClient *c;
+
+ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)))
+ {
+ MBWMXmlDecor *d;
+
+ d = mb_wm_xml_decor_find_by_type (c->decors, type);
+
+ if (d)
+ {
+ decor = mb_wm_decor_new (wm, type);
+ decor->absolute_packing = True;
+ mb_wm_decor_attach (decor, client);
+ construct_buttons (MB_WM_THEME_PNG (theme), decor, d);
+ }
+ }
+
+ return decor;
+}
+
+static void
+mb_wm_theme_png_get_button_size (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type,
+ int *width,
+ int *height)
+{
+ MBWindowManagerClient * client = decor->parent_client;
+ MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+ MBWMThemePng *p_theme = MB_WM_THEME_PNG (theme);
+ MBWMXmlClient * c;
+ MBWMXmlDecor * d;
+
+ /* FIXME -- assumes button on the north decor only */
+ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) &&
+ (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type)))
+ {
+ MBWMXmlButton * b = mb_wm_xml_button_find_by_type (d->buttons, type);
+
+ if (b)
+ {
+ if (width)
+ *width = b->width;
+
+ if (height)
+ *height = b->height;
+
+ return;
+ }
+ }
+
+ if (width)
+ *width = 0;
+
+ if (height)
+ *height = 0;
+}
+
+static void
+mb_wm_theme_png_get_button_position (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type,
+ int *x,
+ int *y)
+{
+ MBWindowManagerClient * client = decor->parent_client;
+ MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+ MBWMThemePng *p_theme = MB_WM_THEME_PNG (theme);
+ MBWMXmlClient * c;
+ MBWMXmlDecor * d;
+
+ /* FIXME -- assumes button on the north decor only */
+ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) &&
+ (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type)))
+ {
+ MBWMXmlButton * b = mb_wm_xml_button_find_by_type (d->buttons, type);
+
+ if (b)
+ {
+ if (x)
+ {
+ int button_x;
+
+ /* Here we automagically determine if the button should be left or
+ * right aligned in the case that a decor is expanded wider than
+ * the template image. If the coordinate comes before the point
+ * where decor padding is added, it's left aligned else it's
+ * right aligned. If no padding hints were given in the theme.xml,
+ * then we assume padding happens in the center.
+ * Note: we look at pad_length because pad_offset could be 0
+ */
+ button_x = b->x - d->x;
+ if (button_x > (d->pad_length ? d->pad_offset : d->width/2) )
+ button_x = decor->geom.width - (d->x + d->width - b->x);
+
+ *x = button_x;
+ }
+
+ if (y)
+ *y = b->y - d->y;
+
+ return;
+ }
+ }
+
+ if (x)
+ *x = 0;
+
+ if (y)
+ *y = 0;
+}
+
+static void
+mb_wm_theme_png_get_decor_dimensions (MBWMTheme *theme,
+ MBWindowManagerClient *client,
+ int *north,
+ int *south,
+ int *west,
+ int *east)
+{
+ MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+ MBWMThemePng *p_theme = MB_WM_THEME_PNG (theme);
+ MBWMXmlClient * c;
+ MBWMXmlDecor * d;
+
+ /* FIXME -- assumes button on the north decor only */
+ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)))
+ {
+ if (north)
+ {
+ d = mb_wm_xml_decor_find_by_type (c->decors, MBWMDecorTypeNorth);
+
+ if (d)
+ *north = d->height;
+ else
+ *north = 0;
+ }
+
+ if (south)
+ {
+ d = mb_wm_xml_decor_find_by_type (c->decors, MBWMDecorTypeSouth);
+
+ if (d)
+ *south = d->height;
+ else
+ *south = 0;
+ }
+
+ if (west)
+ {
+ d = mb_wm_xml_decor_find_by_type (c->decors, MBWMDecorTypeWest);
+
+ if (d)
+ *west = d->width;
+ else
+ *west = 0;
+ }
+
+ if (east)
+ {
+ d = mb_wm_xml_decor_find_by_type (c->decors, MBWMDecorTypeEast);
+
+ if (d)
+ *east = d->width;
+ else
+ *east = 0;
+ }
+
+ return;
+ }
+
+ if (north)
+ *north = 0;
+
+ if (south)
+ *south = 0;
+
+ if (west)
+ *west = 0;
+
+ if (east)
+ *east = 0;
+}
+
+/*
+ * From matchbox-keyboard
+ */
+static unsigned char*
+mb_wm_theme_png_load_file (const char *file,
+ int *width,
+ int *height)
+{
+ FILE *fd;
+ unsigned char *data;
+ unsigned char header[8];
+ int bit_depth, color_type;
+
+ png_uint_32 png_width, png_height, i, rowbytes;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_bytep *row_pointers;
+
+ if ((fd = fopen (file, "rb")) == NULL)
+ return NULL;
+
+ fread (header, 1, 8, fd);
+ if (!png_check_sig (header, 8))
+ {
+ fclose(fd);
+ return NULL;
+ }
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ fclose(fd);
+ return NULL;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct (&png_ptr, NULL, NULL);
+ fclose(fd);
+ return NULL;
+ }
+
+ if (setjmp (png_ptr->jmpbuf))
+ {
+ png_destroy_read_struct( &png_ptr, &info_ptr, NULL);
+ fclose(fd);
+ return NULL;
+ }
+
+ png_init_io (png_ptr, fd);
+ png_set_sig_bytes (png_ptr, 8);
+ png_read_info (png_ptr, info_ptr);
+ png_get_IHDR (png_ptr, info_ptr, &png_width, &png_height, &bit_depth,
+ &color_type, NULL, NULL, NULL);
+
+ *width = (int) png_width;
+ *height = (int) png_height;
+
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+ if (bit_depth < 8)
+ png_set_packing(png_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+ /* Add alpha */
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_RGB)
+ png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE ||
+ png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_expand (png_ptr);
+
+ png_read_update_info (png_ptr, info_ptr);
+
+ /* allocate space for data and row pointers */
+ rowbytes = png_get_rowbytes (png_ptr, info_ptr);
+ data = (unsigned char*) malloc ((rowbytes * (*height + 1)));
+ row_pointers = (png_bytep *) malloc ((*height) * sizeof (png_bytep));
+
+ if (!data || !row_pointers)
+ {
+ png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+
+ if (data)
+ free (data);
+
+ if (row_pointers)
+ free (row_pointers);
+
+ return NULL;
+ }
+
+ for (i = 0; i < *height; i++)
+ row_pointers[i] = data + i * rowbytes;
+
+ png_read_image (png_ptr, row_pointers);
+ png_read_end (png_ptr, NULL);
+
+ free (row_pointers);
+ png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+ fclose(fd);
+
+ return data;
+}
+
+static int
+mb_wm_theme_png_ximg (MBWMThemePng * theme, const char * img)
+{
+ MBWindowManager * wm = MB_WM_THEME (theme)->wm;
+ Display * dpy = wm->xdpy;
+ int screen = wm->xscreen;
+
+ XImage * ximg, * shape_img;
+ GC gc, gcm;
+ int x;
+ int y;
+ int width;
+ int height;
+ XRenderPictFormat *ren_fmt;
+ XRenderPictureAttributes ren_attr;
+ unsigned char * p;
+ unsigned char * png_data = mb_wm_theme_png_load_file (img, &width, &height);
+ Bool shaped = MB_WM_THEME (theme)->shaped;
+
+ if (!png_data || !width || !height)
+ return 0;
+
+ ren_fmt = XRenderFindStandardFormat(dpy, PictStandardARGB32);
+
+ theme->xdraw =
+ XCreatePixmap (dpy, RootWindow(dpy,screen), width, height, ren_fmt->depth);
+
+ if (shaped)
+ theme->shape_mask =
+ XCreatePixmap (dpy, RootWindow(dpy,screen), width, height, 1);
+
+ XSync (dpy, False);
+
+ ren_attr.dither = True;
+ ren_attr.component_alpha = True;
+ ren_attr.repeat = False;
+
+ gc = XCreateGC (dpy, theme->xdraw, 0, NULL);
+
+ if (shaped)
+ gcm = XCreateGC (dpy, theme->shape_mask, 0, NULL);
+
+ ximg = XCreateImage (dpy, DefaultVisual (dpy, screen),
+ ren_fmt->depth, ZPixmap,
+ 0, NULL, width, height, 32, 0);
+
+ ximg->data = malloc (ximg->bytes_per_line * ximg->height);
+
+ if (shaped)
+ {
+ shape_img = XCreateImage (dpy, DefaultVisual (dpy, screen),
+ 1, ZPixmap,
+ 0, NULL, width, height, 8, 0);
+
+ shape_img->data = malloc (shape_img->bytes_per_line * shape_img->height);
+ }
+
+ p = png_data;
+
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ {
+ unsigned char a, r, g, b;
+ r = *p++; g = *p++; b = *p++; a = *p++;
+ r = (r * (a + 1)) / 256;
+ g = (g * (a + 1)) / 256;
+ b = (b * (a + 1)) / 256;
+
+ XPutPixel (ximg, x, y, (a << 24) | (r << 16) | (g << 8) | b);
+
+ if (shaped)
+ {
+ XPutPixel (shape_img, x, y, a ? 1 : 0);
+ }
+ }
+
+ XPutImage (dpy, theme->xdraw, gc, ximg, 0, 0, 0, 0, width, height);
+
+ if (shaped)
+ XPutImage (dpy, theme->shape_mask, gcm, shape_img,
+ 0, 0, 0, 0, width, height);
+
+ theme->xpic = XRenderCreatePicture (dpy, theme->xdraw, ren_fmt,
+ CPRepeat|CPDither|CPComponentAlpha,
+ &ren_attr);
+
+ free (ximg->data);
+ ximg->data = NULL;
+ XDestroyImage (ximg);
+ XFreeGC (dpy, gc);
+
+ if (shaped)
+ {
+ free (shape_img->data);
+ shape_img->data = NULL;
+ XDestroyImage (shape_img);
+ XFreeGC (dpy, gcm);
+ }
+
+ free (png_data);
+
+ return 1;
+}
diff --git a/matchbox2/theme-engines/mb-wm-theme-png.h b/matchbox2/theme-engines/mb-wm-theme-png.h
new file mode 100644
index 0000000..bfc4c18
--- /dev/null
+++ b/matchbox2/theme-engines/mb-wm-theme-png.h
@@ -0,0 +1,56 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2005 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_THEME_PNG_H
+#define _HAVE_MB_WM_THEME_PNG_H
+
+#include <matchbox2/mb-wm-config.h>
+#include <matchbox2/theme-engines/mb-wm-theme.h>
+
+#include <X11/extensions/Xrender.h>
+
+#if USE_PANGO
+#include <pango/pango.h>
+#include <pango/pangoxft.h>
+#endif
+
+struct MBWMThemePngClass
+{
+ MBWMThemeClass parent;
+
+};
+
+struct MBWMThemePng
+{
+ MBWMTheme parent;
+
+ Pixmap xdraw;
+ Picture xpic;
+ Pixmap shape_mask;
+
+#if USE_PANGO
+ PangoContext * context;
+ PangoFontMap * fontmap;
+#endif
+};
+
+int mb_wm_theme_png_class_type (void);
+
+#endif
diff --git a/matchbox2/theme-engines/mb-wm-theme-xml.c b/matchbox2/theme-engines/mb-wm-theme-xml.c
new file mode 100644
index 0000000..e075b7b
--- /dev/null
+++ b/matchbox2/theme-engines/mb-wm-theme-xml.c
@@ -0,0 +1,212 @@
+/*
+ * Matchbox Window Manager 2 - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2007 OpenedHand Ltd - http://o-hand.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mb-wm-theme-xml.h"
+#include "mb-wm-theme.h"
+
+/*****************************************************************
+ * XML Parser stuff
+ */
+MBWMXmlButton *
+mb_wm_xml_button_new ()
+{
+ MBWMXmlButton * b = mb_wm_util_malloc0 (sizeof (MBWMXmlButton));
+
+ b->x = -1;
+ b->y = -1;
+ b->active_x = -1;
+ b->active_y = -1;
+ b->inactive_x = -1;
+ b->inactive_y = -1;
+
+ return b;
+}
+
+void
+mb_wm_xml_button_free (MBWMXmlButton * b)
+{
+ free (b);
+}
+
+MBWMXmlDecor *
+mb_wm_xml_decor_new ()
+{
+ MBWMXmlDecor * d = mb_wm_util_malloc0 (sizeof (MBWMXmlDecor));
+ return d;
+}
+
+void
+mb_wm_xml_decor_free (MBWMXmlDecor * d)
+{
+ MBWMList * l;
+
+ if (!d)
+ return;
+
+ l = d->buttons;
+ while (l)
+ {
+ MBWMXmlButton * b = l->data;
+ MBWMList * n = l->next;
+ mb_wm_xml_button_free (b);
+ free (l);
+
+ l = n;
+ }
+
+ if (d->font_family)
+ free (d->font_family);
+
+ free (d);
+}
+
+MBWMXmlClient *
+mb_wm_xml_client_new ()
+{
+ MBWMXmlClient * c = mb_wm_util_malloc0 (sizeof (MBWMXmlClient));
+
+ c->x = -1;
+ c->y = -1;
+ c->width = -1;
+ c->height = -1;
+
+ return c;
+}
+
+void
+mb_wm_xml_client_free (MBWMXmlClient * c)
+{
+ MBWMList * l;
+
+ if (!c)
+ return;
+
+ l = c->decors;
+ while (l)
+ {
+ MBWMXmlDecor * d = l->data;
+ MBWMList * n = l->next;
+ mb_wm_xml_decor_free (d);
+ free (l);
+
+ l = n;
+ }
+
+ free (c);
+}
+
+void
+mb_wm_xml_clr_from_string (MBWMColor * clr, const char *s)
+{
+ int r, g, b, a;
+
+ if (!s || *s != '#')
+ {
+ clr->set = False;
+ return;
+ }
+
+ sscanf (s+1,"%2x%2x%2x%2x", &r, &g, &b, &a);
+ clr->r = (double) r / 255.0;
+ clr->g = (double) g / 255.0;
+ clr->b = (double) b / 255.0;
+ clr->a = (double) a / 255.0;
+
+ clr->set = True;
+}
+
+MBWMXmlClient *
+mb_wm_xml_client_find_by_type (MBWMList *l, MBWMClientType type)
+{
+ while (l)
+ {
+ MBWMXmlClient * c = l->data;
+ if (c->type == type)
+ return c;
+
+ l = l->next;
+ }
+
+ return NULL;
+}
+
+MBWMXmlDecor *
+mb_wm_xml_decor_find_by_type (MBWMList *l, MBWMDecorType type)
+{
+ while (l)
+ {
+ MBWMXmlDecor * d = l->data;
+ if (d->type == type)
+ return d;
+
+ l = l->next;
+ }
+
+ return NULL;
+}
+
+MBWMXmlButton *
+mb_wm_xml_button_find_by_type (MBWMList *l, MBWMDecorButtonType type)
+{
+ while (l)
+ {
+ MBWMXmlButton * b = l->data;
+ if (b->type == type)
+ return b;
+
+ l = l->next;
+ }
+
+ return NULL;
+}
+
+#if 0
+void
+mb_wm_xml_client_dump (MBWMList * l)
+{
+ printf ("=== XML Clients =====\n");
+ while (l)
+ {
+ MBWMXmlClient * c = l->data;
+ MBWMList *l2 = c->decors;
+ printf ("===== client type %d =====\n", c->type);
+
+ while (l2)
+ {
+ MBWMXmlDecor * d = l2->data;
+ MBWMList *l3 = d->buttons;
+ printf ("======= decor type %d =====\n", d->type);
+
+ while (l3)
+ {
+ MBWMXmlButton * b = l3->data;
+ printf ("========= button type %d =====\n", d->type);
+
+ l3 = l3->next;
+ }
+
+ l2 = l2->next;
+ }
+
+ l = l->next;
+ }
+ printf ("=== XML Clients End =====\n");
+}
+#endif
diff --git a/matchbox2/theme-engines/mb-wm-theme-xml.h b/matchbox2/theme-engines/mb-wm-theme-xml.h
new file mode 100644
index 0000000..8388985
--- /dev/null
+++ b/matchbox2/theme-engines/mb-wm-theme-xml.h
@@ -0,0 +1,106 @@
+#ifndef _HAVE_MB_WM_THEME_PRIVATE_H
+#define _HAVE_MB_WM_THEME_PRIVATE_H
+
+#include <matchbox2/core/mb-wm.h>
+#include <matchbox2/theme-engines/mb-wm-theme.h>
+/*
+ * Helper structs for xml theme
+ */
+typedef struct Button
+{
+ MBWMDecorButtonType type;
+ MBWMDecorButtonPack packing;
+
+ MBWMColor clr_fg;
+ MBWMColor clr_bg;
+
+ int x;
+ int y;
+ int width;
+ int height;
+
+ /* Needed by png themes */
+ int active_x;
+ int active_y;
+
+ int inactive_x;
+ int inactive_y;
+
+ int press_activated;
+} MBWMXmlButton;
+
+typedef enum _MBWMXmlFontUnits
+{
+ MBWMXmlFontUnitsPixels,
+ MBWMXmlFontUnitsPoints,
+} MBWMXmlFontUnits;
+
+typedef struct Decor
+{
+ MBWMDecorType type;
+
+ MBWMColor clr_fg;
+ MBWMColor clr_bg;
+
+ int x;
+ int y;
+ int width;
+ int height;
+ int pad_offset;
+ int pad_length;
+ int show_title;
+
+ int font_size;
+ MBWMXmlFontUnits font_units;
+ char * font_family;
+
+ MBWMList * buttons;
+}MBWMXmlDecor;
+
+typedef struct Client
+{
+ MBWMClientType type;
+
+ int x;
+ int y;
+ int width;
+ int height;
+
+ Bool shaped;
+
+ MBWMList *decors;
+
+ MBWMClientLayoutHints layout_hints;
+}MBWMXmlClient;
+
+MBWMXmlButton *
+mb_wm_xml_button_new ();
+
+void
+mb_wm_xml_button_free (MBWMXmlButton * b);
+
+MBWMXmlDecor *
+mb_wm_xml_decor_new ();
+
+void
+mb_wm_xml_decor_free (MBWMXmlDecor * d);
+
+MBWMXmlClient *
+mb_wm_xml_client_new ();
+
+void
+mb_wm_xml_client_free (MBWMXmlClient * c);
+
+MBWMXmlClient *
+mb_wm_xml_client_find_by_type (MBWMList *l, MBWMClientType type);
+
+MBWMXmlDecor *
+mb_wm_xml_decor_find_by_type (MBWMList *l, MBWMDecorType type);
+
+MBWMXmlButton *
+mb_wm_xml_button_find_by_type (MBWMList *l, MBWMDecorButtonType type);
+
+void
+mb_wm_xml_clr_from_string (MBWMColor * clr, const char *s);
+
+#endif
diff --git a/matchbox2/theme-engines/mb-wm-theme.c b/matchbox2/theme-engines/mb-wm-theme.c
new file mode 100644
index 0000000..93e8fe7
--- /dev/null
+++ b/matchbox2/theme-engines/mb-wm-theme.c
@@ -0,0 +1,2099 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Tomas Frydrych <tf@o-hand.com>
+ *
+ * Copyright (c) 2005 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-theme.h"
+#include "mb-wm-theme-xml.h"
+
+#include <sys/stat.h>
+#include <expat.h>
+#include <X11/Xft/Xft.h>
+
+#define SIMPLE_FRAME_TITLEBAR_HEIGHT 40
+#define SIMPLE_FRAME_EDGE_SIZE 3
+
+MBWMThemeCustomClientTypeFunc custom_client_type_func = NULL;
+void *custom_client_type_func_data = NULL;
+
+MBWMThemeCustomButtonTypeFunc custom_button_type_func = NULL;
+void *custom_button_type_func_data = NULL;
+
+MBWMThemeCustomThemeTypeFunc custom_theme_type_func = NULL;
+void *custom_theme_type_func_data = NULL;
+
+MBWMThemeCustomThemeAllocFunc custom_theme_alloc_func = NULL;
+
+static void
+xml_element_start_cb (void *data, const char *tag, const char **expat_attr);
+
+static void
+xml_element_end_cb (void *data, const char *tag);
+
+static void
+xml_stack_free (MBWMList *stack);
+
+static void
+mb_wm_theme_simple_paint_decor (MBWMTheme *theme, MBWMDecor *decor);
+static void
+mb_wm_theme_simple_paint_button (MBWMTheme *theme, MBWMDecorButton *button);
+static void
+mb_wm_theme_simple_get_decor_dimensions (MBWMTheme *, MBWindowManagerClient *,
+ int *, int *, int *, int *);
+static void
+mb_wm_theme_simple_get_button_size (MBWMTheme *, MBWMDecor *,
+ MBWMDecorButtonType, int *, int *);
+static void
+mb_wm_theme_simple_get_button_position (MBWMTheme *, MBWMDecor *,
+ MBWMDecorButtonType, int*, int*);
+static MBWMDecor *
+mb_wm_theme_simple_create_decor (MBWMTheme *, MBWindowManagerClient *,
+ MBWMDecorType);
+
+static void
+mb_wm_theme_class_init (MBWMObjectClass *klass)
+{
+ MBWMThemeClass *t_class = MB_WM_THEME_CLASS (klass);
+
+ t_class->paint_decor = mb_wm_theme_simple_paint_decor;
+ t_class->paint_button = mb_wm_theme_simple_paint_button;
+ t_class->decor_dimensions = mb_wm_theme_simple_get_decor_dimensions;
+ t_class->button_size = mb_wm_theme_simple_get_button_size;
+ t_class->button_position = mb_wm_theme_simple_get_button_position;
+ t_class->create_decor = mb_wm_theme_simple_create_decor;
+
+#if MBWM_WANT_DEBUG
+ klass->klass_name = "MBWMTheme";
+#endif
+}
+
+static void
+mb_wm_theme_destroy (MBWMObject *obj)
+{
+ MBWMTheme *theme = MB_WM_THEME (obj);
+
+ if (theme->path)
+ free (theme->path);
+
+ MBWMList *l = theme->xml_clients;
+
+ while (l)
+ {
+ MBWMXmlClient * c = l->data;
+ MBWMList * n = l->next;
+ mb_wm_xml_client_free (c);
+ free (l);
+
+ l = n;
+ }
+}
+
+static int
+mb_wm_theme_init (MBWMObject *obj, va_list vap)
+{
+ MBWMTheme *theme = MB_WM_THEME (obj);
+ MBWindowManager *wm = NULL;
+ MBWMObjectProp prop;
+ MBWMList *xml_clients = NULL;
+ char *path = NULL;
+ MBWMColor *clr_lowlight = NULL;
+ MBWMColor *clr_shadow = NULL;
+
+ prop = va_arg(vap, MBWMObjectProp);
+ while (prop)
+ {
+ switch (prop)
+ {
+ case MBWMObjectPropWm:
+ wm = va_arg(vap, MBWindowManager *);
+ break;
+ case MBWMObjectPropThemePath:
+ path = va_arg(vap, char *);
+ break;
+ case MBWMObjectPropThemeXmlClients:
+ xml_clients = va_arg(vap, MBWMList *);
+ break;
+ case MBWMObjectPropThemeColorLowlight:
+ clr_lowlight = va_arg(vap, MBWMColor *);
+ break;
+ case MBWMObjectPropThemeColorShadow:
+ clr_shadow = va_arg(vap, MBWMColor *);
+ break;
+ case MBWMObjectPropThemeShadowType:
+ theme->shadow_type = va_arg(vap, int);
+ break;
+ case MBWMObjectPropThemeCompositing:
+ theme->compositing = va_arg(vap, int);
+ break;
+ case MBWMObjectPropThemeShaped:
+ theme->shaped = va_arg(vap, int);
+ break;
+
+ default:
+ MBWMO_PROP_EAT (vap, prop);
+ }
+
+ prop = va_arg(vap, MBWMObjectProp);
+ }
+
+ theme->wm = wm;
+ theme->xml_clients = xml_clients;
+
+ if (path)
+ theme->path = strdup (path);
+
+ if (clr_shadow && clr_shadow->set)
+ {
+ theme->color_shadow.r = clr_shadow->r;
+ theme->color_shadow.g = clr_shadow->g;
+ theme->color_shadow.b = clr_shadow->b;
+ theme->color_shadow.a = clr_shadow->a;
+ }
+ else
+ {
+ theme->color_shadow.r = 0.0;
+ theme->color_shadow.g = 0.0;
+ theme->color_shadow.b = 0.0;
+ theme->color_shadow.a = 0.95;
+ }
+
+ if (clr_lowlight && clr_lowlight->set)
+ {
+ theme->color_lowlight.r = clr_lowlight->r;
+ theme->color_lowlight.g = clr_lowlight->g;
+ theme->color_lowlight.b = clr_lowlight->b;
+ theme->color_lowlight.a = clr_lowlight->a;
+ }
+ else
+ {
+ theme->color_lowlight.r = 0.0;
+ theme->color_lowlight.g = 0.0;
+ theme->color_lowlight.b = 0.0;
+ theme->color_lowlight.a = 0.55;
+ }
+
+ return 1;
+}
+
+int
+mb_wm_theme_class_type ()
+{
+ static int type = 0;
+
+ if (UNLIKELY(type == 0))
+ {
+ static MBWMObjectClassInfo info = {
+ sizeof (MBWMThemeClass),
+ sizeof (MBWMTheme),
+ mb_wm_theme_init,
+ mb_wm_theme_destroy,
+ mb_wm_theme_class_init
+ };
+
+ type = mb_wm_object_register_class (&info, MB_WM_TYPE_OBJECT, 0);
+ }
+
+ return type;
+}
+
+Bool
+mb_wm_theme_is_button_press_activated (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type)
+{
+ MBWindowManagerClient * client;
+ MBWMXmlClient * c;
+ MBWMXmlDecor * d;
+ MBWMXmlButton * b;
+ MBWMClientType c_type;
+
+ if (!theme || !theme->xml_clients || !decor || !decor->parent_client)
+ return False;
+
+ client = decor->parent_client;
+ c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+
+ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) &&
+ (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type)) &&
+ (b = mb_wm_xml_button_find_by_type (d->buttons, type)))
+ {
+ return b->press_activated;
+ }
+
+ return False;
+}
+
+void
+mb_wm_theme_get_button_size (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type,
+ int *width,
+ int *height)
+{
+ MBWMThemeClass *klass;
+
+ MBWM_ASSERT (decor && decor->parent_client);
+
+ if (!theme || !decor || !decor->parent_client)
+ return;
+
+ klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme));
+
+ if (klass->button_size)
+ klass->button_size (theme, decor, type, width, height);
+}
+
+/*
+ * If the parent decor uses absolute postioning, the returned values
+ * are absolute. If the decor does packing, these values are added to
+ * calculated button position.
+ */
+void
+mb_wm_theme_get_button_position (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type,
+ int *x,
+ int *y)
+{
+ MBWMThemeClass *klass;
+
+ MBWM_ASSERT (decor && decor->parent_client);
+
+ if (!theme || !decor || !decor->parent_client)
+ return;
+
+ klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme));
+
+ if (klass->button_position)
+ klass->button_position (theme, decor, type, x, y);
+ else
+ {
+ if (x)
+ *x = 2;
+
+ if (y)
+ *y = 2;
+ }
+}
+
+void
+mb_wm_theme_get_decor_dimensions (MBWMTheme *theme,
+ MBWindowManagerClient *client,
+ int *north,
+ int *south,
+ int *west,
+ int *east)
+{
+ MBWMThemeClass *klass;
+
+ MBWM_ASSERT (client);
+
+ if (!theme || !client)
+ return;
+
+ klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme));
+
+ if (klass->decor_dimensions)
+ klass->decor_dimensions (theme, client, north, south, west, east);
+}
+
+void
+mb_wm_theme_paint_decor (MBWMTheme *theme, MBWMDecor *decor)
+{
+ MBWMThemeClass *klass;
+
+ if (!theme)
+ return;
+
+ klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme));
+
+ if (klass->paint_decor)
+ klass->paint_decor (theme, decor);
+}
+
+void
+mb_wm_theme_paint_button (MBWMTheme *theme, MBWMDecorButton *button)
+{
+ MBWMThemeClass *klass;
+
+ if (!theme)
+ return;
+
+ klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme));
+
+ if (klass->paint_button)
+ klass->paint_button (theme, button);
+}
+
+Bool
+mb_wm_theme_supports (MBWMTheme *theme, MBWMThemeCaps capability)
+{
+ if (theme)
+ return False;
+
+ return ((capability & theme->caps) != False);
+}
+
+typedef enum
+{
+ XML_CTX_UNKNOWN = 0,
+ XML_CTX_THEME,
+ XML_CTX_CLIENT,
+ XML_CTX_DECOR,
+ XML_CTX_BUTTON,
+ XML_CTX_IMG,
+} XmlCtx;
+
+struct stack_data
+{
+ XmlCtx ctx;
+ void *data;
+};
+
+struct expat_data
+{
+ XML_Parser par;
+ int theme_type;
+ int version;
+ MBWMList *xml_clients;
+ char *img;
+ MBWMList *stack;
+ MBWMColor color_lowlight;
+ MBWMColor color_shadow;
+ MBWMCompMgrShadowType shadow_type;
+ Bool compositing;
+ Bool shaped;
+};
+
+MBWMTheme *
+mb_wm_theme_new (MBWindowManager * wm, const char * theme_path)
+{
+ MBWMTheme *theme = NULL;
+ int theme_type = 0;
+ char *path = NULL;
+ char buf[256];
+ XML_Parser par = NULL;
+ FILE *file = NULL;
+ MBWMList *xml_clients = NULL;
+ char *img = NULL;
+ MBWMColor clr_lowlight;
+ MBWMColor clr_shadow;
+ MBWMCompMgrShadowType shadow_type;
+ Bool compositing;
+ Bool shaped;
+ struct stat st;
+
+ /*
+ * If no theme specified, we try to load the default one, if that fails,
+ * we automatically fallback on the built-in defaults.
+ */
+ if (!theme_path)
+ theme_path = "Default";
+
+ /* Attempt to parse the xml theme, if any, retrieving the theme type
+ *
+ * NB: We cannot do this in the _init function, since we need to know the
+ * type *before* we can create the underlying object on which the
+ * init method operates.
+ */
+
+ if (*theme_path == '/')
+ {
+ if (!stat (theme_path, &st))
+ path = (char *) theme_path;
+ }
+ else
+ {
+ const char *home = getenv("HOME");
+ int size;
+
+ if (home)
+ {
+ const char *fmt = "%s/.themes/%s/matchbox2/theme.xml";
+
+ size = strlen (theme_path) + strlen (fmt) + strlen (home);
+ path = alloca (size);
+ snprintf (path, size, fmt, home, theme_path);
+
+ if (stat (path, &st))
+ path = NULL;
+ }
+
+ if (!path)
+ {
+ const char * fmt = "%s/themes/%s/matchbox2/theme.xml";
+
+ size = strlen (theme_path) + strlen (fmt) + strlen (DATADIR);
+ path = alloca (size);
+ snprintf (path, size, fmt, DATADIR, theme_path);
+
+ if (stat (path, &st))
+ path = NULL;
+ }
+ }
+
+ if (path)
+ {
+ struct expat_data udata;
+
+ if (!(file = fopen (path, "r")) ||
+ !(par = XML_ParserCreate(NULL)))
+ {
+ goto default_theme;
+ }
+
+ memset (&udata, 0, sizeof (struct expat_data));
+ udata.compositing = True;
+ udata.par = par;
+
+ XML_SetElementHandler (par,
+ xml_element_start_cb,
+ xml_element_end_cb);
+
+ XML_SetUserData(par, (void *)&udata);
+
+ while (fgets (buf, sizeof (buf), file) &&
+ XML_Parse(par, buf, strlen(buf), 0));
+
+ XML_Parse(par, NULL, 0, 1);
+
+ if (udata.version == 2)
+ {
+ theme_type = udata.theme_type;
+ xml_clients = udata.xml_clients;
+
+ if (udata.img)
+ {
+ if (*udata.img == '/')
+ img = udata.img;
+ else
+ {
+ int len = strlen (path) + strlen (udata.img);
+ char * s;
+ char * p = malloc (len + 1);
+ strncpy (p, path, len);
+
+ s = strrchr (p, '/');
+
+ if (s)
+ {
+ *(s+1) = 0;
+ strcat (p, udata.img);
+ }
+ else
+ {
+ strncpy (p, udata.img, len);
+ }
+
+ img = p;
+ free (udata.img);
+ }
+ }
+ }
+
+ clr_lowlight.r = udata.color_lowlight.r;
+ clr_lowlight.g = udata.color_lowlight.g;
+ clr_lowlight.b = udata.color_lowlight.b;
+ clr_lowlight.a = udata.color_lowlight.a;
+ clr_lowlight.set = udata.color_lowlight.set;
+
+ clr_shadow.r = udata.color_shadow.r;
+ clr_shadow.g = udata.color_shadow.g;
+ clr_shadow.b = udata.color_shadow.b;
+ clr_shadow.a = udata.color_shadow.a;
+ clr_shadow.set = udata.color_shadow.set;
+
+ shadow_type = udata.shadow_type;
+ compositing = udata.compositing;
+ shaped = udata.shaped;
+
+ xml_stack_free (udata.stack);
+ }
+
+ if (custom_theme_alloc_func)
+ {
+ theme =
+ custom_theme_alloc_func (theme_type,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropThemePath, path,
+ MBWMObjectPropThemeImg, img,
+ MBWMObjectPropThemeXmlClients, xml_clients,
+ MBWMObjectPropThemeColorLowlight, &clr_lowlight,
+ MBWMObjectPropThemeColorShadow, &clr_shadow,
+ MBWMObjectPropThemeShadowType, shadow_type,
+ MBWMObjectPropThemeCompositing, compositing,
+ MBWMObjectPropThemeShaped, shaped,
+ NULL);
+ }
+ else if (theme_type)
+ {
+ theme =
+ MB_WM_THEME (mb_wm_object_new (theme_type,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropThemePath, path,
+ MBWMObjectPropThemeImg, img,
+ MBWMObjectPropThemeXmlClients, xml_clients,
+ MBWMObjectPropThemeColorLowlight, &clr_lowlight,
+ MBWMObjectPropThemeColorShadow, &clr_shadow,
+ MBWMObjectPropThemeShadowType, shadow_type,
+ MBWMObjectPropThemeCompositing, compositing,
+ MBWMObjectPropThemeShaped, shaped,
+ NULL));
+ }
+
+ default_theme:
+
+ if (!theme)
+ {
+ theme = MB_WM_THEME (mb_wm_object_new (
+ MB_WM_TYPE_THEME,
+ MBWMObjectPropWm, wm,
+ MBWMObjectPropThemeXmlClients, xml_clients,
+ MBWMObjectPropThemeColorLowlight, &clr_lowlight,
+ MBWMObjectPropThemeColorShadow, &clr_shadow,
+ MBWMObjectPropThemeShadowType, shadow_type,
+ MBWMObjectPropThemeCompositing, compositing,
+ MBWMObjectPropThemeShaped, shaped,
+ NULL));
+ }
+
+ if (par)
+ XML_ParserFree (par);
+
+ if (file)
+ fclose (file);
+
+ if (img)
+ free (img);
+
+ return theme;
+}
+
+MBWMDecor *
+mb_wm_theme_create_decor (MBWMTheme *theme,
+ MBWindowManagerClient *client,
+ MBWMDecorType type)
+{
+ MBWMThemeClass *klass;
+
+ MBWM_ASSERT (client);
+
+ if (!theme || !client)
+ return NULL;
+
+ klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme));
+
+ if (klass->create_decor)
+ return klass->create_decor (theme, client, type);
+
+ return NULL;
+}
+
+void
+mb_wm_theme_resize_decor (MBWMTheme *theme, MBWMDecor *decor)
+{
+ MBWMThemeClass *klass;
+
+ MBWM_ASSERT (decor);
+
+ if (!theme || !decor)
+ return;
+
+ klass = MB_WM_THEME_CLASS(MB_WM_OBJECT_GET_CLASS (theme));
+
+ if (klass->resize_decor)
+ klass->resize_decor (theme, decor);
+}
+
+MBWMClientLayoutHints
+mb_wm_theme_get_client_layout_hints (MBWMTheme * theme,
+ MBWindowManagerClient * client)
+{
+ MBWMXmlClient * c;
+ MBWMClientType c_type;
+
+ if (!client || !theme)
+ return 0;
+
+ 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 0;
+ }
+
+ return c->layout_hints;
+}
+
+/*
+ * Returns True if the theme prescribes at least one value for the geometry
+ */
+Bool
+mb_wm_theme_get_client_geometry (MBWMTheme * theme,
+ MBWindowManagerClient * client,
+ MBGeometry * geom)
+{
+ MBWMXmlClient * c;
+ MBWMClientType c_type;
+
+ if (!geom || !client || !theme)
+ return False;
+
+ c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+
+ if (!theme || !theme->xml_clients ||
+ !(c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) ||
+ (c->x < 0 && c->y < 0 && c->width < 0 && c->height < 0))
+ {
+ return False;
+ }
+
+ geom->x = c->x;
+ geom->y = c->y;
+ geom->width = c->width;
+ geom->height = c->height;
+
+ return True;
+}
+
+Bool
+mb_wm_theme_is_client_shaped (MBWMTheme * theme,
+ MBWindowManagerClient * client)
+{
+#ifdef HAVE_XEXT
+ MBWMXmlClient * c;
+ MBWMClientType c_type;
+
+ if (!client || !theme || !theme->shaped || client->is_argb32)
+ return False;
+
+ 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 c->shaped;
+ }
+
+ return False;
+#else
+ return False;
+#endif
+}
+
+/*
+ * Retrieves color to be used for lowlighting (16-bit rgba)
+ */
+void
+mb_wm_theme_get_lowlight_color (MBWMTheme * theme,
+ unsigned int * red,
+ unsigned int * green,
+ unsigned int * blue,
+ unsigned int * alpha)
+{
+ if (theme)
+ {
+ if (red)
+ *red = (unsigned int)(theme->color_lowlight.r * (double)0xffff);
+
+ if (green)
+ *green = (unsigned int)(theme->color_lowlight.g * (double)0xffff);
+
+ if (blue)
+ *blue = (unsigned int)(theme->color_lowlight.b * (double)0xffff);
+
+ if (alpha)
+ *alpha = (unsigned int)(theme->color_lowlight.a * (double)0xffff);
+
+ return;
+ }
+
+ if (red)
+ *red = 0;
+
+ if (green)
+ *green = 0;
+
+ if (blue)
+ *blue = 0;
+
+ if (*alpha)
+ *alpha = 0x8d8d;
+}
+
+/*
+ * Retrieves color to be used for lowlighting (16-bit rgba)
+ */
+void
+mb_wm_theme_get_shadow_color (MBWMTheme * theme,
+ unsigned int * red,
+ unsigned int * green,
+ unsigned int * blue,
+ unsigned int * alpha)
+{
+ if (theme)
+ {
+ if (red)
+ *red = (unsigned int)(theme->color_shadow.r * (double)0xffff);
+
+ if (green)
+ *green = (unsigned int)(theme->color_shadow.g * (double)0xffff);
+
+ if (blue)
+ *blue = (unsigned int)(theme->color_shadow.b * (double)0xffff);
+
+ if (alpha)
+ *alpha = (unsigned int)(theme->color_shadow.a * (double)0xffff);
+
+ return;
+ }
+
+ if (red)
+ *red = 0;
+
+ if (green)
+ *green = 0;
+
+ if (blue)
+ *blue = 0;
+
+ if (*alpha)
+ *alpha = 0xff00;
+}
+
+MBWMCompMgrShadowType
+mb_wm_theme_get_shadow_type (MBWMTheme * theme)
+{
+ if (!theme)
+ return MBWM_COMP_MGR_SHADOW_NONE;
+
+ return theme->shadow_type;
+}
+
+Bool
+mb_wm_theme_use_compositing_mgr (MBWMTheme * theme)
+{
+ if (!theme)
+ return False;
+
+ return theme->compositing;
+}
+
+/*
+ * Expat callback stuff
+ */
+
+static void
+xml_stack_push (MBWMList ** stack, XmlCtx ctx)
+{
+ struct stack_data * s = malloc (sizeof (struct stack_data));
+
+ s->ctx = ctx;
+ s->data = NULL;
+
+ *stack = mb_wm_util_list_prepend (*stack, s);
+}
+
+static XmlCtx
+xml_stack_top_ctx (MBWMList *stack)
+{
+ struct stack_data * s = stack->data;
+
+ return s->ctx;
+}
+
+static void *
+xml_stack_top_data (MBWMList *stack)
+{
+ struct stack_data * s = stack->data;
+
+ return s->data;
+}
+
+static void
+xml_stack_top_set_data (MBWMList *stack, void * data)
+{
+ struct stack_data * s = stack->data;
+
+ s->data = data;
+}
+
+static void
+xml_stack_pop (MBWMList ** stack)
+{
+ MBWMList * top = *stack;
+ struct stack_data * s = top->data;
+
+ *stack = top->next;
+ free (s);
+ free (top);
+}
+
+static void
+xml_stack_free (MBWMList *stack)
+{
+ MBWMList * l = stack;
+ while (l)
+ {
+ MBWMList * n = l->next;
+ free (l->data);
+ free (l);
+
+ l = n;
+ }
+}
+
+static void
+xml_element_start_cb (void *data, const char *tag, const char **expat_attr)
+{
+ struct expat_data * exd = data;
+
+ MBWM_DBG ("tag <%s>\n", tag);
+
+ if (!strcmp (tag, "theme"))
+ {
+ MBWMColor clr;
+ const char ** p = expat_attr;
+
+ xml_stack_push (&exd->stack, XML_CTX_THEME);
+
+ while (*p)
+ {
+ if (!strcmp (*p, "engine-version"))
+ exd->version = atoi (*(p+1));
+ else if (!strcmp (*p, "engine-type"))
+ {
+ if (!strcmp (*(p+1), "default"))
+ exd->theme_type = MB_WM_TYPE_THEME;
+#if THEME_PNG
+ else if (!strcmp (*(p+1), "png"))
+ exd->theme_type = MB_WM_TYPE_THEME_PNG;
+#endif
+ else if (custom_theme_type_func)
+ exd->theme_type = custom_theme_type_func (*(p+1),
+ custom_theme_type_func_data);
+ }
+ else if (!strcmp (*p, "shaped"))
+ {
+ if (!strcmp (*(p+1), "yes") || !strcmp (*(p+1), "1"))
+ exd->shaped = 1;
+ }
+ else if (!strcmp (*p, "color-shadow"))
+ {
+ mb_wm_xml_clr_from_string (&clr, *(p+1));
+
+ if (clr.set)
+ {
+ exd->color_shadow.r = clr.r;
+ exd->color_shadow.g = clr.g;
+ exd->color_shadow.b = clr.b;
+ exd->color_shadow.a = clr.a;
+ exd->color_shadow.set = True;
+ }
+ }
+ else if (!strcmp (*p, "color-lowlight"))
+ {
+ mb_wm_xml_clr_from_string (&clr, *(p+1));
+
+ if (clr.set)
+ {
+ exd->color_lowlight.r = clr.r;
+ exd->color_lowlight.g = clr.g;
+ exd->color_lowlight.b = clr.b;
+ exd->color_lowlight.a = clr.a;
+ exd->color_lowlight.set = True;
+ }
+ }
+ else if (!strcmp (*p, "shadow-type"))
+ {
+ if (!strcmp (*(p+1), "simple"))
+ exd->shadow_type = MBWM_COMP_MGR_SHADOW_SIMPLE;
+ else if (!strcmp (*(p+1), "gaussian"))
+ exd->shadow_type = MBWM_COMP_MGR_SHADOW_GAUSSIAN;
+ }
+ else if (!strcmp (*p, "compositing"))
+ {
+ if (!strcmp (*(p+1), "yes") || !strcmp (*(p+1), "1"))
+ exd->compositing = True;
+ else
+ exd->compositing = False;
+ }
+
+ p += 2;
+ }
+ }
+
+ if (!strcmp (tag, "client"))
+ {
+ MBWMXmlClient * c = mb_wm_xml_client_new ();
+ const char **p = expat_attr;
+
+ XmlCtx ctx = xml_stack_top_ctx (exd->stack);
+
+ xml_stack_push (&exd->stack, XML_CTX_CLIENT);
+
+ if (ctx != XML_CTX_THEME)
+ {
+ MBWM_DBG ("Expected context theme");
+ return;
+ }
+
+ while (*p)
+ {
+ if (!strcmp (*p, "type"))
+ {
+ if (!strcmp (*(p+1), "app"))
+ c->type = MBWMClientTypeApp;
+ else if (!strcmp (*(p+1), "dialog"))
+ c->type = MBWMClientTypeDialog;
+ else if (!strcmp (*(p+1), "panel"))
+ c->type = MBWMClientTypePanel;
+ else if (!strcmp (*(p+1), "input"))
+ c->type = MBWMClientTypeInput;
+ else if (!strcmp (*(p+1), "desktop"))
+ c->type = MBWMClientTypeDesktop;
+ else if (!strcmp (*(p+1), "notification"))
+ c->type = MBWMClientTypeNote;
+ else if (custom_client_type_func)
+ c->type = custom_client_type_func (*(p+1),
+ custom_client_type_func_data);
+ }
+ else if (!strcmp (*p, "shaped"))
+ {
+ if (!strcmp (*(p+1), "yes") || !strcmp (*(p+1), "1"))
+ c->shaped = 1;
+ }
+ else if (!strcmp (*p, "width"))
+ {
+ c->width = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "height"))
+ {
+ c->height = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "x"))
+ {
+ c->x = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "y"))
+ {
+ c->y = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "layout-hints") && *(p+1))
+ {
+ /* comma-separate list of hints */
+ char * duph = strdup (*(p+1));
+ char * comma;
+ char * h = duph;
+
+ while (h)
+ {
+ comma = strchr (h, ',');
+
+ if (comma)
+ *comma = 0;
+
+ if (!strcmp (h, "reserve-edge-north"))
+ {
+ c->layout_hints |= LayoutPrefReserveEdgeNorth;
+ }
+ else if (!strcmp (h, "reserve-edge-south"))
+ {
+ c->layout_hints |= LayoutPrefReserveEdgeSouth;
+ }
+ else if (!strcmp (h, "reserve-edge-west"))
+ {
+ c->layout_hints |= LayoutPrefReserveEdgeWest;
+ }
+ else if (!strcmp (h, "reserve-edge-east"))
+ {
+ c->layout_hints |= LayoutPrefReserveEdgeEast;
+ }
+ if (!strcmp (h, "reserve-north"))
+ {
+ c->layout_hints |= LayoutPrefReserveNorth;
+ }
+ else if (!strcmp (h, "reserve-south"))
+ {
+ c->layout_hints |= LayoutPrefReserveSouth;
+ }
+ else if (!strcmp (h, "reserve-west"))
+ {
+ c->layout_hints |= LayoutPrefReserveWest;
+ }
+ else if (!strcmp (h, "reserve-east"))
+ {
+ c->layout_hints |= LayoutPrefReserveEast;
+ }
+ else if (!strcmp (h, "grow"))
+ {
+ c->layout_hints |= LayoutPrefGrowToFreeSpace;
+ }
+ else if (!strcmp (h, "free"))
+ {
+ c->layout_hints |= LayoutPrefPositionFree;
+ }
+ else if (!strcmp (h, "full-screen"))
+ {
+ c->layout_hints |= LayoutPrefFullscreen;
+ }
+ else if (!strcmp (h, "fixed-x"))
+ {
+ c->layout_hints |= LayoutPrefFixedX;
+ }
+ else if (!strcmp (h, "fixed-y"))
+ {
+ c->layout_hints |= LayoutPrefFixedY;
+ }
+ else if (!strcmp (h, "overlaps"))
+ {
+ c->layout_hints |= LayoutPrefOverlaps;
+ }
+
+ if (comma)
+ h = comma + 1;
+ else
+ break;
+ }
+
+ free (duph);
+ }
+
+ p += 2;
+ }
+
+ if (!c->type)
+ mb_wm_xml_client_free (c);
+ else
+ {
+ exd->xml_clients = mb_wm_util_list_prepend (exd->xml_clients, c);
+ xml_stack_top_set_data (exd->stack, c);
+ }
+
+
+ return;
+ }
+
+ if (!strcmp (tag, "decor"))
+ {
+ MBWMXmlDecor * d = mb_wm_xml_decor_new ();
+ const char **p = expat_attr;
+ XmlCtx ctx = xml_stack_top_ctx (exd->stack);
+ MBWMXmlClient * c = xml_stack_top_data (exd->stack);
+
+ xml_stack_push (&exd->stack, XML_CTX_DECOR);
+
+ if (ctx != XML_CTX_CLIENT || !c)
+ {
+ MBWM_DBG ("Expected context client");
+ return;
+ }
+
+ while (*p)
+ {
+ if (!strcmp (*p, "color-fg"))
+ mb_wm_xml_clr_from_string (&d->clr_fg, *(p+1));
+ else if (!strcmp (*p, "color-bg"))
+ mb_wm_xml_clr_from_string (&d->clr_bg, *(p+1));
+ else if (!strcmp (*p, "type"))
+ {
+ if (!strcmp (*(p+1), "north"))
+ d->type = MBWMDecorTypeNorth;
+ else if (!strcmp (*(p+1), "south"))
+ d->type = MBWMDecorTypeSouth;
+ else if (!strcmp (*(p+1), "east"))
+ d->type = MBWMDecorTypeEast;
+ else if (!strcmp (*(p+1), "west"))
+ d->type = MBWMDecorTypeWest;
+ }
+ else if (!strcmp (*p, "template-width"))
+ {
+ d->width = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "template-height"))
+ {
+ d->height = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "template-x"))
+ {
+ d->x = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "template-y"))
+ {
+ d->y = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "template-pad-offset"))
+ {
+ d->pad_offset = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "template-pad-length"))
+ {
+ d->pad_length = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "font-size"))
+ {
+ char * end_size = NULL;
+
+ d->font_units = MBWMXmlFontUnitsPixels;
+ d->font_size = strtol (*(p+1), &end_size, 0);
+
+ if (end_size && *end_size)
+ {
+ if (*end_size == 'p')
+ {
+ switch (*(end_size+1))
+ {
+ case 't':
+ d->font_units = MBWMXmlFontUnitsPoints;
+ break;
+ case 'x':
+ default:
+ ;
+ }
+ }
+ }
+ }
+ else if (!strcmp (*p, "font-family"))
+ {
+ d->font_family = strdup (*(p+1));
+ }
+ else if (!strcmp (*p, "show-title"))
+ {
+ if (!strcmp (*(p+1), "yes") || !strcmp (*(p+1), "1"))
+ d->show_title = 1;
+ }
+
+ p += 2;
+ }
+
+ if (!d->type)
+ mb_wm_xml_decor_free (d);
+ else
+ {
+ c->decors = mb_wm_util_list_prepend (c->decors, d);
+ xml_stack_top_set_data (exd->stack, d);
+ }
+
+ return;
+ }
+
+ if (!strcmp (tag, "button"))
+ {
+ MBWMXmlButton * b = mb_wm_xml_button_new ();
+ const char **p = expat_attr;
+ XmlCtx ctx = xml_stack_top_ctx (exd->stack);
+ MBWMXmlDecor * d = xml_stack_top_data (exd->stack);
+
+ xml_stack_push (&exd->stack, XML_CTX_BUTTON);
+
+ if (ctx != XML_CTX_DECOR || !d)
+ {
+ MBWM_DBG ("Expected context decor");
+ return;
+ }
+
+ while (*p)
+ {
+ if (!strcmp (*p, "color-fg"))
+ mb_wm_xml_clr_from_string (&b->clr_fg, *(p+1));
+ else if (!strcmp (*p, "color-bg"))
+ mb_wm_xml_clr_from_string (&b->clr_bg, *(p+1));
+ else if (!strcmp (*p, "type"))
+ {
+ if (!strcmp (*(p+1), "minimize"))
+ b->type = MBWMDecorButtonMinimize;
+ else if (!strcmp (*(p+1), "close"))
+ b->type = MBWMDecorButtonClose;
+ else if (!strcmp (*(p+1), "menu"))
+ b->type = MBWMDecorButtonMenu;
+ else if (!strcmp (*(p+1), "accept"))
+ b->type = MBWMDecorButtonAccept;
+ else if (!strcmp (*(p+1), "fullscreen"))
+ b->type = MBWMDecorButtonFullscreen;
+ else if (!strcmp (*(p+1), "help"))
+ b->type = MBWMDecorButtonHelp;
+ else if (custom_button_type_func)
+ b->type = custom_button_type_func (*(p+1),
+ custom_button_type_func_data);
+ }
+ else if (!strcmp (*p, "packing"))
+ {
+ if (!strcmp (*(p+1), "end"))
+ b->packing = MBWMDecorButtonPackEnd;
+ else if (!strcmp (*(p+1), "start"))
+ b->packing = MBWMDecorButtonPackStart;
+ }
+ else if (!strcmp (*p, "template-x"))
+ {
+ b->x = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "template-y"))
+ {
+ b->y = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "width"))
+ {
+ b->width = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "height"))
+ {
+ b->height = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "template-active-x"))
+ {
+ b->active_x = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "template-active-y"))
+ {
+ b->active_y = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "template-inactive-x"))
+ {
+ b->inactive_x = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "template-inactive-y"))
+ {
+ b->inactive_y = atoi (*(p+1));
+ }
+ else if (!strcmp (*p, "press-activated"))
+ {
+ if (!strcmp (*(p+1), "yes") || !strcmp (*(p+1), "1"))
+ b->press_activated = 1;
+ }
+
+ p += 2;
+ }
+
+ if (!b->type)
+ {
+ mb_wm_xml_button_free (b);
+ return;
+ }
+
+ d->buttons = mb_wm_util_list_append (d->buttons, b);
+
+ xml_stack_top_set_data (exd->stack, b);
+
+ return;
+ }
+
+ if (!strcmp (tag, "img"))
+ {
+ const char **p = expat_attr;
+ XmlCtx ctx = xml_stack_top_ctx (exd->stack);
+
+ xml_stack_push (&exd->stack, XML_CTX_IMG);
+
+ if (ctx != XML_CTX_THEME)
+ {
+ MBWM_DBG ("Expected context theme");
+ return;
+ }
+
+ while (*p)
+ {
+ if (!strcmp (*p, "src"))
+ {
+ exd->img = strdup (*(p+1));
+ return;
+ }
+
+ p += 2;
+ }
+
+ return;
+ }
+
+}
+
+static void
+xml_element_end_cb (void *data, const char *tag)
+{
+ struct expat_data * exd = data;
+
+ XmlCtx ctx = xml_stack_top_ctx (exd->stack);
+
+ MBWM_DBG ("tag </%s>\n", tag);
+
+ if (!strcmp (tag, "theme"))
+ {
+ XML_StopParser (exd->par, 0);
+ }
+ else if (!strcmp (tag, "client"))
+ {
+ if (ctx == XML_CTX_CLIENT)
+ {
+ xml_stack_pop (&exd->stack);
+ }
+ else
+ MBWM_DBG ("Expected client on the top of the stack!");
+ }
+ else if (!strcmp (tag, "decor"))
+ {
+ if (ctx == XML_CTX_DECOR)
+ {
+ xml_stack_pop (&exd->stack);
+ }
+ else
+ MBWM_DBG ("Expected decor on the top of the stack!");
+ }
+ else if (!strcmp (tag, "button"))
+ {
+ if (ctx == XML_CTX_BUTTON)
+ {
+ xml_stack_pop (&exd->stack);
+ }
+ else
+ MBWM_DBG ("Expected button on the top of the stack!");
+ }
+ else if (!strcmp (tag, "img"))
+ {
+ if (ctx == XML_CTX_IMG)
+ {
+ xml_stack_pop (&exd->stack);
+ }
+ else
+ MBWM_DBG ("Expected img on the top of the stack!");
+ }
+}
+
+
+
+static void
+construct_buttons (MBWMTheme * theme,
+ MBWMDecor * decor, MBWMXmlDecor *d)
+{
+ MBWindowManagerClient *client = decor->parent_client;
+ MBWindowManager *wm = client->wmref;
+ MBWMDecorButton *button;
+
+ if (d)
+ {
+ MBWMList * l = d->buttons;
+ while (l)
+ {
+ MBWMXmlButton * b = l->data;
+
+ button = mb_wm_decor_button_stock_new (wm,
+ b->type,
+ b->packing,
+ decor,
+ 0);
+
+ mb_wm_decor_button_show (button);
+ mb_wm_object_unref (MB_WM_OBJECT (button));
+
+ l = l->next;
+ }
+
+ return;
+ }
+
+ button = mb_wm_decor_button_stock_new (wm,
+ MBWMDecorButtonClose,
+ MBWMDecorButtonPackEnd,
+ decor,
+ 0);
+
+ mb_wm_decor_button_show (button);
+ mb_wm_object_unref (MB_WM_OBJECT (button));
+
+#if 0
+ /*
+ * We probably do not want this in the default client, but for now
+ * it is useful for testing purposes
+ */
+ button = mb_wm_decor_button_stock_new (wm,
+ MBWMDecorButtonFullscreen,
+ MBWMDecorButtonPackEnd,
+ decor,
+ 0);
+
+ mb_wm_decor_button_show (button);
+ mb_wm_object_unref (MB_WM_OBJECT (button));
+
+ button = mb_wm_decor_button_stock_new (wm,
+ MBWMDecorButtonHelp,
+ MBWMDecorButtonPackEnd,
+ decor,
+ 0);
+
+ mb_wm_decor_button_show (button);
+ mb_wm_object_unref (MB_WM_OBJECT (button));
+
+ button = mb_wm_decor_button_stock_new (wm,
+ MBWMDecorButtonAccept,
+ MBWMDecorButtonPackEnd,
+ decor,
+ 0);
+
+ mb_wm_decor_button_show (button);
+ mb_wm_object_unref (MB_WM_OBJECT (button));
+
+ button = mb_wm_decor_button_stock_new (wm,
+ MBWMDecorButtonMinimize,
+ MBWMDecorButtonPackEnd,
+ decor,
+ 0);
+
+ mb_wm_decor_button_show (button);
+ mb_wm_object_unref (MB_WM_OBJECT (button));
+
+ button = mb_wm_decor_button_stock_new (wm,
+ MBWMDecorButtonMenu,
+ MBWMDecorButtonPackStart,
+ decor,
+ 0);
+
+ mb_wm_decor_button_show (button);
+ mb_wm_object_unref (MB_WM_OBJECT (button));
+#endif
+}
+
+struct DecorData
+{
+ Pixmap xpix;
+ XftDraw *xftdraw;
+ XftColor clr;
+ XftFont *font;
+};
+
+static void
+decordata_free (MBWMDecor * decor, void *data)
+{
+ struct DecorData * dd = data;
+ Display * xdpy = decor->parent_client->wmref->xdpy;
+
+ XFreePixmap (xdpy, dd->xpix);
+
+ XftDrawDestroy (dd->xftdraw);
+
+ if (dd->font)
+ XftFontClose (xdpy, dd->font);
+
+ free (dd);
+}
+
+static MBWMDecor *
+mb_wm_theme_simple_create_decor (MBWMTheme *theme,
+ MBWindowManagerClient *client,
+ MBWMDecorType type)
+{
+ MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+ MBWMDecor *decor = NULL;
+ MBWindowManager *wm = client->wmref;
+ MBWMXmlClient *c;
+
+ if (MB_WM_THEME (theme)->xml_clients &&
+ (c = mb_wm_xml_client_find_by_type (MB_WM_THEME (theme)->xml_clients,
+ c_type)))
+ {
+ MBWMXmlDecor *d;
+
+ d = mb_wm_xml_decor_find_by_type (c->decors, type);
+
+ if (d)
+ {
+ decor = mb_wm_decor_new (wm, type);
+ mb_wm_decor_attach (decor, client);
+ construct_buttons (theme, decor, d);
+ }
+
+ return decor;
+ }
+
+ switch (c_type)
+ {
+ case MBWMClientTypeApp:
+ switch (type)
+ {
+ case MBWMDecorTypeNorth:
+ decor = mb_wm_decor_new (wm, type);
+ mb_wm_decor_attach (decor, client);
+ construct_buttons (theme, decor, NULL);
+ break;
+ default:
+ decor = mb_wm_decor_new (wm, type);
+ mb_wm_decor_attach (decor, client);
+ }
+ break;
+
+ case MBWMClientTypeDialog:
+ decor = mb_wm_decor_new (wm, type);
+ mb_wm_decor_attach (decor, client);
+ break;
+
+ case MBWMClientTypePanel:
+ case MBWMClientTypeDesktop:
+ case MBWMClientTypeInput:
+ default:
+ decor = mb_wm_decor_new (wm, type);
+ mb_wm_decor_attach (decor, client);
+ }
+
+ return decor;
+}
+
+static void
+mb_wm_theme_simple_get_button_size (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type,
+ int *width,
+ int *height)
+{
+ MBWindowManagerClient * client = decor->parent_client;
+ MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+ MBWMXmlClient * c;
+ MBWMXmlDecor * d;
+
+ /* FIXME -- assumes button on the north decor only */
+ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) &&
+ (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type)))
+ {
+ MBWMXmlButton * b = mb_wm_xml_button_find_by_type (d->buttons, type);
+
+ if (b)
+ {
+ if (width)
+ *width = b->width;
+
+ if (height)
+ *height = b->height;
+
+ return;
+ }
+ }
+
+ /*
+ * These are defaults when no theme description was loaded
+ */
+ switch (c_type)
+ {
+ case MBWMClientTypeApp:
+ case MBWMClientTypeDialog:
+ case MBWMClientTypePanel:
+ case MBWMClientTypeDesktop:
+ case MBWMClientTypeInput:
+ default:
+ if (width)
+ *width = SIMPLE_FRAME_TITLEBAR_HEIGHT-4;
+
+ if (height)
+ *height = SIMPLE_FRAME_TITLEBAR_HEIGHT-4;
+ }
+}
+
+static void
+mb_wm_theme_simple_get_button_position (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type,
+ int *x,
+ int *y)
+{
+ MBWindowManagerClient * client = decor->parent_client;
+ MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+ MBWMXmlClient * c;
+ MBWMXmlDecor * d;
+
+ /* FIXME -- assumes button on the north decor only */
+ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) &&
+ (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type)))
+ {
+ MBWMXmlButton * b = mb_wm_xml_button_find_by_type (d->buttons, type);
+
+ if (b)
+ {
+ if (x)
+ if (b->x >= 0)
+ *x = b->x;
+ else
+ *x = 2;
+
+ if (y)
+ if (b->y >= 0)
+ *y = b->y;
+ else
+ *y = 2;
+
+ return;
+ }
+ }
+
+ if (x)
+ *x = 2;
+
+ if (y)
+ *y = 2;
+}
+
+static void
+mb_wm_theme_simple_get_decor_dimensions (MBWMTheme *theme,
+ MBWindowManagerClient *client,
+ int *north,
+ int *south,
+ int *west,
+ int *east)
+{
+ MBWMClientType c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+ MBWMXmlClient * c;
+ MBWMXmlDecor * d;
+
+ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)))
+ {
+ if (north)
+ if ((d = mb_wm_xml_decor_find_by_type (c->decors,MBWMDecorTypeNorth)))
+ *north = d->height;
+ else
+ *north = SIMPLE_FRAME_TITLEBAR_HEIGHT;
+
+ if (south)
+ if ((d = mb_wm_xml_decor_find_by_type (c->decors,MBWMDecorTypeSouth)))
+ *south = d->height;
+ else
+ *south = SIMPLE_FRAME_EDGE_SIZE;
+
+ if (west)
+ if ((d = mb_wm_xml_decor_find_by_type (c->decors, MBWMDecorTypeWest)))
+ *west = d->width;
+ else
+ *west = SIMPLE_FRAME_EDGE_SIZE;
+
+ if (east)
+ if ((d = mb_wm_xml_decor_find_by_type (c->decors, MBWMDecorTypeEast)))
+ *east = d->width;
+ else
+ *east = SIMPLE_FRAME_EDGE_SIZE;
+
+ return;
+ }
+
+ /*
+ * These are defaults when no theme description was loaded
+ */
+ switch (c_type)
+ {
+ case MBWMClientTypeDialog:
+ case MBWMClientTypeApp:
+ if (north)
+ *north = SIMPLE_FRAME_TITLEBAR_HEIGHT;
+
+ if (south)
+ *south = SIMPLE_FRAME_EDGE_SIZE;
+
+ if (west)
+ *west = SIMPLE_FRAME_EDGE_SIZE;
+
+ if (east)
+ *east = SIMPLE_FRAME_EDGE_SIZE;
+ break;
+
+ case MBWMClientTypePanel:
+ case MBWMClientTypeDesktop:
+ case MBWMClientTypeInput:
+ default:
+ if (north)
+ *north = 0;
+
+ if (south)
+ *south = 0;
+
+ if (west)
+ *west = 0;
+
+ if (east)
+ *east = 0;
+ }
+}
+
+static unsigned long
+pixel_from_clr (Display * dpy, int screen, MBWMColor * clr)
+{
+ XColor xcol;
+
+ xcol.red = (int)(clr->r * (double)0xffff);
+ xcol.green = (int)(clr->g * (double)0xffff);
+ xcol.blue = (int)(clr->b * (double)0xffff);
+ xcol.flags = DoRed|DoGreen|DoBlue;
+
+ XAllocColor (dpy, DefaultColormap (dpy, screen), &xcol);
+
+ return xcol.pixel;
+}
+
+static XftFont *
+xft_load_font (MBWMDecor * decor, MBWMXmlDecor *d)
+{
+ char desc[512];
+ XftFont * font;
+ Display * xdpy = decor->parent_client->wmref->xdpy;
+ int xscreen = decor->parent_client->wmref->xscreen;
+ int font_size;
+
+ font_size = d && d->font_size ? d->font_size : SIMPLE_FRAME_TITLEBAR_HEIGHT / 2;
+
+ if (!d || d->font_units == MBWMXmlFontUnitsPixels)
+ {
+ font_size = mb_wm_util_pixels_to_points (decor->parent_client->wmref,
+ font_size);
+ }
+
+ snprintf (desc, sizeof (desc), "%s-%i",
+ d && d->font_family ? d->font_family : "Sans",
+ font_size);
+
+ font = XftFontOpenName (xdpy, xscreen, desc);
+
+ return font;
+}
+
+static void
+mb_wm_theme_simple_paint_decor (MBWMTheme *theme, MBWMDecor *decor)
+{
+ MBWMDecorType type;
+ const MBGeometry *geom;
+ MBWindowManagerClient *client;
+ Window xwin;
+ MBWindowManager *wm = theme->wm;
+ MBWMColor clr_bg;
+ MBWMColor clr_fg;
+ MBWMClientType c_type;
+ MBWMXmlClient *c = NULL;
+ MBWMXmlDecor *d = NULL;
+ struct DecorData *dd;
+ int x, y, w, h;
+ GC gc;
+ Display *xdpy = wm->xdpy;
+ int xscreen = wm->xscreen;
+ const char *title;
+
+ clr_fg.r = 1.0;
+ clr_fg.g = 1.0;
+ clr_fg.b = 1.0;
+
+ clr_bg.r = 0.5;
+ clr_bg.g = 0.5;
+ clr_bg.b = 0.5;
+
+ client = mb_wm_decor_get_parent (decor);
+ xwin = mb_wm_decor_get_x_window (decor);
+
+ if (client == NULL || xwin == None)
+ return;
+
+ dd = mb_wm_decor_get_theme_data (decor);
+
+ type = mb_wm_decor_get_type (decor);
+ geom = mb_wm_decor_get_geometry (decor);
+ c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+
+ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) &&
+ (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type)))
+ {
+ if (d->clr_fg.set)
+ {
+ clr_fg.r = d->clr_fg.r;
+ clr_fg.g = d->clr_fg.g;
+ clr_fg.b = d->clr_fg.b;
+ }
+
+ if (d->clr_bg.set)
+ {
+ clr_bg.r = d->clr_bg.r;
+ clr_bg.g = d->clr_bg.g;
+ clr_bg.b = d->clr_bg.b;
+ }
+ }
+
+ if (!dd)
+ {
+ XRenderColor rclr;
+
+ dd = malloc (sizeof (struct DecorData));
+ dd->xpix = XCreatePixmap(xdpy, xwin,
+ decor->geom.width, decor->geom.height,
+ DefaultDepth(xdpy, xscreen));
+
+ dd->xftdraw = XftDrawCreate (xdpy, dd->xpix,
+ DefaultVisual (xdpy, xscreen),
+ DefaultColormap (xdpy, xscreen));
+
+ rclr.red = (int)(clr_fg.r * (double)0xffff);
+ rclr.green = (int)(clr_fg.g * (double)0xffff);
+ rclr.blue = (int)(clr_fg.b * (double)0xffff);
+ rclr.alpha = 0xffff;
+
+ XftColorAllocValue (xdpy, DefaultVisual (xdpy, xscreen),
+ DefaultColormap (xdpy, xscreen),
+ &rclr, &dd->clr);
+
+ dd->font = xft_load_font (decor, d);
+
+ XSetWindowBackgroundPixmap(xdpy, xwin, dd->xpix);
+
+ mb_wm_decor_set_theme_data (decor, dd, decordata_free);
+ }
+
+ gc = XCreateGC (xdpy, dd->xpix, 0, NULL);
+
+ XSetLineAttributes (xdpy, gc, 1, LineSolid, CapProjecting, JoinMiter);
+ XSetBackground (xdpy, gc, pixel_from_clr (xdpy, xscreen, &clr_bg));
+ XSetForeground (xdpy, gc, pixel_from_clr (xdpy, xscreen, &clr_bg));
+
+ w = geom->width; h = geom->height; x = geom->x; y = geom->y;
+
+ XFillRectangle (xdpy, dd->xpix, gc, 0, 0, w, h);
+
+ if (mb_wm_decor_get_type(decor) == MBWMDecorTypeNorth &&
+ (title = mb_wm_client_get_name (client)))
+ {
+ XRectangle rec;
+
+ int pack_start_x = mb_wm_decor_get_pack_start_x (decor);
+ int pack_end_x = mb_wm_decor_get_pack_end_x (decor);
+ int west_width = mb_wm_client_frame_west_width (client);
+ int y = (decor->geom.height -
+ (dd->font->ascent + dd->font->descent)) / 2
+ + dd->font->ascent;
+
+ rec.x = 0;
+ rec.y = 0;
+ rec.width = pack_end_x - 2;
+ rec.height = d ? d->height : SIMPLE_FRAME_TITLEBAR_HEIGHT;
+
+ XftDrawSetClipRectangles (dd->xftdraw, 0, 0, &rec, 1);
+
+ XftDrawStringUtf8(dd->xftdraw,
+ &dd->clr,
+ dd->font,
+ west_width + pack_start_x + (h / 5), y,
+ title, strlen (title));
+ }
+
+ XFreeGC (xdpy, gc);
+
+ XClearWindow (xdpy, xwin);
+}
+
+static void
+mb_wm_theme_simple_paint_button (MBWMTheme *theme, MBWMDecorButton *button)
+{
+ MBWMDecor *decor;
+ MBWindowManagerClient *client;
+ Window xwin;
+ MBWindowManager *wm = theme->wm;
+ int x, y, w, h;
+ MBWMColor clr_bg;
+ MBWMColor clr_fg;
+ MBWMClientType c_type;
+ MBWMXmlClient *c = NULL;
+ MBWMXmlDecor *d = NULL;
+ MBWMXmlButton *b = NULL;
+ struct DecorData * dd;
+ GC gc;
+ Display *xdpy = wm->xdpy;
+ int xscreen = wm->xscreen;
+
+ clr_fg.r = 1.0;
+ clr_fg.g = 1.0;
+ clr_fg.b = 1.0;
+
+ clr_bg.r = 0.0;
+ clr_bg.g = 0.0;
+ clr_bg.b = 0.0;
+
+ decor = button->decor;
+ client = mb_wm_decor_get_parent (decor);
+ xwin = decor->xwin;
+ dd = mb_wm_decor_get_theme_data (decor);
+
+ if (client == NULL || xwin == None || dd->xpix == None)
+ return;
+
+ c_type = MB_WM_CLIENT_CLIENT_TYPE (client);
+
+ if ((c = mb_wm_xml_client_find_by_type (theme->xml_clients, c_type)) &&
+ (d = mb_wm_xml_decor_find_by_type (c->decors, decor->type)) &&
+ (b = mb_wm_xml_button_find_by_type (d->buttons, button->type)))
+ {
+ clr_fg.r = b->clr_fg.r;
+ clr_fg.g = b->clr_fg.g;
+ clr_fg.b = b->clr_fg.b;
+
+ clr_bg.r = b->clr_bg.r;
+ clr_bg.g = b->clr_bg.g;
+ clr_bg.b = b->clr_bg.b;
+ }
+
+ w = button->geom.width;
+ h = button->geom.height;
+ x = button->geom.x;
+ y = button->geom.y;
+
+ gc = XCreateGC (xdpy, dd->xpix, 0, NULL);
+
+ XSetLineAttributes (xdpy, gc, 1, LineSolid, CapRound, JoinRound);
+
+
+
+ if (button->state == MBWMDecorButtonStateInactive)
+ {
+ XSetForeground (xdpy, gc, pixel_from_clr (xdpy, xscreen, &clr_bg));
+ }
+ else
+ {
+ /* FIXME -- think of a better way of doing this */
+ MBWMColor clr;
+ clr.r = clr_bg.r + 0.2;
+ clr.g = clr_bg.g + 0.2;
+ clr.b = clr_bg.b + 0.2;
+
+ XSetForeground (xdpy, gc, pixel_from_clr (xdpy, xscreen, &clr));
+ }
+
+ XFillRectangle (xdpy, dd->xpix, gc, x, y, w+1, h+1);
+
+ XSetLineAttributes (xdpy, gc, 3, LineSolid, CapRound, JoinRound);
+ XSetForeground (xdpy, gc, pixel_from_clr (xdpy, xscreen, &clr_fg));
+
+ if (button->type == MBWMDecorButtonClose)
+ {
+ XDrawLine (xdpy, dd->xpix, gc, x + 3, y + 3, x + w - 3, y + h - 3);
+ XDrawLine (xdpy, dd->xpix, gc, x + 3, y + h - 3, x + w - 3, y + 3);
+ }
+ else if (button->type == MBWMDecorButtonFullscreen)
+ {
+ XDrawLine (xdpy, dd->xpix, gc, x + 3, y + 3, x + 3, y + h - 3);
+ XDrawLine (xdpy, dd->xpix, gc, x + 3, y + h - 3, x + w - 3, y + h - 3);
+ XDrawLine (xdpy, dd->xpix, gc, x + w - 3, y + h - 3, x + w - 3, y + 3);
+ XDrawLine (xdpy, dd->xpix, gc, x + w - 3, y + 3, x + 3, y + 3);
+ }
+ else if (button->type == MBWMDecorButtonMinimize)
+ {
+ XDrawLine (xdpy, dd->xpix, gc, x + 3, y + h - 5, x + w - 3, y + h - 5);
+ }
+ else if (button->type == MBWMDecorButtonHelp)
+ {
+ char desc[512];
+ XftFont *font;
+ XRenderColor rclr;
+ XftColor clr;
+ XRectangle rec;
+
+ snprintf (desc, sizeof (desc), "%s-%i:bold",
+ d && d->font_family ? d->font_family : "Sans", h*3/4);
+
+ font = XftFontOpenName (xdpy, xscreen, desc);
+
+ rclr.red = (int)(clr_fg.r * (double)0xffff);
+ rclr.green = (int)(clr_fg.g * (double)0xffff);
+ rclr.blue = (int)(clr_fg.b * (double)0xffff);
+ rclr.alpha = 0xffff;
+
+ XftColorAllocValue (xdpy, DefaultVisual (xdpy, xscreen),
+ DefaultColormap (xdpy, xscreen),
+ &rclr, &clr);
+
+ rec.x = x;
+ rec.y = y;
+ rec.width = w;
+ rec.height = h;
+
+ XftDrawSetClipRectangles (dd->xftdraw, 0, 0, &rec, 1);
+
+ XftDrawStringUtf8 (dd->xftdraw, &clr, font,
+ x + 4,
+ y + (h - (font->ascent + font->descent))/2 +
+ font->ascent,
+ "?", 1);
+
+ XftFontClose (xdpy, font);
+ }
+ else if (button->type == MBWMDecorButtonMenu)
+ {
+ XSetLineAttributes (xdpy, gc, 3, LineSolid, CapRound, JoinMiter);
+ XDrawLine (xdpy, dd->xpix, gc, x + 3, y + 5, x + w/2, y + h - 5);
+ XDrawLine (xdpy, dd->xpix, gc, x + w/2, y + h - 5, x + w - 3, y + 5);
+ }
+ else if (button->type == MBWMDecorButtonAccept)
+ {
+ XDrawArc (xdpy, dd->xpix, gc, x + 4, y + 4, w - 8, h - 8, 0, 64 * 360);
+ }
+
+ XFreeGC (xdpy, gc);
+
+ XClearWindow (wm->xdpy, xwin);
+}
+
+/*
+ * Installs a global handler that can be used to translate custom client type
+ * names to their numerical values.
+ *
+ * NB: this is not an object function, since we need it before we allocate the
+ * actual MBWMTheme object in the XML parser.
+ */
+void
+mb_wm_theme_set_custom_client_type_func (MBWMThemeCustomClientTypeFunc func,
+ void *user_data)
+{
+ custom_client_type_func = func;
+ custom_client_type_func_data = user_data;
+}
+
+/*
+ * Installs a global handler that can be used to translate custom theme names
+ * to their numerical (MBWMObject) values.
+ *
+ * NB: this is not an object function, since we need it before we allocate the
+ * actual MBWMTheme object in the XML parser.
+ */
+void
+mb_wm_theme_set_custom_theme_type_func (MBWMThemeCustomThemeTypeFunc func,
+ void *user_data)
+{
+ custom_theme_type_func = func;
+ custom_theme_type_func_data = user_data;
+}
+
+/*
+ * Installs a global handler that can be used to translate custom button names
+ * to their numerical values.
+ *
+ * NB: this is not an object function, since we need it before we allocate the
+ * actual MBWMTheme object in the XML parser.
+ */
+void
+mb_wm_theme_set_custom_button_type_func (MBWMThemeCustomButtonTypeFunc func,
+ void *user_data)
+{
+ custom_button_type_func = func;
+ custom_button_type_func_data = user_data;
+}
+
+/*
+ * Installs a global handler that can be used to allocate a custom
+ * MBWMThemeSubclass.
+ *
+ * NB: this is not an object function, since we need it before we allocate the
+ * actual MBWMTheme object in the XML parser.
+ */
+void
+mb_wm_theme_set_custom_theme_alloc_func (MBWMThemeCustomThemeAllocFunc func)
+{
+ custom_theme_alloc_func = func;
+}
diff --git a/matchbox2/theme-engines/mb-wm-theme.h b/matchbox2/theme-engines/mb-wm-theme.h
new file mode 100644
index 0000000..4c25297
--- /dev/null
+++ b/matchbox2/theme-engines/mb-wm-theme.h
@@ -0,0 +1,214 @@
+/*
+ * Matchbox Window Manager II - A lightweight window manager not for the
+ * desktop.
+ *
+ * Authored By Matthew Allum <mallum@o-hand.com>
+ *
+ * Copyright (c) 2005 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_THEME_H
+#define _HAVE_MB_WM_THEME_H
+
+#include <matchbox2/mb-wm-config.h>
+#include <matchbox2/core/mb-wm.h>
+
+#define MB_WM_THEME(c) ((MBWMTheme*)(c))
+#define MB_WM_THEME_CLASS(c) ((MBWMThemeClass*)(c))
+#define MB_WM_TYPE_THEME (mb_wm_theme_class_type ())
+
+#define MB_WM_THEME_PNG(c) ((MBWMThemePng*)(c))
+#define MB_WM_THEME_PNG_CLASS(c) ((MBWMThemePngClass*)(c))
+#define MB_WM_TYPE_THEME_PNG (mb_wm_theme_png_class_type ())
+
+enum MBWMThemeCaps
+{
+ MBWMThemeCapsFrameMainButtonActionAccept = (1<<0),
+ MBWMThemeCapsFrameDlgButtonActionAccept = (1<<1),
+ MBWMThemeCapsFrameMainButtonActionHelp = (1<<2),
+ MBWMThemeCapsFrameDlgButtonActionHelp = (1<<3),
+ MBWMThemeCapsFrameMainButtonActionCustom = (1<<4),
+ MBWMThemeCapsFrameDlgButtonActionCustom = (1<<5),
+};
+
+
+struct MBWMThemeClass
+{
+ MBWMObjectClass parent;
+
+ void (*paint_decor) (MBWMTheme *theme,
+ MBWMDecor *decor);
+
+ void (*paint_button) (MBWMTheme *theme,
+ MBWMDecorButton *button);
+
+ void (*decor_dimensions) (MBWMTheme *theme,
+ MBWindowManagerClient *client,
+ int *north,
+ int *south,
+ int *west,
+ int *east);
+
+ void (*button_size) (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type,
+ int *width,
+ int *height);
+
+ void (*button_position) (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type,
+ int *x,
+ int *y);
+
+ MBWMDecor* (*create_decor) (MBWMTheme *theme,
+ MBWindowManagerClient *client,
+ MBWMDecorType type);
+
+ void (*resize_decor) (MBWMTheme *theme,
+ MBWMDecor *decor);
+};
+
+struct MBWMTheme
+{
+ MBWMObject parent;
+
+ MBWindowManager *wm;
+ MBWMThemeCaps caps;
+ char *path;
+ MBWMList *xml_clients;
+
+ Bool compositing;
+ Bool shaped;
+ MBWMColor color_lowlight;
+ MBWMColor color_shadow;
+ MBWMCompMgrShadowType shadow_type;
+};
+
+int
+mb_wm_theme_class_type ();
+
+MBWMTheme *
+mb_wm_theme_new (MBWindowManager * wm, const char * theme_path);
+
+void
+mb_wm_theme_paint_decor (MBWMTheme *theme,
+ MBWMDecor *decor);
+
+void
+mb_wm_theme_paint_button (MBWMTheme *theme,
+ MBWMDecorButton *button);
+
+Bool
+mb_wm_theme_supports (MBWMTheme *theme,
+ MBWMThemeCaps capability);
+
+void
+mb_wm_theme_get_decor_dimensions (MBWMTheme *theme,
+ MBWindowManagerClient *client,
+ int *north,
+ int *south,
+ int *west,
+ int *east);
+
+void
+mb_wm_theme_get_button_size (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type,
+ int *width,
+ int *height);
+
+void
+mb_wm_theme_get_button_position (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type,
+ int *x,
+ int *y);
+
+Bool
+mb_wm_theme_is_button_press_activated (MBWMTheme *theme,
+ MBWMDecor *decor,
+ MBWMDecorButtonType type);
+
+MBWMDecor *
+mb_wm_theme_create_decor (MBWMTheme *theme,
+ MBWindowManagerClient *client,
+ MBWMDecorType type);
+
+void
+mb_wm_theme_resize_decor (MBWMTheme *theme,
+ MBWMDecor *decor);
+
+Bool
+mb_wm_theme_get_client_geometry (MBWMTheme * theme,
+ MBWindowManagerClient * client,
+ MBGeometry * geom);
+
+MBWMClientLayoutHints
+mb_wm_theme_get_client_layout_hints (MBWMTheme * theme,
+ MBWindowManagerClient * client);
+
+Bool
+mb_wm_theme_is_client_shaped (MBWMTheme * theme,
+ MBWindowManagerClient * client);
+
+void
+mb_wm_theme_get_lowlight_color (MBWMTheme * theme,
+ unsigned int * red,
+ unsigned int * green,
+ unsigned int * blue,
+ unsigned int * alpha);
+
+void
+mb_wm_theme_get_shadow_color (MBWMTheme * theme,
+ unsigned int * red,
+ unsigned int * green,
+ unsigned int * blue,
+ unsigned int * alpha);
+
+
+MBWMCompMgrShadowType
+mb_wm_theme_get_shadow_type (MBWMTheme * theme);
+
+Bool
+mb_wm_theme_use_compositing_mgr (MBWMTheme * theme);
+
+typedef unsigned int (*MBWMThemeCustomClientTypeFunc) (const char *type_name,
+ void *user_data);
+
+void
+mb_wm_theme_set_custom_client_type_func (MBWMThemeCustomClientTypeFunc func,
+ void *user_data);
+
+typedef unsigned int (*MBWMThemeCustomButtonTypeFunc) (const char *type_name,
+ void *user_data);
+
+void
+mb_wm_theme_set_custom_button_type_func (MBWMThemeCustomButtonTypeFunc func,
+ void *user_data);
+
+typedef unsigned int (*MBWMThemeCustomThemeTypeFunc) (const char *type_name,
+ void *user_data);
+
+void
+mb_wm_theme_set_custom_theme_type_func (MBWMThemeCustomThemeTypeFunc func,
+ void *user_data);
+
+
+typedef MBWMTheme * (*MBWMThemeCustomThemeAllocFunc) (int theme_type, ...);
+
+void
+mb_wm_theme_set_custom_theme_alloc_func (MBWMThemeCustomThemeAllocFunc func);
+
+#endif