Implement plugin engine to draw frame (Follow Master patch)
authorBenoît Gschwind <doth.gschwind@gmail.com>
Thu, 14 Feb 2008 02:06:12 +0000 (21:06 -0500)
committerDana Jansens <danakj@orodu.net>
Thu, 21 Feb 2008 17:05:24 +0000 (12:05 -0500)
61 files changed:
Makefile.am
configure.ac
engines/concept/config.c [new file with mode: 0644]
engines/concept/config.h [new file with mode: 0644]
engines/concept/plugin.c [new file with mode: 0644]
engines/concept/plugin.h [new file with mode: 0644]
engines/concept2/frame_concept2_config.c [new file with mode: 0644]
engines/concept2/frame_concept2_config.h [new file with mode: 0644]
engines/concept2/frame_concept2_plugin.c [new file with mode: 0644]
engines/concept2/frame_concept2_plugin.h [new file with mode: 0644]
engines/concept2/frame_concept2_render.c [new file with mode: 0644]
engines/concept2/frame_concept2_render.h [new file with mode: 0644]
engines/default/config.c [new file with mode: 0644]
engines/default/config.h [new file with mode: 0644]
engines/default/plugin.c [new file with mode: 0644]
engines/default/plugin.h [new file with mode: 0644]
engines/default/render.c [new file with mode: 0644]
engines/default/render.h [new file with mode: 0644]
engines/minimal/frame_minimal_config.c [new file with mode: 0644]
engines/minimal/frame_minimal_config.h [new file with mode: 0644]
engines/minimal/frame_minimal_plugin.c [new file with mode: 0644]
engines/minimal/frame_minimal_plugin.h [new file with mode: 0644]
engines/minimal/frame_minimal_render.c [new file with mode: 0644]
engines/minimal/frame_minimal_render.h [new file with mode: 0644]
openbox/actions.h
openbox/actions/growtoedge.c
openbox/actions/if.c
openbox/actions/moverelative.c
openbox/actions/moveresizeto.c
openbox/actions/movetoedge.c
openbox/actions/resize.c
openbox/actions/resizerelative.c
openbox/client.c
openbox/client_menu.c
openbox/engine_interface.c [new file with mode: 0644]
openbox/engine_interface.h [new file with mode: 0644]
openbox/event.c
openbox/focus_cycle.c
openbox/focus_cycle.h
openbox/focus_cycle_indicator.c
openbox/frame.c [deleted file]
openbox/frame.h [deleted file]
openbox/framerender.c [deleted file]
openbox/framerender.h [deleted file]
openbox/keyboard.c
openbox/keyboard.h
openbox/mouse.c
openbox/mouse.h
openbox/moveresize.c
openbox/moveresize.h
openbox/openbox.c
openbox/openbox.h
openbox/place.c
openbox/popup.c
openbox/resist.c
openbox/screen.c
openbox/stacking.c
openbox/window.c
openbox/window.h
render/theme.c
render/theme.h

index d8dba2c7a27cdbcfce52c614bc8e2632b88e0703..4b84842904d90efc4aaf1e97637b13563c4f631a 100644 (file)
@@ -26,7 +26,11 @@ check_PROGRAMS = \
 
 lib_LTLIBRARIES = \
        render/libobrender.la \
-       obt/libobt.la
+       obt/libobt.la \
+       engines/libconcept.la \
+       engines/libdefault.la
+#   engines/libconcept2.la \
+#      engines/libminimal.la
 
 bin_PROGRAMS = \
        openbox/openbox \
@@ -94,6 +98,144 @@ render_libobrender_la_SOURCES = \
        render/render.c \
        render/theme.h \
        render/theme.c
+## frame_default ##
+engines_libdefault_la_CPPFLAGS = \
+       $(X_CFLAGS) \
+       $(GLIB_CFLAGS) \
+       $(XML_CFLAGS) \
+       $(PANGO_CFLAGS) \
+       $(XFT_CFLAGS) \
+       -DG_LOG_DOMAIN=\"ObRender\" \
+       -DDEFAULT_THEME=\"$(theme)\"
+engines_libdefault_la_LDFLAGS = \
+       -version-info $(RR_CURRENT):$(RR_REVISION):$(RR_AGE)
+engines_libdefault_la_LIBADD = \
+       render/libobrender.la \
+       $(X_LIBS) \
+       $(PANGO_LIBS) \
+       $(XFT_LIBS) \
+       $(GLIB_LIBS) \
+       $(XML_LIBS)
+engines_libdefault_la_SOURCES = \
+       gettext.h \
+       render/color.h \
+       render/color.c \
+       render/font.h \
+       render/font.c \
+       render/geom.h \
+       render/gradient.h \
+       render/gradient.c \
+       render/icon.h \
+       render/image.h \
+       render/image.c \
+       render/instance.h \
+       render/instance.c \
+       render/mask.h \
+       render/mask.c \
+       render/render.h \
+       render/render.c \
+       openbox/engine_interface.h \
+       openbox/engine_interface.c \
+       engines/default/config.h \
+       engines/default/config.c \
+       engines/default/render.h \
+       engines/default/render.c \
+       engines/default/plugin.h \
+       engines/default/plugin.c
+
+## frame_minimal ##
+#engines_libminimal_la_CPPFLAGS = \
+#    $(X_CFLAGS) \
+#    $(GLIB_CFLAGS) \
+#    $(XML_CFLAGS) \
+#    $(PANGO_CFLAGS) \
+#    $(XFT_CFLAGS) \
+#    -DG_LOG_DOMAIN=\"ObRender\" \
+#    -DDEFAULT_THEME=\"$(theme)\"
+#engines_libminimal_la_LDFLAGS = \
+#    -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+#engines_libminimal_la_LIBADD = \
+#    parser/libobparser.la \
+#    $(X_LIBS) \
+#    $(PANGO_LIBS) \
+#    $(XFT_LIBS) \
+#    $(GLIB_LIBS) \
+#    $(XML_LIBS)
+#engines_libminimal_la_SOURCES = \
+#    gettext.h \
+#    render/color.h \
+#    render/color.c \
+#    render/font.h \
+#    render/font.c \
+#    render/geom.h \
+#    render/gradient.h \
+#    render/gradient.c \
+#    render/icon.h \
+#    render/image.h \
+#    render/image.c \
+#    render/instance.h \
+#    render/instance.c \
+#    render/mask.h \
+#    render/mask.c \
+#    render/render.h \
+#    render/render.c \
+#    openbox/engine_interface.h \
+#    openbox/engine_interface.c \
+#    engines/minimal/frame_minimal_config.h \
+#    engines/minimal/frame_minimal_config.c \
+#    engines/minimal/frame_minimal_render.h \
+#    engines/minimal/frame_minimal_render.c \
+#    engines/minimal/frame_minimal_plugin.h \
+#    engines/minimal/frame_minimal_plugin.c
+
+## frame_concept ##
+engines_libconcept_la_CPPFLAGS = \
+    $(X_CFLAGS) \
+    $(GLIB_CFLAGS) \
+    $(XML_CFLAGS) \
+    $(PANGO_CFLAGS) \
+    $(XFT_CFLAGS) \
+    $(IMLIB2_CFLAGS) \
+    $(GDK_PIXBUF_CFLAGS) \
+    $(GDK_PIXBUF_XLIB_CFLAGS) \
+    -DG_LOG_DOMAIN=\"ObRender\" \
+    -DDEFAULT_THEME=\"$(theme)\"
+engines_libconcept_la_LDFLAGS = \
+    -version-info $(RR_CURRENT):$(RR_REVISION):$(RR_AGE)
+engines_libconcept_la_LIBADD = \
+    render/libobrender.la \
+    $(X_LIBS) \
+    $(PANGO_LIBS) \
+    $(XFT_LIBS) \
+    $(GLIB_LIBS) \
+    $(IMLIB2_LIBS) \
+    $(GDK_PIXBUF_LIBS) \
+    $(GDK_PIXBUF_XLIB_LIBS) \
+    $(XML_LIBS)
+engines_libconcept_la_SOURCES = \
+    gettext.h \
+    render/color.h \
+    render/color.c \
+    render/font.h \
+    render/font.c \
+    render/geom.h \
+    render/gradient.h \
+    render/gradient.c \
+    render/icon.h \
+    render/image.h \
+    render/image.c \
+    render/instance.h \
+    render/instance.c \
+    render/mask.h \
+    render/mask.c \
+    render/render.h \
+    render/render.c \
+    openbox/engine_interface.h \
+    openbox/engine_interface.c \
+    engines/concept/config.h \
+    engines/concept/config.c \
+    engines/concept/plugin.h \
+    engines/concept/plugin.c
 
 ## obt ##
 
@@ -230,10 +372,8 @@ openbox_openbox_SOURCES = \
        openbox/focus_cycle_indicator.h \
        openbox/focus_cycle_popup.c \
        openbox/focus_cycle_popup.h \
-       openbox/frame.c \
-       openbox/frame.h \
-       openbox/framerender.c \
-       openbox/framerender.h \
+    openbox/engine_interface.h \
+    openbox/engine_interface.c \
        openbox/geom.h \
        openbox/grab.c \
        openbox/grab.h \
index 463e7fb352ac31e7885bc336b249e6f740b38992..4c5d2114ed318e16ab501d9489b34124ccdf4e71 100644 (file)
@@ -110,6 +110,14 @@ PKG_CHECK_MODULES(XML, [libxml-2.0 >= 2.6.0])
 AC_SUBST(XML_CFLAGS)
 AC_SUBST(XML_LIBS)
 
+PKG_CHECK_MODULES(GDK_PIXBUF, [gdk-pixbuf-2.0 >= 2.6.0])
+AC_SUBST(GDK_PIXBUF_CFLAGS)
+AC_SUBST(GDK_PIXBUF_LIBS)
+
+PKG_CHECK_MODULES(GDK_PIXBUF_XLIB, [gdk-pixbuf-xlib-2.0 >= 2.6.0])
+AC_SUBST(GDK_PIXBUF_XLIB_CFLAGS)
+AC_SUBST(GDK_PIXBUF_XLIB_LIBS)
+
 AC_ARG_ENABLE(startup-notification,
   AC_HELP_STRING(
     [--disable-startup-notification],
diff --git a/engines/concept/config.c b/engines/concept/config.c
new file mode 100644 (file)
index 0000000..b88348b
--- /dev/null
@@ -0,0 +1,432 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_config.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#include <X11/Xlib.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "render/render.h"
+#include "render/color.h"
+#include "render/font.h"
+#include "render/mask.h"
+#include "render/icon.h"
+#include "obt/parse.h"
+
+#include "config.h"
+#include "plugin.h"
+
+void load_pixmap(const gchar * theme_name, const gchar * base_name,
+        GdkPixbuf ** gp, Pixmap * p);
+static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value);
+static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value);
+static gboolean read_color(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrColor **value);
+static gboolean read_mask(const RrInstance *inst, const gchar *path,
+        ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value);
+static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrAppearance *value, gboolean allow_trans);
+static int parse_inline_number(const char *p);
+static RrPixel32* read_c_image(gint width, gint height, const guint8 *data);
+static void set_default_appearance(RrAppearance *a);
+
+gint load_theme_config(const RrInstance *inst, const gchar *name,
+        const gchar * path, XrmDatabase db, RrFont *active_window_font,
+        RrFont *inactive_window_font, RrFont *menu_title_font,
+        RrFont *menu_item_font, RrFont *osd_font)
+{
+    gchar *str;
+
+    if (!read_int(db, "concept.border_width", &theme_config.border_width)) {
+        theme_config.border_width = 2;
+    }
+    if (!read_color(db, inst, "concept.focus_border_color",
+            &theme_config.focus_border_color)) {
+        theme_config.focus_border_color = RrColorNew(inst, 0, 0, 0);
+    }
+
+    if (!read_color(db, inst, "concept.focus_corner_color",
+            &theme_config.focus_corner_color)) {
+        theme_config.focus_corner_color = RrColorNew(inst, 0, 0, 0);
+    }
+
+    if (!read_color(db, inst, "concept.unfocus_border_color",
+            &theme_config.unfocus_border_color)) {
+        theme_config.focus_border_color = RrColorNew(inst, 0, 0, 0);
+    }
+
+    if (!read_color(db, inst, "concept.unfocus_corner_color",
+            &theme_config.unfocus_corner_color)) {
+        theme_config.focus_corner_color = RrColorNew(inst, 0, 0, 0);
+    }
+
+    theme_config.inst = inst;
+    theme_config.name = g_strdup(name ? name : DEFAULT_THEME);
+
+    gdk_pixbuf_xlib_init(plugin.ob_display, plugin.ob_screen);
+
+    load_pixmap(name, "focus-top.png", &theme_config.focus_top,
+            &theme_config.px_focus_top);
+    load_pixmap(name, "focus-left.png", &theme_config.focus_left,
+            &theme_config.px_focus_left);
+    load_pixmap(name, "focus-right.png", &theme_config.focus_right,
+            &theme_config.px_focus_right);
+    load_pixmap(name, "focus-bottom.png", &theme_config.focus_bottom,
+            &theme_config.px_focus_bottom);
+
+    load_pixmap(name, "unfocus-top.png", &theme_config.unfocus_top,
+            &theme_config.px_unfocus_top);
+    load_pixmap(name, "unfocus-left.png", &theme_config.unfocus_left,
+            &theme_config.px_unfocus_left);
+    load_pixmap(name, "unfocus-right.png", &theme_config.unfocus_right,
+            &theme_config.px_unfocus_right);
+    load_pixmap(name, "unfocus-bottom.png", &theme_config.unfocus_bottom,
+            &theme_config.px_unfocus_bottom);
+
+    load_pixmap(name, "focus-topleft.png", &theme_config.focus_topleft,
+            &theme_config.px_focus_topleft);
+    load_pixmap(name, "focus-bottomleft.png", &theme_config.focus_bottomleft,
+            &theme_config.px_focus_bottomleft);
+    load_pixmap(name, "focus-topright.png", &theme_config.focus_topright,
+            &theme_config.px_focus_topright);
+    load_pixmap(name, "focus-bottomright.png", &theme_config.focus_bottomright,
+            &theme_config.px_focus_bottomright);
+
+    load_pixmap(name, "unfocus-topleft.png", &theme_config.unfocus_topleft,
+            &theme_config.px_unfocus_topleft);
+    load_pixmap(name, "unfocus-bottomleft.png",
+            &theme_config.unfocus_bottomleft,
+            &theme_config.px_unfocus_bottomleft);
+    load_pixmap(name, "unfocus-topright.png", &theme_config.unfocus_topright,
+            &theme_config.px_unfocus_topright);
+    load_pixmap(name, "unfocus-bottomright.png",
+            &theme_config.unfocus_bottomright,
+            &theme_config.px_unfocus_bottomright);
+
+    return 1;
+}
+
+void load_pixmap(const gchar * theme_name, const gchar * base_name,
+        GdkPixbuf ** gp, Pixmap * p)
+{
+    gchar * s = g_build_filename(g_get_home_dir(), ".themes", theme_name,
+            "openbox-3", base_name, NULL);
+    ob_debug("Load file %s.\n", s);
+    *gp = gdk_pixbuf_new_from_file(s, NULL);
+    //GdkPixbuff * mask = NULL;
+    gdk_pixbuf_xlib_render_pixmap_and_mask(*gp, p, NULL, 128);
+    g_free(s);
+}
+
+static gchar *create_class_name(const gchar *rname)
+{
+    gchar *rclass = g_strdup(rname);
+    gchar *p = rclass;
+
+    while (TRUE) {
+        *p = toupper(*p);
+        p = strchr(p+1, '.');
+        if (p == NULL)
+            break;
+        ++p;
+        if (*p == '\0')
+            break;
+    }
+    return rclass;
+}
+
+static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype, *end;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        *value = (gint)strtol(retvalue.addr, &end, 10);
+        if (end != retvalue.addr)
+            ret = TRUE;
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        *value = retvalue.addr;
+        ret = TRUE;
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_color(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrColor **value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        RrColor *c = RrColorParse(inst, retvalue.addr);
+        if (c != NULL) {
+            *value = c;
+            ret = TRUE;
+        }
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_mask(const RrInstance *inst, const gchar *path,
+        ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value)
+{
+    gboolean ret = FALSE;
+    gchar *s;
+    gint hx, hy; /* ignored */
+    guint w, h;
+    guchar *b;
+
+    s = g_build_filename(path, maskname, NULL);
+    if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) {
+        ret = TRUE;
+        *value = RrPixmapMaskNew(inst, w, h, (gchar*)b);
+        XFree(b);
+    }
+    g_free(s);
+
+    return ret;
+}
+
+static void parse_appearance(gchar *tex, RrSurfaceColorType *grad,
+        RrReliefType *relief, RrBevelType *bevel, gboolean *interlaced,
+        gboolean *border, gboolean allow_trans)
+{
+    gchar *t;
+
+    /* convert to all lowercase */
+    for (t = tex; *t != '\0'; ++t)
+        *t = g_ascii_tolower(*t);
+
+    if (allow_trans && strstr(tex, "parentrelative") != NULL) {
+        *grad = RR_SURFACE_PARENTREL;
+    }
+    else {
+        if (strstr(tex, "gradient") != NULL) {
+            if (strstr(tex, "crossdiagonal") != NULL)
+                *grad = RR_SURFACE_CROSS_DIAGONAL;
+            else if (strstr(tex, "pyramid") != NULL)
+                *grad = RR_SURFACE_PYRAMID;
+            else if (strstr(tex, "mirrorhorizontal") != NULL)
+                *grad = RR_SURFACE_MIRROR_HORIZONTAL;
+            else if (strstr(tex, "horizontal") != NULL)
+                *grad = RR_SURFACE_HORIZONTAL;
+            else if (strstr(tex, "splitvertical") != NULL)
+                *grad = RR_SURFACE_SPLIT_VERTICAL;
+            else if (strstr(tex, "vertical") != NULL)
+                *grad = RR_SURFACE_VERTICAL;
+            else
+                *grad = RR_SURFACE_DIAGONAL;
+        }
+        else {
+            *grad = RR_SURFACE_SOLID;
+        }
+    }
+
+    if (strstr(tex, "sunken") != NULL)
+        *relief = RR_RELIEF_SUNKEN;
+    else if (strstr(tex, "flat") != NULL)
+        *relief = RR_RELIEF_FLAT;
+    else if (strstr(tex, "raised") != NULL)
+        *relief = RR_RELIEF_RAISED;
+    else
+        *relief = (*grad == RR_SURFACE_PARENTREL) ? RR_RELIEF_FLAT
+                : RR_RELIEF_RAISED;
+
+    *border = FALSE;
+    if (*relief == RR_RELIEF_FLAT) {
+        if (strstr(tex, "border") != NULL)
+            *border = TRUE;
+    }
+    else {
+        if (strstr(tex, "bevel2") != NULL)
+            *bevel = RR_BEVEL_2;
+        else
+            *bevel = RR_BEVEL_1;
+    }
+
+    if (strstr(tex, "interlaced") != NULL)
+        *interlaced = TRUE;
+    else
+        *interlaced = FALSE;
+}
+
+static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrAppearance *value, gboolean allow_trans)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *cname, *ctoname, *bcname, *icname, *hname, *sname;
+    gchar *csplitname, *ctosplitname;
+    gchar *rettype;
+    XrmValue retvalue;
+    gint i;
+
+    cname = g_strconcat(rname, ".color", NULL);
+    ctoname = g_strconcat(rname, ".colorTo", NULL);
+    bcname = g_strconcat(rname, ".border.color", NULL);
+    icname = g_strconcat(rname, ".interlace.color", NULL);
+    hname = g_strconcat(rname, ".highlight", NULL);
+    sname = g_strconcat(rname, ".shadow", NULL);
+    csplitname = g_strconcat(rname, ".color.splitTo", NULL);
+    ctosplitname = g_strconcat(rname, ".colorTo.splitTo", NULL);
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        parse_appearance(retvalue.addr, &value->surface.grad,
+                &value->surface.relief, &value->surface.bevel,
+                &value->surface.interlaced, &value->surface.border, allow_trans);
+        if (!read_color(db, inst, cname, &value->surface.primary))
+            value->surface.primary = RrColorNew(inst, 0, 0, 0);
+        if (!read_color(db, inst, ctoname, &value->surface.secondary))
+            value->surface.secondary = RrColorNew(inst, 0, 0, 0);
+        if (value->surface.border)
+            if (!read_color(db, inst, bcname, &value->surface.border_color))
+                value->surface.border_color = RrColorNew(inst, 0, 0, 0);
+        if (value->surface.interlaced)
+            if (!read_color(db, inst, icname, &value->surface.interlace_color))
+                value->surface.interlace_color = RrColorNew(inst, 0, 0, 0);
+        if (read_int(db, hname, &i) && i >= 0)
+            value->surface.bevel_light_adjust = i;
+        if (read_int(db, sname, &i) && i >= 0 && i <= 256)
+            value->surface.bevel_dark_adjust = i;
+
+        if (value->surface.grad == RR_SURFACE_SPLIT_VERTICAL) {
+            gint r, g, b;
+
+            if (!read_color(db, inst, csplitname, &value->surface.split_primary)) {
+                r = value->surface.primary->r;
+                r += r >> 2;
+                g = value->surface.primary->g;
+                g += g >> 2;
+                b = value->surface.primary->b;
+                b += b >> 2;
+                if (r > 0xFF)
+                    r = 0xFF;
+                if (g > 0xFF)
+                    g = 0xFF;
+                if (b > 0xFF)
+                    b = 0xFF;
+                value->surface.split_primary = RrColorNew(inst, r, g, b);
+            }
+
+            if (!read_color(db, inst, ctosplitname,
+                    &value->surface.split_secondary)) {
+                r = value->surface.secondary->r;
+                r += r >> 4;
+                g = value->surface.secondary->g;
+                g += g >> 4;
+                b = value->surface.secondary->b;
+                b += b >> 4;
+                if (r > 0xFF)
+                    r = 0xFF;
+                if (g > 0xFF)
+                    g = 0xFF;
+                if (b > 0xFF)
+                    b = 0xFF;
+                value->surface.split_secondary = RrColorNew(inst, r, g, b);
+            }
+        }
+
+        ret = TRUE;
+    }
+
+    g_free(ctosplitname);
+    g_free(csplitname);
+    g_free(sname);
+    g_free(hname);
+    g_free(icname);
+    g_free(bcname);
+    g_free(ctoname);
+    g_free(cname);
+    g_free(rclass);
+    return ret;
+}
+
+static int parse_inline_number(const char *p)
+{
+    int neg = 1;
+    int res = 0;
+    if (*p == '-') {
+        neg = -1;
+        ++p;
+    }
+    for (; isdigit(*p); ++p)
+        res = res * 10 + *p - '0';
+    res *= neg;
+    return res;
+}
+
+static void set_default_appearance(RrAppearance *a)
+{
+    a->surface.grad = RR_SURFACE_SOLID;
+    a->surface.relief = RR_RELIEF_FLAT;
+    a->surface.bevel = RR_BEVEL_1;
+    a->surface.interlaced = FALSE;
+    a->surface.border = FALSE;
+    a->surface.primary = RrColorNew(a->inst, 0, 0, 0);
+    a->surface.secondary = RrColorNew(a->inst, 0, 0, 0);
+}
+
+/* Reads the output from gimp's C-Source file format into valid RGBA data for
+ an RrTextureRGBA. */
+static RrPixel32* read_c_image(gint width, gint height, const guint8 *data)
+{
+    RrPixel32 *im, *p;
+    gint i;
+
+    p = im = g_memdup(data, width * height * sizeof(RrPixel32));
+
+    for (i = 0; i < width * height; ++i) {
+        guchar a = ((*p >> 24) & 0xff);
+        guchar b = ((*p >> 16) & 0xff);
+        guchar g = ((*p >> 8) & 0xff);
+        guchar r = ((*p >> 0) & 0xff);
+
+        *p = ((r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset) + (b
+                << RrDefaultBlueOffset) + (a << RrDefaultAlphaOffset));
+        p++;
+    }
+
+    return im;
+}
diff --git a/engines/concept/config.h b/engines/concept/config.h
new file mode 100644 (file)
index 0000000..d328fb7
--- /dev/null
@@ -0,0 +1,92 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_config.h for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+#ifndef FRAME_CONCEPT_CONFIG_H_
+#define FRAME_CONCEPT_CONFIG_H_
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <X11/Xresource.h>
+#include "render/render.h"
+
+G_BEGIN_DECLS
+
+struct _ObFrameThemeConfig
+{
+    const RrInstance *inst;
+
+    gint border_width;
+    RrColor * focus_border_color;
+    RrColor * focus_corner_color;
+    RrColor * unfocus_border_color;
+    RrColor * unfocus_corner_color;
+
+    GdkPixbuf * focus_top;
+    GdkPixbuf * focus_left;
+    GdkPixbuf * focus_right;
+    GdkPixbuf * focus_bottom;
+
+    GdkPixbuf * focus_topleft;
+    GdkPixbuf * focus_bottomleft;
+    GdkPixbuf * focus_topright;
+    GdkPixbuf * focus_bottomright;
+
+    GdkPixbuf * unfocus_top;
+    GdkPixbuf * unfocus_left;
+    GdkPixbuf * unfocus_right;
+    GdkPixbuf * unfocus_bottom;
+
+    GdkPixbuf * unfocus_topleft;
+    GdkPixbuf * unfocus_bottomleft;
+    GdkPixbuf * unfocus_topright;
+    GdkPixbuf * unfocus_bottomright;
+
+    Pixmap px_focus_top;
+    Pixmap px_focus_left;
+    Pixmap px_focus_right;
+    Pixmap px_focus_bottom;
+
+    Pixmap px_focus_topleft;
+    Pixmap px_focus_bottomleft;
+    Pixmap px_focus_topright;
+    Pixmap px_focus_bottomright;
+
+    Pixmap px_unfocus_top;
+    Pixmap px_unfocus_left;
+    Pixmap px_unfocus_right;
+    Pixmap px_unfocus_bottom;
+
+    Pixmap px_unfocus_topleft;
+    Pixmap px_unfocus_bottomleft;
+    Pixmap px_unfocus_topright;
+    Pixmap px_unfocus_bottomright;
+
+    gchar *name;
+};
+
+typedef struct _ObFrameThemeConfig ObFrameThemeConfig;
+
+/*! The font values are all optional. If a NULL is used for any of them, then
+ the default font will be used. */
+gint load_theme_config(const RrInstance *inst, const gchar *name,
+        const gchar * path, XrmDatabase db, RrFont *active_window_font,
+        RrFont *inactive_window_font, RrFont *menu_title_font,
+        RrFont *menu_item_font, RrFont *osd_font);
+
+G_END_DECLS
+
+#endif /*FRAME_CONCEPT_CONFIG_H_*/
diff --git a/engines/concept/plugin.c b/engines/concept/plugin.c
new file mode 100644 (file)
index 0000000..30f52e6
--- /dev/null
@@ -0,0 +1,1158 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_plugin.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#include "openbox/client.h"
+#include "openbox/openbox.h"
+#include "openbox/prop.h"
+#include "openbox/grab.h"
+#include "openbox/config.h"
+#include "obt/mainloop.h"
+#include "openbox/focus_cycle.h"
+#include "openbox/focus_cycle_indicator.h"
+#include "openbox/moveresize.h"
+#include "openbox/screen.h"
+#include "render/theme.h"
+
+#include "plugin.h"
+
+typedef enum
+{
+    OB_FLAG_MAX = 1 << 0,
+    OB_FLAG_CLOSE = 1 << 1,
+    OB_FLAG_DESK = 1 << 2,
+    OB_FLAG_SHADE = 1 << 3,
+    OB_FLAG_ICONIFY = 1 << 4
+} ObFrameFlags;
+
+#define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
+                         ButtonPressMask | ButtonReleaseMask | \
+                         SubstructureRedirectMask | FocusChangeMask)
+#define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
+                           ButtonMotionMask | PointerMotionMask | \
+                           EnterWindowMask | LeaveWindowMask)
+
+#define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
+#define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
+
+#define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_b)
+
+static gulong frame_animate_iconify_time_left(gpointer _self,
+        const GTimeVal *now);
+
+Window createWindow(Window parent, Visual *visual, gulong mask,
+        XSetWindowAttributes *attrib)
+{
+    return XCreateWindow(plugin.ob_display, parent, 0, 0, 1, 1, 0, (visual ? 32
+            : RrDepth(plugin.ob_rr_inst)), InputOutput, (visual ? visual
+            : RrVisual(plugin.ob_rr_inst)), mask, attrib);
+
+}
+
+Visual *check_32bit_client(ObClient *c)
+{
+    XWindowAttributes wattrib;
+    Status ret;
+
+    /* we're already running at 32 bit depth, yay. we don't need to use their
+     visual */
+    if (RrDepth(plugin.ob_rr_inst) == 32)
+        return NULL;
+
+    ret = XGetWindowAttributes(plugin.ob_display, c->window, &wattrib);
+    g_assert(ret != BadDrawable);
+    g_assert(ret != BadWindow);
+
+    if (wattrib.depth == 32)
+        return wattrib.visual;
+    return NULL;
+}
+
+/* Not used */
+gint init(Display * display, gint screen)
+{
+    plugin.ob_display = display;
+    plugin.ob_screen = screen;
+}
+
+/* Create a frame */
+gpointer frame_new(struct _ObClient * client)
+{
+    XSetWindowAttributes attrib;
+    gulong mask;
+    ObConceptFrame *self;
+    Visual *visual;
+
+    self = g_new0(ObConceptFrame, 1);
+    self->client = client;
+
+    visual = check_32bit_client(client);
+
+    /* create the non-visible decor windows */
+
+    mask = 0;
+    if (visual) {
+        /* client has a 32-bit visual */
+        mask |= CWColormap | CWBackPixel | CWBorderPixel;
+        /* create a colormap with the visual */
+        OBCONCEPTFRAME(self)->colormap = attrib.colormap = XCreateColormap(
+                plugin.ob_display, RootWindow(plugin.ob_display,
+                        plugin.ob_screen), visual, AllocNone);
+        attrib.background_pixel = BlackPixel(plugin.ob_display,
+                plugin.ob_screen);
+        attrib.border_pixel = BlackPixel(plugin.ob_display, plugin.ob_screen);
+    }
+    self->window = createWindow(
+            RootWindow(plugin.ob_display, plugin.ob_screen), visual, mask,
+            &attrib);
+
+    /* create the visible decor windows */
+
+    mask = 0;
+    if (visual) {
+        /* client has a 32-bit visual */
+        mask |= CWColormap | CWBackPixel | CWBorderPixel;
+        attrib.colormap = RrColormap(plugin.ob_rr_inst);
+    }
+
+    self->background = createWindow(self->window, NULL, mask, &attrib);
+
+    mask |= CWEventMask;
+    attrib.event_mask = ELEMENT_EVENTMASK;
+
+    self->title = createWindow(self->window, NULL, mask, &attrib);
+
+    self->top = createWindow(self->window, NULL, mask, &attrib);
+    self->bottom = createWindow(self->window, NULL, mask, &attrib);
+    self->left = createWindow(self->window, NULL, mask, &attrib);
+    self->right = createWindow(self->window, NULL, mask, &attrib);
+
+    self->top_left = createWindow(self->window, NULL, mask, &attrib);
+    self->top_right = createWindow(self->window, NULL, mask, &attrib);
+    self->bottom_left = createWindow(self->window, NULL, mask, &attrib);
+    self->bottom_right = createWindow(self->window, NULL, mask, &attrib);
+
+    XMapWindow(plugin.ob_display, self->background);
+
+    self->focused = FALSE;
+
+    self->hover_flag = OB_BUTTON_NONE;
+    self->press_flag = OB_BUTTON_NONE;
+
+    set_theme_statics(self);
+
+    return self;
+}
+
+void set_theme_statics(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    /* do this before changing the frame's status like max_horz max_vert */
+
+    XResizeWindow(plugin.ob_display, self->top_left, 5, 5);
+    XResizeWindow(plugin.ob_display, self->top_right, 5, 5);
+    XResizeWindow(plugin.ob_display, self->bottom_left, 5, 5);
+    XResizeWindow(plugin.ob_display, self->bottom_right, 5, 5);
+}
+
+void free_theme_statics(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+}
+
+void frame_free(gpointer self)
+{
+    free_theme_statics(OBCONCEPTFRAME(self));
+    XDestroyWindow(plugin.ob_display, OBCONCEPTFRAME(self)->window);
+    if (OBCONCEPTFRAME(self)->colormap)
+        XFreeColormap(plugin.ob_display, OBCONCEPTFRAME(self)->colormap);
+    g_free(self);
+}
+
+void frame_show(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    if (!self->visible) {
+        self->visible = TRUE;
+        frame_update_skin(self);
+        /* Grab the server to make sure that the frame window is mapped before
+         the client gets its MapNotify, i.e. to make sure the client is
+         _visible_ when it gets MapNotify. */
+        grab_server(TRUE);
+        XMapWindow(plugin.ob_display, self->client->window);
+        XMapWindow(plugin.ob_display, self->window);
+        grab_server(FALSE);
+    }
+}
+
+gint frame_hide(gpointer self)
+{
+    if (OBCONCEPTFRAME(self)->visible) {
+        OBCONCEPTFRAME(self)->visible = FALSE;
+        if (!frame_iconify_animating(self))
+            XUnmapWindow(plugin.ob_display, OBCONCEPTFRAME(self)->window);
+        /* we unmap the client itself so that we can get MapRequest
+         events, and because the ICCCM tells us to! */
+        XUnmapWindow(plugin.ob_display, OBCONCEPTFRAME(self)->client->window);
+        /* We ignore 1 unmap */
+        return 1;
+    }
+    else
+        return 0;
+}
+
+void frame_adjust_theme(gpointer self)
+{
+    free_theme_statics(self);
+    set_theme_statics(self);
+}
+
+void frame_adjust_shape(gpointer _self)
+{
+#ifdef SHAPE
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    gint num;
+    XRectangle xrect[2];
+
+    if (!self->client->shaped)
+    {
+        /* clear the shape on the frame window */
+        XShapeCombineMask(plugin.ob_display, self->window, ShapeBounding,
+                self->size.left,
+                self->size.top,
+                None, ShapeSet);
+    }
+    else
+    {
+        /* make the frame's shape match the clients */
+        XShapeCombineShape(plugin.ob_display, self->window, ShapeBounding,
+                self->size.left,
+                self->size.top,
+                self->client->window,
+                ShapeBounding, ShapeSet);
+
+        num = 0;
+        if (self->decorations)
+        {
+            xrect[0].x = 0;
+            xrect[0].y = 0;
+            xrect[0].width = self->window_area.width;
+            xrect[0].height = self->size.top;
+            ++num;
+        }
+
+        XShapeCombineRectangles(plugin.ob_display, self->window,
+                ShapeBounding, 0, 0, xrect, num,
+                ShapeUnion, Unsorted);
+    }
+#endif
+}
+
+void frame_grab(gpointer _self, GHashTable * map)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    /* DO NOT map the client window here. we used to do that, but it is bogus.
+     we need to set up the client's dimensions and everything before we
+     send a mapnotify or we create race conditions.
+     */
+
+    /* reparent the client to the frame */
+    XReparentWindow(plugin.ob_display, self->client->window, self->window, 0, 0);
+
+    /*
+     When reparenting the client window, it is usually not mapped yet, since
+     this occurs from a MapRequest. However, in the case where Openbox is
+     starting up, the window is already mapped, so we'll see an unmap event
+     for it.
+     */
+    if (ob_state() == OB_STATE_STARTING)
+        ++self->client->ignore_unmaps;
+
+    /* select the event mask on the client's parent (to receive config/map
+     req's) the ButtonPress is to catch clicks on the client border */
+    XSelectInput(plugin.ob_display, self->window, FRAME_EVENTMASK);
+
+    /* set all the windows for the frame in the window_map */
+    g_hash_table_insert(map, &self->window, self->client);
+
+    g_hash_table_insert(map, &self->title, self->client);
+
+    g_hash_table_insert(map, &self->left, self->client);
+    g_hash_table_insert(map, &self->right, self->client);
+    g_hash_table_insert(map, &self->top, self->client);
+    g_hash_table_insert(map, &self->bottom, self->client);
+
+    g_hash_table_insert(map, &self->top_left, self->client);
+    g_hash_table_insert(map, &self->top_right, self->client);
+    g_hash_table_insert(map, &self->bottom_left, self->client);
+    g_hash_table_insert(map, &self->bottom_right, self->client);
+
+}
+
+void frame_ungrab(gpointer _self, GHashTable * map)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    XEvent ev;
+    gboolean reparent = TRUE;
+
+    /* if there was any animation going on, kill it */
+    obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
+            frame_animate_iconify, self, FALSE);
+
+    /* check if the app has already reparented its window away */
+    while (XCheckTypedWindowEvent(plugin.ob_display, self->client->window,
+            ReparentNotify, &ev)) {
+        /* This check makes sure we don't catch our own reparent action to
+         our frame window. This doesn't count as the app reparenting itself
+         away of course.
+
+         Reparent events that are generated by us are just discarded here.
+         They are of no consequence to us anyhow.
+         */
+        if (ev.xreparent.parent != self->window) {
+            reparent = FALSE;
+            XPutBackEvent(plugin.ob_display, &ev);
+            break;
+        }
+    }
+
+    if (reparent) {
+        /* according to the ICCCM - if the client doesn't reparent itself,
+         then we will reparent the window to root for them */
+        XReparentWindow(plugin.ob_display, self->client->window, RootWindow(
+                plugin.ob_display, plugin.ob_screen), self->client->area.x,
+                self->client->area.y);
+    }
+
+    /* remove all the windows for the frame from the window_map */
+    g_hash_table_remove(map, &self->window);
+
+    g_hash_table_remove(map, &self->title);
+
+    g_hash_table_remove(map, &self->left);
+    g_hash_table_remove(map, &self->right);
+    g_hash_table_remove(map, &self->top);
+    g_hash_table_remove(map, &self->bottom);
+
+    g_hash_table_remove(map, &self->top_left);
+    g_hash_table_remove(map, &self->top_right);
+    g_hash_table_remove(map, &self->bottom_left);
+    g_hash_table_remove(map, &self->bottom_right);
+
+    obt_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
+            TRUE);
+}
+
+ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
+{
+    /* Here because client can be NULL */
+    ObConceptFrame *self = OBCONCEPTFRAME(_self);
+
+    if (self->shaded)
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    if (win == self->title)
+        return OB_FRAME_CONTEXT_TITLEBAR;
+
+    if (win == self->window)
+        return OB_FRAME_CONTEXT_FRAME;
+
+    if (win == self->bottom)
+        return OB_FRAME_CONTEXT_BOTTOM;
+
+    if (win == self->bottom_left)
+        return OB_FRAME_CONTEXT_BLCORNER;
+
+    if (win == self->bottom_right)
+        return OB_FRAME_CONTEXT_BRCORNER;
+
+    if (win == self->top)
+        return OB_FRAME_CONTEXT_TOP;
+
+    if (win == self->top_left)
+        return OB_FRAME_CONTEXT_TLCORNER;
+
+    if (win == self->top_right)
+        return OB_FRAME_CONTEXT_TRCORNER;
+
+    if (win == self->left)
+        return OB_FRAME_CONTEXT_LEFT;
+    if (win == self->right)
+        return OB_FRAME_CONTEXT_RIGHT;
+
+    return OB_FRAME_CONTEXT_NONE;
+}
+
+void frame_set_is_visible(gpointer self, gboolean b)
+{
+    OBCONCEPTFRAME(self)->visible = b;
+    if (b) {
+        OBCONCEPTFRAME(self)->frame_stase_flags |= OB_FRAME_STASE_IS_VISIBLE;
+    }
+    else {
+        OBCONCEPTFRAME(self)->frame_stase_flags &= ~OB_FRAME_STASE_IS_VISIBLE;
+    }
+}
+
+void frame_set_is_focus(gpointer self, gboolean b)
+{
+    OBCONCEPTFRAME(self)->focused = b;
+    if (b) {
+        OBCONCEPTFRAME(self)->frame_stase_flags |= OB_FRAME_STASE_IS_FOCUS;
+    }
+    else {
+        OBCONCEPTFRAME(self)->frame_stase_flags &= ~OB_FRAME_STASE_IS_FOCUS;
+    }
+}
+
+void frame_set_is_max_vert(gpointer self, gboolean b)
+{
+    OBCONCEPTFRAME(self)->max_vert = b;
+    if (b) {
+        OBCONCEPTFRAME(self)->frame_stase_flags |= OB_FRAME_STASE_IS_MAX_VERT;
+    }
+    else {
+        OBCONCEPTFRAME(self)->frame_stase_flags &= ~OB_FRAME_STASE_IS_MAX_VERT;
+    }
+}
+
+void frame_set_is_max_horz(gpointer self, gboolean b)
+{
+    OBCONCEPTFRAME(self)->max_horz = b;
+    if (b) {
+        OBCONCEPTFRAME(self)->frame_stase_flags |= OB_FRAME_STASE_IS_MAX_HORZ;
+    }
+    else {
+        OBCONCEPTFRAME(self)->frame_stase_flags &= ~OB_FRAME_STASE_IS_MAX_HORZ;
+    }
+}
+
+void frame_set_is_shaded(gpointer self, gboolean b)
+{
+    OBCONCEPTFRAME(self)->shaded = b;
+    if (b) {
+        OBCONCEPTFRAME(self)->frame_stase_flags |= OB_FRAME_STASE_IS_SHADED;
+    }
+    else {
+        OBCONCEPTFRAME(self)->frame_stase_flags &= ~OB_FRAME_STASE_IS_SHADED;
+    }
+}
+
+void frame_unfocus(gpointer self)
+{
+    OBCONCEPTFRAME(self)->focused = FALSE;
+}
+
+void frame_flash_start(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->flash_on = self->focused;
+
+    if (!self->flashing)
+        obt_main_loop_timeout_add(plugin.ob_main_loop, G_USEC_PER_SEC * 0.6,
+                flash_timeout, self, g_direct_equal, flash_done);
+    g_get_current_time(&self->flash_end);
+    g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
+
+    self->flashing = TRUE;
+}
+
+void frame_flash_stop(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->flashing = FALSE;
+}
+
+void frame_begin_iconify_animation(gpointer _self, gboolean iconifying)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    gulong time;
+    gboolean new_anim = FALSE;
+    gboolean set_end = TRUE;
+    GTimeVal now;
+
+    /* if there is no titlebar, just don't animate for now
+     XXX it would be nice tho.. */
+    if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
+        return;
+
+    /* get the current time */
+    g_get_current_time(&now);
+
+    /* get how long until the end */
+    time = FRAME_ANIMATE_ICONIFY_TIME;
+    if (self->iconify_animation_going) {
+        if (!!iconifying != (self->iconify_animation_going > 0)) {
+            /* animation was already going on in the opposite direction */
+            time = time - frame_animate_iconify_time_left(self, &now);
+        }
+        else
+            /* animation was already going in the same direction */
+            set_end = FALSE;
+    }
+    else
+        new_anim = TRUE;
+    self->iconify_animation_going = iconifying ? 1 : -1;
+
+    /* set the ending time */
+    if (set_end) {
+        self->iconify_animation_end.tv_sec = now.tv_sec;
+        self->iconify_animation_end.tv_usec = now.tv_usec;
+        g_time_val_add(&self->iconify_animation_end, time);
+    }
+
+    if (new_anim) {
+        obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
+                frame_animate_iconify, self, FALSE);
+        obt_main_loop_timeout_add(plugin.ob_main_loop,
+        FRAME_ANIMATE_ICONIFY_STEP_TIME, frame_animate_iconify, self,
+                g_direct_equal, NULL);
+
+        /* do the first step */
+        frame_animate_iconify(self);
+
+        /* show it during the animation even if it is not "visible" */
+        if (!self->visible)
+            XMapWindow(plugin.ob_display, self->window);
+    }
+}
+
+void frame_end_iconify_animation(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    /* see if there is an animation going */
+    if (self->iconify_animation_going == 0)
+        return;
+
+    if (!self->visible)
+        XUnmapWindow(plugin.ob_display, self->window);
+    else {
+        /* Send a ConfigureNotify when the animation is done, this fixes
+         KDE's pager showing the window in the wrong place.  since the
+         window is mapped at a different location and is then moved, we
+         need to send the synthetic configurenotify, since apps may have
+         read the position when the client mapped, apparently. */
+        client_reconfigure(self->client, TRUE);
+    }
+
+    /* we're not animating any more ! */
+    self->iconify_animation_going = 0;
+
+    XMoveResizeWindow(plugin.ob_display, self->window, self->window_area.x,
+            self->window_area.y, self->window_area.width,
+            self->window_area.height);
+    /* we delay re-rendering until after we're done animating */
+    frame_update_skin(self);
+    XFlush(plugin.ob_display);
+}
+
+gboolean frame_iconify_animating(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    return self->iconify_animation_going != 0;
+}
+
+void frame_set_decorations(gpointer self, ObFrameDecorations d)
+{
+    OBCONCEPTFRAME(self)->decorations = d;
+}
+
+Rect frame_get_window_area(gpointer self)
+{
+    return OBCONCEPTFRAME(self)->window_area;
+}
+void frame_set_client_area(gpointer self, Rect r)
+{
+    OBCONCEPTFRAME(self)->client_area = r;
+}
+
+void frame_update_layout(gpointer _self, gboolean is_resize, gboolean is_fake)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+
+    /* do this before changing the frame's status like max_horz max_vert */
+    frame_adjust_cursors(self);
+
+    if (self->decorations && !self->shaded) {
+        self->cbwidth_l = 5;
+        self->cbwidth_r = 5;
+        self->cbwidth_t = 5;
+        self->cbwidth_b = 5;
+
+        self->title_width = 20;
+
+        STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t, self->cbwidth_r
+                + self->title_width, self->cbwidth_b);
+
+        RECT_SET_SIZE(self->window_area, self->client_area.width
+                + self->size.left + self->size.right, self->client_area.height
+                + self->size.top + self->size.bottom);
+
+        if (!is_fake) {
+
+            XMoveResizeWindow(plugin.ob_display, self->top, 5, 0,
+                    self->window_area.width - 10, theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->top);
+
+            XMoveResizeWindow(plugin.ob_display, self->bottom, 5,
+                    self->window_area.height - theme_config.border_width,
+                    self->window_area.width - 10, theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->bottom);
+
+            XMoveResizeWindow(plugin.ob_display, self->left, 0,
+                    theme_config.border_width, theme_config.border_width,
+                    self->window_area.height - 2*theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->left);
+
+            XMoveResizeWindow(plugin.ob_display, self->right,
+                    self->window_area.width - theme_config.border_width,
+                    theme_config.border_width, theme_config.border_width,
+                    self->window_area.height - 2 *theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->right);
+
+            XMoveWindow(plugin.ob_display, self->top_left, 0, 0);
+            XMapWindow(plugin.ob_display, self->top_left);
+            XMoveWindow(plugin.ob_display, self->top_right,
+                    self->window_area.width - 5, 0);
+            XMapWindow(plugin.ob_display, self->top_right);
+            XMoveWindow(plugin.ob_display, self->bottom_left, 0,
+                    self->window_area.height - theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->bottom_left);
+            XMoveWindow(plugin.ob_display, self->bottom_right,
+                    self->window_area.width - 5, self->window_area.height
+                            - theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->bottom_right);
+
+            XMoveResizeWindow(plugin.ob_display, self->title,
+                    self->window_area.width - theme_config.border_width
+                            - self->title_width, theme_config.border_width,
+                    self->title_width, self->window_area.height - 2
+                            *theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->title);
+
+            /* find the new coordinates, done after setting the frame.size, for
+             frame_client_gravity. */
+            self->window_area.x = self->client_area.x;
+            self->window_area.y = self->client_area.y;
+            frame_client_gravity(self->client, &self->window_area.x,
+                    &self->window_area.y);
+
+            XMoveResizeWindow(plugin.ob_display, self->background,
+                    theme_config.border_width, theme_config.border_width,
+                    self->window_area.width - 2 * theme_config.border_width
+                            - self->title_width, self->window_area.height - 2
+                            * theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->background);
+
+            if (!is_resize) {
+                XMoveResizeWindow(plugin.ob_display, self->client->window,
+                        self->size.left, self->size.top,
+                        self->window_area.width - self->size.left
+                                - self->size.right, self->window_area.height
+                                - self->size.top - self->size.bottom);
+            }
+            XMoveResizeWindow(plugin.ob_display, self->window,
+                    self->window_area.x, self->window_area.y,
+                    self->window_area.width, self->window_area.height);
+
+        }
+    }
+    else if (self->shaded) {
+        self->cbwidth_l = 0;
+        self->cbwidth_r = 0;
+        self->cbwidth_b = 0;
+        self->cbwidth_t = 0;
+
+        self->title_width = 20;
+
+        STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t, self->cbwidth_r
+                + self->title_width, self->cbwidth_b);
+
+        RECT_SET_SIZE(self->window_area, 30, 30);
+
+        /* find the new coordinates, done after setting the frame.size, for
+         frame_client_gravity. */
+        frame_client_gravity(self->client, &self->window_area.x,
+                &self->window_area.y);
+
+        if (!is_fake) {
+            XUnmapWindow(plugin.ob_display, self->top);
+            XUnmapWindow(plugin.ob_display, self->bottom);
+            XUnmapWindow(plugin.ob_display, self->left);
+            XUnmapWindow(plugin.ob_display, self->right);
+            XUnmapWindow(plugin.ob_display, self->top_left);
+            XUnmapWindow(plugin.ob_display, self->top_right);
+            XUnmapWindow(plugin.ob_display, self->bottom_left);
+            XUnmapWindow(plugin.ob_display, self->bottom_right);
+
+            XUnmapWindow(plugin.ob_display, self->title);
+
+            XMoveResizeWindow(plugin.ob_display, self->background, 0, 0, 30, 30);
+            XMapWindow(plugin.ob_display, self->background);
+
+            XMoveWindow(plugin.ob_display, self->window, 35, 35);
+            XResizeWindow(plugin.ob_display, self->window, 30, 30);
+        }
+    }
+    else // No decord :)
+    {
+        self->cbwidth_l = 0;
+        self->cbwidth_r = 0;
+        self->cbwidth_b = 0;
+        self->cbwidth_t = 0;
+        STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t,
+                self->cbwidth_r, self->cbwidth_b);
+
+        RECT_SET_SIZE(self->window_area, self->client->area.width
+                + self->size.left + self->size.right, self->client->area.height
+                + self->size.top + self->size.bottom);
+
+        /* find the new coordinates, done after setting the frame.size, for
+         frame_client_gravity. */
+        self->window_area.x = self->client_area.x;
+        self->window_area.y = self->client_area.y;
+        frame_client_gravity(self->client, &self->window_area.x,
+                &self->window_area.y);
+
+        if (!is_fake) {
+            XUnmapWindow(plugin.ob_display, self->top);
+            XUnmapWindow(plugin.ob_display, self->bottom);
+            XUnmapWindow(plugin.ob_display, self->left);
+            XUnmapWindow(plugin.ob_display, self->right);
+            XUnmapWindow(plugin.ob_display, self->top_left);
+            XUnmapWindow(plugin.ob_display, self->top_right);
+            XUnmapWindow(plugin.ob_display, self->bottom_left);
+            XUnmapWindow(plugin.ob_display, self->bottom_right);
+
+            XUnmapWindow(plugin.ob_display, self->title);
+
+            XMoveResizeWindow(plugin.ob_display, self->background, 0, 0,
+                    self->window_area.width, self->window_area.height);
+            XMapWindow(plugin.ob_display, self->background);
+            if (!is_resize) {
+                XMoveResizeWindow(plugin.ob_display, self->client->window,
+                        self->size.left, self->size.top,
+                        self->window_area.width, self->window_area.height);
+            }
+            XMoveResizeWindow(plugin.ob_display, self->window,
+                    self->window_area.x, self->window_area.y,
+                    self->window_area.width, self->window_area.height);
+        }
+    }
+}
+
+void frame_update_skin(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    if (plugin.frame_iconify_animating(self))
+        return; /* delay redrawing until the animation is done */
+
+    if (!self->visible)
+        return;
+    self->need_render = FALSE;
+
+    gulong border_px, corner_px;
+
+    if (self->focused) {
+        border_px = RrColorPixel(theme_config.focus_border_color);
+        corner_px = RrColorPixel(theme_config.focus_corner_color);
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->left,
+                theme_config.px_focus_left);
+        XClearWindow(plugin.ob_display, self->left);
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->right,
+                theme_config.px_focus_right);
+        XClearWindow(plugin.ob_display, self->right);
+
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->top,
+                theme_config.px_focus_top);
+        XClearWindow(plugin.ob_display, self->top);
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom,
+                theme_config.px_focus_bottom);
+        XClearWindow(plugin.ob_display, self->bottom);
+
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->top_left,
+                theme_config.px_focus_topleft);
+        XClearWindow(plugin.ob_display, self->top_left);
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->top_right,
+                theme_config.px_focus_topright);
+        XClearWindow(plugin.ob_display, self->top_right);
+
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom_left,
+                theme_config.px_focus_bottomleft);
+        XClearWindow(plugin.ob_display, self->bottom_left);
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom_right,
+                theme_config.px_focus_bottomright);
+        XClearWindow(plugin.ob_display, self->bottom_right);
+
+        XSetWindowBackground(plugin.ob_display, self->title, 0x00ffff);
+        XClearWindow(plugin.ob_display, self->title);
+        XSetWindowBackground(plugin.ob_display, self->background, 0);
+        XClearWindow(plugin.ob_display, self->background);
+    }
+    else {
+        border_px = RrColorPixel(theme_config.unfocus_border_color);
+        corner_px = RrColorPixel(theme_config.unfocus_corner_color);
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->left,
+                theme_config.px_unfocus_left);
+        XClearWindow(plugin.ob_display, self->left);
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->right,
+                theme_config.px_unfocus_right);
+        XClearWindow(plugin.ob_display, self->right);
+
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->top,
+                theme_config.px_unfocus_top);
+        XClearWindow(plugin.ob_display, self->top);
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom,
+                theme_config.px_unfocus_bottom);
+        XClearWindow(plugin.ob_display, self->bottom);
+
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->top_left,
+                theme_config.px_unfocus_topleft);
+        XClearWindow(plugin.ob_display, self->top_left);
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->top_right,
+                theme_config.px_unfocus_topright);
+        XClearWindow(plugin.ob_display, self->top_right);
+
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom_left,
+                theme_config.px_unfocus_bottomleft);
+        XClearWindow(plugin.ob_display, self->bottom_left);
+        XSetWindowBackgroundPixmap(plugin.ob_display, self->bottom_right,
+                theme_config.px_unfocus_bottomright);
+        XClearWindow(plugin.ob_display, self->bottom_right);
+
+        XSetWindowBackground(plugin.ob_display, self->title, 0x00ffff);
+        XClearWindow(plugin.ob_display, self->title);
+        XSetWindowBackground(plugin.ob_display, self->background, 0);
+        XClearWindow(plugin.ob_display, self->background);
+    }
+    XFlush(plugin.ob_display);
+}
+
+void frame_set_hover_flag(gpointer self, ObFrameButton button)
+{
+    if (OBCONCEPTFRAME(self)->hover_flag != button) {
+        OBCONCEPTFRAME(self)->hover_flag = button;
+        frame_update_skin(self);
+    }
+}
+
+void frame_set_press_flag(gpointer self, ObFrameButton button)
+{
+    if (OBCONCEPTFRAME(self)->press_flag != button) {
+        OBCONCEPTFRAME(self)->press_flag = button;
+        frame_update_skin(self);
+    }
+}
+
+Window frame_get_window(gpointer self)
+{
+    return OBCONCEPTFRAME(self)->window;
+}
+
+Strut frame_get_size(gpointer self)
+{
+    return OBCONCEPTFRAME(self)->size;
+}
+
+gint frame_get_decorations(gpointer self)
+{
+    return OBCONCEPTFRAME(self)->decorations;
+}
+
+gboolean frame_is_visible(gpointer self)
+{
+    return OBCONCEPTFRAME(self)->visible;
+}
+
+gboolean frame_is_max_horz(gpointer self)
+{
+    return OBCONCEPTFRAME(self)->max_horz;
+}
+
+gboolean frame_is_max_vert(gpointer self)
+{
+    return OBCONCEPTFRAME(self)->max_vert;
+}
+
+static gulong frame_animate_iconify_time_left(gpointer _self,
+        const GTimeVal *now)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    glong sec, usec;
+    sec = self->iconify_animation_end.tv_sec - now->tv_sec;
+    usec = self->iconify_animation_end.tv_usec - now->tv_usec;
+    if (usec < 0) {
+        usec += G_USEC_PER_SEC;
+        sec--;
+    }
+    /* no negative values */
+    return MAX(sec * G_USEC_PER_SEC + usec, 0);
+}
+
+gboolean frame_animate_iconify(gpointer p)
+{
+    ObConceptFrame *self = p;
+    gint x, y, w, h;
+    gint iconx, icony, iconw;
+    GTimeVal now;
+    gulong time;
+    gboolean iconifying;
+
+    if (self->client->icon_geometry.width == 0) {
+        /* there is no icon geometry set so just go straight down */
+        Rect
+                *a =
+                        screen_physical_area_monitor(screen_find_monitor(&self->window_area));
+        iconx = self->window_area.x + self->window_area.width / 2 + 32;
+        icony = a->y + a->width;
+        iconw = 64;
+        g_free(a);
+    }
+    else {
+        iconx = self->client->icon_geometry.x;
+        icony = self->client->icon_geometry.y;
+        iconw = self->client->icon_geometry.width;
+    }
+
+    iconifying = self->iconify_animation_going > 0;
+
+    /* how far do we have left to go ? */
+    g_get_current_time(&now);
+    time = frame_animate_iconify_time_left(self, &now);
+
+    if (time == 0 || iconifying) {
+        /* start where the frame is supposed to be */
+        x = self->window_area.x;
+        y = self->window_area.y;
+        w = self->window_area.width;
+        h = self->window_area.height;
+    }
+    else {
+        /* start at the icon */
+        x = iconx;
+        y = icony;
+        w = iconw;
+        h = self->size.top; /* just the titlebar */
+    }
+
+    if (time > 0) {
+        glong dx, dy, dw;
+        glong elapsed;
+
+        dx = self->window_area.x - iconx;
+        dy = self->window_area.y - icony;
+        dw = self->window_area.width - iconw;
+        /* if restoring, we move in the opposite direction */
+        if (!iconifying) {
+            dx = -dx;
+            dy = -dy;
+            dw = -dw;
+        }
+
+        elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
+        x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        h = self->size.top; /* just the titlebar */
+    }
+
+    if (time == 0)
+        frame_end_iconify_animation(self);
+    else {
+        XMoveResizeWindow(plugin.ob_display, self->window, x, y, w, h);
+        XFlush(plugin.ob_display);
+    }
+
+    return time > 0; /* repeat until we're out of time */
+}
+
+/* change the cursor */
+void frame_adjust_cursors(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+
+    XSetWindowAttributes a;
+    a.cursor = ob_cursor(OB_CURSOR_NORTH);
+    XChangeWindowAttributes(plugin.ob_display, self->top, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_SOUTH);
+    XChangeWindowAttributes(plugin.ob_display, self->bottom, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_WEST);
+    XChangeWindowAttributes(plugin.ob_display, self->left, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_EAST);
+    XChangeWindowAttributes(plugin.ob_display, self->right, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_NORTHWEST);
+    XChangeWindowAttributes(plugin.ob_display, self->top_left, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_NORTHEAST);
+    XChangeWindowAttributes(plugin.ob_display, self->top_right, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_SOUTHWEST);
+    XChangeWindowAttributes(plugin.ob_display, self->bottom_left, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_SOUTHEAST);
+    XChangeWindowAttributes(plugin.ob_display, self->bottom_right, CWCursor, &a);
+
+}
+
+void frame_adjust_client_area(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    /* adjust the window which is there to prevent flashing on unmap */
+    XMoveResizeWindow(plugin.ob_display, self->background, 0, 0,
+            self->client->area.width, self->client->area.height);
+}
+
+void frame_adjust_state(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->need_render = TRUE;
+    frame_update_skin(self);
+}
+
+void frame_adjust_focus(gpointer _self, gboolean hilite)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->focused = hilite;
+    self->need_render = TRUE;
+    frame_update_skin(self);
+    XFlush(plugin.ob_display);
+}
+
+void frame_adjust_title(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->need_render = TRUE;
+    frame_update_skin(self);
+}
+
+void frame_adjust_icon(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->need_render = TRUE;
+    frame_update_skin(self);
+}
+
+/* is there anything present between us and the label? */
+static gboolean is_button_present(ObConceptFrame *_self, const gchar *lc,
+        gint dir)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
+        if (*lc == ' ')
+            continue; /* it was invalid */
+        if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
+            return TRUE;
+        if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
+            return TRUE;
+        if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
+            return TRUE;
+        if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
+            return TRUE;
+        if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
+            return TRUE;
+        if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
+            return TRUE;
+        if (*lc == 'L')
+            return FALSE;
+    }
+    return FALSE;
+}
+
+void flash_done(gpointer data)
+{
+    ObConceptFrame *self = data;
+
+    if (self->focused != self->flash_on)
+        frame_adjust_focus(self, self->focused);
+}
+
+gboolean flash_timeout(gpointer data)
+{
+    ObConceptFrame *self = data;
+    GTimeVal now;
+
+    g_get_current_time(&now);
+    if (now.tv_sec > self->flash_end.tv_sec
+            || (now.tv_sec == self->flash_end.tv_sec && now.tv_usec
+                    >= self->flash_end.tv_usec))
+        self->flashing = FALSE;
+
+    if (!self->flashing)
+        return FALSE; /* we are done */
+
+    self->flash_on = !self->flash_on;
+    if (!self->focused) {
+        frame_adjust_focus(self, self->flash_on);
+        self->focused = FALSE;
+    }
+
+    return TRUE; /* go again */
+}
+
+ObFramePlugin plugin = { 0, //gpointer handler;
+        "libconcept.la", //gchar * filename;
+        "Concept", //gchar * name;
+        init, //gint (*init) (Display * display, gint screen);
+        0, frame_new, //gpointer (*frame_new) (struct _ObClient *c);
+        frame_free, //void (*frame_free) (gpointer self);
+        frame_show, //void (*frame_show) (gpointer self);
+        frame_hide, //void (*frame_hide) (gpointer self);
+        frame_adjust_theme, //void (*frame_adjust_theme) (gpointer self);
+        frame_adjust_shape, //void (*frame_adjust_shape) (gpointer self);
+        frame_grab, //void (*frame_adjust_area) (gpointer self, gboolean moved, gboolean resized, gboolean fake);
+        frame_ungrab, frame_context, //void (*frame_adjust_state) (gpointer self);
+        frame_set_is_visible, frame_set_is_focus, frame_set_is_max_vert,
+                frame_set_is_max_horz, frame_set_is_shaded,
+
+        frame_flash_start, frame_flash_stop, frame_begin_iconify_animation,
+                frame_end_iconify_animation, frame_iconify_animating,
+
+        frame_set_decorations,
+        /* This give the window area */
+        frame_get_window_area, frame_set_client_area,
+        /* Draw the frame */
+        frame_update_layout, frame_update_skin,
+
+        frame_set_hover_flag, frame_set_press_flag,
+
+        frame_get_window,
+
+        frame_get_size, frame_get_decorations,
+
+        frame_is_visible, frame_is_max_horz, frame_is_max_vert,
+
+        load_theme_config,
+
+        /* This fields are fill by openbox. */
+        0, //Display * ob_display;
+        0, //gint ob_screen;
+        0, //RrInstance *ob_rr_inst;
+        0, //gboolean config_theme_keepborder;
+        0, //struct _ObClient *focus_cycle_target;
+        0, //gchar *config_title_layout;
+        FALSE, //gboolean moveresize_in_progress;
+        0, //struct _ObMainLoop *ob_main_loop;
+};
+
+ObFramePlugin * get_info()
+{
+    return &plugin;
+}
diff --git a/engines/concept/plugin.h b/engines/concept/plugin.h
new file mode 100644 (file)
index 0000000..0f22499
--- /dev/null
@@ -0,0 +1,198 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_plugin.h for the Openbox window manager
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+#ifndef FRAME_CONCEPT_PLUGIN_H_
+#define FRAME_CONCEPT_PLUGIN_H_
+
+#include "config.h"
+
+#include "render/render.h"
+#include "openbox/engine_interface.h"
+
+ObFrameThemeConfig theme_config;
+
+typedef enum {
+    OB_FRAME_STASE_IS_VISIBLE = 1 << 0,
+    OB_FRAME_STASE_IS_FOCUS = 1 << 1,
+    OB_FRAME_STASE_IS_MAX_VERT = 1 << 2,
+    OB_FRAME_STASE_IS_MAX_HORZ = 1 << 3,
+    OB_FRAME_STASE_IS_SHADED = 1 << 4
+} ObFrameStaseFlags;
+
+struct _ObConceptFrame
+{
+    /* PUBLIC : */
+
+    /* PRIVATE: */
+    /* You are free to add what you want here */
+    Window window;
+
+    gboolean visible;
+
+    gboolean max_horz; /* when maxed some decorations are hidden */
+    gboolean max_vert; /* when maxed some decorations are hidden */
+
+    struct _ObClient *client;
+    guint decorations;
+
+    Strut size;
+    Rect client_area; /* the area of the client window */
+    Rect window_area; /* the area of the window with/without decorations */
+
+    ObFrameButton hover_flag;
+    ObFrameButton press_flag;
+
+    ObStyle style;
+
+    guint functions;
+
+    gint iconify_animation_going;
+    /* These are borders of the frame and its elements */
+
+    Window title;
+
+    Window top;
+    Window bottom;
+    Window left;
+    Window right;
+
+    Window top_left;
+    Window top_right;
+
+    Window bottom_left;
+    Window bottom_right;
+
+    Window background;
+
+    Colormap colormap;
+
+    RrAppearance *a_unfocused_title;
+    RrAppearance *a_focused_title;
+    RrAppearance *a_unfocused_label;
+    RrAppearance *a_focused_label;
+    RrAppearance *a_icon;
+    RrAppearance *a_unfocused_handle;
+    RrAppearance *a_focused_handle;
+
+    gint icon_on; /* if the window icon button is on */
+    gint label_on; /* if the window title is on */
+    gint iconify_on; /* if the window iconify button is on */
+    gint desk_on; /* if the window all-desktops button is on */
+    gint shade_on; /* if the window shade button is on */
+    gint max_on; /* if the window maximize button is on */
+    gint close_on; /* if the window close button is on */
+
+    gint title_width; /* width of the titlebar and handle */
+
+    gint label_width; /* width of the label in the titlebar */
+    gint icon_x; /* x-position of the window icon button */
+    gint label_x; /* x-position of the window title */
+    gint iconify_x; /* x-position of the window iconify button */
+    gint desk_x; /* x-position of the window all-desktops button */
+    gint shade_x; /* x-position of the window shade button */
+    gint max_x; /* x-position of the window maximize button */
+    gint close_x; /* x-position of the window close button */
+
+    gint cbwidth_l; /* client border width */
+    gint cbwidth_t; /* client border width */
+    gint cbwidth_r; /* client border width */
+    gint cbwidth_b; /* client border width */
+    gboolean shaded; /* decorations adjust when shaded */
+
+    /* the leftmost and rightmost elements in the titlebar */
+    ObFrameContext leftmost;
+    ObFrameContext rightmost;
+
+    gboolean focused;
+    gboolean need_render;
+
+    gboolean flashing;
+    gboolean flash_on;
+    GTimeVal flash_end;
+
+    GTimeVal iconify_animation_end;
+
+    ObFrameStaseFlags frame_stase_flags;
+
+};
+
+typedef struct _ObConceptFrame ObConceptFrame;
+
+/* Function use for interface */
+gint init(Display *, gint);
+
+gpointer frame_new(struct _ObClient *c);
+void frame_free(gpointer self);
+
+void frame_show(gpointer self);
+gint frame_hide(gpointer self);
+
+void frame_adjust_theme(gpointer self);
+void frame_adjust_shape(gpointer self);
+
+void frame_grab(gpointer self, GHashTable *);
+void frame_ungrab(gpointer self, GHashTable *);
+
+ObFrameContext frame_context(gpointer, Window, gint, gint);
+
+void frame_set_is_visible(gpointer, gboolean);
+void frame_set_is_focus(gpointer, gboolean);
+void frame_set_is_max_vert(gpointer, gboolean);
+void frame_set_is_max_horz(gpointer, gboolean);
+void frame_set_is_shaded(gpointer, gboolean);
+
+void frame_flash_start(gpointer self);
+void frame_flash_stop(gpointer self);
+void frame_begin_iconify_animation(gpointer self, gboolean iconifying);
+void frame_end_iconify_animation(gpointer self);
+gboolean frame_iconify_animating(gpointer _self);
+
+/* Set the layout wanted by client */
+void frame_update_state(gpointer, ObFrameState);
+/* This give the allowed area for client window */
+Rect frame_get_window_area(gpointer);
+void frame_set_client_area(gpointer, Rect);
+/* Draw the frame */
+void frame_update_layout(gpointer, gboolean, gboolean);
+void frame_update_skin(gpointer);
+
+void frame_set_hover_flag(gpointer, ObFrameButton);
+void frame_set_press_flag(gpointer, ObFrameButton);
+
+Window frame_get_window(gpointer);
+
+Strut frame_get_size(gpointer);
+
+gint frame_get_decorations(gpointer);
+
+gboolean frame_is_visible(gpointer);
+gboolean frame_is_max_horz(gpointer);
+gboolean frame_is_max_vert(gpointer);
+
+/* Internal function */
+void flash_done(gpointer data);
+gboolean flash_timeout(gpointer data);
+void set_theme_statics(gpointer self);
+void free_theme_statics(gpointer self);
+gboolean frame_animate_iconify(gpointer self);
+void frame_adjust_cursors(gpointer self);
+
+/* Global for frame_concept_render.c only */
+extern ObFramePlugin plugin;
+#define OBCONCEPTFRAME(x) ((ObConceptFrame *)(x))
+
+#endif /*FRAME_CONCEPT_PLUGIN_H_*/
diff --git a/engines/concept2/frame_concept2_config.c b/engines/concept2/frame_concept2_config.c
new file mode 100644 (file)
index 0000000..de77cc8
--- /dev/null
@@ -0,0 +1,421 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_config.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#include "frame_concept2_config.h"
+#include "frame_concept2_plugin.h"
+
+#include "render/render.h"
+#include "render/color.h"
+#include "render/font.h"
+#include "render/mask.h"
+#include "render/icon.h"
+#include "parser/parse.h"
+
+#include <X11/Xlib.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+static XrmDatabase loaddb(const gchar *name, gchar **path);
+static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value);
+static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value);
+static gboolean read_color(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrColor **value);
+static gboolean read_mask(const RrInstance *inst, const gchar *path,
+        ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value);
+static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrAppearance *value, gboolean allow_trans);
+static int parse_inline_number(const char *p);
+static RrPixel32* read_c_image(gint width, gint height, const guint8 *data);
+static void set_default_appearance(RrAppearance *a);
+
+gint load_theme_config(const RrInstance *inst, const gchar *name,
+        const gchar * path, XrmDatabase db, RrFont *active_window_font,
+        RrFont *inactive_window_font, RrFont *menu_title_font,
+        RrFont *menu_item_font, RrFont *osd_font)
+{
+    gchar *str;
+
+    if (!read_int(db, "concept.border_width", &theme_config.border_width)) {
+        theme_config.border_width = 2;
+    }
+    if (!read_int(db, "concept.left_width", &theme_config.left_width)) {
+        theme_config.left_width = 15;
+    }
+    if (!read_color(db, inst, "concept.focus_border_color",
+            &theme_config.focus_border_color)) {
+        theme_config.focus_border_color = RrColorNew(inst, 0, 0, 0);
+    }
+
+    if (!read_color(db, inst, "concept.focus_corner_color",
+            &theme_config.focus_corner_color)) {
+        theme_config.focus_corner_color = RrColorNew(inst, 0, 0, 0);
+    }
+
+    if (!read_color(db, inst, "concept.unfocus_border_color",
+            &theme_config.unfocus_border_color)) {
+        theme_config.focus_border_color = RrColorNew(inst, 0, 0, 0);
+    }
+
+    if (!read_color(db, inst, "concept.unfocus_corner_color",
+            &theme_config.unfocus_corner_color)) {
+        theme_config.focus_corner_color = RrColorNew(inst, 0, 0, 0);
+    }
+
+    theme_config.inst = inst;
+    theme_config.name = g_strdup(name ? name : DEFAULT_THEME);
+
+    return 1;
+}
+
+static XrmDatabase loaddb(const gchar *name, gchar **path)
+{
+    GSList *it;
+    XrmDatabase db = NULL;
+    gchar *s;
+
+    if (name[0] == '/') {
+        s = g_build_filename(name, "openbox-3", "themerc", NULL);
+        if ((db = XrmGetFileDatabase(s)))
+            *path = g_path_get_dirname(s);
+        g_free(s);
+    }
+    else {
+        /* XXX backwards compatibility, remove me sometime later */
+        s = g_build_filename(g_get_home_dir(), ".themes", name, "openbox-3",
+                "themerc", NULL);
+        if ((db = XrmGetFileDatabase(s)))
+            *path = g_path_get_dirname(s);
+        g_free(s);
+
+        for (it = parse_xdg_data_dir_paths(); !db && it; it = g_slist_next(it)) {
+            s = g_build_filename(it->data, "themes", name, "openbox-3",
+                    "themerc", NULL);
+            if ((db = XrmGetFileDatabase(s)))
+                *path = g_path_get_dirname(s);
+            g_free(s);
+        }
+    }
+
+    if (db == NULL) {
+        s = g_build_filename(name, "themerc", NULL);
+        if ((db = XrmGetFileDatabase(s)))
+            *path = g_path_get_dirname(s);
+        g_free(s);
+    }
+
+    return db;
+}
+
+static gchar *create_class_name(const gchar *rname)
+{
+    gchar *rclass = g_strdup(rname);
+    gchar *p = rclass;
+
+    while (TRUE) {
+        *p = toupper(*p);
+        p = strchr(p+1, '.');
+        if (p == NULL)
+            break;
+        ++p;
+        if (*p == '\0')
+            break;
+    }
+    return rclass;
+}
+
+static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype, *end;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        *value = (gint)strtol(retvalue.addr, &end, 10);
+        if (end != retvalue.addr)
+            ret = TRUE;
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        *value = retvalue.addr;
+        ret = TRUE;
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_color(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrColor **value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        RrColor *c = RrColorParse(inst, retvalue.addr);
+        if (c != NULL) {
+            *value = c;
+            ret = TRUE;
+        }
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_mask(const RrInstance *inst, const gchar *path,
+        ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value)
+{
+    gboolean ret = FALSE;
+    gchar *s;
+    gint hx, hy; /* ignored */
+    guint w, h;
+    guchar *b;
+
+    s = g_build_filename(path, maskname, NULL);
+    if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) {
+        ret = TRUE;
+        *value = RrPixmapMaskNew(inst, w, h, (gchar*)b);
+        XFree(b);
+    }
+    g_free(s);
+
+    return ret;
+}
+
+static void parse_appearance(gchar *tex, RrSurfaceColorType *grad,
+        RrReliefType *relief, RrBevelType *bevel, gboolean *interlaced,
+        gboolean *border, gboolean allow_trans)
+{
+    gchar *t;
+
+    /* convert to all lowercase */
+    for (t = tex; *t != '\0'; ++t)
+        *t = g_ascii_tolower(*t);
+
+    if (allow_trans && strstr(tex, "parentrelative") != NULL) {
+        *grad = RR_SURFACE_PARENTREL;
+    }
+    else {
+        if (strstr(tex, "gradient") != NULL) {
+            if (strstr(tex, "crossdiagonal") != NULL)
+                *grad = RR_SURFACE_CROSS_DIAGONAL;
+            else if (strstr(tex, "pyramid") != NULL)
+                *grad = RR_SURFACE_PYRAMID;
+            else if (strstr(tex, "mirrorhorizontal") != NULL)
+                *grad = RR_SURFACE_MIRROR_HORIZONTAL;
+            else if (strstr(tex, "horizontal") != NULL)
+                *grad = RR_SURFACE_HORIZONTAL;
+            else if (strstr(tex, "splitvertical") != NULL)
+                *grad = RR_SURFACE_SPLIT_VERTICAL;
+            else if (strstr(tex, "vertical") != NULL)
+                *grad = RR_SURFACE_VERTICAL;
+            else
+                *grad = RR_SURFACE_DIAGONAL;
+        }
+        else {
+            *grad = RR_SURFACE_SOLID;
+        }
+    }
+
+    if (strstr(tex, "sunken") != NULL)
+        *relief = RR_RELIEF_SUNKEN;
+    else if (strstr(tex, "flat") != NULL)
+        *relief = RR_RELIEF_FLAT;
+    else if (strstr(tex, "raised") != NULL)
+        *relief = RR_RELIEF_RAISED;
+    else
+        *relief = (*grad == RR_SURFACE_PARENTREL) ? RR_RELIEF_FLAT
+                : RR_RELIEF_RAISED;
+
+    *border = FALSE;
+    if (*relief == RR_RELIEF_FLAT) {
+        if (strstr(tex, "border") != NULL)
+            *border = TRUE;
+    }
+    else {
+        if (strstr(tex, "bevel2") != NULL)
+            *bevel = RR_BEVEL_2;
+        else
+            *bevel = RR_BEVEL_1;
+    }
+
+    if (strstr(tex, "interlaced") != NULL)
+        *interlaced = TRUE;
+    else
+        *interlaced = FALSE;
+}
+
+static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrAppearance *value, gboolean allow_trans)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *cname, *ctoname, *bcname, *icname, *hname, *sname;
+    gchar *csplitname, *ctosplitname;
+    gchar *rettype;
+    XrmValue retvalue;
+    gint i;
+
+    cname = g_strconcat(rname, ".color", NULL);
+    ctoname = g_strconcat(rname, ".colorTo", NULL);
+    bcname = g_strconcat(rname, ".border.color", NULL);
+    icname = g_strconcat(rname, ".interlace.color", NULL);
+    hname = g_strconcat(rname, ".highlight", NULL);
+    sname = g_strconcat(rname, ".shadow", NULL);
+    csplitname = g_strconcat(rname, ".color.splitTo", NULL);
+    ctosplitname = g_strconcat(rname, ".colorTo.splitTo", NULL);
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        parse_appearance(retvalue.addr, &value->surface.grad,
+                &value->surface.relief, &value->surface.bevel,
+                &value->surface.interlaced, &value->surface.border, allow_trans);
+        if (!read_color(db, inst, cname, &value->surface.primary))
+            value->surface.primary = RrColorNew(inst, 0, 0, 0);
+        if (!read_color(db, inst, ctoname, &value->surface.secondary))
+            value->surface.secondary = RrColorNew(inst, 0, 0, 0);
+        if (value->surface.border)
+            if (!read_color(db, inst, bcname, &value->surface.border_color))
+                value->surface.border_color = RrColorNew(inst, 0, 0, 0);
+        if (value->surface.interlaced)
+            if (!read_color(db, inst, icname, &value->surface.interlace_color))
+                value->surface.interlace_color = RrColorNew(inst, 0, 0, 0);
+        if (read_int(db, hname, &i) && i >= 0)
+            value->surface.bevel_light_adjust = i;
+        if (read_int(db, sname, &i) && i >= 0 && i <= 256)
+            value->surface.bevel_dark_adjust = i;
+
+        if (value->surface.grad == RR_SURFACE_SPLIT_VERTICAL) {
+            gint r, g, b;
+
+            if (!read_color(db, inst, csplitname, &value->surface.split_primary)) {
+                r = value->surface.primary->r;
+                r += r >> 2;
+                g = value->surface.primary->g;
+                g += g >> 2;
+                b = value->surface.primary->b;
+                b += b >> 2;
+                if (r > 0xFF)
+                    r = 0xFF;
+                if (g > 0xFF)
+                    g = 0xFF;
+                if (b > 0xFF)
+                    b = 0xFF;
+                value->surface.split_primary = RrColorNew(inst, r, g, b);
+            }
+
+            if (!read_color(db, inst, ctosplitname,
+                    &value->surface.split_secondary)) {
+                r = value->surface.secondary->r;
+                r += r >> 4;
+                g = value->surface.secondary->g;
+                g += g >> 4;
+                b = value->surface.secondary->b;
+                b += b >> 4;
+                if (r > 0xFF)
+                    r = 0xFF;
+                if (g > 0xFF)
+                    g = 0xFF;
+                if (b > 0xFF)
+                    b = 0xFF;
+                value->surface.split_secondary = RrColorNew(inst, r, g, b);
+            }
+        }
+
+        ret = TRUE;
+    }
+
+    g_free(ctosplitname);
+    g_free(csplitname);
+    g_free(sname);
+    g_free(hname);
+    g_free(icname);
+    g_free(bcname);
+    g_free(ctoname);
+    g_free(cname);
+    g_free(rclass);
+    return ret;
+}
+
+static int parse_inline_number(const char *p)
+{
+    int neg = 1;
+    int res = 0;
+    if (*p == '-') {
+        neg = -1;
+        ++p;
+    }
+    for (; isdigit(*p); ++p)
+        res = res * 10 + *p - '0';
+    res *= neg;
+    return res;
+}
+
+static void set_default_appearance(RrAppearance *a)
+{
+    a->surface.grad = RR_SURFACE_SOLID;
+    a->surface.relief = RR_RELIEF_FLAT;
+    a->surface.bevel = RR_BEVEL_1;
+    a->surface.interlaced = FALSE;
+    a->surface.border = FALSE;
+    a->surface.primary = RrColorNew(a->inst, 0, 0, 0);
+    a->surface.secondary = RrColorNew(a->inst, 0, 0, 0);
+}
+
+/* Reads the output from gimp's C-Source file format into valid RGBA data for
+ an RrTextureRGBA. */
+static RrPixel32* read_c_image(gint width, gint height, const guint8 *data)
+{
+    RrPixel32 *im, *p;
+    gint i;
+
+    p = im = g_memdup(data, width * height * sizeof(RrPixel32));
+
+    for (i = 0; i < width * height; ++i) {
+        guchar a = ((*p >> 24) & 0xff);
+        guchar b = ((*p >> 16) & 0xff);
+        guchar g = ((*p >> 8) & 0xff);
+        guchar r = ((*p >> 0) & 0xff);
+
+        *p = ((r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset) + (b
+                << RrDefaultBlueOffset) + (a << RrDefaultAlphaOffset));
+        p++;
+    }
+
+    return im;
+}
diff --git a/engines/concept2/frame_concept2_config.h b/engines/concept2/frame_concept2_config.h
new file mode 100644 (file)
index 0000000..d7d18b4
--- /dev/null
@@ -0,0 +1,52 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_config.h for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+#ifndef FRAME_CONCEPT2_CONFIG_H_
+#define FRAME_CONCEPT2_CONFIG_H_
+
+#include <X11/Xresource.h>
+#include "render/render.h"
+
+G_BEGIN_DECLS
+
+struct _ObFrameThemeConfig
+{
+    const RrInstance *inst;
+
+    gint border_width;
+    gint left_width;
+    RrColor * focus_border_color;
+    RrColor * focus_corner_color;
+    RrColor * unfocus_border_color;
+    RrColor * unfocus_corner_color;
+
+    gchar *name;
+};
+
+typedef struct _ObFrameThemeConfig ObFrameThemeConfig;
+
+/*! The font values are all optional. If a NULL is used for any of them, then
+ the default font will be used. */
+gint load_theme_config(const RrInstance *inst, const gchar *name,
+        const gchar * path, XrmDatabase db, RrFont *active_window_font,
+        RrFont *inactive_window_font, RrFont *menu_title_font,
+        RrFont *menu_item_font, RrFont *osd_font);
+
+G_END_DECLS
+
+#endif /*FRAME_CONCEPT2_CONFIG_H_*/
diff --git a/engines/concept2/frame_concept2_plugin.c b/engines/concept2/frame_concept2_plugin.c
new file mode 100644 (file)
index 0000000..585dbbf
--- /dev/null
@@ -0,0 +1,1144 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_plugin.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#include "frame_concept2_plugin.h"
+#include "frame_concept2_render.h"
+
+#include "openbox/frame.h"
+#include "openbox/client.h"
+#include "openbox/openbox.h"
+#include "openbox/extensions.h"
+#include "openbox/prop.h"
+#include "openbox/grab.h"
+#include "openbox/config.h"
+#include "openbox/mainloop.h"
+#include "openbox/focus_cycle.h"
+#include "openbox/focus_cycle_indicator.h"
+#include "openbox/moveresize.h"
+#include "openbox/screen.h"
+#include "render/theme.h"
+
+typedef enum
+{
+    OB_FLAG_MAX = 1 << 0,
+    OB_FLAG_CLOSE = 1 << 1,
+    OB_FLAG_DESK = 1 << 2,
+    OB_FLAG_SHADE = 1 << 3,
+    OB_FLAG_ICONIFY = 1 << 4
+} ObFrameFlags;
+
+#define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
+                         ButtonPressMask | ButtonReleaseMask | \
+                         SubstructureRedirectMask | FocusChangeMask)
+#define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
+                           ButtonMotionMask | PointerMotionMask | \
+                           EnterWindowMask | LeaveWindowMask)
+
+#define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
+#define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
+
+#define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_b)
+
+Window createWindow(Window parent, Visual *visual, gulong mask,
+        XSetWindowAttributes *attrib)
+{
+    return XCreateWindow(plugin.ob_display, parent, 0, 0, 1, 1, 0, (visual ? 32
+            : RrDepth(plugin.ob_rr_inst)), InputOutput, (visual ? visual
+            : RrVisual(plugin.ob_rr_inst)), mask, attrib);
+
+}
+
+Visual *check_32bit_client(ObClient *c)
+{
+    XWindowAttributes wattrib;
+    Status ret;
+
+    /* we're already running at 32 bit depth, yay. we don't need to use their
+     visual */
+    if (RrDepth(plugin.ob_rr_inst) == 32)
+        return NULL;
+
+    ret = XGetWindowAttributes(plugin.ob_display, c->window, &wattrib);
+    g_assert(ret != BadDrawable);
+    g_assert(ret != BadWindow);
+
+    if (wattrib.depth == 32)
+        return wattrib.visual;
+    return NULL;
+}
+
+/* Not used */
+gint init(Display * display, gint screen)
+{
+    plugin.ob_display = display;
+    plugin.ob_screen = screen;
+}
+
+gpointer frame_new(struct _ObClient * client)
+{
+    XSetWindowAttributes attrib;
+    gulong mask;
+    ObConceptFrame *self;
+    Visual *visual;
+
+    self = g_new0(ObConceptFrame, 1);
+    self->client = client;
+
+    visual = check_32bit_client(client);
+
+    /* create the non-visible decor windows */
+
+    mask = 0;
+    if (visual) {
+        /* client has a 32-bit visual */
+        mask |= CWColormap | CWBackPixel | CWBorderPixel;
+        /* create a colormap with the visual */
+        OBCONCEPTFRAME(self)->colormap = attrib.colormap = XCreateColormap(
+                plugin.ob_display, RootWindow(plugin.ob_display,
+                        plugin.ob_screen), visual, AllocNone);
+        attrib.background_pixel = BlackPixel(plugin.ob_display,
+                plugin.ob_screen);
+        attrib.border_pixel = BlackPixel(plugin.ob_display, plugin.ob_screen);
+    }
+    self->window = createWindow(
+            RootWindow(plugin.ob_display, plugin.ob_screen), visual, mask,
+            &attrib);
+
+    /* create the visible decor windows */
+
+    mask = 0;
+    if (visual) {
+        /* client has a 32-bit visual */
+        mask |= CWColormap | CWBackPixel | CWBorderPixel;
+        attrib.colormap = RrColormap(plugin.ob_rr_inst);
+    }
+
+    self->background = createWindow(self->window, NULL, mask, &attrib);
+
+    mask |= CWEventMask;
+    attrib.event_mask = ELEMENT_EVENTMASK;
+
+    self->top = createWindow(self->window, NULL, mask, &attrib);
+    self->bottom = createWindow(self->window, NULL, mask, &attrib);
+    self->left = createWindow(self->window, NULL, mask, &attrib);
+    self->right = createWindow(self->window, NULL, mask, &attrib);
+
+    self->left_close = createWindow(self->left, NULL, mask, &attrib);
+    self->left_iconify = createWindow(self->left, NULL, mask, &attrib);
+    self->left_maximize = createWindow(self->left, NULL, mask, &attrib);
+    self->left_shade = createWindow(self->left, NULL, mask, &attrib);
+
+    self->handle = createWindow(self->left, NULL, mask, &attrib);
+
+    self->top_left = createWindow(self->window, NULL, mask, &attrib);
+    self->top_right = createWindow(self->window, NULL, mask, &attrib);
+
+    self->bottom_left = createWindow(self->window, NULL, mask, &attrib);
+    self->bottom_right = createWindow(self->window, NULL, mask, &attrib);
+
+    XMapWindow(plugin.ob_display, self->background);
+
+    self->focused = FALSE;
+
+    self->max_press = FALSE;
+    self->close_press = FALSE;
+    self->desk_press = FALSE;
+    self->iconify_press = FALSE;
+    self->shade_press = FALSE;
+    self->max_hover = FALSE;
+    self->close_hover = FALSE;
+    self->desk_hover = FALSE;
+    self->iconify_hover = FALSE;
+    self->shade_hover = FALSE;
+
+    set_theme_statics(self);
+
+    return (ObFrame*)self;
+}
+
+void set_theme_statics(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    /* do this before changing the frame's status like max_horz max_vert */
+
+    XResizeWindow(plugin.ob_display, self->top_left, 15,
+            theme_config.border_width);
+    XResizeWindow(plugin.ob_display, self->top_right, 15,
+            theme_config.border_width);
+    XResizeWindow(plugin.ob_display, self->bottom_left, 15,
+            theme_config.border_width);
+    XResizeWindow(plugin.ob_display, self->bottom_right, 15,
+            theme_config.border_width);
+
+    XResizeWindow(plugin.ob_display, self->left_close, theme_config.left_width,
+            15);
+    XResizeWindow(plugin.ob_display, self->left_iconify,
+            theme_config.left_width, 15);
+    XResizeWindow(plugin.ob_display, self->left_maximize,
+            theme_config.left_width, 15);
+    XResizeWindow(plugin.ob_display, self->left_shade, theme_config.left_width,
+            15);
+    XResizeWindow(plugin.ob_display, self->handle, theme_config.left_width, 15);
+
+    XMoveWindow(plugin.ob_display, self->left_close, 0, 0);
+    XMoveWindow(plugin.ob_display, self->left_iconify, 0, 15);
+    XMoveWindow(plugin.ob_display, self->left_maximize, 0, 30);
+    XMoveWindow(plugin.ob_display, self->left_shade, 0, 45);
+    XMoveWindow(plugin.ob_display, self->handle, 0, 60);
+
+}
+
+void free_theme_statics(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+}
+
+void frame_free(gpointer self)
+{
+    free_theme_statics(OBCONCEPTFRAME(self));
+    XDestroyWindow(plugin.ob_display, OBCONCEPTFRAME(self)->window);
+    if (OBCONCEPTFRAME(self)->colormap)
+        XFreeColormap(plugin.ob_display, OBCONCEPTFRAME(self)->colormap);
+    g_free(self);
+}
+
+void frame_show(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    if (!self->visible) {
+        self->visible = TRUE;
+        frame_update_skin(self);
+        /* Grab the server to make sure that the frame window is mapped before
+         the client gets its MapNotify, i.e. to make sure the client is
+         _visible_ when it gets MapNotify. */
+        grab_server(TRUE);
+        XMapWindow(plugin.ob_display, self->client->window);
+        XMapWindow(plugin.ob_display, self->window);
+        grab_server(FALSE);
+    }
+}
+
+void frame_hide(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    if (self->visible) {
+        self->visible = FALSE;
+        if (!frame_iconify_animating(self))
+            XUnmapWindow(plugin.ob_display, self->window);
+        /* we unmap the client itself so that we can get MapRequest
+         events, and because the ICCCM tells us to! */
+        XUnmapWindow(plugin.ob_display, self->client->window);
+        self->client->ignore_unmaps += 1;
+    }
+}
+
+void frame_adjust_theme(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    free_theme_statics(self);
+    set_theme_statics(self);
+}
+
+void frame_adjust_shape(gpointer _self)
+{
+#ifdef SHAPE
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    gint num;
+    XRectangle xrect[2];
+
+    if (!self->client->shaped)
+    {
+        /* clear the shape on the frame window */
+        XShapeCombineMask(plugin.ob_display, self->window, ShapeBounding,
+                self->size.left,
+                self->size.top,
+                None, ShapeSet);
+    }
+    else
+    {
+        /* make the frame's shape match the clients */
+        XShapeCombineShape(plugin.ob_display, self->window, ShapeBounding,
+                self->size.left,
+                self->size.top,
+                self->client->window,
+                ShapeBounding, ShapeSet);
+
+        num = 0;
+        if (self->decorations)
+        {
+            xrect[0].x = 0;
+            xrect[0].y = 0;
+            xrect[0].width = self->area.width;
+            xrect[0].height = self->size.top;
+            ++num;
+        }
+
+        XShapeCombineRectangles(plugin.ob_display, self->window,
+                ShapeBounding, 0, 0, xrect, num,
+                ShapeUnion, Unsorted);
+    }
+#endif
+}
+
+void frame_adjust_area(gpointer _self, gboolean moved, gboolean resized,
+        gboolean fake)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+
+    /* do this before changing the frame's status like max_horz max_vert */
+    frame_adjust_cursors(self);
+
+    /* Copy client status */
+    self->functions = self->client->functions;
+    self->decorations = self->client->decorations;
+    self->max_horz = self->client->max_horz;
+    self->max_vert = self->client->max_vert;
+    self->shaded = self->client->shaded;
+
+    if (self->decorations && !self->shaded) {
+        self->cbwidth_l = theme_config.left_width;
+        self->cbwidth_r = theme_config.border_width;
+        self->cbwidth_t = theme_config.border_width;
+        self->cbwidth_b = theme_config.border_width;
+
+        if (self->max_horz) {
+            self->cbwidth_l = theme_config.left_width;
+            self->cbwidth_r = 0;
+        }
+
+        if (self->max_vert) {
+            self->cbwidth_b = 0;
+            self->cbwidth_t = 0;
+        }
+
+        STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t,
+                self->cbwidth_r, self->cbwidth_b);
+
+        RECT_SET_SIZE(self->area, self->client->area.width + self->size.left
+                + self->size.right, self->client->area.height + self->size.top
+                + self->size.bottom);
+
+        self->width = self->area.width;
+
+        if (!fake) {
+
+            XMoveResizeWindow(plugin.ob_display, self->top, 15, 0,
+                    self->area.width - 30, theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->top);
+
+            XMoveResizeWindow(plugin.ob_display, self->bottom, 15,
+                    self->area.height - theme_config.border_width,
+                    self->area.width - 30, theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->bottom);
+
+            XMoveResizeWindow(plugin.ob_display, self->left, 0,
+                    theme_config.border_width, theme_config.left_width,
+                    self->area.height - 2*theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->left);
+
+            XMoveResizeWindow(plugin.ob_display, self->right, self->area.width
+                    - theme_config.border_width, theme_config.border_width,
+                    theme_config.border_width, self->area.height - 2
+                            *theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->right);
+
+            XMoveWindow(plugin.ob_display, self->top_left, 0, 0);
+            XMapWindow(plugin.ob_display, self->top_left);
+            XMoveWindow(plugin.ob_display, self->top_right, self->area.width
+                    - 15, 0);
+            XMapWindow(plugin.ob_display, self->top_right);
+            XMoveWindow(plugin.ob_display, self->bottom_left, 0,
+                    self->area.height - theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->bottom_left);
+            XMoveWindow(plugin.ob_display, self->bottom_right, self->area.width
+                    - 15, self->area.height - theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->bottom_right);
+
+            XMapWindow(plugin.ob_display, self->left_close);
+            XMapWindow(plugin.ob_display, self->left_iconify);
+            XMapWindow(plugin.ob_display, self->left_maximize);
+            XMapWindow(plugin.ob_display, self->left_shade);
+            XMapWindow(plugin.ob_display, self->handle);
+            /* find the new coordinates, done after setting the frame.size, for
+             frame_client_gravity. */
+            self->area.x = self->client->area.x;
+            self->area.y = self->client->area.y;
+            frame_client_gravity(self, &self->area.x, &self->area.y);
+
+            XMoveResizeWindow(plugin.ob_display, self->background,
+                    theme_config.border_width, theme_config.border_width,
+                    self->area.width - 2 * theme_config.border_width,
+                    self->area.height - 2 * theme_config.border_width);
+            XMapWindow(plugin.ob_display, self->background);
+        }
+
+        XMoveWindow(plugin.ob_display, self->client->window, self->size.left,
+                self->size.top);
+        XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
+                self->area.y, self->area.width, self->area.height);
+
+    }
+    else if (self->shaded) {
+        self->cbwidth_l = theme_config.left_width;
+        self->cbwidth_r = 0;
+        self->cbwidth_b = 0;
+        self->cbwidth_t = 0;
+        STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t,
+                self->cbwidth_r, self->cbwidth_b);
+
+        RECT_SET_SIZE(self->area, theme_config.left_width, self->area.height);
+
+        /* find the new coordinates, done after setting the frame.size, for
+         frame_client_gravity. */
+        self->area.x = self->client->area.x;
+        self->area.y = self->client->area.y;
+        //frame_client_gravity(self, &self->area.x, &self->area.y);
+        self->width = self->area.width;
+        if (!fake) {
+            XUnmapWindow(plugin.ob_display, self->top);
+            XUnmapWindow(plugin.ob_display, self->bottom);
+            XUnmapWindow(plugin.ob_display, self->right);
+            XUnmapWindow(plugin.ob_display, self->top_left);
+            XUnmapWindow(plugin.ob_display, self->top_right);
+            XUnmapWindow(plugin.ob_display, self->bottom_left);
+            XUnmapWindow(plugin.ob_display, self->bottom_right);
+
+            XMoveResizeWindow(plugin.ob_display, self->left, 0, 0,
+                    theme_config.left_width, self->area.height);
+            XMapWindow(plugin.ob_display, self->left);
+        }
+
+        XMoveWindow(plugin.ob_display, self->client->window,
+                theme_config.left_width, 0);
+        XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
+                self->area.y, self->area.width, self->area.height);
+    }
+    else {
+        self->cbwidth_l = 0;
+        self->cbwidth_r = 0;
+        self->cbwidth_b = 0;
+        self->cbwidth_t = 0;
+        STRUT_SET(self->size, self->cbwidth_l, self->cbwidth_t,
+                self->cbwidth_r, self->cbwidth_b);
+
+        RECT_SET_SIZE(self->area, self->client->area.width + self->size.left
+                + self->size.right, self->client->area.height + self->size.top
+                + self->size.bottom);
+
+        /* find the new coordinates, done after setting the frame.size, for
+         frame_client_gravity. */
+        self->area.x = self->client->area.x;
+        self->area.y = self->client->area.y;
+        frame_client_gravity(self, &self->area.x, &self->area.y);
+
+        self->width = self->area.width;
+        if (!fake) {
+            XUnmapWindow(plugin.ob_display, self->top);
+            XUnmapWindow(plugin.ob_display, self->bottom);
+            XUnmapWindow(plugin.ob_display, self->left);
+            XUnmapWindow(plugin.ob_display, self->right);
+            XUnmapWindow(plugin.ob_display, self->top_left);
+            XUnmapWindow(plugin.ob_display, self->top_right);
+            XUnmapWindow(plugin.ob_display, self->bottom_left);
+            XUnmapWindow(plugin.ob_display, self->bottom_right);
+
+            XUnmapWindow(plugin.ob_display, self->handle);
+
+            XMoveResizeWindow(plugin.ob_display, self->background, 0, 0,
+                    self->area.width, self->area.height);
+            XMapWindow(plugin.ob_display, self->background);
+        }
+
+        XMoveWindow(plugin.ob_display, self->client->window, self->size.left,
+                self->size.top);
+        XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
+                self->area.y, self->area.width, self->area.height);
+    }
+}
+
+void frame_adjust_cursors(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+
+    XSetWindowAttributes a;
+    a.cursor = ob_cursor(OB_CURSOR_NORTH);
+    XChangeWindowAttributes(plugin.ob_display, self->top, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_SOUTH);
+    XChangeWindowAttributes(plugin.ob_display, self->bottom, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_WEST);
+    XChangeWindowAttributes(plugin.ob_display, self->left, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_EAST);
+    XChangeWindowAttributes(plugin.ob_display, self->right, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_NORTHWEST);
+    XChangeWindowAttributes(plugin.ob_display, self->top_left, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_NORTHEAST);
+    XChangeWindowAttributes(plugin.ob_display, self->top_right, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_SOUTHWEST);
+    XChangeWindowAttributes(plugin.ob_display, self->bottom_left, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_SOUTHEAST);
+    XChangeWindowAttributes(plugin.ob_display, self->bottom_right, CWCursor, &a);
+
+    a.cursor = ob_cursor(OB_CURSOR_POINTER);
+    XChangeWindowAttributes(plugin.ob_display, self->left_close, CWCursor, &a);
+    XChangeWindowAttributes(plugin.ob_display, self->left_iconify, CWCursor, &a);
+    XChangeWindowAttributes(plugin.ob_display, self->left_maximize, CWCursor,
+            &a);
+    XChangeWindowAttributes(plugin.ob_display, self->left_shade, CWCursor, &a);
+    XChangeWindowAttributes(plugin.ob_display, self->handle, CWCursor, &a);
+
+}
+
+void frame_adjust_client_area(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    /* adjust the window which is there to prevent flashing on unmap */
+    XMoveResizeWindow(plugin.ob_display, self->background, 0, 0,
+            self->client->area.width, self->client->area.height);
+}
+
+void frame_adjust_state(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->need_render = TRUE;
+    framerender_frame(self);
+}
+
+void frame_adjust_focus(gpointer _self, gboolean hilite)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->focused = hilite;
+    self->need_render = TRUE;
+    framerender_frame(self);
+    XFlush(plugin.ob_display);
+}
+
+void frame_adjust_title(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->need_render = TRUE;
+    framerender_frame(self);
+}
+
+void frame_adjust_icon(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->need_render = TRUE;
+    framerender_frame(self);
+}
+
+void frame_grab_client(gpointer _self, GHashTable * map)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    /* DO NOT map the client window here. we used to do that, but it is bogus.
+     we need to set up the client's dimensions and everything before we
+     send a mapnotify or we create race conditions.
+     */
+
+    /* reparent the client to the frame */
+    XReparentWindow(plugin.ob_display, self->client->window, self->window, 0, 0);
+
+    /*
+     When reparenting the client window, it is usually not mapped yet, since
+     this occurs from a MapRequest. However, in the case where Openbox is
+     starting up, the window is already mapped, so we'll see an unmap event
+     for it.
+     */
+    if (ob_state() == OB_STATE_STARTING)
+        ++self->client->ignore_unmaps;
+
+    /* select the event mask on the client's parent (to receive config/map
+     req's) the ButtonPress is to catch clicks on the client border */
+    XSelectInput(plugin.ob_display, self->window, FRAME_EVENTMASK);
+
+    /* set all the windows for the frame in the window_map */
+    g_hash_table_insert(map, &self->window, self->client);
+    g_hash_table_insert(map, &self->left, self->client);
+    g_hash_table_insert(map, &self->right, self->client);
+
+    g_hash_table_insert(map, &self->top, self->client);
+    g_hash_table_insert(map, &self->bottom, self->client);
+
+    g_hash_table_insert(map, &self->top_left, self->client);
+    g_hash_table_insert(map, &self->top_right, self->client);
+
+    g_hash_table_insert(map, &self->bottom_left, self->client);
+    g_hash_table_insert(map, &self->bottom_right, self->client);
+
+    g_hash_table_insert(map, &self->left_close, self->client);
+    g_hash_table_insert(map, &self->left_iconify, self->client);
+    g_hash_table_insert(map, &self->left_maximize, self->client);
+    g_hash_table_insert(map, &self->left_shade, self->client);
+
+    g_hash_table_insert(map, &self->handle, self->client);
+
+}
+
+void frame_release_client(gpointer _self, GHashTable * map)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    XEvent ev;
+    gboolean reparent = TRUE;
+
+    /* if there was any animation going on, kill it */
+    ob_main_loop_timeout_remove_data(plugin.ob_main_loop,
+            frame_animate_iconify, self, FALSE);
+
+    /* check if the app has already reparented its window away */
+    while (XCheckTypedWindowEvent(plugin.ob_display, self->client->window,
+            ReparentNotify, &ev)) {
+        /* This check makes sure we don't catch our own reparent action to
+         our frame window. This doesn't count as the app reparenting itself
+         away of course.
+
+         Reparent events that are generated by us are just discarded here.
+         They are of no consequence to us anyhow.
+         */
+        if (ev.xreparent.parent != self->window) {
+            reparent = FALSE;
+            XPutBackEvent(plugin.ob_display, &ev);
+            break;
+        }
+    }
+
+    if (reparent) {
+        /* according to the ICCCM - if the client doesn't reparent itself,
+         then we will reparent the window to root for them */
+        XReparentWindow(plugin.ob_display, self->client->window, RootWindow(
+                plugin.ob_display, plugin.ob_screen), self->client->area.x,
+                self->client->area.y);
+    }
+
+    /* remove all the windows for the frame from the window_map */
+    g_hash_table_remove(map, &self->window);
+
+    g_hash_table_remove(map, &self->left);
+    g_hash_table_remove(map, &self->right);
+
+    g_hash_table_remove(map, &self->top);
+    g_hash_table_remove(map, &self->bottom);
+
+    g_hash_table_remove(map, &self->top_left);
+    g_hash_table_remove(map, &self->top_right);
+
+    g_hash_table_remove(map, &self->bottom_left);
+    g_hash_table_remove(map, &self->bottom_right);
+
+    g_hash_table_remove(map, &self->left_close);
+    g_hash_table_remove(map, &self->left_iconify);
+    g_hash_table_remove(map, &self->left_maximize);
+    g_hash_table_remove(map, &self->left_shade);
+
+    g_hash_table_remove(map, &self->handle);
+
+    ob_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
+            TRUE);
+}
+
+/* is there anything present between us and the label? */
+static gboolean is_button_present(ObConceptFrame *_self, const gchar *lc,
+        gint dir)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
+        if (*lc == ' ')
+            continue; /* it was invalid */
+        if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
+            return TRUE;
+        if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
+            return TRUE;
+        if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
+            return TRUE;
+        if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
+            return TRUE;
+        if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
+            return TRUE;
+        if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
+            return TRUE;
+        if (*lc == 'L')
+            return FALSE;
+    }
+    return FALSE;
+}
+
+ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
+{
+    /* Here because client can be NULL */
+    ObConceptFrame *self = OBCONCEPTFRAME(_self);
+
+    if (win == self->window)
+        return OB_FRAME_CONTEXT_FRAME;
+
+    if (win == self->bottom)
+        return OB_FRAME_CONTEXT_BOTTOM;
+
+    if (win == self->bottom_left)
+        return OB_FRAME_CONTEXT_BLCORNER;
+
+    if (win == self->bottom_right)
+        return OB_FRAME_CONTEXT_BRCORNER;
+
+    if (win == self->top)
+        return OB_FRAME_CONTEXT_TOP;
+
+    if (win == self->top_left)
+        return OB_FRAME_CONTEXT_TLCORNER;
+
+    if (win == self->top_right)
+        return OB_FRAME_CONTEXT_TRCORNER;
+
+    if (win == self->left_close)
+        return OB_FRAME_CONTEXT_CLOSE;
+    if (win == self->left_iconify)
+        return OB_FRAME_CONTEXT_ICONIFY;
+    if (win == self->left_maximize)
+        return OB_FRAME_CONTEXT_MAXIMIZE;
+    if (win == self->left_shade)
+        return OB_FRAME_CONTEXT_SHADE;
+    if (win == self->handle)
+        return OB_FRAME_CONTEXT_TITLEBAR;
+
+    if (win == self->left)
+        return OB_FRAME_CONTEXT_LEFT;
+    if (win == self->right)
+        return OB_FRAME_CONTEXT_RIGHT;
+
+    return OB_FRAME_CONTEXT_NONE;
+}
+
+void frame_client_gravity(gpointer _self, gint *x, gint *y)
+{
+    ObConceptFrame * self = OBCONCEPTFRAME(_self);
+    /* horizontal */
+    switch (self->client->gravity) {
+    default:
+    case NorthWestGravity:
+    case SouthWestGravity:
+    case WestGravity:
+        break;
+
+    case NorthGravity:
+    case SouthGravity:
+    case CenterGravity:
+        /* the middle of the client will be the middle of the frame */
+        *x -= (self->size.right - self->size.left) / 2;
+        break;
+
+    case NorthEastGravity:
+    case SouthEastGravity:
+    case EastGravity:
+        /* the right side of the client will be the right side of the frame */
+        *x -= self->size.right + self->size.left - self->client->border_width
+                * 2;
+        break;
+
+    case ForgetGravity:
+    case StaticGravity:
+        /* the client's position won't move */
+        *x -= self->size.left - self->client->border_width;
+        break;
+    }
+
+    /* vertical */
+    switch (self->client->gravity) {
+    default:
+    case NorthWestGravity:
+    case NorthEastGravity:
+    case NorthGravity:
+        break;
+
+    case CenterGravity:
+    case EastGravity:
+    case WestGravity:
+        /* the middle of the client will be the middle of the frame */
+        *y -= (self->size.bottom - self->size.top) / 2;
+        break;
+
+    case SouthWestGravity:
+    case SouthEastGravity:
+    case SouthGravity:
+        /* the bottom of the client will be the bottom of the frame */
+        *y -= self->size.bottom + self->size.top - self->client->border_width
+                * 2;
+        break;
+
+    case ForgetGravity:
+    case StaticGravity:
+        /* the client's position won't move */
+        *y -= self->size.top - self->client->border_width;
+        break;
+    }
+}
+
+void frame_frame_gravity(gpointer _self, gint *x, gint *y)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    /* horizontal */
+    switch (self->client->gravity) {
+    default:
+    case NorthWestGravity:
+    case WestGravity:
+    case SouthWestGravity:
+        break;
+    case NorthGravity:
+    case CenterGravity:
+    case SouthGravity:
+        /* the middle of the client will be the middle of the frame */
+        *x += (self->size.right - self->size.left) / 2;
+        break;
+    case NorthEastGravity:
+    case EastGravity:
+    case SouthEastGravity:
+        /* the right side of the client will be the right side of the frame */
+        *x += self->size.right + self->size.left - self->client->border_width
+                * 2;
+        break;
+    case StaticGravity:
+    case ForgetGravity:
+        /* the client's position won't move */
+        *x += self->size.left - self->client->border_width;
+        break;
+    }
+
+    /* vertical */
+    switch (self->client->gravity) {
+    default:
+    case NorthWestGravity:
+    case NorthGravity:
+    case NorthEastGravity:
+        break;
+    case WestGravity:
+    case CenterGravity:
+    case EastGravity:
+        /* the middle of the client will be the middle of the frame */
+        *y += (self->size.bottom - self->size.top) / 2;
+        break;
+    case SouthWestGravity:
+    case SouthGravity:
+    case SouthEastGravity:
+        /* the bottom of the client will be the bottom of the frame */
+        *y += self->size.bottom + self->size.top - self->client->border_width
+                * 2;
+        break;
+    case StaticGravity:
+    case ForgetGravity:
+        /* the client's position won't move */
+        *y += self->size.top - self->client->border_width;
+        break;
+    }
+}
+
+void frame_rect_to_frame(gpointer _self, Rect *r)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    r->width += self->size.left + self->size.right;
+    r->height += self->size.top + self->size.bottom;
+    frame_client_gravity(self, &r->x, &r->y);
+}
+
+void frame_rect_to_client(gpointer _self, Rect *r)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    r->width -= self->size.left + self->size.right;
+    r->height -= self->size.top + self->size.bottom;
+    frame_frame_gravity(self, &r->x, &r->y);
+}
+
+void flash_done(gpointer data)
+{
+    ObConceptFrame *self = data;
+
+    if (self->focused != self->flash_on)
+        frame_adjust_focus(self, self->focused);
+}
+
+gboolean flash_timeout(gpointer data)
+{
+    ObConceptFrame *self = data;
+    GTimeVal now;
+
+    g_get_current_time(&now);
+    if (now.tv_sec > self->flash_end.tv_sec
+            || (now.tv_sec == self->flash_end.tv_sec && now.tv_usec
+                    >= self->flash_end.tv_usec))
+        self->flashing = FALSE;
+
+    if (!self->flashing)
+        return FALSE; /* we are done */
+
+    self->flash_on = !self->flash_on;
+    if (!self->focused) {
+        frame_adjust_focus(self, self->flash_on);
+        self->focused = FALSE;
+    }
+
+    return TRUE; /* go again */
+}
+
+void frame_flash_start(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->flash_on = self->focused;
+
+    if (!self->flashing)
+        ob_main_loop_timeout_add(plugin.ob_main_loop, G_USEC_PER_SEC * 0.6,
+                flash_timeout, self, g_direct_equal, flash_done);
+    g_get_current_time(&self->flash_end);
+    g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
+
+    self->flashing = TRUE;
+}
+
+void frame_flash_stop(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    self->flashing = FALSE;
+}
+
+static gulong frame_animate_iconify_time_left(gpointer _self,
+        const GTimeVal *now)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    glong sec, usec;
+    sec = self->iconify_animation_end.tv_sec - now->tv_sec;
+    usec = self->iconify_animation_end.tv_usec - now->tv_usec;
+    if (usec < 0) {
+        usec += G_USEC_PER_SEC;
+        sec--;
+    }
+    /* no negative values */
+    return MAX(sec * G_USEC_PER_SEC + usec, 0);
+}
+
+gboolean frame_animate_iconify(gpointer p)
+{
+    ObConceptFrame *self = p;
+    gint x, y, w, h;
+    gint iconx, icony, iconw;
+    GTimeVal now;
+    gulong time;
+    gboolean iconifying;
+
+    if (self->client->icon_geometry.width == 0) {
+        /* there is no icon geometry set so just go straight down */
+        Rect *a =
+                screen_physical_area_monitor(screen_find_monitor(&self->area));
+        iconx = self->area.x + self->area.width / 2 + 32;
+        icony = a->y + a->width;
+        iconw = 64;
+        g_free(a);
+    }
+    else {
+        iconx = self->client->icon_geometry.x;
+        icony = self->client->icon_geometry.y;
+        iconw = self->client->icon_geometry.width;
+    }
+
+    iconifying = self->iconify_animation_going > 0;
+
+    /* how far do we have left to go ? */
+    g_get_current_time(&now);
+    time = frame_animate_iconify_time_left(self, &now);
+
+    if (time == 0 || iconifying) {
+        /* start where the frame is supposed to be */
+        x = self->area.x;
+        y = self->area.y;
+        w = self->area.width;
+        h = self->area.height;
+    }
+    else {
+        /* start at the icon */
+        x = iconx;
+        y = icony;
+        w = iconw;
+        h = self->size.top; /* just the titlebar */
+    }
+
+    if (time > 0) {
+        glong dx, dy, dw;
+        glong elapsed;
+
+        dx = self->area.x - iconx;
+        dy = self->area.y - icony;
+        dw = self->area.width - self->bwidth * 2 - iconw;
+        /* if restoring, we move in the opposite direction */
+        if (!iconifying) {
+            dx = -dx;
+            dy = -dy;
+            dw = -dw;
+        }
+
+        elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
+        x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        h = self->size.top; /* just the titlebar */
+    }
+
+    if (time == 0)
+        frame_end_iconify_animation(self);
+    else {
+        XMoveResizeWindow(plugin.ob_display, self->window, x, y, w, h);
+        XFlush(plugin.ob_display);
+    }
+
+    return time > 0; /* repeat until we're out of time */
+}
+
+void frame_end_iconify_animation(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    /* see if there is an animation going */
+    if (self->iconify_animation_going == 0)
+        return;
+
+    if (!self->visible)
+        XUnmapWindow(plugin.ob_display, self->window);
+    else {
+        /* Send a ConfigureNotify when the animation is done, this fixes
+         KDE's pager showing the window in the wrong place.  since the
+         window is mapped at a different location and is then moved, we
+         need to send the synthetic configurenotify, since apps may have
+         read the position when the client mapped, apparently. */
+        client_reconfigure(self->client, TRUE);
+    }
+
+    /* we're not animating any more ! */
+    self->iconify_animation_going = 0;
+
+    XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
+            self->area.y, self->area.width, self->area.height);
+    /* we delay re-rendering until after we're done animating */
+    framerender_frame(self);
+    XFlush(plugin.ob_display);
+}
+
+void frame_begin_iconify_animation(gpointer _self, gboolean iconifying)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    gulong time;
+    gboolean new_anim = FALSE;
+    gboolean set_end = TRUE;
+    GTimeVal now;
+
+    /* if there is no titlebar, just don't animate for now
+     XXX it would be nice tho.. */
+    if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
+        return;
+
+    /* get the current time */
+    g_get_current_time(&now);
+
+    /* get how long until the end */
+    time = FRAME_ANIMATE_ICONIFY_TIME;
+    if (self->iconify_animation_going) {
+        if (!!iconifying != (self->iconify_animation_going > 0)) {
+            /* animation was already going on in the opposite direction */
+            time = time - frame_animate_iconify_time_left(self, &now);
+        }
+        else
+            /* animation was already going in the same direction */
+            set_end = FALSE;
+    }
+    else
+        new_anim = TRUE;
+    self->iconify_animation_going = iconifying ? 1 : -1;
+
+    /* set the ending time */
+    if (set_end) {
+        self->iconify_animation_end.tv_sec = now.tv_sec;
+        self->iconify_animation_end.tv_usec = now.tv_usec;
+        g_time_val_add(&self->iconify_animation_end, time);
+    }
+
+    if (new_anim) {
+        ob_main_loop_timeout_remove_data(plugin.ob_main_loop,
+                frame_animate_iconify, self, FALSE);
+        ob_main_loop_timeout_add(plugin.ob_main_loop,
+        FRAME_ANIMATE_ICONIFY_STEP_TIME, frame_animate_iconify, self,
+                g_direct_equal, NULL);
+
+        /* do the first step */
+        frame_animate_iconify(self);
+
+        /* show it during the animation even if it is not "visible" */
+        if (!self->visible)
+            XMapWindow(plugin.ob_display, self->window);
+    }
+}
+
+gboolean frame_iconify_animating(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    return self->iconify_animation_going != 0;
+}
+
+ObFramePlugin plugin = { 0, //gpointer handler;
+        "libdefault.la", //gchar * filename;
+        "Default", //gchar * name;
+        init, //gint (*init) (Display * display, gint screen);
+        0, // release
+        frame_new, //gpointer (*frame_new) (struct _ObClient *c);
+        frame_free, //void (*frame_free) (gpointer self);
+        frame_show, //void (*frame_show) (gpointer self);
+        frame_hide, //void (*frame_hide) (gpointer self);
+        frame_adjust_theme, //void (*frame_adjust_theme) (gpointer self);
+        frame_adjust_shape, //void (*frame_adjust_shape) (gpointer self);
+        frame_adjust_area, //void (*frame_adjust_area) (gpointer self, gboolean moved, gboolean resized, gboolean fake);
+        frame_adjust_client_area, //void (*frame_adjust_client_area) (gpointer self);
+        frame_adjust_state, //void (*frame_adjust_state) (gpointer self);
+        frame_adjust_focus, //void (*frame_adjust_focus) (gpointer self, gboolean hilite);
+        frame_adjust_title, //void (*frame_adjust_title) (gpointer self);
+        frame_adjust_icon, //void (*frame_adjust_icon) (gpointer self);
+        frame_grab_client, //void (*frame_grab_client) (gpointer self);
+        frame_release_client, //void (*frame_release_client) (gpointer self);
+        frame_context, //ObFrameContext (*frame_context) (struct _ObClient *self, Window win, gint x, gint y);
+        frame_client_gravity, //void (*frame_client_gravity) (gpointer self, gint *x, gint *y);
+        frame_frame_gravity, //void (*frame_frame_gravity) (gpointer self, gint *x, gint *y);
+        frame_rect_to_frame, //void (*frame_rect_to_frame) (gpointer self, Rect *r);
+        frame_rect_to_client, //void (*frame_rect_to_client) (gpointer self, Rect *r);
+        frame_flash_start, //void (*frame_flash_start) (gpointer self);
+        frame_flash_stop, //void (*frame_flash_stop) (gpointer self);
+        frame_begin_iconify_animation, //void (*frame_begin_iconify_animation) (gpointer self, gboolean iconifying);
+        frame_end_iconify_animation, //void (*frame_end_iconify_animation) (gpointer self);
+        frame_iconify_animating, // gboolean (*frame_iconify_animating)(gpointer p);
+        load_theme_config,
+
+        /* This fields are fill by openbox. */
+        0, //Display * ob_display;
+        0, //gint ob_screen;
+        0, //RrInstance *ob_rr_inst;
+        0, //gboolean config_theme_keepborder;
+        0, //struct _ObClient *focus_cycle_target;
+        0, //gchar *config_title_layout;
+        FALSE, //gboolean moveresize_in_progress;
+        0, //struct _ObMainLoop *ob_main_loop;
+};
+
+ObFramePlugin * get_info()
+{
+    return &plugin;
+}
diff --git a/engines/concept2/frame_concept2_plugin.h b/engines/concept2/frame_concept2_plugin.h
new file mode 100644 (file)
index 0000000..e392188
--- /dev/null
@@ -0,0 +1,181 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_plugin.h for the Openbox window manager
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+#ifndef FRAME_CONCEPT2_PLUGIN_H_
+#define FRAME_CONCEPT2_PLUGIN_H_
+
+#include "frame_concept2_config.h"
+
+#include "render/render.h"
+#include "openbox/engine_interface.h"
+
+ObFrameThemeConfig theme_config;
+
+struct _ObConceptFrame
+{
+    // PUBLIC :
+    struct _ObClient *client;
+
+    Window window;
+
+    Strut size;
+    Rect area;
+    gint bwidth; /* border width */
+    guint decorations;
+
+    gboolean visible;
+
+    gboolean max_horz; /* when maxed some decorations are hidden */
+    gboolean max_vert; /* when maxed some decorations are hidden */
+
+    gboolean max_press;
+    gboolean close_press;
+    gboolean desk_press;
+    gboolean shade_press;
+    gboolean iconify_press;
+
+    gboolean max_hover;
+    gboolean close_hover;
+    gboolean desk_hover;
+    gboolean shade_hover;
+    gboolean iconify_hover;
+
+    gint iconify_animation_going;
+
+    /* PRIVATE: */
+    /* You are free to add what you want here */
+
+    ObStyle style;
+
+    guint functions;
+
+    /* These are borders of the frame and its elements */
+
+    Window top;
+    Window bottom;
+    Window left;
+    Window right;
+
+    Window top_left;
+    Window top_right;
+
+    Window bottom_left;
+    Window bottom_right;
+
+    Window background;
+
+    Window left_shade;
+    Window left_close;
+    Window left_iconify;
+    Window left_maximize;
+
+    Window handle;
+
+    Colormap colormap;
+
+    RrAppearance *a_unfocused_title;
+    RrAppearance *a_focused_title;
+    RrAppearance *a_unfocused_label;
+    RrAppearance *a_focused_label;
+    RrAppearance *a_icon;
+    RrAppearance *a_unfocused_handle;
+    RrAppearance *a_focused_handle;
+
+    gint icon_on; /* if the window icon button is on */
+    gint label_on; /* if the window title is on */
+    gint iconify_on; /* if the window iconify button is on */
+    gint desk_on; /* if the window all-desktops button is on */
+    gint shade_on; /* if the window shade button is on */
+    gint max_on; /* if the window maximize button is on */
+    gint close_on; /* if the window close button is on */
+
+    gint width; /* width of the titlebar and handle */
+
+    gint label_width; /* width of the label in the titlebar */
+    gint icon_x; /* x-position of the window icon button */
+    gint label_x; /* x-position of the window title */
+    gint iconify_x; /* x-position of the window iconify button */
+    gint desk_x; /* x-position of the window all-desktops button */
+    gint shade_x; /* x-position of the window shade button */
+    gint max_x; /* x-position of the window maximize button */
+    gint close_x; /* x-position of the window close button */
+
+    gint cbwidth_l; /* client border width */
+    gint cbwidth_t; /* client border width */
+    gint cbwidth_r; /* client border width */
+    gint cbwidth_b; /* client border width */
+    gboolean shaded; /* decorations adjust when shaded */
+
+    /* the leftmost and rightmost elements in the titlebar */
+    ObFrameContext leftmost;
+    ObFrameContext rightmost;
+
+    gboolean focused;
+    gboolean need_render;
+
+    gboolean flashing;
+    gboolean flash_on;
+    GTimeVal flash_end;
+
+    GTimeVal iconify_animation_end;
+
+};
+
+typedef struct _ObConceptFrame ObConceptFrame;
+
+/* Function use for interface */
+gint init(Display *, gint);
+gpointer frame_new(struct _ObClient *c);
+void frame_free(gpointer self);
+void frame_show(gpointer self);
+void frame_hide(gpointer self);
+void frame_adjust_theme(gpointer self);
+void frame_adjust_shape(gpointer self);
+void frame_adjust_area(gpointer self, gboolean moved, gboolean resized,
+        gboolean fake);
+void frame_adjust_client_area(gpointer self);
+void frame_adjust_state(gpointer self);
+void frame_adjust_focus(gpointer self, gboolean hilite);
+void frame_adjust_title(gpointer self);
+void frame_adjust_icon(gpointer self);
+void frame_grab_client(gpointer self, GHashTable *);
+void frame_release_client(gpointer self, GHashTable *);
+
+ObFrameContext frame_context(gpointer, Window, gint, gint);
+void frame_client_gravity(gpointer self, gint *x, gint *y);
+void frame_frame_gravity(gpointer self, gint *x, gint *y);
+void frame_rect_to_frame(gpointer self, Rect *r);
+void frame_rect_to_client(gpointer self, Rect *r);
+void frame_flash_start(gpointer self);
+void frame_flash_stop(gpointer self);
+void frame_begin_iconify_animation(gpointer self, gboolean iconifying);
+void frame_end_iconify_animation(gpointer self);
+gboolean frame_iconify_animating(gpointer _self);
+
+void flash_done(gpointer data);
+gboolean flash_timeout(gpointer data);
+
+void set_theme_statics(gpointer self);
+void free_theme_statics(gpointer self);
+gboolean frame_animate_iconify(gpointer self);
+void frame_adjust_cursors(gpointer self);
+
+/* Global for frame_concept_render.c only */
+extern ObFramePlugin plugin;
+#define OBCONCEPTFRAME(x) ((ObConceptFrame *)(x))
+
+#endif /*FRAME_CONCEPT2_PLUGIN_H_*/
diff --git a/engines/concept2/frame_concept2_render.c b/engines/concept2/frame_concept2_render.c
new file mode 100644 (file)
index 0000000..ce4a573
--- /dev/null
@@ -0,0 +1,95 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_render.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+#include "frame_concept2_render.h"
+#include "frame_concept2_plugin.h"
+
+#include "openbox/engine_interface.h"
+#include "openbox/openbox.h"
+#include "openbox/screen.h"
+#include "openbox/client.h"
+
+#include "render/theme.h"
+
+static void framerender_label(ObConceptFrame *self, RrAppearance *a);
+static void framerender_icon(ObConceptFrame *self, RrAppearance *a);
+static void framerender_max(ObConceptFrame *self, RrAppearance *a);
+static void framerender_iconify(ObConceptFrame *self, RrAppearance *a);
+static void framerender_desk(ObConceptFrame *self, RrAppearance *a);
+static void framerender_shade(ObConceptFrame *self, RrAppearance *a);
+static void framerender_close(ObConceptFrame *self, RrAppearance *a);
+
+void framerender_frame(gpointer _self)
+{
+    ObConceptFrame * self = (ObConceptFrame *) _self;
+    if (plugin.frame_iconify_animating(self))
+        return; /* delay redrawing until the animation is done */
+    if (!self->need_render)
+        return;
+    if (!self->visible)
+        return;
+    self->need_render = FALSE;
+
+    gulong border_px, corner_px;
+
+    if (self->focused) {
+        border_px = RrColorPixel(theme_config.focus_border_color);
+        corner_px = RrColorPixel(theme_config.focus_corner_color);
+    }
+    else {
+        border_px = RrColorPixel(theme_config.unfocus_border_color);
+        corner_px = RrColorPixel(theme_config.unfocus_corner_color);
+    }
+
+    XSetWindowBackground(plugin.ob_display, self->left, border_px);
+    XClearWindow(plugin.ob_display, self->left);
+    XSetWindowBackground(plugin.ob_display, self->right, border_px);
+    XClearWindow(plugin.ob_display, self->right);
+
+    XSetWindowBackground(plugin.ob_display, self->top, border_px);
+    XClearWindow(plugin.ob_display, self->top);
+    XSetWindowBackground(plugin.ob_display, self->bottom, border_px);
+    XClearWindow(plugin.ob_display, self->bottom);
+
+    XSetWindowBackground(plugin.ob_display, self->top_left, corner_px);
+    XClearWindow(plugin.ob_display, self->top_left);
+    XSetWindowBackground(plugin.ob_display, self->top_right, corner_px);
+    XClearWindow(plugin.ob_display, self->top_right);
+
+    XSetWindowBackground(plugin.ob_display, self->bottom_left, corner_px);
+    XClearWindow(plugin.ob_display, self->bottom_left);
+    XSetWindowBackground(plugin.ob_display, self->bottom_right, corner_px);
+    XClearWindow(plugin.ob_display, self->bottom_right);
+
+    XSetWindowBackground(plugin.ob_display, self->background, 0);
+    XClearWindow(plugin.ob_display, self->background);
+
+    XSetWindowBackground(plugin.ob_display, self->left_close, 0xff0000);
+    XClearWindow(plugin.ob_display, self->left_close);
+    XSetWindowBackground(plugin.ob_display, self->left_iconify, 0x00ff00);
+    XClearWindow(plugin.ob_display, self->left_iconify);
+    XSetWindowBackground(plugin.ob_display, self->left_maximize, 0x0000ff);
+    XClearWindow(plugin.ob_display, self->left_maximize);
+    XSetWindowBackground(plugin.ob_display, self->left_shade, 0xffff00);
+    XClearWindow(plugin.ob_display, self->left_shade);
+
+    XSetWindowBackground(plugin.ob_display, self->handle, 0x00ffff);
+    XClearWindow(plugin.ob_display, self->handle);
+
+    XFlush(plugin.ob_display);
+}
diff --git a/engines/concept2/frame_concept2_render.h b/engines/concept2/frame_concept2_render.h
new file mode 100644 (file)
index 0000000..deab47c
--- /dev/null
@@ -0,0 +1,26 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_render.h for the Openbox window manager
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#ifndef FRAME_CONCEPT2_RENDER_H_
+#define FRAME_CONCEPT2_RENDER_H_
+
+#include "frame_concept2_plugin.h"
+
+void framerender_frame(gpointer self);
+
+#endif
diff --git a/engines/default/config.c b/engines/default/config.c
new file mode 100644 (file)
index 0000000..893f8c2
--- /dev/null
@@ -0,0 +1,1552 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_config.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#include "config.h"
+#include "plugin.h"
+
+#include "render/render.h"
+#include "render/color.h"
+#include "render/font.h"
+#include "render/mask.h"
+#include "render/icon.h"
+#include "obt/parse.h"
+
+#include <X11/Xlib.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+static XrmDatabase loaddb(const gchar *name, gchar **path);
+static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value);
+static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value);
+static gboolean read_color(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrColor **value);
+static gboolean read_mask(const RrInstance *inst, const gchar *path,
+        ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value);
+static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrAppearance *value, gboolean allow_trans);
+static int parse_inline_number(const char *p);
+static RrPixel32* read_c_image(gint width, gint height, const guint8 *data);
+static void set_default_appearance(RrAppearance *a);
+
+gint load_theme_config(const RrInstance *inst, const gchar *name,
+        const gchar * path, XrmDatabase db, RrFont *active_window_font,
+        RrFont *inactive_window_font, RrFont *menu_title_font,
+        RrFont *menu_item_font, RrFont *osd_font)
+{
+    RrJustify winjust, mtitlejust;
+    gchar *str;
+    ObFrameThemeConfig * theme = &theme_config;
+    gboolean userdef;
+
+    //theme = g_new0(ObFrameTheme, 1);
+
+    theme->inst = inst;
+    theme->name = g_strdup(name ? name : DEFAULT_THEME);
+
+    theme->a_disabled_focused_max = RrAppearanceNew(inst, 1);
+    theme->a_disabled_unfocused_max = RrAppearanceNew(inst, 1);
+    theme->a_hover_focused_max = RrAppearanceNew(inst, 1);
+    theme->a_hover_unfocused_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_focused_unpressed_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_unfocused_unpressed_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_hover_focused_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_hover_unfocused_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_focused_pressed_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_unfocused_pressed_max = RrAppearanceNew(inst, 1);
+    theme->a_focused_unpressed_max = RrAppearanceNew(inst, 1);
+    theme->a_focused_pressed_max = RrAppearanceNew(inst, 1);
+    theme->a_unfocused_unpressed_max = RrAppearanceNew(inst, 1);
+    theme->a_unfocused_pressed_max = RrAppearanceNew(inst, 1);
+    theme->a_focused_grip = RrAppearanceNew(inst, 0);
+    theme->a_unfocused_grip = RrAppearanceNew(inst, 0);
+    theme->a_focused_title = RrAppearanceNew(inst, 0);
+    theme->a_unfocused_title = RrAppearanceNew(inst, 0);
+    theme->a_focused_label = RrAppearanceNew(inst, 1);
+    theme->a_unfocused_label = RrAppearanceNew(inst, 1);
+    theme->a_icon = RrAppearanceNew(inst, 1);
+    theme->a_focused_handle = RrAppearanceNew(inst, 0);
+    theme->a_unfocused_handle = RrAppearanceNew(inst, 0);
+    theme->a_menu = RrAppearanceNew(inst, 0);
+    theme->a_menu_title = RrAppearanceNew(inst, 0);
+    theme->a_menu_text_title = RrAppearanceNew(inst, 1);
+    theme->a_menu_normal = RrAppearanceNew(inst, 0);
+    theme->a_menu_selected = RrAppearanceNew(inst, 0);
+    theme->a_menu_disabled = RrAppearanceNew(inst, 0);
+    theme->a_menu_disabled_selected = RrAppearanceNew(inst, 0);
+    theme->a_menu_text_normal = RrAppearanceNew(inst, 1);
+    theme->a_menu_text_selected = RrAppearanceNew(inst, 1);
+    theme->a_menu_text_disabled = RrAppearanceNew(inst, 1);
+    theme->a_menu_text_disabled_selected = RrAppearanceNew(inst, 1);
+    theme->a_menu_bullet_normal = RrAppearanceNew(inst, 1);
+    theme->a_menu_bullet_selected = RrAppearanceNew(inst, 1);
+    theme->a_clear = RrAppearanceNew(inst, 0);
+    theme->a_clear_tex = RrAppearanceNew(inst, 1);
+    theme->osd_hilite_bg = RrAppearanceNew(inst, 0);
+    theme->osd_hilite_label = RrAppearanceNew(inst, 1);
+    theme->osd_hilite_fg = RrAppearanceNew(inst, 0);
+    theme->osd_unhilite_fg = RrAppearanceNew(inst, 0);
+
+    /* load the font stuff */
+    if (active_window_font) {
+        theme->win_font_focused = active_window_font;
+        RrFontRef(active_window_font);
+    }
+    else
+        theme->win_font_focused = RrFontOpenDefault(inst);
+
+    if (inactive_window_font) {
+        theme->win_font_unfocused = inactive_window_font;
+        RrFontRef(inactive_window_font);
+    }
+    else
+        theme->win_font_unfocused = RrFontOpenDefault(inst);
+
+    winjust = RR_JUSTIFY_LEFT;
+    if (read_string(db, "window.label.text.justify", &str)) {
+        if (!g_ascii_strcasecmp(str, "right"))
+            winjust = RR_JUSTIFY_RIGHT;
+        else if (!g_ascii_strcasecmp(str, "center"))
+            winjust = RR_JUSTIFY_CENTER;
+    }
+
+    if (menu_title_font) {
+        theme->menu_title_font = menu_title_font;
+        RrFontRef(menu_title_font);
+    }
+    else
+        theme->menu_title_font = RrFontOpenDefault(inst);
+
+    mtitlejust = RR_JUSTIFY_LEFT;
+    if (read_string(db, "menu.title.text.justify", &str)) {
+        if (!g_ascii_strcasecmp(str, "right"))
+            mtitlejust = RR_JUSTIFY_RIGHT;
+        else if (!g_ascii_strcasecmp(str, "center"))
+            mtitlejust = RR_JUSTIFY_CENTER;
+    }
+
+    if (menu_item_font) {
+        theme->menu_font = menu_item_font;
+        RrFontRef(menu_item_font);
+    }
+    else
+        theme->menu_font = RrFontOpenDefault(inst);
+
+    if (osd_font) {
+        theme->osd_font = osd_font;
+        RrFontRef(osd_font);
+    }
+    else
+        theme->osd_font = RrFontOpenDefault(inst);
+
+    /* load direct dimensions */
+    if (!read_int(db, "menu.overlap", &theme->menu_overlap)
+            || theme->menu_overlap < -100 || theme->menu_overlap > 100)
+        theme->menu_overlap = 0;
+    if (!read_int(db, "window.handle.width", &theme->handle_height)
+            || theme->handle_height < 0 || theme->handle_height > 100)
+        theme->handle_height = 6;
+    if (!read_int(db, "padding.width", &theme->paddingx) || theme->paddingx < 0
+            || theme->paddingx > 100)
+        theme->paddingx = 3;
+    if (!read_int(db, "padding.height", &theme->paddingy) || theme->paddingy
+            < 0 || theme->paddingy > 100)
+        theme->paddingy = theme->paddingx;
+    if (!read_int(db, "border.width", &theme->fbwidth) || theme->fbwidth < 0
+            || theme->fbwidth > 100)
+        theme->fbwidth = 1;
+    /* menu border width inherits from the frame border width */
+    if (!read_int(db, "menu.border.width", &theme->mbwidth) || theme->mbwidth
+            < 0 || theme->mbwidth > 100)
+        theme->mbwidth = theme->fbwidth;
+    /* osd border width inherits from the frame border width */
+    if (!read_int(db, "osd.border.width", &theme->obwidth) || theme->obwidth
+            < 0 || theme->obwidth > 100)
+        theme->obwidth = theme->fbwidth;
+    if (!read_int(db, "window.client.padding.width", &theme->cbwidthx)
+            || theme->cbwidthx < 0 || theme->cbwidthx > 100)
+        theme->cbwidthx = theme->paddingx;
+    if (!read_int(db, "window.client.padding.height", &theme->cbwidthy)
+            || theme->cbwidthy < 0 || theme->cbwidthy > 100)
+        theme->cbwidthy = theme->cbwidthx;
+
+    /* load colors */
+    if (!read_color(db, inst, "window.active.border.color",
+            &theme->frame_focused_border_color) && !read_color(db, inst,
+            "border.color", &theme->frame_focused_border_color))
+        theme->frame_focused_border_color = RrColorNew(inst, 0, 0, 0);
+    /* title separator focused color inherits from focused boder color */
+    if (!read_color(db, inst, "window.active.title.separator.color",
+            &theme->title_separator_focused_color))
+        theme->title_separator_focused_color = RrColorNew(inst,
+                theme->frame_focused_border_color->r,
+                theme->frame_focused_border_color->g,
+                theme->frame_focused_border_color->b);
+    /* unfocused border color inherits from frame focused border color */
+    if (!read_color(db, inst, "window.inactive.border.color",
+            &theme->frame_unfocused_border_color))
+        theme->frame_unfocused_border_color = RrColorNew(inst,
+                theme->frame_focused_border_color->r,
+                theme->frame_focused_border_color->g,
+                theme->frame_focused_border_color->b);
+    /* title separator unfocused color inherits from unfocused boder color */
+    if (!read_color(db, inst, "window.inactive.title.separator.color",
+            &theme->title_separator_unfocused_color))
+        theme->title_separator_unfocused_color = RrColorNew(inst,
+                theme->frame_unfocused_border_color->r,
+                theme->frame_unfocused_border_color->g,
+                theme->frame_unfocused_border_color->b);
+
+    /* menu border color inherits from frame focused border color */
+    if (!read_color(db, inst, "menu.border.color", &theme->menu_border_color))
+        theme->menu_border_color = RrColorNew(inst,
+                theme->frame_focused_border_color->r,
+                theme->frame_focused_border_color->g,
+                theme->frame_focused_border_color->b);
+    /* osd border color inherits from frame focused border color */
+    if (!read_color(db, inst, "osd.border.color", &theme->osd_border_color))
+        theme->osd_border_color = RrColorNew(inst,
+                theme->frame_focused_border_color->r,
+                theme->frame_focused_border_color->g,
+                theme->frame_focused_border_color->b);
+    if (!read_color(db, inst, "window.active.client.color",
+            &theme->cb_focused_color))
+        theme->cb_focused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
+    if (!read_color(db, inst, "window.inactive.client.color",
+            &theme->cb_unfocused_color))
+        theme->cb_unfocused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
+    if (!read_color(db, inst, "window.active.label.text.color",
+            &theme->title_focused_color))
+        theme->title_focused_color = RrColorNew(inst, 0x0, 0x0, 0x0);
+    if (!read_color(db, inst, "osd.label.text.color", &theme->osd_color))
+        theme->osd_color = RrColorNew(inst, theme->title_focused_color->r,
+                theme->title_focused_color->g, theme->title_focused_color->b);
+    if (!read_color(db, inst, "window.inactive.label.text.color",
+            &theme->title_unfocused_color))
+        theme->title_unfocused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
+    if (!read_color(db, inst, "window.active.button.unpressed.image.color",
+            &theme->titlebut_focused_unpressed_color))
+        theme->titlebut_focused_unpressed_color = RrColorNew(inst, 0, 0, 0);
+    if (!read_color(db, inst, "window.inactive.button.unpressed.image.color",
+            &theme->titlebut_unfocused_unpressed_color))
+        theme->titlebut_unfocused_unpressed_color = RrColorNew(inst, 0xff,
+                0xff, 0xff);
+    if (!read_color(db, inst, "window.active.button.pressed.image.color",
+            &theme->titlebut_focused_pressed_color))
+        theme->titlebut_focused_pressed_color = RrColorNew(inst,
+                theme->titlebut_focused_unpressed_color->r,
+                theme->titlebut_focused_unpressed_color->g,
+                theme->titlebut_focused_unpressed_color->b);
+    if (!read_color(db, inst, "window.inactive.button.pressed.image.color",
+            &theme->titlebut_unfocused_pressed_color))
+        theme->titlebut_unfocused_pressed_color = RrColorNew(inst,
+                theme->titlebut_unfocused_unpressed_color->r,
+                theme->titlebut_unfocused_unpressed_color->g,
+                theme->titlebut_unfocused_unpressed_color->b);
+    if (!read_color(db, inst, "window.active.button.disabled.image.color",
+            &theme->titlebut_disabled_focused_color))
+        theme->titlebut_disabled_focused_color = RrColorNew(inst, 0xff, 0xff,
+                0xff);
+    if (!read_color(db, inst, "window.inactive.button.disabled.image.color",
+            &theme->titlebut_disabled_unfocused_color))
+        theme->titlebut_disabled_unfocused_color = RrColorNew(inst, 0, 0, 0);
+    if (!read_color(db, inst, "window.active.button.hover.image.color",
+            &theme->titlebut_hover_focused_color))
+        theme->titlebut_hover_focused_color = RrColorNew(inst,
+                theme->titlebut_focused_unpressed_color->r,
+                theme->titlebut_focused_unpressed_color->g,
+                theme->titlebut_focused_unpressed_color->b);
+    if (!read_color(db, inst, "window.inactive.button.hover.image.color",
+            &theme->titlebut_hover_unfocused_color))
+        theme->titlebut_hover_unfocused_color = RrColorNew(inst,
+                theme->titlebut_unfocused_unpressed_color->r,
+                theme->titlebut_unfocused_unpressed_color->g,
+                theme->titlebut_unfocused_unpressed_color->b);
+    if (!read_color(db, inst,
+            "window.active.button.toggled.unpressed.image.color",
+            &theme->titlebut_toggled_focused_unpressed_color) && !read_color(
+            db, inst, "window.active.button.toggled.image.color",
+            &theme->titlebut_toggled_focused_unpressed_color))
+        theme->titlebut_toggled_focused_unpressed_color = RrColorNew(inst,
+                theme->titlebut_focused_pressed_color->r,
+                theme->titlebut_focused_pressed_color->g,
+                theme->titlebut_focused_pressed_color->b);
+    if (!read_color(db, inst,
+            "window.inactive.button.toggled.unpressed.image.color",
+            &theme->titlebut_toggled_unfocused_unpressed_color) && !read_color(
+            db, inst, "window.inactive.button.toggled.image.color",
+            &theme->titlebut_toggled_unfocused_unpressed_color))
+        theme->titlebut_toggled_unfocused_unpressed_color = RrColorNew(inst,
+                theme->titlebut_unfocused_pressed_color->r,
+                theme->titlebut_unfocused_pressed_color->g,
+                theme->titlebut_unfocused_pressed_color->b);
+    if (!read_color(db, inst, "window.active.button.toggled.hover.image.color",
+            &theme->titlebut_toggled_hover_focused_color))
+        theme->titlebut_toggled_hover_focused_color = RrColorNew(inst,
+                theme->titlebut_toggled_focused_unpressed_color->r,
+                theme->titlebut_toggled_focused_unpressed_color->g,
+                theme->titlebut_toggled_focused_unpressed_color->b);
+    if (!read_color(db, inst,
+            "window.inactive.button.toggled.hover.image.color",
+            &theme->titlebut_toggled_hover_unfocused_color))
+        theme->titlebut_toggled_hover_unfocused_color = RrColorNew(inst,
+                theme->titlebut_toggled_unfocused_unpressed_color->r,
+                theme->titlebut_toggled_unfocused_unpressed_color->g,
+                theme->titlebut_toggled_unfocused_unpressed_color->b);
+    if (!read_color(db, inst,
+            "window.active.button.toggled.pressed.image.color",
+            &theme->titlebut_toggled_focused_pressed_color))
+        theme->titlebut_toggled_focused_pressed_color = RrColorNew(inst,
+                theme->titlebut_focused_pressed_color->r,
+                theme->titlebut_focused_pressed_color->g,
+                theme->titlebut_focused_pressed_color->b);
+    if (!read_color(db, inst,
+            "window.inactive.button.toggled.pressed.image.color",
+            &theme->titlebut_toggled_unfocused_pressed_color))
+        theme->titlebut_toggled_unfocused_pressed_color = RrColorNew(inst,
+                theme->titlebut_unfocused_pressed_color->r,
+                theme->titlebut_unfocused_pressed_color->g,
+                theme->titlebut_unfocused_pressed_color->b);
+    if (!read_color(db, inst, "menu.title.text.color", &theme->menu_title_color))
+        theme->menu_title_color = RrColorNew(inst, 0, 0, 0);
+    if (!read_color(db, inst, "menu.items.text.color", &theme->menu_color))
+        theme->menu_color = RrColorNew(inst, 0xff, 0xff, 0xff);
+    if (!read_color(db, inst, "menu.items.disabled.text.color",
+            &theme->menu_disabled_color))
+        theme->menu_disabled_color = RrColorNew(inst, 0, 0, 0);
+    if (!read_color(db, inst, "menu.items.active.disabled.text.color",
+            &theme->menu_disabled_selected_color))
+        theme->menu_disabled_selected_color = RrColorNew(inst,
+                theme->menu_disabled_color->r, theme->menu_disabled_color->g,
+                theme->menu_disabled_color->b);
+    if (!read_color(db, inst, "menu.items.active.text.color",
+            &theme->menu_selected_color))
+        theme->menu_selected_color = RrColorNew(inst, 0, 0, 0);
+
+    /* load the image masks */
+
+    /* maximize button masks */
+    userdef = TRUE;
+    if (!read_mask(inst, path, theme, "max.xbm", &theme->max_mask)) {
+        guchar data[] = { 0x3f, 0x3f, 0x21, 0x21, 0x21, 0x3f };
+        theme->max_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+        userdef = FALSE;
+    }
+    if (!read_mask(inst, path, theme, "max_toggled.xbm",
+            &theme->max_toggled_mask)) {
+        if (userdef)
+            theme->max_toggled_mask = RrPixmapMaskCopy(theme->max_mask);
+        else {
+            guchar data[] = { 0x3e, 0x22, 0x2f, 0x29, 0x39, 0x0f };
+            theme->max_toggled_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+        }
+    }
+    if (!read_mask(inst, path, theme, "max_pressed.xbm",
+            &theme->max_pressed_mask))
+        theme->max_pressed_mask = RrPixmapMaskCopy(theme->max_mask);
+    if (!read_mask(inst, path, theme, "max_disabled.xbm",
+            &theme->max_disabled_mask))
+        theme->max_disabled_mask = RrPixmapMaskCopy(theme->max_mask);
+    if (!read_mask(inst, path, theme, "max_hover.xbm", &theme->max_hover_mask))
+        theme->max_hover_mask = RrPixmapMaskCopy(theme->max_mask);
+    if (!read_mask(inst, path, theme, "max_toggled_pressed.xbm",
+            &theme->max_toggled_pressed_mask))
+        theme->max_toggled_pressed_mask
+                = RrPixmapMaskCopy(theme->max_toggled_mask);
+    if (!read_mask(inst, path, theme, "max_toggled_hover.xbm",
+            &theme->max_toggled_hover_mask))
+        theme->max_toggled_hover_mask
+                = RrPixmapMaskCopy(theme->max_toggled_mask);
+
+    /* iconify button masks */
+    if (!read_mask(inst, path, theme, "iconify.xbm", &theme->iconify_mask)) {
+        guchar data[] = { 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f };
+        theme->iconify_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+    }
+    if (!read_mask(inst, path, theme, "iconify_pressed.xbm",
+            &theme->iconify_pressed_mask))
+        theme->iconify_pressed_mask = RrPixmapMaskCopy(theme->iconify_mask);
+    if (!read_mask(inst, path, theme, "iconify_disabled.xbm",
+            &theme->iconify_disabled_mask))
+        theme->iconify_disabled_mask = RrPixmapMaskCopy(theme->iconify_mask);
+    if (!read_mask(inst, path, theme, "iconify_hover.xbm",
+            &theme->iconify_hover_mask))
+        theme->iconify_hover_mask = RrPixmapMaskCopy(theme->iconify_mask);
+
+    /* all desktops button masks */
+    userdef = TRUE;
+    if (!read_mask(inst, path, theme, "desk.xbm", &theme->desk_mask)) {
+        guchar data[] = { 0x33, 0x33, 0x00, 0x00, 0x33, 0x33 };
+        theme->desk_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+        userdef = FALSE;
+    }
+    if (!read_mask(inst, path, theme, "desk_toggled.xbm",
+            &theme->desk_toggled_mask)) {
+        if (userdef)
+            theme->desk_toggled_mask = RrPixmapMaskCopy(theme->desk_mask);
+        else {
+            guchar data[] = { 0x00, 0x1e, 0x1a, 0x16, 0x1e, 0x00 };
+            theme->desk_toggled_mask
+                    = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+        }
+    }
+    if (!read_mask(inst, path, theme, "desk_pressed.xbm",
+            &theme->desk_pressed_mask))
+        theme->desk_pressed_mask = RrPixmapMaskCopy(theme->desk_mask);
+    if (!read_mask(inst, path, theme, "desk_disabled.xbm",
+            &theme->desk_disabled_mask))
+        theme->desk_disabled_mask = RrPixmapMaskCopy(theme->desk_mask);
+    if (!read_mask(inst, path, theme, "desk_hover.xbm", &theme->desk_hover_mask))
+        theme->desk_hover_mask = RrPixmapMaskCopy(theme->desk_mask);
+    if (!read_mask(inst, path, theme, "desk_toggled_pressed.xbm",
+            &theme->desk_toggled_pressed_mask))
+        theme->desk_toggled_pressed_mask
+                = RrPixmapMaskCopy(theme->desk_toggled_mask);
+    if (!read_mask(inst, path, theme, "desk_toggled_hover.xbm",
+            &theme->desk_toggled_hover_mask))
+        theme->desk_toggled_hover_mask
+                = RrPixmapMaskCopy(theme->desk_toggled_mask);
+
+    /* shade button masks */
+    if (!read_mask(inst, path, theme, "shade.xbm", &theme->shade_mask)) {
+        guchar data[] = { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 };
+        theme->shade_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+    }
+    if (!read_mask(inst, path, theme, "shade_toggled.xbm",
+            &theme->shade_toggled_mask))
+        theme->shade_toggled_mask = RrPixmapMaskCopy(theme->shade_mask);
+    if (!read_mask(inst, path, theme, "shade_pressed.xbm",
+            &theme->shade_pressed_mask))
+        theme->shade_pressed_mask = RrPixmapMaskCopy(theme->shade_mask);
+    if (!read_mask(inst, path, theme, "shade_disabled.xbm",
+            &theme->shade_disabled_mask))
+        theme->shade_disabled_mask = RrPixmapMaskCopy(theme->shade_mask);
+    if (!read_mask(inst, path, theme, "shade_hover.xbm",
+            &theme->shade_hover_mask))
+        theme->shade_hover_mask = RrPixmapMaskCopy(theme->shade_mask);
+    if (!read_mask(inst, path, theme, "shade_toggled_pressed.xbm",
+            &theme->shade_toggled_pressed_mask))
+        theme->shade_toggled_pressed_mask
+                = RrPixmapMaskCopy(theme->shade_toggled_mask);
+    if (!read_mask(inst, path, theme, "shade_toggled_hover.xbm",
+            &theme->shade_toggled_hover_mask))
+        theme->shade_toggled_hover_mask
+                = RrPixmapMaskCopy(theme->shade_toggled_mask);
+
+    /* close button masks */
+    if (!read_mask(inst, path, theme, "close.xbm", &theme->close_mask)) {
+        guchar data[] = { 0x33, 0x3f, 0x1e, 0x1e, 0x3f, 0x33 };
+        theme->close_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+    }
+    if (!read_mask(inst, path, theme, "close_pressed.xbm",
+            &theme->close_pressed_mask))
+        theme->close_pressed_mask = RrPixmapMaskCopy(theme->close_mask);
+    if (!read_mask(inst, path, theme, "close_disabled.xbm",
+            &theme->close_disabled_mask))
+        theme->close_disabled_mask = RrPixmapMaskCopy(theme->close_mask);
+    if (!read_mask(inst, path, theme, "close_hover.xbm",
+            &theme->close_hover_mask))
+        theme->close_hover_mask = RrPixmapMaskCopy(theme->close_mask);
+
+    /* submenu bullet mask */
+    if (!read_mask(inst, path, theme, "bullet.xbm", &theme->menu_bullet_mask)) {
+        guchar data[] = { 0x01, 0x03, 0x07, 0x0f, 0x07, 0x03, 0x01 };
+        theme->menu_bullet_mask = RrPixmapMaskNew(inst, 4, 7, (gchar*)data);
+    }
+
+    /* setup the default window icon */
+    theme->def_win_icon = read_c_image(OB_DEFAULT_ICON_WIDTH,
+            OB_DEFAULT_ICON_HEIGHT, OB_DEFAULT_ICON_pixel_data);
+
+    /* the toggled hover mask = the toggled unpressed mask (i.e. no change) */
+    theme->max_toggled_hover_mask = RrPixmapMaskCopy(theme->max_toggled_mask);
+    theme->desk_toggled_hover_mask = RrPixmapMaskCopy(theme->desk_toggled_mask);
+    theme->shade_toggled_hover_mask
+            = RrPixmapMaskCopy(theme->shade_toggled_mask);
+    /* the toggled pressed mask = the toggled unpressed mask (i.e. no change)*/
+    theme->max_toggled_pressed_mask = RrPixmapMaskCopy(theme->max_toggled_mask);
+    theme->desk_toggled_pressed_mask
+            = RrPixmapMaskCopy(theme->desk_toggled_mask);
+    theme->shade_toggled_pressed_mask
+            = RrPixmapMaskCopy(theme->shade_toggled_mask);
+
+    /* read the decoration textures */
+    if (!read_appearance(db, inst, "window.active.title.bg",
+            theme->a_focused_title, FALSE))
+        set_default_appearance(theme->a_focused_title);
+    if (!read_appearance(db, inst, "window.inactive.title.bg",
+            theme->a_unfocused_title, FALSE))
+        set_default_appearance(theme->a_unfocused_title);
+    if (!read_appearance(db, inst, "window.active.label.bg",
+            theme->a_focused_label, TRUE))
+        set_default_appearance(theme->a_focused_label);
+    if (!read_appearance(db, inst, "window.inactive.label.bg",
+            theme->a_unfocused_label, TRUE))
+        set_default_appearance(theme->a_unfocused_label);
+    if (!read_appearance(db, inst, "window.active.handle.bg",
+            theme->a_focused_handle, FALSE))
+        set_default_appearance(theme->a_focused_handle);
+    if (!read_appearance(db, inst, "window.inactive.handle.bg",
+            theme->a_unfocused_handle, FALSE))
+        set_default_appearance(theme->a_unfocused_handle);
+    if (!read_appearance(db, inst, "window.active.grip.bg",
+            theme->a_focused_grip, TRUE))
+        set_default_appearance(theme->a_focused_grip);
+    if (!read_appearance(db, inst, "window.inactive.grip.bg",
+            theme->a_unfocused_grip, TRUE))
+        set_default_appearance(theme->a_unfocused_grip);
+    if (!read_appearance(db, inst, "menu.items.bg", theme->a_menu, FALSE))
+        set_default_appearance(theme->a_menu);
+    if (!read_appearance(db, inst, "menu.title.bg", theme->a_menu_title, TRUE))
+        set_default_appearance(theme->a_menu_title);
+    if (!read_appearance(db, inst, "menu.items.active.bg",
+            theme->a_menu_selected, TRUE))
+        set_default_appearance(theme->a_menu_selected);
+    theme->a_menu_disabled_selected = RrAppearanceCopy(theme->a_menu_selected);
+
+    /* read appearances for non-decorations (on-screen-display) */
+    if (!read_appearance(db, inst, "osd.bg", theme->osd_hilite_bg, FALSE)) {
+        RrAppearanceFree(theme->osd_hilite_bg);
+        theme->osd_hilite_bg = RrAppearanceCopy(theme->a_focused_title);
+    }
+    if (!read_appearance(db, inst, "osd.label.bg", theme->osd_hilite_label,
+            TRUE)) {
+        RrAppearanceFree(theme->osd_hilite_label);
+        theme->osd_hilite_label = RrAppearanceCopy(theme->a_focused_label);
+    }
+    /* osd_hilite_fg can't be parentrel */
+    if (!read_appearance(db, inst, "osd.hilight.bg", theme->osd_hilite_fg,
+            FALSE)) {
+        RrAppearanceFree(theme->osd_hilite_fg);
+        if (theme->a_focused_label->surface.grad != RR_SURFACE_PARENTREL)
+            theme->osd_hilite_fg = RrAppearanceCopy(theme->a_focused_label);
+        else
+            theme->osd_hilite_fg = RrAppearanceCopy(theme->a_focused_title);
+    }
+    /* osd_unhilite_fg can't be parentrel either */
+    if (!read_appearance(db, inst, "osd.unhilight.bg", theme->osd_unhilite_fg,
+            FALSE)) {
+        RrAppearanceFree(theme->osd_unhilite_fg);
+        if (theme->a_unfocused_label->surface.grad != RR_SURFACE_PARENTREL)
+            theme->osd_unhilite_fg=RrAppearanceCopy(theme->a_unfocused_label);
+        else
+            theme->osd_unhilite_fg=RrAppearanceCopy(theme->a_unfocused_title);
+    }
+
+    /* read buttons textures */
+    if (!read_appearance(db, inst, "window.active.button.disabled.bg",
+            theme->a_disabled_focused_max, TRUE))
+        set_default_appearance(theme->a_disabled_focused_max);
+    if (!read_appearance(db, inst, "window.inactive.button.disabled.bg",
+            theme->a_disabled_unfocused_max, TRUE))
+        set_default_appearance(theme->a_disabled_unfocused_max);
+    if (!read_appearance(db, inst, "window.active.button.pressed.bg",
+            theme->a_focused_pressed_max, TRUE))
+        set_default_appearance(theme->a_focused_pressed_max);
+    if (!read_appearance(db, inst, "window.inactive.button.pressed.bg",
+            theme->a_unfocused_pressed_max, TRUE))
+        set_default_appearance(theme->a_unfocused_pressed_max);
+    if (!read_appearance(db, inst, "window.active.button.toggled.unpressed.bg",
+            theme->a_toggled_focused_unpressed_max, TRUE) && !read_appearance(
+            db, inst, "window.active.button.toggled.bg",
+            theme->a_toggled_focused_unpressed_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_focused_unpressed_max);
+        theme->a_toggled_focused_unpressed_max
+                = RrAppearanceCopy(theme->a_focused_pressed_max);
+    }
+    if (!read_appearance(db, inst,
+            "window.inactive.button.toggled.unpressed.bg",
+            theme->a_toggled_unfocused_unpressed_max, TRUE)
+            && !read_appearance(db, inst, "window.inactive.button.toggled.bg",
+                    theme->a_toggled_unfocused_unpressed_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_unfocused_unpressed_max);
+        theme->a_toggled_unfocused_unpressed_max
+                = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    }
+    if (!read_appearance(db, inst, "window.active.button.toggled.hover.bg",
+            theme->a_toggled_hover_focused_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_hover_focused_max);
+        theme->a_toggled_hover_focused_max
+                = RrAppearanceCopy(theme->a_toggled_focused_unpressed_max);
+    }
+    if (!read_appearance(db, inst, "window.inactive.button.toggled.hover.bg",
+            theme->a_toggled_hover_unfocused_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_hover_unfocused_max);
+        theme->a_toggled_hover_unfocused_max
+                = RrAppearanceCopy(theme->a_toggled_unfocused_unpressed_max);
+    }
+    if (!read_appearance(db, inst, "window.active.button.toggled.pressed.bg",
+            theme->a_toggled_focused_pressed_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_focused_pressed_max);
+        theme->a_toggled_focused_pressed_max
+                = RrAppearanceCopy(theme->a_focused_pressed_max);
+    }
+    if (!read_appearance(db, inst, "window.inactive.button.toggled.pressed.bg",
+            theme->a_toggled_unfocused_pressed_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_unfocused_pressed_max);
+        theme->a_toggled_unfocused_pressed_max
+                = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    }
+    if (!read_appearance(db, inst, "window.active.button.unpressed.bg",
+            theme->a_focused_unpressed_max, TRUE))
+        set_default_appearance(theme->a_focused_unpressed_max);
+    if (!read_appearance(db, inst, "window.inactive.button.unpressed.bg",
+            theme->a_unfocused_unpressed_max, TRUE))
+        set_default_appearance(theme->a_unfocused_unpressed_max);
+    if (!read_appearance(db, inst, "window.active.button.hover.bg",
+            theme->a_hover_focused_max, TRUE)) {
+        RrAppearanceFree(theme->a_hover_focused_max);
+        theme->a_hover_focused_max
+                = RrAppearanceCopy(theme->a_focused_unpressed_max);
+    }
+    if (!read_appearance(db, inst, "window.inactive.button.hover.bg",
+            theme->a_hover_unfocused_max, TRUE)) {
+        RrAppearanceFree(theme->a_hover_unfocused_max);
+        theme->a_hover_unfocused_max
+                = RrAppearanceCopy(theme->a_unfocused_unpressed_max);
+    }
+
+    theme->a_disabled_focused_close
+            = RrAppearanceCopy(theme->a_disabled_focused_max);
+    theme->a_disabled_unfocused_close
+            = RrAppearanceCopy(theme->a_disabled_unfocused_max);
+    theme->a_hover_focused_close = RrAppearanceCopy(theme->a_hover_focused_max);
+    theme->a_hover_unfocused_close
+            = RrAppearanceCopy(theme->a_hover_unfocused_max);
+    theme->a_unfocused_unpressed_close
+            = RrAppearanceCopy(theme->a_unfocused_unpressed_max);
+    theme->a_unfocused_pressed_close
+            = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    theme->a_focused_unpressed_close
+            = RrAppearanceCopy(theme->a_focused_unpressed_max);
+    theme->a_focused_pressed_close
+            = RrAppearanceCopy(theme->a_focused_pressed_max);
+    theme->a_disabled_focused_desk
+            = RrAppearanceCopy(theme->a_disabled_focused_max);
+    theme->a_disabled_unfocused_desk
+            = RrAppearanceCopy(theme->a_disabled_unfocused_max);
+    theme->a_hover_focused_desk = RrAppearanceCopy(theme->a_hover_focused_max);
+    theme->a_hover_unfocused_desk
+            = RrAppearanceCopy(theme->a_hover_unfocused_max);
+    theme->a_toggled_hover_focused_desk
+            = RrAppearanceCopy(theme->a_toggled_hover_focused_max);
+    theme->a_toggled_hover_unfocused_desk
+            = RrAppearanceCopy(theme->a_toggled_hover_unfocused_max);
+    theme->a_toggled_focused_unpressed_desk
+            = RrAppearanceCopy(theme->a_toggled_focused_unpressed_max);
+    theme->a_toggled_unfocused_unpressed_desk
+            = RrAppearanceCopy(theme->a_toggled_unfocused_unpressed_max);
+    theme->a_toggled_focused_pressed_desk
+            = RrAppearanceCopy(theme->a_toggled_focused_pressed_max);
+    theme->a_toggled_unfocused_pressed_desk
+            = RrAppearanceCopy(theme->a_toggled_unfocused_pressed_max);
+    theme->a_unfocused_unpressed_desk
+            = RrAppearanceCopy(theme->a_unfocused_unpressed_max);
+    theme->a_unfocused_pressed_desk
+            = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    theme->a_focused_unpressed_desk
+            = RrAppearanceCopy(theme->a_focused_unpressed_max);
+    theme->a_focused_pressed_desk
+            = RrAppearanceCopy(theme->a_focused_pressed_max);
+    theme->a_disabled_focused_shade
+            = RrAppearanceCopy(theme->a_disabled_focused_max);
+    theme->a_disabled_unfocused_shade
+            = RrAppearanceCopy(theme->a_disabled_unfocused_max);
+    theme->a_hover_focused_shade = RrAppearanceCopy(theme->a_hover_focused_max);
+    theme->a_hover_unfocused_shade
+            = RrAppearanceCopy(theme->a_hover_unfocused_max);
+    theme->a_toggled_hover_focused_shade
+            = RrAppearanceCopy(theme->a_toggled_hover_focused_max);
+    theme->a_toggled_hover_unfocused_shade
+            = RrAppearanceCopy(theme->a_toggled_hover_unfocused_max);
+    theme->a_toggled_focused_unpressed_shade
+            = RrAppearanceCopy(theme->a_toggled_focused_unpressed_max);
+    theme->a_toggled_unfocused_unpressed_shade
+            = RrAppearanceCopy(theme->a_toggled_unfocused_unpressed_max);
+    theme->a_toggled_focused_pressed_shade
+            = RrAppearanceCopy(theme->a_toggled_focused_pressed_max);
+    theme->a_toggled_unfocused_pressed_shade
+            = RrAppearanceCopy(theme->a_toggled_unfocused_pressed_max);
+    theme->a_unfocused_unpressed_shade
+            = RrAppearanceCopy(theme->a_unfocused_unpressed_max);
+    theme->a_unfocused_pressed_shade
+            = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    theme->a_focused_unpressed_shade
+            = RrAppearanceCopy(theme->a_focused_unpressed_max);
+    theme->a_focused_pressed_shade
+            = RrAppearanceCopy(theme->a_focused_pressed_max);
+    theme->a_disabled_focused_iconify
+            = RrAppearanceCopy(theme->a_disabled_focused_max);
+    theme->a_disabled_unfocused_iconify
+            = RrAppearanceCopy(theme->a_disabled_focused_max);
+    theme->a_hover_focused_iconify
+            = RrAppearanceCopy(theme->a_hover_focused_max);
+    theme->a_hover_unfocused_iconify
+            = RrAppearanceCopy(theme->a_hover_unfocused_max);
+    theme->a_unfocused_unpressed_iconify
+            = RrAppearanceCopy(theme->a_unfocused_unpressed_max);
+    theme->a_unfocused_pressed_iconify
+            = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    theme->a_focused_unpressed_iconify
+            = RrAppearanceCopy(theme->a_focused_unpressed_max);
+    theme->a_focused_pressed_iconify
+            = RrAppearanceCopy(theme->a_focused_pressed_max);
+
+    theme->a_icon->surface.grad
+            = theme->a_clear->surface.grad
+                    = theme->a_clear_tex->surface.grad
+                            = theme->a_menu_text_title->surface.grad
+                                    = theme->a_menu_normal->surface.grad
+                                            = theme->a_menu_disabled->surface.grad
+                                                    = theme->a_menu_text_normal->surface.grad
+                                                            = theme->a_menu_text_selected->surface.grad
+                                                                    = theme->a_menu_text_disabled->surface.grad
+                                                                            = theme->a_menu_text_disabled_selected->surface.grad
+                                                                                    = theme->a_menu_bullet_normal->surface.grad
+                                                                                            = theme->a_menu_bullet_selected->surface.grad
+                                                                                                    = RR_SURFACE_PARENTREL;
+
+    /* set up the textures */
+    theme->a_focused_label->texture[0].type = RR_TEXTURE_TEXT;
+    theme->a_focused_label->texture[0].data.text.justify = winjust;
+    theme->a_focused_label->texture[0].data.text.font=theme->win_font_focused;
+    theme->a_focused_label->texture[0].data.text.color
+            = theme->title_focused_color;
+
+    if (read_string(db, "window.active.label.text.font", &str)) {
+        char *p;
+        gint i = 0;
+        gint j;
+        if (strstr(str, "shadow=y")) {
+            if ((p = strstr(str, "shadowoffset=")))
+                i = parse_inline_number(p + strlen("shadowoffset="));
+            else
+                i = 1;
+            theme->a_focused_label->texture[0].data.text.shadow_offset_x = i;
+            theme->a_focused_label->texture[0].data.text.shadow_offset_y = i;
+        }
+        if ((p = strstr(str, "shadowtint="))) {
+            i = parse_inline_number(p + strlen("shadowtint="));
+            j = (i > 0 ? 0 : 255);
+            i = ABS(i*255/100);
+
+            theme->title_focused_shadow_color = RrColorNew(inst, j, j, j);
+            theme->title_focused_shadow_alpha = i;
+        }
+        else {
+            theme->title_focused_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->title_focused_shadow_alpha = 50;
+        }
+    }
+
+    theme->a_focused_label->texture[0].data.text.shadow_color
+            = theme->title_focused_shadow_color;
+    theme->a_focused_label->texture[0].data.text.shadow_alpha
+            = theme->title_focused_shadow_alpha;
+
+    theme->osd_hilite_label->texture[0].type = RR_TEXTURE_TEXT;
+    theme->osd_hilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
+    theme->osd_hilite_label->texture[0].data.text.font = theme->osd_font;
+    theme->osd_hilite_label->texture[0].data.text.color = theme->osd_color;
+
+    if (read_string(db, "osd.label.text.font", &str)) {
+        char *p;
+        gint i = 0;
+        gint j;
+        if (strstr(str, "shadow=y")) {
+            if ((p = strstr(str, "shadowoffset=")))
+                i = parse_inline_number(p + strlen("shadowoffset="));
+            else
+                i = 1;
+            theme->a_focused_label->texture[0].data.text.shadow_offset_x = i;
+            theme->a_focused_label->texture[0].data.text.shadow_offset_y = i;
+            theme->osd_hilite_label->texture[0].data.text.shadow_offset_x = i;
+            theme->osd_hilite_label->texture[0].data.text.shadow_offset_y = i;
+        }
+        if ((p = strstr(str, "shadowtint="))) {
+            i = parse_inline_number(p + strlen("shadowtint="));
+            j = (i > 0 ? 0 : 255);
+            i = ABS(i*255/100);
+
+            theme->title_focused_shadow_color = RrColorNew(inst, j, j, j);
+            theme->title_focused_shadow_alpha = i;
+            theme->osd_shadow_color = RrColorNew(inst, j, j, j);
+            theme->osd_shadow_alpha = i;
+        }
+        else {
+            theme->title_focused_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->title_focused_shadow_alpha = 50;
+            theme->osd_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->osd_shadow_alpha = 50;
+        }
+    }
+    else {
+        /* inherit the font settings from the focused label */
+        theme->osd_hilite_label->texture[0].data.text.shadow_offset_x
+                = theme->a_focused_label->texture[0].data.text.shadow_offset_x;
+        theme->osd_hilite_label->texture[0].data.text.shadow_offset_y
+                = theme->a_focused_label->texture[0].data.text.shadow_offset_y;
+        if (theme->title_focused_shadow_color)
+            theme->osd_shadow_color = RrColorNew(inst,
+                    theme->title_focused_shadow_color->r,
+                    theme->title_focused_shadow_color->g,
+                    theme->title_focused_shadow_color->b);
+        else
+            theme->osd_shadow_color = RrColorNew(inst, 0, 0, 0);
+        theme->osd_shadow_alpha = theme->title_focused_shadow_alpha;
+    }
+
+    theme->osd_hilite_label->texture[0].data.text.shadow_color
+            = theme->osd_shadow_color;
+    theme->osd_hilite_label->texture[0].data.text.shadow_alpha
+            = theme->osd_shadow_alpha;
+
+    theme->a_unfocused_label->texture[0].type = RR_TEXTURE_TEXT;
+    theme->a_unfocused_label->texture[0].data.text.justify = winjust;
+    theme->a_unfocused_label->texture[0].data.text.font
+            = theme->win_font_unfocused;
+    theme->a_unfocused_label->texture[0].data.text.color
+            = theme->title_unfocused_color;
+
+    if (read_string(db, "window.inactive.label.text.font", &str)) {
+        char *p;
+        gint i = 0;
+        gint j;
+        if (strstr(str, "shadow=y")) {
+            if ((p = strstr(str, "shadowoffset=")))
+                i = parse_inline_number(p + strlen("shadowoffset="));
+            else
+                i = 1;
+            theme->a_unfocused_label->texture[0].data.text.shadow_offset_x = i;
+            theme->a_unfocused_label->texture[0].data.text.shadow_offset_y = i;
+        }
+        if ((p = strstr(str, "shadowtint="))) {
+            i = parse_inline_number(p + strlen("shadowtint="));
+            j = (i > 0 ? 0 : 255);
+            i = ABS(i*255/100);
+
+            theme->title_unfocused_shadow_color = RrColorNew(inst, j, j, j);
+            theme->title_unfocused_shadow_alpha = i;
+        }
+        else {
+            theme->title_unfocused_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->title_unfocused_shadow_alpha = 50;
+        }
+    }
+
+    theme->a_unfocused_label->texture[0].data.text.shadow_color
+            = theme->title_unfocused_shadow_color;
+    theme->a_unfocused_label->texture[0].data.text.shadow_alpha
+            = theme->title_unfocused_shadow_alpha;
+
+    theme->a_menu_text_title->texture[0].type = RR_TEXTURE_TEXT;
+    theme->a_menu_text_title->texture[0].data.text.justify = mtitlejust;
+    theme->a_menu_text_title->texture[0].data.text.font
+            = theme->menu_title_font;
+    theme->a_menu_text_title->texture[0].data.text.color
+            = theme->menu_title_color;
+
+    if (read_string(db, "menu.title.text.font", &str)) {
+        char *p;
+        gint i = 0;
+        gint j;
+        if (strstr(str, "shadow=y")) {
+            if ((p = strstr(str, "shadowoffset=")))
+                i = parse_inline_number(p + strlen("shadowoffset="));
+            else
+                i = 1;
+            theme->a_menu_text_title->texture[0].data.text.shadow_offset_x = i;
+            theme->a_menu_text_title->texture[0].data.text.shadow_offset_y = i;
+        }
+        if ((p = strstr(str, "shadowtint="))) {
+            i = parse_inline_number(p + strlen("shadowtint="));
+            j = (i > 0 ? 0 : 255);
+            i = ABS(i*255/100);
+
+            theme->menu_title_shadow_color = RrColorNew(inst, j, j, j);
+            theme->menu_title_shadow_alpha = i;
+        }
+        else {
+            theme->menu_title_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->menu_title_shadow_alpha = 50;
+        }
+    }
+
+    theme->a_menu_text_title->texture[0].data.text.shadow_color
+            = theme->menu_title_shadow_color;
+    theme->a_menu_text_title->texture[0].data.text.shadow_alpha
+            = theme->menu_title_shadow_alpha;
+
+    theme->a_menu_text_normal->texture[0].type
+            = theme->a_menu_text_selected->texture[0].type
+                    = theme->a_menu_text_disabled->texture[0].type
+                            = theme->a_menu_text_disabled_selected->texture[0].type
+                                    = RR_TEXTURE_TEXT;
+    theme->a_menu_text_normal->texture[0].data.text.justify
+            = theme->a_menu_text_selected->texture[0].data.text.justify
+                    = theme->a_menu_text_disabled->texture[0].data.text.justify
+                            = theme->a_menu_text_disabled_selected->texture[0].data.text.justify
+                                    = RR_JUSTIFY_LEFT;
+    theme->a_menu_text_normal->texture[0].data.text.font
+            = theme->a_menu_text_selected->texture[0].data.text.font
+                    = theme->a_menu_text_disabled->texture[0].data.text.font
+                            = theme->a_menu_text_disabled_selected->texture[0].data.text.font
+                                    = theme->menu_font;
+    theme->a_menu_text_normal->texture[0].data.text.color = theme->menu_color;
+    theme->a_menu_text_selected->texture[0].data.text.color
+            = theme->menu_selected_color;
+    theme->a_menu_text_disabled->texture[0].data.text.color
+            = theme->menu_disabled_color;
+    theme->a_menu_text_disabled_selected->texture[0].data.text.color
+            = theme->menu_disabled_selected_color;
+
+    if (read_string(db, "menu.items.font", &str)) {
+        char *p;
+        gint i = 0;
+        gint j;
+        if (strstr(str, "shadow=y")) {
+            if ((p = strstr(str, "shadowoffset=")))
+                i = parse_inline_number(p + strlen("shadowoffset="));
+            else
+                i = 1;
+            theme->a_menu_text_normal->
+            texture[0].data.text.shadow_offset_x = i;
+            theme->a_menu_text_normal->
+            texture[0].data.text.shadow_offset_y = i;
+            theme->a_menu_text_selected->
+            texture[0].data.text.shadow_offset_x = i;
+            theme->a_menu_text_selected->
+            texture[0].data.text.shadow_offset_y = i;
+            theme->a_menu_text_disabled->
+            texture[0].data.text.shadow_offset_x = i;
+            theme->a_menu_text_disabled->
+            texture[0].data.text.shadow_offset_y = i;
+            theme->a_menu_text_disabled_selected->
+            texture[0].data.text.shadow_offset_x = i;
+            theme->a_menu_text_disabled_selected->
+            texture[0].data.text.shadow_offset_y = i;
+        }
+        if ((p = strstr(str, "shadowtint="))) {
+            i = parse_inline_number(p + strlen("shadowtint="));
+            j = (i > 0 ? 0 : 255);
+            i = ABS(i*255/100);
+
+            theme->menu_text_normal_shadow_color = RrColorNew(inst, j, j, j);
+            theme->menu_text_selected_shadow_color = RrColorNew(inst, j, j, j);
+            theme->menu_text_disabled_shadow_color = RrColorNew(inst, j, j, j);
+            theme->menu_text_normal_shadow_alpha = i;
+            theme->menu_text_selected_shadow_alpha = i;
+            theme->menu_text_disabled_shadow_alpha = i;
+            theme->menu_text_disabled_selected_shadow_alpha = i;
+        }
+        else {
+            theme->menu_text_normal_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->menu_text_selected_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->menu_text_disabled_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->menu_text_normal_shadow_alpha = 50;
+            theme->menu_text_selected_shadow_alpha = 50;
+            theme->menu_text_disabled_selected_shadow_alpha = 50;
+        }
+    }
+
+    theme->a_menu_text_normal->texture[0].data.text.shadow_color
+            = theme->menu_text_normal_shadow_color;
+    theme->a_menu_text_normal->texture[0].data.text.shadow_alpha
+            = theme->menu_text_normal_shadow_alpha;
+    theme->a_menu_text_selected->texture[0].data.text.shadow_color
+            = theme->menu_text_selected_shadow_color;
+    theme->a_menu_text_selected->texture[0].data.text.shadow_alpha
+            = theme->menu_text_selected_shadow_alpha;
+    theme->a_menu_text_disabled->texture[0].data.text.shadow_color
+            = theme->menu_text_disabled_shadow_color;
+    theme->a_menu_text_disabled->texture[0].data.text.shadow_alpha
+            = theme->menu_text_disabled_shadow_alpha;
+    theme->a_menu_text_disabled_selected->texture[0].data.text.shadow_color
+            = theme->menu_text_disabled_shadow_color;
+    theme->a_menu_text_disabled_selected->texture[0].data.text.shadow_alpha
+            = theme->menu_text_disabled_shadow_alpha;
+
+    theme->a_disabled_focused_max->texture[0].type
+            = theme->a_disabled_unfocused_max->texture[0].type
+                    = theme->a_hover_focused_max->texture[0].type
+                            = theme->a_hover_unfocused_max->texture[0].type
+                                    = theme->a_toggled_hover_focused_max->texture[0].type
+                                            = theme->a_toggled_hover_unfocused_max->texture[0].type
+                                                    = theme->a_toggled_focused_unpressed_max->texture[0].type
+                                                            = theme->a_toggled_unfocused_unpressed_max->texture[0].type
+                                                                    = theme->a_toggled_focused_pressed_max->texture[0].type
+                                                                            = theme->a_toggled_unfocused_pressed_max->texture[0].type
+                                                                                    = theme->a_focused_unpressed_max->texture[0].type
+                                                                                            = theme->a_focused_pressed_max->texture[0].type
+                                                                                                    = theme->a_unfocused_unpressed_max->texture[0].type
+                                                                                                            = theme->a_unfocused_pressed_max->texture[0].type
+                                                                                                                    = theme->a_disabled_focused_close->texture[0].type
+                                                                                                                            = theme->a_disabled_unfocused_close->texture[0].type
+                                                                                                                                    = theme->a_hover_focused_close->texture[0].type
+                                                                                                                                            = theme->a_hover_unfocused_close->texture[0].type
+                                                                                                                                                    = theme->a_focused_unpressed_close->texture[0].type
+                                                                                                                                                            = theme->a_focused_pressed_close->texture[0].type
+                                                                                                                                                                    = theme->a_unfocused_unpressed_close->texture[0].type
+                                                                                                                                                                            = theme->a_unfocused_pressed_close->texture[0].type
+                                                                                                                                                                                    = theme->a_disabled_focused_desk->texture[0].type
+                                                                                                                                                                                            = theme->a_disabled_unfocused_desk->texture[0].type
+                                                                                                                                                                                                    = theme->a_hover_focused_desk->texture[0].type
+                                                                                                                                                                                                            = theme->a_hover_unfocused_desk->texture[0].type
+                                                                                                                                                                                                                    = theme->a_toggled_hover_focused_desk->texture[0].type
+                                                                                                                                                                                                                            = theme->a_toggled_hover_unfocused_desk->texture[0].type
+                                                                                                                                                                                                                                    = theme->a_toggled_focused_unpressed_desk->texture[0].type
+                                                                                                                                                                                                                                            = theme->a_toggled_unfocused_unpressed_desk->texture[0].type
+                                                                                                                                                                                                                                                    = theme->a_toggled_focused_pressed_desk->texture[0].type
+                                                                                                                                                                                                                                                            = theme->a_toggled_unfocused_pressed_desk->texture[0].type
+                                                                                                                                                                                                                                                                    = theme->a_focused_unpressed_desk->texture[0].type
+                                                                                                                                                                                                                                                                            = theme->a_focused_pressed_desk->texture[0].type
+                                                                                                                                                                                                                                                                                    = theme->a_unfocused_unpressed_desk->texture[0].type
+                                                                                                                                                                                                                                                                                            = theme->a_unfocused_pressed_desk->texture[0].type
+                                                                                                                                                                                                                                                                                                    = theme->a_disabled_focused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                            = theme->a_disabled_unfocused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                    = theme->a_hover_focused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                            = theme->a_hover_unfocused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                    = theme->a_toggled_hover_focused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                            = theme->a_toggled_hover_unfocused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                    = theme->a_toggled_focused_unpressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                            = theme->a_toggled_unfocused_unpressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                    = theme->a_toggled_focused_pressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                            = theme->a_toggled_unfocused_pressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_focused_unpressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_focused_pressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_unfocused_unpressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_unfocused_pressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_disabled_focused_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_disabled_unfocused_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_hover_focused_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_hover_unfocused_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_focused_unpressed_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_focused_pressed_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_unfocused_unpressed_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_unfocused_pressed_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_menu_bullet_normal->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_menu_bullet_selected->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    = RR_TEXTURE_MASK;
+
+    theme->a_disabled_focused_max->texture[0].data.mask.mask
+            = theme->a_disabled_unfocused_max->texture[0].data.mask.mask
+                    = theme->max_disabled_mask;
+    theme->a_hover_focused_max->texture[0].data.mask.mask
+            = theme->a_hover_unfocused_max->texture[0].data.mask.mask
+                    = theme->max_hover_mask;
+    theme->a_focused_pressed_max->texture[0].data.mask.mask
+            = theme->a_unfocused_pressed_max->texture[0].data.mask.mask
+                    = theme->max_pressed_mask;
+    theme->a_focused_unpressed_max->texture[0].data.mask.mask
+            = theme->a_unfocused_unpressed_max->texture[0].data.mask.mask
+                    = theme->max_mask;
+    theme->a_toggled_hover_focused_max->texture[0].data.mask.mask
+            = theme->a_toggled_hover_unfocused_max->texture[0].data.mask.mask
+                    = theme->max_toggled_hover_mask;
+    theme->a_toggled_focused_unpressed_max->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_unpressed_max->texture[0].data.mask.mask
+                    = theme->max_toggled_mask;
+    theme->a_toggled_focused_pressed_max->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_pressed_max->texture[0].data.mask.mask
+                    = theme->max_toggled_pressed_mask;
+    theme->a_disabled_focused_close->texture[0].data.mask.mask
+            = theme->a_disabled_unfocused_close->texture[0].data.mask.mask
+                    = theme->close_disabled_mask;
+    theme->a_hover_focused_close->texture[0].data.mask.mask
+            = theme->a_hover_unfocused_close->texture[0].data.mask.mask
+                    = theme->close_hover_mask;
+    theme->a_focused_pressed_close->texture[0].data.mask.mask
+            = theme->a_unfocused_pressed_close->texture[0].data.mask.mask
+                    = theme->close_pressed_mask;
+    theme->a_focused_unpressed_close->texture[0].data.mask.mask
+            = theme->a_unfocused_unpressed_close->texture[0].data.mask.mask
+                    = theme->close_mask;
+    theme->a_disabled_focused_desk->texture[0].data.mask.mask
+            = theme->a_disabled_unfocused_desk->texture[0].data.mask.mask
+                    = theme->desk_disabled_mask;
+    theme->a_hover_focused_desk->texture[0].data.mask.mask
+            = theme->a_hover_unfocused_desk->texture[0].data.mask.mask
+                    = theme->desk_hover_mask;
+    theme->a_focused_pressed_desk->texture[0].data.mask.mask
+            = theme->a_unfocused_pressed_desk->texture[0].data.mask.mask
+                    = theme->desk_pressed_mask;
+    theme->a_focused_unpressed_desk->texture[0].data.mask.mask
+            = theme->a_unfocused_unpressed_desk->texture[0].data.mask.mask
+                    = theme->desk_mask;
+    theme->a_toggled_hover_focused_desk->texture[0].data.mask.mask
+            = theme->a_toggled_hover_unfocused_desk->texture[0].data.mask.mask
+                    = theme->desk_toggled_hover_mask;
+    theme->a_toggled_focused_unpressed_desk->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_unpressed_desk->texture[0].data.mask.mask
+                    = theme->desk_toggled_mask;
+    theme->a_toggled_focused_pressed_desk->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_pressed_desk->texture[0].data.mask.mask
+                    = theme->desk_toggled_pressed_mask;
+    theme->a_disabled_focused_shade->texture[0].data.mask.mask
+            = theme->a_disabled_unfocused_shade->texture[0].data.mask.mask
+                    = theme->shade_disabled_mask;
+    theme->a_hover_focused_shade->texture[0].data.mask.mask
+            = theme->a_hover_unfocused_shade->texture[0].data.mask.mask
+                    = theme->shade_hover_mask;
+    theme->a_focused_pressed_shade->texture[0].data.mask.mask
+            = theme->a_unfocused_pressed_shade->texture[0].data.mask.mask
+                    = theme->shade_pressed_mask;
+    theme->a_focused_unpressed_shade->texture[0].data.mask.mask
+            = theme->a_unfocused_unpressed_shade->texture[0].data.mask.mask
+                    = theme->shade_mask;
+    theme->a_toggled_hover_focused_shade->texture[0].data.mask.mask
+            = theme->a_toggled_hover_unfocused_shade->texture[0].data.mask.mask
+                    = theme->shade_toggled_hover_mask;
+    theme->a_toggled_focused_unpressed_shade->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_unpressed_shade->texture[0].data.mask.mask
+                    = theme->shade_toggled_mask;
+    theme->a_toggled_focused_pressed_shade->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_pressed_shade->texture[0].data.mask.mask
+                    = theme->shade_toggled_pressed_mask;
+    theme->a_disabled_focused_iconify->texture[0].data.mask.mask
+            = theme->a_disabled_unfocused_iconify->texture[0].data.mask.mask
+                    = theme->iconify_disabled_mask;
+    theme->a_hover_focused_iconify->texture[0].data.mask.mask
+            = theme->a_hover_unfocused_iconify->texture[0].data.mask.mask
+                    = theme->iconify_hover_mask;
+    theme->a_focused_pressed_iconify->texture[0].data.mask.mask
+            = theme->a_unfocused_pressed_iconify->texture[0].data.mask.mask
+                    = theme->iconify_pressed_mask;
+    theme->a_focused_unpressed_iconify->texture[0].data.mask.mask
+            = theme->a_unfocused_unpressed_iconify->texture[0].data.mask.mask
+                    = theme->iconify_mask;
+    theme->a_menu_bullet_normal->texture[0].data.mask.mask
+            = theme->a_menu_bullet_selected->texture[0].data.mask.mask
+                    = theme->menu_bullet_mask;
+    theme->a_disabled_focused_max->texture[0].data.mask.color
+            = theme->a_disabled_focused_close->texture[0].data.mask.color
+                    = theme->a_disabled_focused_desk->texture[0].data.mask.color
+                            = theme->a_disabled_focused_shade->texture[0].data.mask.color
+                                    = theme->a_disabled_focused_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_disabled_focused_color;
+    theme->a_disabled_unfocused_max->texture[0].data.mask.color
+            = theme->a_disabled_unfocused_close->texture[0].data.mask.color
+                    = theme->a_disabled_unfocused_desk->texture[0].data.mask.color
+                            = theme->a_disabled_unfocused_shade->texture[0].data.mask.color
+                                    = theme->a_disabled_unfocused_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_disabled_unfocused_color;
+    theme->a_hover_focused_max->texture[0].data.mask.color
+            = theme->a_hover_focused_close->texture[0].data.mask.color
+                    = theme->a_hover_focused_desk->texture[0].data.mask.color
+                            = theme->a_hover_focused_shade->texture[0].data.mask.color
+                                    = theme->a_hover_focused_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_hover_focused_color;
+    theme->a_hover_unfocused_max->texture[0].data.mask.color
+            = theme->a_hover_unfocused_close->texture[0].data.mask.color
+                    = theme->a_hover_unfocused_desk->texture[0].data.mask.color
+                            = theme->a_hover_unfocused_shade->texture[0].data.mask.color
+                                    = theme->a_hover_unfocused_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_hover_unfocused_color;
+    theme->a_toggled_hover_focused_max->texture[0].data.mask.color
+            = theme->a_toggled_hover_focused_desk->texture[0].data.mask.color
+                    = theme->a_toggled_hover_focused_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_hover_focused_color;
+    theme->a_toggled_hover_unfocused_max->texture[0].data.mask.color
+            = theme->a_toggled_hover_unfocused_desk->texture[0].data.mask.color
+                    = theme->a_toggled_hover_unfocused_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_hover_unfocused_color;
+    theme->a_toggled_focused_unpressed_max->texture[0].data.mask.color
+            = theme->a_toggled_focused_unpressed_desk->texture[0].data.mask.color
+                    = theme->a_toggled_focused_unpressed_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_focused_unpressed_color;
+    theme->a_toggled_unfocused_unpressed_max->texture[0].data.mask.color
+            = theme->a_toggled_unfocused_unpressed_desk->texture[0].data.mask.color
+                    = theme->a_toggled_unfocused_unpressed_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_unfocused_unpressed_color;
+    theme->a_toggled_focused_pressed_max->texture[0].data.mask.color
+            = theme->a_toggled_focused_pressed_desk->texture[0].data.mask.color
+                    = theme->a_toggled_focused_pressed_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_focused_pressed_color;
+    theme->a_toggled_unfocused_pressed_max->texture[0].data.mask.color
+            = theme->a_toggled_unfocused_pressed_desk->texture[0].data.mask.color
+                    = theme->a_toggled_unfocused_pressed_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_unfocused_pressed_color;
+    theme->a_focused_unpressed_max->texture[0].data.mask.color
+            = theme->a_focused_unpressed_close->texture[0].data.mask.color
+                    = theme->a_focused_unpressed_desk->texture[0].data.mask.color
+                            = theme->a_focused_unpressed_shade->texture[0].data.mask.color
+                                    = theme->a_focused_unpressed_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_focused_unpressed_color;
+    theme->a_focused_pressed_max->texture[0].data.mask.color
+            = theme->a_focused_pressed_close->texture[0].data.mask.color
+                    = theme->a_focused_pressed_desk->texture[0].data.mask.color
+                            = theme->a_focused_pressed_shade->texture[0].data.mask.color
+                                    = theme->a_focused_pressed_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_focused_pressed_color;
+    theme->a_unfocused_unpressed_max->texture[0].data.mask.color
+            = theme->a_unfocused_unpressed_close->texture[0].data.mask.color
+                    = theme->a_unfocused_unpressed_desk->texture[0].data.mask.color
+                            = theme->a_unfocused_unpressed_shade->texture[0].data.mask.color
+                                    = theme->a_unfocused_unpressed_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_unfocused_unpressed_color;
+    theme->a_unfocused_pressed_max->texture[0].data.mask.color
+            = theme->a_unfocused_pressed_close->texture[0].data.mask.color
+                    = theme->a_unfocused_pressed_desk->texture[0].data.mask.color
+                            = theme->a_unfocused_pressed_shade->texture[0].data.mask.color
+                                    = theme->a_unfocused_pressed_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_unfocused_pressed_color;
+    theme->a_menu_bullet_normal->texture[0].data.mask.color = theme->menu_color;
+    theme->a_menu_bullet_selected->texture[0].data.mask.color
+            = theme->menu_selected_color;
+
+    /* set the font heights */
+    theme->win_font_height = RrFontHeight(theme->win_font_focused,
+            theme->a_focused_label->texture[0].data.text.shadow_offset_y);
+    theme->win_font_height = MAX(theme->win_font_height, RrFontHeight(
+            theme->win_font_focused,
+            theme->a_unfocused_label->texture[0].data.text.shadow_offset_y));
+    theme->menu_title_font_height = RrFontHeight(theme->menu_title_font,
+            theme->a_menu_text_title->texture[0].data.text.shadow_offset_y);
+    theme->menu_font_height = RrFontHeight(theme->menu_font,
+            theme->a_menu_text_normal->texture[0].data.text.shadow_offset_y);
+
+    /* calculate some last extents */
+    {
+        gint ft, fb, fl, fr, ut, ub, ul, ur;
+
+        RrMargins(theme->a_focused_label, &fl, &ft, &fr, &fb);
+        RrMargins(theme->a_unfocused_label, &ul, &ut, &ur, &ub);
+        theme->label_height = theme->win_font_height + MAX(ft + fb, ut + ub);
+        theme->label_height += theme->label_height % 2;
+
+        /* this would be nice I think, since padding.width can now be 0,
+         but it breaks frame.c horribly and I don't feel like fixing that
+         right now, so if anyone complains, here is how to keep text from
+         going over the title's bevel/border with a padding.width of 0 and a
+         bevelless/borderless label
+         RrMargins(theme->a_focused_title, &fl, &ft, &fr, &fb);
+         RrMargins(theme->a_unfocused_title, &ul, &ut, &ur, &ub);
+         theme->title_height = theme->label_height +
+         MAX(MAX(theme->padding * 2, ft + fb),
+         MAX(theme->padding * 2, ut + ub));
+         */
+        theme->title_height = theme->label_height + theme->paddingy * 2;
+
+        RrMargins(theme->a_menu_title, &ul, &ut, &ur, &ub);
+        theme->menu_title_label_height = theme->menu_title_font_height+ut+ub;
+        theme->menu_title_height = theme->menu_title_label_height
+                + theme->paddingy * 2;
+    }
+    theme->button_size = theme->label_height - 2;
+    theme->grip_width = 25;
+
+    return 1;
+}
+
+static gchar *create_class_name(const gchar *rname)
+{
+    gchar *rclass = g_strdup(rname);
+    gchar *p = rclass;
+
+    while (TRUE) {
+        *p = toupper(*p);
+        p = strchr(p+1, '.');
+        if (p == NULL)
+            break;
+        ++p;
+        if (*p == '\0')
+            break;
+    }
+    return rclass;
+}
+
+static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype, *end;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        *value = (gint)strtol(retvalue.addr, &end, 10);
+        if (end != retvalue.addr)
+            ret = TRUE;
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        *value = retvalue.addr;
+        ret = TRUE;
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_color(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrColor **value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        RrColor *c = RrColorParse(inst, retvalue.addr);
+        if (c != NULL) {
+            *value = c;
+            ret = TRUE;
+        }
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_mask(const RrInstance *inst, const gchar *path,
+        ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value)
+{
+    gboolean ret = FALSE;
+    gchar *s;
+    gint hx, hy; /* ignored */
+    guint w, h;
+    guchar *b;
+
+    s = g_build_filename(path, maskname, NULL);
+    if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) {
+        ret = TRUE;
+        *value = RrPixmapMaskNew(inst, w, h, (gchar*)b);
+        XFree(b);
+    }
+    g_free(s);
+
+    return ret;
+}
+
+static void parse_appearance(gchar *tex, RrSurfaceColorType *grad,
+        RrReliefType *relief, RrBevelType *bevel, gboolean *interlaced,
+        gboolean *border, gboolean allow_trans)
+{
+    gchar *t;
+
+    /* convert to all lowercase */
+    for (t = tex; *t != '\0'; ++t)
+        *t = g_ascii_tolower(*t);
+
+    if (allow_trans && strstr(tex, "parentrelative") != NULL) {
+        *grad = RR_SURFACE_PARENTREL;
+    }
+    else {
+        if (strstr(tex, "gradient") != NULL) {
+            if (strstr(tex, "crossdiagonal") != NULL)
+                *grad = RR_SURFACE_CROSS_DIAGONAL;
+            else if (strstr(tex, "pyramid") != NULL)
+                *grad = RR_SURFACE_PYRAMID;
+            else if (strstr(tex, "mirrorhorizontal") != NULL)
+                *grad = RR_SURFACE_MIRROR_HORIZONTAL;
+            else if (strstr(tex, "horizontal") != NULL)
+                *grad = RR_SURFACE_HORIZONTAL;
+            else if (strstr(tex, "splitvertical") != NULL)
+                *grad = RR_SURFACE_SPLIT_VERTICAL;
+            else if (strstr(tex, "vertical") != NULL)
+                *grad = RR_SURFACE_VERTICAL;
+            else
+                *grad = RR_SURFACE_DIAGONAL;
+        }
+        else {
+            *grad = RR_SURFACE_SOLID;
+        }
+    }
+
+    if (strstr(tex, "sunken") != NULL)
+        *relief = RR_RELIEF_SUNKEN;
+    else if (strstr(tex, "flat") != NULL)
+        *relief = RR_RELIEF_FLAT;
+    else if (strstr(tex, "raised") != NULL)
+        *relief = RR_RELIEF_RAISED;
+    else
+        *relief = (*grad == RR_SURFACE_PARENTREL) ? RR_RELIEF_FLAT
+                : RR_RELIEF_RAISED;
+
+    *border = FALSE;
+    if (*relief == RR_RELIEF_FLAT) {
+        if (strstr(tex, "border") != NULL)
+            *border = TRUE;
+    }
+    else {
+        if (strstr(tex, "bevel2") != NULL)
+            *bevel = RR_BEVEL_2;
+        else
+            *bevel = RR_BEVEL_1;
+    }
+
+    if (strstr(tex, "interlaced") != NULL)
+        *interlaced = TRUE;
+    else
+        *interlaced = FALSE;
+}
+
+static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrAppearance *value, gboolean allow_trans)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *cname, *ctoname, *bcname, *icname, *hname, *sname;
+    gchar *csplitname, *ctosplitname;
+    gchar *rettype;
+    XrmValue retvalue;
+    gint i;
+
+    cname = g_strconcat(rname, ".color", NULL);
+    ctoname = g_strconcat(rname, ".colorTo", NULL);
+    bcname = g_strconcat(rname, ".border.color", NULL);
+    icname = g_strconcat(rname, ".interlace.color", NULL);
+    hname = g_strconcat(rname, ".highlight", NULL);
+    sname = g_strconcat(rname, ".shadow", NULL);
+    csplitname = g_strconcat(rname, ".color.splitTo", NULL);
+    ctosplitname = g_strconcat(rname, ".colorTo.splitTo", NULL);
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        parse_appearance(retvalue.addr, &value->surface.grad,
+                &value->surface.relief, &value->surface.bevel,
+                &value->surface.interlaced, &value->surface.border, allow_trans);
+        if (!read_color(db, inst, cname, &value->surface.primary))
+            value->surface.primary = RrColorNew(inst, 0, 0, 0);
+        if (!read_color(db, inst, ctoname, &value->surface.secondary))
+            value->surface.secondary = RrColorNew(inst, 0, 0, 0);
+        if (value->surface.border)
+            if (!read_color(db, inst, bcname, &value->surface.border_color))
+                value->surface.border_color = RrColorNew(inst, 0, 0, 0);
+        if (value->surface.interlaced)
+            if (!read_color(db, inst, icname, &value->surface.interlace_color))
+                value->surface.interlace_color = RrColorNew(inst, 0, 0, 0);
+        if (read_int(db, hname, &i) && i >= 0)
+            value->surface.bevel_light_adjust = i;
+        if (read_int(db, sname, &i) && i >= 0 && i <= 256)
+            value->surface.bevel_dark_adjust = i;
+
+        if (value->surface.grad == RR_SURFACE_SPLIT_VERTICAL) {
+            gint r, g, b;
+
+            if (!read_color(db, inst, csplitname, &value->surface.split_primary)) {
+                r = value->surface.primary->r;
+                r += r >> 2;
+                g = value->surface.primary->g;
+                g += g >> 2;
+                b = value->surface.primary->b;
+                b += b >> 2;
+                if (r > 0xFF)
+                    r = 0xFF;
+                if (g > 0xFF)
+                    g = 0xFF;
+                if (b > 0xFF)
+                    b = 0xFF;
+                value->surface.split_primary = RrColorNew(inst, r, g, b);
+            }
+
+            if (!read_color(db, inst, ctosplitname,
+                    &value->surface.split_secondary)) {
+                r = value->surface.secondary->r;
+                r += r >> 4;
+                g = value->surface.secondary->g;
+                g += g >> 4;
+                b = value->surface.secondary->b;
+                b += b >> 4;
+                if (r > 0xFF)
+                    r = 0xFF;
+                if (g > 0xFF)
+                    g = 0xFF;
+                if (b > 0xFF)
+                    b = 0xFF;
+                value->surface.split_secondary = RrColorNew(inst, r, g, b);
+            }
+        }
+
+        ret = TRUE;
+    }
+
+    g_free(ctosplitname);
+    g_free(csplitname);
+    g_free(sname);
+    g_free(hname);
+    g_free(icname);
+    g_free(bcname);
+    g_free(ctoname);
+    g_free(cname);
+    g_free(rclass);
+    return ret;
+}
+
+static int parse_inline_number(const char *p)
+{
+    int neg = 1;
+    int res = 0;
+    if (*p == '-') {
+        neg = -1;
+        ++p;
+    }
+    for (; isdigit(*p); ++p)
+        res = res * 10 + *p - '0';
+    res *= neg;
+    return res;
+}
+
+static void set_default_appearance(RrAppearance *a)
+{
+    a->surface.grad = RR_SURFACE_SOLID;
+    a->surface.relief = RR_RELIEF_FLAT;
+    a->surface.bevel = RR_BEVEL_1;
+    a->surface.interlaced = FALSE;
+    a->surface.border = FALSE;
+    a->surface.primary = RrColorNew(a->inst, 0, 0, 0);
+    a->surface.secondary = RrColorNew(a->inst, 0, 0, 0);
+}
+
+/* Reads the output from gimp's C-Source file format into valid RGBA data for
+ an RrTextureRGBA. */
+static RrPixel32* read_c_image(gint width, gint height, const guint8 *data)
+{
+    RrPixel32 *im, *p;
+    gint i;
+
+    p = im = g_memdup(data, width * height * sizeof(RrPixel32));
+
+    for (i = 0; i < width * height; ++i) {
+        guchar a = ((*p >> 24) & 0xff);
+        guchar b = ((*p >> 16) & 0xff);
+        guchar g = ((*p >> 8) & 0xff);
+        guchar r = ((*p >> 0) & 0xff);
+
+        *p = ((r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset) + (b
+                << RrDefaultBlueOffset) + (a << RrDefaultAlphaOffset));
+        p++;
+    }
+
+    return im;
+}
diff --git a/engines/default/config.h b/engines/default/config.h
new file mode 100644 (file)
index 0000000..5601604
--- /dev/null
@@ -0,0 +1,250 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_config.h for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+#ifndef FRAME_DEFAULT_CONFIG_H_
+#define FRAME_DEFAULT_CONFIG_H_
+
+#include <X11/Xresource.h>
+#include "render/render.h"
+
+G_BEGIN_DECLS
+
+struct _ObFrameThemeConfig
+{
+    const RrInstance *inst;
+
+    /* style settings - fonts */
+    RrFont *win_font_focused;
+    RrFont *win_font_unfocused;
+    RrFont *menu_title_font;
+    RrFont *menu_font;
+    RrFont *osd_font;
+
+    /* style settings - geometry */
+    gint paddingx;
+    gint paddingy;
+    gint handle_height;
+    gint fbwidth; /*!< frame border width */
+    gint mbwidth; /*!< menu border width */
+    gint obwidth; /*!< osd border width */
+    gint cbwidthx;
+    gint cbwidthy;
+    gint menu_overlap;
+    /* these ones are calculated, not set directly by the theme file */
+    gint win_font_height;
+    gint menu_title_font_height;
+    gint menu_font_height;
+    gint label_height;
+    gint title_height;
+    gint button_size;
+    gint grip_width;
+    gint menu_title_label_height;
+    gint menu_title_height;
+
+    /* style settings - colors */
+    RrColor *menu_border_color;
+    RrColor *osd_border_color;
+    RrColor *frame_focused_border_color;
+    RrColor *frame_unfocused_border_color;
+    RrColor *title_separator_focused_color;
+    RrColor *title_separator_unfocused_color;
+    RrColor *cb_focused_color;
+    RrColor *cb_unfocused_color;
+    RrColor *title_focused_color;
+    RrColor *title_unfocused_color;
+    RrColor *titlebut_disabled_focused_color;
+    RrColor *titlebut_disabled_unfocused_color;
+    RrColor *titlebut_hover_focused_color;
+    RrColor *titlebut_hover_unfocused_color;
+    RrColor *titlebut_toggled_hover_focused_color;
+    RrColor *titlebut_toggled_hover_unfocused_color;
+    RrColor *titlebut_toggled_focused_pressed_color;
+    RrColor *titlebut_toggled_unfocused_pressed_color;
+    RrColor *titlebut_toggled_focused_unpressed_color;
+    RrColor *titlebut_toggled_unfocused_unpressed_color;
+    RrColor *titlebut_focused_pressed_color;
+    RrColor *titlebut_unfocused_pressed_color;
+    RrColor *titlebut_focused_unpressed_color;
+    RrColor *titlebut_unfocused_unpressed_color;
+    RrColor *menu_title_color;
+    RrColor *menu_color;
+    RrColor *menu_selected_color;
+    RrColor *menu_disabled_color;
+    RrColor *menu_disabled_selected_color;
+    RrColor *title_focused_shadow_color;
+    gchar title_focused_shadow_alpha;
+    RrColor *title_unfocused_shadow_color;
+    gchar title_unfocused_shadow_alpha;
+    RrColor *osd_color;
+    RrColor *osd_shadow_color;
+    gchar osd_shadow_alpha;
+    RrColor *menu_title_shadow_color;
+    gchar menu_title_shadow_alpha;
+    RrColor *menu_text_normal_shadow_color;
+    gchar menu_text_normal_shadow_alpha;
+    RrColor *menu_text_selected_shadow_color;
+    gchar menu_text_selected_shadow_alpha;
+    RrColor *menu_text_disabled_shadow_color;
+    gchar menu_text_disabled_shadow_alpha;
+    RrColor *menu_text_disabled_selected_shadow_color;
+    gchar menu_text_disabled_selected_shadow_alpha;
+
+    /* style settings - pics */
+    RrPixel32 *def_win_icon; /* 48x48 RGBA */
+
+    /* style settings - masks */
+    RrPixmapMask *max_mask;
+    RrPixmapMask *max_hover_mask;
+    RrPixmapMask *max_pressed_mask;
+    RrPixmapMask *max_toggled_mask;
+    RrPixmapMask *max_toggled_hover_mask;
+    RrPixmapMask *max_toggled_pressed_mask;
+    RrPixmapMask *max_disabled_mask;
+    RrPixmapMask *iconify_mask;
+    RrPixmapMask *iconify_hover_mask;
+    RrPixmapMask *iconify_pressed_mask;
+    RrPixmapMask *iconify_disabled_mask;
+    RrPixmapMask *desk_mask;
+    RrPixmapMask *desk_hover_mask;
+    RrPixmapMask *desk_pressed_mask;
+    RrPixmapMask *desk_toggled_mask;
+    RrPixmapMask *desk_toggled_hover_mask;
+    RrPixmapMask *desk_toggled_pressed_mask;
+    RrPixmapMask *desk_disabled_mask;
+    RrPixmapMask *shade_mask;
+    RrPixmapMask *shade_hover_mask;
+    RrPixmapMask *shade_pressed_mask;
+    RrPixmapMask *shade_toggled_mask;
+    RrPixmapMask *shade_toggled_hover_mask;
+    RrPixmapMask *shade_toggled_pressed_mask;
+    RrPixmapMask *shade_disabled_mask;
+    RrPixmapMask *close_mask;
+    RrPixmapMask *close_hover_mask;
+    RrPixmapMask *close_disabled_mask;
+    RrPixmapMask *close_pressed_mask;
+
+    RrPixmapMask *menu_bullet_mask; /* submenu pointer */
+#if 0
+    RrPixmapMask *menu_toggle_mask; /* menu boolean */
+#endif
+
+    /* global appearances */
+    RrAppearance *a_disabled_focused_max;
+    RrAppearance *a_disabled_unfocused_max;
+    RrAppearance *a_hover_focused_max;
+    RrAppearance *a_hover_unfocused_max;
+    RrAppearance *a_focused_unpressed_max;
+    RrAppearance *a_focused_pressed_max;
+    RrAppearance *a_unfocused_unpressed_max;
+    RrAppearance *a_unfocused_pressed_max;
+    RrAppearance *a_toggled_hover_focused_max;
+    RrAppearance *a_toggled_hover_unfocused_max;
+    RrAppearance *a_toggled_focused_unpressed_max;
+    RrAppearance *a_toggled_focused_pressed_max;
+    RrAppearance *a_toggled_unfocused_unpressed_max;
+    RrAppearance *a_toggled_unfocused_pressed_max;
+    RrAppearance *a_disabled_focused_close;
+    RrAppearance *a_disabled_unfocused_close;
+    RrAppearance *a_hover_focused_close;
+    RrAppearance *a_hover_unfocused_close;
+    RrAppearance *a_focused_unpressed_close;
+    RrAppearance *a_focused_pressed_close;
+    RrAppearance *a_unfocused_unpressed_close;
+    RrAppearance *a_unfocused_pressed_close;
+    RrAppearance *a_disabled_focused_desk;
+    RrAppearance *a_disabled_unfocused_desk;
+    RrAppearance *a_hover_focused_desk;
+    RrAppearance *a_hover_unfocused_desk;
+    RrAppearance *a_focused_unpressed_desk;
+    RrAppearance *a_focused_pressed_desk;
+    RrAppearance *a_unfocused_unpressed_desk;
+    RrAppearance *a_unfocused_pressed_desk;
+    RrAppearance *a_toggled_hover_focused_desk;
+    RrAppearance *a_toggled_hover_unfocused_desk;
+    RrAppearance *a_toggled_focused_unpressed_desk;
+    RrAppearance *a_toggled_focused_pressed_desk;
+    RrAppearance *a_toggled_unfocused_unpressed_desk;
+    RrAppearance *a_toggled_unfocused_pressed_desk;
+    RrAppearance *a_disabled_focused_shade;
+    RrAppearance *a_disabled_unfocused_shade;
+    RrAppearance *a_hover_focused_shade;
+    RrAppearance *a_hover_unfocused_shade;
+    RrAppearance *a_focused_unpressed_shade;
+    RrAppearance *a_focused_pressed_shade;
+    RrAppearance *a_unfocused_unpressed_shade;
+    RrAppearance *a_unfocused_pressed_shade;
+    RrAppearance *a_toggled_hover_focused_shade;
+    RrAppearance *a_toggled_hover_unfocused_shade;
+    RrAppearance *a_toggled_focused_unpressed_shade;
+    RrAppearance *a_toggled_focused_pressed_shade;
+    RrAppearance *a_toggled_unfocused_unpressed_shade;
+    RrAppearance *a_toggled_unfocused_pressed_shade;
+    RrAppearance *a_disabled_focused_iconify;
+    RrAppearance *a_disabled_unfocused_iconify;
+    RrAppearance *a_hover_focused_iconify;
+    RrAppearance *a_hover_unfocused_iconify;
+    RrAppearance *a_focused_unpressed_iconify;
+    RrAppearance *a_focused_pressed_iconify;
+    RrAppearance *a_unfocused_unpressed_iconify;
+    RrAppearance *a_unfocused_pressed_iconify;
+    RrAppearance *a_focused_grip;
+    RrAppearance *a_unfocused_grip;
+    RrAppearance *a_focused_title;
+    RrAppearance *a_unfocused_title;
+    RrAppearance *a_focused_label;
+    RrAppearance *a_unfocused_label;
+    /* always parentrelative, so no focused/unfocused */
+    RrAppearance *a_icon;
+    RrAppearance *a_focused_handle;
+    RrAppearance *a_unfocused_handle;
+    RrAppearance *a_menu_text_title;
+    RrAppearance *a_menu_title;
+    RrAppearance *a_menu;
+    RrAppearance *a_menu_normal;
+    RrAppearance *a_menu_selected;
+    RrAppearance *a_menu_disabled;
+    RrAppearance *a_menu_disabled_selected;
+    RrAppearance *a_menu_text_normal;
+    RrAppearance *a_menu_text_disabled;
+    RrAppearance *a_menu_text_disabled_selected;
+    RrAppearance *a_menu_text_selected;
+    RrAppearance *a_menu_bullet_normal;
+    RrAppearance *a_menu_bullet_selected;
+    RrAppearance *a_clear; /* clear with no texture */
+    RrAppearance *a_clear_tex; /* clear with a texture */
+
+    RrAppearance *osd_hilite_bg; /* can never be parent relative */
+    RrAppearance *osd_hilite_fg; /* can never be parent relative */
+    RrAppearance *osd_hilite_label; /* can be parent relative */
+    RrAppearance *osd_unhilite_fg; /* can never be parent relative */
+
+    gchar *name;
+};
+
+typedef struct _ObFrameThemeConfig ObFrameThemeConfig;
+
+/*! The font values are all optional. If a NULL is used for any of them, then
+ the default font will be used. */
+gint load_theme_config(const RrInstance *inst, const gchar *name,
+        const gchar * path, XrmDatabase db, RrFont *active_window_font,
+        RrFont *inactive_window_font, RrFont *menu_title_font,
+        RrFont *menu_item_font, RrFont *osd_font);
+
+G_END_DECLS
+
+#endif /*FRAME_DEFAULT_CONFIG_H_*/
diff --git a/engines/default/plugin.c b/engines/default/plugin.c
new file mode 100644 (file)
index 0000000..a8adc86
--- /dev/null
@@ -0,0 +1,1830 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_plugin.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#include "openbox/client.h"
+#include "openbox/openbox.h"
+#include "obt/prop.h"
+#include "openbox/grab.h"
+#include "openbox/config.h"
+#include "obt/mainloop.h"
+#include "openbox/focus_cycle.h"
+#include "openbox/focus_cycle_indicator.h"
+#include "openbox/moveresize.h"
+#include "openbox/screen.h"
+#include "render/theme.h"
+
+#include "plugin.h"
+#include "render.h"
+
+typedef enum
+{
+    OB_FLAG_MAX = 1 << 0,
+    OB_FLAG_CLOSE = 1 << 1,
+    OB_FLAG_DESK = 1 << 2,
+    OB_FLAG_SHADE = 1 << 3,
+    OB_FLAG_ICONIFY = 1 << 4
+} ObFrameFlags;
+
+#define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
+                         ButtonPressMask | ButtonReleaseMask | \
+                         SubstructureRedirectMask | FocusChangeMask)
+#define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
+                           ButtonMotionMask | PointerMotionMask | \
+                           EnterWindowMask | LeaveWindowMask)
+
+#define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
+#define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
+
+#define FRAME_HANDLE_Y(f) (f->size.top + f->client_area.height + f->cbwidth_b)
+
+Window createWindow(Window parent, Visual *visual, gulong mask,
+        XSetWindowAttributes *attrib)
+{
+    return XCreateWindow(plugin.ob_display, parent, 0, 0, 1, 1, 0, (visual ? 32
+            : RrDepth(plugin.ob_rr_inst)), InputOutput, (visual ? visual
+            : RrVisual(plugin.ob_rr_inst)), mask, attrib);
+
+}
+
+Visual *check_32bit_client(ObClient *c)
+{
+    XWindowAttributes wattrib;
+    Status ret;
+
+    /* we're already running at 32 bit depth, yay. we don't need to use their
+     visual */
+    if (RrDepth(plugin.ob_rr_inst) == 32)
+        return NULL;
+
+    ret = XGetWindowAttributes(plugin.ob_display, c->window, &wattrib);
+    g_assert(ret != BadDrawable);
+    g_assert(ret != BadWindow);
+
+    if (wattrib.depth == 32)
+        return wattrib.visual;
+    return NULL;
+}
+
+/* Not used */
+gint init(Display * display, gint screen)
+{
+    plugin.ob_display = display;
+    plugin.ob_screen = screen;
+}
+
+gpointer frame_new(struct _ObClient * client)
+{
+    XSetWindowAttributes attrib;
+    gulong mask;
+    ObDefaultFrame *self;
+    Visual *visual;
+
+    self = g_new0(ObDefaultFrame, 1);
+    self->client = client;
+
+    visual = check_32bit_client(client);
+
+    /* create the non-visible decor windows */
+
+    mask = 0;
+    if (visual) {
+        /* client has a 32-bit visual */
+        mask |= CWColormap | CWBackPixel | CWBorderPixel;
+        /* create a colormap with the visual */
+        OBDEFAULTFRAME(self)->colormap = attrib.colormap = XCreateColormap(
+                plugin.ob_display, RootWindow(plugin.ob_display,
+                        plugin.ob_screen), visual, AllocNone);
+        attrib.background_pixel = BlackPixel(plugin.ob_display,
+                plugin.ob_screen);
+        attrib.border_pixel = BlackPixel(plugin.ob_display, plugin.ob_screen);
+    }
+    self->window = createWindow(
+            RootWindow(plugin.ob_display, plugin.ob_screen), visual, mask,
+            &attrib);
+
+    /* create the visible decor windows */
+
+    mask = 0;
+    if (visual) {
+        /* client has a 32-bit visual */
+        mask |= CWColormap | CWBackPixel | CWBorderPixel;
+        attrib.colormap = RrColormap(plugin.ob_rr_inst);
+    }
+
+    self->backback = createWindow(self->window, NULL, mask, &attrib);
+    self->backfront = createWindow(self->backback, NULL, mask, &attrib);
+
+    mask |= CWEventMask;
+    attrib.event_mask = ELEMENT_EVENTMASK;
+    self->innerleft = createWindow(self->window, NULL, mask, &attrib);
+    self->innertop = createWindow(self->window, NULL, mask, &attrib);
+    self->innerright = createWindow(self->window, NULL, mask, &attrib);
+    self->innerbottom = createWindow(self->window, NULL, mask, &attrib);
+
+    self->innerblb = createWindow(self->innerbottom, NULL, mask, &attrib);
+    self->innerbrb = createWindow(self->innerbottom, NULL, mask, &attrib);
+    self->innerbll = createWindow(self->innerleft, NULL, mask, &attrib);
+    self->innerbrr = createWindow(self->innerright, NULL, mask, &attrib);
+
+    self->title = createWindow(self->window, NULL, mask, &attrib);
+    self->titleleft = createWindow(self->window, NULL, mask, &attrib);
+    self->titletop = createWindow(self->window, NULL, mask, &attrib);
+    self->titletopleft = createWindow(self->window, NULL, mask, &attrib);
+    self->titletopright = createWindow(self->window, NULL, mask, &attrib);
+    self->titleright = createWindow(self->window, NULL, mask, &attrib);
+    self->titlebottom = createWindow(self->window, NULL, mask, &attrib);
+
+    self->topresize = createWindow(self->title, NULL, mask, &attrib);
+    self->tltresize = createWindow(self->title, NULL, mask, &attrib);
+    self->tllresize = createWindow(self->title, NULL, mask, &attrib);
+    self->trtresize = createWindow(self->title, NULL, mask, &attrib);
+    self->trrresize = createWindow(self->title, NULL, mask, &attrib);
+
+    self->left = createWindow(self->window, NULL, mask, &attrib);
+    self->right = createWindow(self->window, NULL, mask, &attrib);
+
+    self->label = createWindow(self->title, NULL, mask, &attrib);
+    self->max = createWindow(self->title, NULL, mask, &attrib);
+    self->close = createWindow(self->title, NULL, mask, &attrib);
+    self->desk = createWindow(self->title, NULL, mask, &attrib);
+    self->shade = createWindow(self->title, NULL, mask, &attrib);
+    self->icon = createWindow(self->title, NULL, mask, &attrib);
+    self->iconify = createWindow(self->title, NULL, mask, &attrib);
+
+    self->handle = createWindow(self->window, NULL, mask, &attrib);
+    self->lgrip = createWindow(self->handle, NULL, mask, &attrib);
+    self->rgrip = createWindow(self->handle, NULL, mask, &attrib);
+
+    self->handleleft = createWindow(self->handle, NULL, mask, &attrib);
+    self->handleright = createWindow(self->handle, NULL, mask, &attrib);
+
+    self->handletop = createWindow(self->window, NULL, mask, &attrib);
+    self->handlebottom = createWindow(self->window, NULL, mask, &attrib);
+    self->lgripleft = createWindow(self->window, NULL, mask, &attrib);
+    self->lgriptop = createWindow(self->window, NULL, mask, &attrib);
+    self->lgripbottom = createWindow(self->window, NULL, mask, &attrib);
+    self->rgripright = createWindow(self->window, NULL, mask, &attrib);
+    self->rgriptop = createWindow(self->window, NULL, mask, &attrib);
+    self->rgripbottom = createWindow(self->window, NULL, mask, &attrib);
+
+    self->focused = FALSE;
+
+    /* the other stuff is shown based on decor settings */
+    XMapWindow(plugin.ob_display, self->label);
+    XMapWindow(plugin.ob_display, self->backback);
+    XMapWindow(plugin.ob_display, self->backfront);
+
+    self->hover_flag = OB_BUTTON_NONE;
+    self->press_flag = OB_BUTTON_NONE;
+
+    set_theme_statics(self);
+
+    return self;
+}
+
+void set_theme_statics(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    /* set colors/appearance/sizes for stuff that doesn't change */
+    XResizeWindow(plugin.ob_display, self->max, theme_config.button_size,
+            theme_config.button_size);
+    XResizeWindow(plugin.ob_display, self->iconify, theme_config.button_size,
+            theme_config.button_size);
+    XResizeWindow(plugin.ob_display, self->icon, theme_config.button_size + 2,
+            theme_config.button_size + 2);
+    XResizeWindow(plugin.ob_display, self->close, theme_config.button_size,
+            theme_config.button_size);
+    XResizeWindow(plugin.ob_display, self->desk, theme_config.button_size,
+            theme_config.button_size);
+    XResizeWindow(plugin.ob_display, self->shade, theme_config.button_size,
+            theme_config.button_size);
+    XResizeWindow(plugin.ob_display, self->tltresize, theme_config.grip_width,
+            theme_config.paddingy + 1);
+    XResizeWindow(plugin.ob_display, self->trtresize, theme_config.grip_width,
+            theme_config.paddingy + 1);
+    XResizeWindow(plugin.ob_display, self->tllresize,
+            theme_config.paddingx + 1, theme_config.title_height);
+    XResizeWindow(plugin.ob_display, self->trrresize,
+            theme_config.paddingx + 1, theme_config.title_height);
+
+    /* set up the dynamic appearances */
+    self->a_unfocused_title = RrAppearanceCopy(theme_config.a_unfocused_title);
+    self->a_focused_title = RrAppearanceCopy(theme_config.a_focused_title);
+    self->a_unfocused_label = RrAppearanceCopy(theme_config.a_unfocused_label);
+    self->a_focused_label = RrAppearanceCopy(theme_config.a_focused_label);
+    self->a_unfocused_handle
+            = RrAppearanceCopy(theme_config.a_unfocused_handle);
+    self->a_focused_handle = RrAppearanceCopy(theme_config.a_focused_handle);
+    self->a_icon = RrAppearanceCopy(theme_config.a_icon);
+}
+
+void free_theme_statics(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    RrAppearanceFree(self->a_unfocused_title);
+    RrAppearanceFree(self->a_focused_title);
+    RrAppearanceFree(self->a_unfocused_label);
+    RrAppearanceFree(self->a_focused_label);
+    RrAppearanceFree(self->a_unfocused_handle);
+    RrAppearanceFree(self->a_focused_handle);
+    RrAppearanceFree(self->a_icon);
+}
+
+void frame_free(gpointer self)
+{
+    free_theme_statics(OBDEFAULTFRAME(self));
+    XDestroyWindow(plugin.ob_display, OBDEFAULTFRAME(self)->window);
+    if (OBDEFAULTFRAME(self)->colormap)
+        XFreeColormap(plugin.ob_display, OBDEFAULTFRAME(self)->colormap);
+    g_free(self);
+}
+
+void frame_show(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    if (!self->visible) {
+        self->visible = TRUE;
+        frame_update_skin(self);
+        /* Grab the server to make sure that the frame window is mapped before
+         the client gets its MapNotify, i.e. to make sure the client is
+         _visible_ when it gets MapNotify. */
+        grab_server(TRUE);
+        XMapWindow(plugin.ob_display, self->client->window);
+        XMapWindow(plugin.ob_display, self->window);
+        grab_server(FALSE);
+    }
+}
+
+gint frame_hide(gpointer self)
+{
+    if (OBDEFAULTFRAME(self)->visible) {
+        OBDEFAULTFRAME(self)->visible = FALSE;
+        if (!frame_iconify_animating(self))
+            XUnmapWindow(plugin.ob_display, OBDEFAULTFRAME(self)->window);
+        /* we unmap the client itself so that we can get MapRequest
+         events, and because the ICCCM tells us to! */
+        XUnmapWindow(plugin.ob_display, OBDEFAULTFRAME(self)->client->window);
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
+void frame_adjust_theme(gpointer self)
+{
+    free_theme_statics(self);
+    set_theme_statics(self);
+}
+
+void frame_adjust_shape(gpointer _self)
+{
+#ifdef SHAPE
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    gint num;
+    XRectangle xrect[2];
+
+    if (!self->client->shaped)
+    {
+        /* clear the shape on the frame window */
+        XShapeCombineMask(plugin.ob_display, self->window, ShapeBounding,
+                self->size.left,
+                self->size.top,
+                None, ShapeSet);
+    }
+    else
+    {
+        /* make the frame's shape match the clients */
+        XShapeCombineShape(plugin.ob_display, self->window, ShapeBounding,
+                self->size.left,
+                self->size.top,
+                self->client->window,
+                ShapeBounding, ShapeSet);
+
+        num = 0;
+        if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
+        {
+            xrect[0].x = 0;
+            xrect[0].y = 0;
+            xrect[0].width = self->area.width;
+            xrect[0].height = self->size.top;
+            ++num;
+        }
+
+        if (self->decorations & OB_FRAME_DECOR_HANDLE &&
+                theme_config.handle_height> 0)
+        {
+            xrect[1].x = 0;
+            xrect[1].y = FRAME_HANDLE_Y(self);
+            xrect[1].width = self->area.width;
+            xrect[1].height = theme_config.handle_height +
+            self->bwidth * 2;
+            ++num;
+        }
+
+        XShapeCombineRectangles(plugin.ob_display, self->window,
+                ShapeBounding, 0, 0, xrect, num,
+                ShapeUnion, Unsorted);
+    }
+#endif
+}
+
+void frame_grab(gpointer _self, GHashTable * window_map)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    /* DO NOT map the client window here. we used to do that, but it is bogus.
+     we need to set up the client's dimensions and everything before we
+     send a mapnotify or we create race conditions.
+     */
+
+    /* reparent the client to the frame */
+    XReparentWindow(plugin.ob_display, self->client->window, self->window, 0, 0);
+
+    /*
+     When reparenting the client window, it is usually not mapped yet, since
+     this occurs from a MapRequest. However, in the case where Openbox is
+     starting up, the window is already mapped, so we'll see an unmap event
+     for it.
+     */
+    if (ob_state() == OB_STATE_STARTING)
+        ++self->client->ignore_unmaps;
+
+    /* select the event mask on the client's parent (to receive config/map
+     req's) the ButtonPress is to catch clicks on the client border */
+    XSelectInput(plugin.ob_display, self->window, FRAME_EVENTMASK);
+
+    /* set all the windows for the frame in the window_map */
+    g_hash_table_insert(window_map, &self->window, self->client);
+    g_hash_table_insert(window_map, &self->backback, self->client);
+    g_hash_table_insert(window_map, &self->backfront, self->client);
+    g_hash_table_insert(window_map, &self->innerleft, self->client);
+    g_hash_table_insert(window_map, &self->innertop, self->client);
+    g_hash_table_insert(window_map, &self->innerright, self->client);
+    g_hash_table_insert(window_map, &self->innerbottom, self->client);
+    g_hash_table_insert(window_map, &self->title, self->client);
+    g_hash_table_insert(window_map, &self->label, self->client);
+    g_hash_table_insert(window_map, &self->max, self->client);
+    g_hash_table_insert(window_map, &self->close, self->client);
+    g_hash_table_insert(window_map, &self->desk, self->client);
+    g_hash_table_insert(window_map, &self->shade, self->client);
+    g_hash_table_insert(window_map, &self->icon, self->client);
+    g_hash_table_insert(window_map, &self->iconify, self->client);
+    g_hash_table_insert(window_map, &self->handle, self->client);
+    g_hash_table_insert(window_map, &self->lgrip, self->client);
+    g_hash_table_insert(window_map, &self->rgrip, self->client);
+    g_hash_table_insert(window_map, &self->topresize, self->client);
+    g_hash_table_insert(window_map, &self->tltresize, self->client);
+    g_hash_table_insert(window_map, &self->tllresize, self->client);
+    g_hash_table_insert(window_map, &self->trtresize, self->client);
+    g_hash_table_insert(window_map, &self->trrresize, self->client);
+    g_hash_table_insert(window_map, &self->left, self->client);
+    g_hash_table_insert(window_map, &self->right, self->client);
+    g_hash_table_insert(window_map, &self->titleleft, self->client);
+    g_hash_table_insert(window_map, &self->titletop, self->client);
+    g_hash_table_insert(window_map, &self->titletopleft, self->client);
+    g_hash_table_insert(window_map, &self->titletopright, self->client);
+    g_hash_table_insert(window_map, &self->titleright, self->client);
+    g_hash_table_insert(window_map, &self->titlebottom, self->client);
+    g_hash_table_insert(window_map, &self->handleleft, self->client);
+    g_hash_table_insert(window_map, &self->handletop, self->client);
+    g_hash_table_insert(window_map, &self->handleright, self->client);
+    g_hash_table_insert(window_map, &self->handlebottom, self->client);
+    g_hash_table_insert(window_map, &self->lgripleft, self->client);
+    g_hash_table_insert(window_map, &self->lgriptop, self->client);
+    g_hash_table_insert(window_map, &self->lgripbottom, self->client);
+    g_hash_table_insert(window_map, &self->rgripright, self->client);
+    g_hash_table_insert(window_map, &self->rgriptop, self->client);
+    g_hash_table_insert(window_map, &self->rgripbottom, self->client);
+}
+
+void frame_ungrab(gpointer _self, GHashTable * window_map)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    XEvent ev;
+    gboolean reparent = TRUE;
+
+    /* if there was any animation going on, kill it */
+    obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
+            frame_animate_iconify, self, FALSE);
+
+    /* check if the app has already reparented its window away */
+    while (XCheckTypedWindowEvent(plugin.ob_display, self->client->window,
+            ReparentNotify, &ev)) {
+        /* This check makes sure we don't catch our own reparent action to
+         our frame window. This doesn't count as the app reparenting itself
+         away of course.
+
+         Reparent events that are generated by us are just discarded here.
+         They are of no consequence to us anyhow.
+         */
+        if (ev.xreparent.parent != self->window) {
+            reparent = FALSE;
+            XPutBackEvent(plugin.ob_display, &ev);
+            break;
+        }
+    }
+
+    if (reparent) {
+        /* according to the ICCCM - if the client doesn't reparent itself,
+         then we will reparent the window to root for them */
+        XReparentWindow(plugin.ob_display, self->client->window, RootWindow(
+                plugin.ob_display, plugin.ob_screen), self->client_area.x,
+                self->client_area.y);
+    }
+
+    /* remove all the windows for the frame from the window_map */
+    g_hash_table_remove(window_map, &self->window);
+    g_hash_table_remove(window_map, &self->backback);
+    g_hash_table_remove(window_map, &self->backfront);
+    g_hash_table_remove(window_map, &self->innerleft);
+    g_hash_table_remove(window_map, &self->innertop);
+    g_hash_table_remove(window_map, &self->innerright);
+    g_hash_table_remove(window_map, &self->innerbottom);
+    g_hash_table_remove(window_map, &self->title);
+    g_hash_table_remove(window_map, &self->label);
+    g_hash_table_remove(window_map, &self->max);
+    g_hash_table_remove(window_map, &self->close);
+    g_hash_table_remove(window_map, &self->desk);
+    g_hash_table_remove(window_map, &self->shade);
+    g_hash_table_remove(window_map, &self->icon);
+    g_hash_table_remove(window_map, &self->iconify);
+    g_hash_table_remove(window_map, &self->handle);
+    g_hash_table_remove(window_map, &self->lgrip);
+    g_hash_table_remove(window_map, &self->rgrip);
+    g_hash_table_remove(window_map, &self->topresize);
+    g_hash_table_remove(window_map, &self->tltresize);
+    g_hash_table_remove(window_map, &self->tllresize);
+    g_hash_table_remove(window_map, &self->trtresize);
+    g_hash_table_remove(window_map, &self->trrresize);
+    g_hash_table_remove(window_map, &self->left);
+    g_hash_table_remove(window_map, &self->right);
+    g_hash_table_remove(window_map, &self->titleleft);
+    g_hash_table_remove(window_map, &self->titletop);
+    g_hash_table_remove(window_map, &self->titletopleft);
+    g_hash_table_remove(window_map, &self->titletopright);
+    g_hash_table_remove(window_map, &self->titleright);
+    g_hash_table_remove(window_map, &self->titlebottom);
+    g_hash_table_remove(window_map, &self->handleleft);
+    g_hash_table_remove(window_map, &self->handletop);
+    g_hash_table_remove(window_map, &self->handleright);
+    g_hash_table_remove(window_map, &self->handlebottom);
+    g_hash_table_remove(window_map, &self->lgripleft);
+    g_hash_table_remove(window_map, &self->lgriptop);
+    g_hash_table_remove(window_map, &self->lgripbottom);
+    g_hash_table_remove(window_map, &self->rgripright);
+    g_hash_table_remove(window_map, &self->rgriptop);
+    g_hash_table_remove(window_map, &self->rgripbottom);
+
+    obt_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
+            TRUE);
+}
+
+ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
+{
+    ObDefaultFrame * self = OBDEFAULTFRAME(_self);
+
+    /* when the user clicks in the corners of the titlebar and the client
+     is fully maximized, then treat it like they clicked in the
+     button that is there */
+    if (self->max_horz && self->max_vert && (win == self->title || win
+            == self->titletop || win == self->titleleft || win
+            == self->titletopleft || win == self->titleright || win
+            == self->titletopright)) {
+        /* get the mouse coords in reference to the whole frame */
+        gint fx = x;
+        gint fy = y;
+
+        /* these windows are down a border width from the top of the frame */
+        if (win == self->title || win == self->titleleft || win
+                == self->titleright)
+            fy += self->bwidth;
+
+        /* title is a border width in from the edge */
+        if (win == self->title)
+            fx += self->bwidth;
+        /* titletop is a bit to the right */
+        else if (win == self->titletop)
+            fx += theme_config.grip_width + self->bwidth;
+        /* titletopright is way to the right edge */
+        else if (win == self->titletopright)
+            fx += self->area.width - (theme_config.grip_width + self->bwidth);
+        /* titleright is even more way to the right edge */
+        else if (win == self->titleright)
+            fx += self->area.width - self->bwidth;
+
+        /* figure out if we're over the area that should be considered a
+         button */
+        if (fy < self->bwidth + theme_config.paddingy + 1
+                + theme_config.button_size) {
+            if (fx < (self->bwidth + theme_config.paddingx + 1
+                    + theme_config.button_size)) {
+                if (self->leftmost != OB_FRAME_CONTEXT_NONE)
+                    return self->leftmost;
+            }
+            else if (fx >= (self->area.width - (self->bwidth
+                    + theme_config.paddingx + 1 + theme_config.button_size))) {
+                if (self->rightmost != OB_FRAME_CONTEXT_NONE)
+                    return self->rightmost;
+            }
+        }
+
+        /* there is no resizing maximized windows so make them the titlebar
+         context */
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    }
+    else if (self->max_vert
+            && (win == self->titletop || win == self->topresize))
+        /* can't resize vertically when max vert */
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    else if (self->shaded && (win == self->titletop || win == self->topresize))
+        /* can't resize vertically when shaded */
+        return OB_FRAME_CONTEXT_TITLEBAR;
+
+    if (win == self->window)
+        return OB_FRAME_CONTEXT_FRAME;
+    if (win == self->label)
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    if (win == self->handle)
+        return OB_FRAME_CONTEXT_BOTTOM;
+    if (win == self->handletop)
+        return OB_FRAME_CONTEXT_BOTTOM;
+    if (win == self->handlebottom)
+        return OB_FRAME_CONTEXT_BOTTOM;
+    if (win == self->handleleft)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->lgrip)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->lgripleft)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->lgriptop)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->lgripbottom)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->handleright)
+        return OB_FRAME_CONTEXT_BRCORNER;
+    if (win == self->rgrip)
+        return OB_FRAME_CONTEXT_BRCORNER;
+    if (win == self->rgripright)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->rgriptop)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->rgripbottom)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->title)
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    if (win == self->titlebottom)
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    if (win == self->titleleft)
+        return OB_FRAME_CONTEXT_TLCORNER;
+    if (win == self->titletopleft)
+        return OB_FRAME_CONTEXT_TLCORNER;
+    if (win == self->titleright)
+        return OB_FRAME_CONTEXT_TRCORNER;
+    if (win == self->titletopright)
+        return OB_FRAME_CONTEXT_TRCORNER;
+    if (win == self->titletop)
+        return OB_FRAME_CONTEXT_TOP;
+    if (win == self->topresize)
+        return OB_FRAME_CONTEXT_TOP;
+    if (win == self->tltresize)
+        return OB_FRAME_CONTEXT_TLCORNER;
+    if (win == self->tllresize)
+        return OB_FRAME_CONTEXT_TLCORNER;
+    if (win == self->trtresize)
+        return OB_FRAME_CONTEXT_TRCORNER;
+    if (win == self->trrresize)
+        return OB_FRAME_CONTEXT_TRCORNER;
+    if (win == self->left)
+        return OB_FRAME_CONTEXT_LEFT;
+    if (win == self->right)
+        return OB_FRAME_CONTEXT_RIGHT;
+    if (win == self->innertop)
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    if (win == self->innerleft)
+        return OB_FRAME_CONTEXT_LEFT;
+    if (win == self->innerbottom)
+        return OB_FRAME_CONTEXT_BOTTOM;
+    if (win == self->innerright)
+        return OB_FRAME_CONTEXT_RIGHT;
+    if (win == self->max)
+        return OB_FRAME_CONTEXT_MAXIMIZE;
+    if (win == self->iconify)
+        return OB_FRAME_CONTEXT_ICONIFY;
+    if (win == self->close)
+        return OB_FRAME_CONTEXT_CLOSE;
+    if (win == self->icon)
+        return OB_FRAME_CONTEXT_ICON;
+    if (win == self->desk)
+        return OB_FRAME_CONTEXT_ALLDESKTOPS;
+    if (win == self->shade)
+        return OB_FRAME_CONTEXT_SHADE;
+
+    return OB_FRAME_CONTEXT_NONE;
+}
+
+void frame_set_is_visible(gpointer self, gboolean b)
+{
+    OBDEFAULTFRAME(self)->visible = b;
+}
+
+void frame_set_is_focus(gpointer self, gboolean b)
+{
+    OBDEFAULTFRAME(self)->focused = b;
+}
+
+void frame_set_is_max_vert(gpointer self, gboolean b)
+{
+    OBDEFAULTFRAME(self)->max_vert = b;
+}
+
+void frame_set_is_max_horz(gpointer self, gboolean b)
+{
+    OBDEFAULTFRAME(self)->max_horz = b;
+}
+
+void frame_set_is_shaded(gpointer self, gboolean b)
+{
+    OBDEFAULTFRAME(self)->shaded = b;
+}
+
+void frame_unfocus(gpointer self)
+{
+    OBDEFAULTFRAME(self)->focused = FALSE;
+}
+
+void frame_flash_start(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->flash_on = self->focused;
+
+    if (!self->flashing)
+        obt_main_loop_timeout_add(plugin.ob_main_loop, G_USEC_PER_SEC * 0.6,
+                flash_timeout, self, g_direct_equal, flash_done);
+    g_get_current_time(&self->flash_end);
+    g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
+
+    self->flashing = TRUE;
+}
+
+void frame_flash_stop(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->flashing = FALSE;
+}
+
+void frame_begin_iconify_animation(gpointer _self, gboolean iconifying)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    gulong time;
+    gboolean new_anim = FALSE;
+    gboolean set_end = TRUE;
+    GTimeVal now;
+
+    /* if there is no titlebar, just don't animate for now
+     XXX it would be nice tho.. */
+    if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
+        return;
+
+    /* get the current time */
+    g_get_current_time(&now);
+
+    /* get how long until the end */
+    time = FRAME_ANIMATE_ICONIFY_TIME;
+    if (self->iconify_animation_going) {
+        if (!!iconifying != (self->iconify_animation_going > 0)) {
+            /* animation was already going on in the opposite direction */
+            time = time - frame_animate_iconify_time_left(_self, &now);
+        }
+        else
+            /* animation was already going in the same direction */
+            set_end = FALSE;
+    }
+    else
+        new_anim = TRUE;
+    self->iconify_animation_going = iconifying ? 1 : -1;
+
+    /* set the ending time */
+    if (set_end) {
+        self->iconify_animation_end.tv_sec = now.tv_sec;
+        self->iconify_animation_end.tv_usec = now.tv_usec;
+        g_time_val_add(&self->iconify_animation_end, time);
+    }
+
+    if (new_anim) {
+        obt_main_loop_timeout_remove_data(plugin.ob_main_loop,
+                frame_animate_iconify, self, FALSE);
+        obt_main_loop_timeout_add(plugin.ob_main_loop,
+        FRAME_ANIMATE_ICONIFY_STEP_TIME, frame_animate_iconify, self,
+                g_direct_equal, NULL);
+
+        /* do the first step */
+        frame_animate_iconify(self);
+
+        /* show it during the animation even if it is not "visible" */
+        if (!self->visible)
+            XMapWindow(plugin.ob_display, self->window);
+    }
+}
+
+void frame_end_iconify_animation(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    /* see if there is an animation going */
+    if (self->iconify_animation_going == 0)
+        return;
+
+    if (!self->visible)
+        XUnmapWindow(plugin.ob_display, self->window);
+    else {
+        /* Send a ConfigureNotify when the animation is done, this fixes
+         KDE's pager showing the window in the wrong place.  since the
+         window is mapped at a different location and is then moved, we
+         need to send the synthetic configurenotify, since apps may have
+         read the position when the client mapped, apparently. */
+        client_reconfigure(self->client, TRUE);
+    }
+
+    /* we're not animating any more ! */
+    self->iconify_animation_going = 0;
+
+    XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
+            self->area.y, self->area.width, self->area.height);
+    /* we delay re-rendering until after we're done animating */
+    frame_update_skin(self);
+    XFlush(plugin.ob_display);
+}
+
+gboolean frame_iconify_animating(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    return self->iconify_animation_going != 0;
+}
+
+void frame_set_decorations(gpointer self, ObFrameDecorations d)
+{
+    OBDEFAULTFRAME(self)->decorations = d;
+}
+
+Rect frame_get_window_area(gpointer self)
+{
+    return OBDEFAULTFRAME(self)->area;
+}
+void frame_set_client_area(gpointer self, Rect r)
+{
+    OBDEFAULTFRAME(self)->client_area = r;
+}
+
+void frame_update_layout(gpointer _self, gboolean is_resize, gboolean is_fake)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    Strut oldsize;
+
+    oldsize = self->size;
+    self->area = self->client_area;
+
+    /* do this before changing the frame's status like max_horz max_vert */
+    frame_adjust_cursors(self);
+
+    if (self->decorations & OB_FRAME_DECOR_BORDER
+            || (plugin.config_theme_keepborder)) {
+        self->bwidth = theme_config.fbwidth;
+    }
+    else {
+        self->bwidth = 0;
+    }
+
+    if (self->decorations & OB_FRAME_DECOR_BORDER) {
+        self->cbwidth_l = theme_config.cbwidthx;
+        self->cbwidth_r = theme_config.cbwidthx;
+        self->cbwidth_t = theme_config.cbwidthy;
+        self->cbwidth_b = theme_config.cbwidthy;
+    }
+    else {
+        self->cbwidth_l = 0;
+        self->cbwidth_t = 0;
+        self->cbwidth_r = 0;
+        self->cbwidth_b = 0;
+    }
+
+    if (self->max_horz) {
+        self->cbwidth_l = 0;
+        self->cbwidth_r = 0;
+        self->width = self->client_area.width;
+        if (self->max_vert)
+            self->cbwidth_b = 0;
+    }
+    else {
+        self->width = self->client_area.width + self->cbwidth_l
+                + self->cbwidth_r;
+    }
+
+    /* some elements are sized based of the width, so don't let them have
+     negative values */
+    self->width = MAX(self->width, (theme_config.grip_width + self->bwidth) * 2
+            + 1);
+
+    STRUT_SET(self->size, self->cbwidth_l
+            + (!self->max_horz ? self->bwidth : 0), self->cbwidth_t
+            + self->bwidth, self->cbwidth_r + (!self->max_horz ? self->bwidth
+            : 0), self->cbwidth_b
+            + (!self->max_horz || !self->max_vert ? self->bwidth : 0));
+
+    if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
+        self->size.top += theme_config.title_height + self->bwidth;
+    if (self->decorations & OB_FRAME_DECOR_HANDLE && theme_config.handle_height
+            > 0) {
+        self->size.bottom += theme_config.handle_height + self->bwidth;
+    }
+
+    /* position/size and map/unmap all the windows */
+    if (!is_fake) {
+        gint innercornerheight = theme_config.grip_width - self->size.bottom;
+
+        if (self->cbwidth_l) {
+            XMoveResizeWindow(plugin.ob_display, self->innerleft,
+                    self->size.left - self->cbwidth_l, self->size.top,
+                    self->cbwidth_l, self->client_area.height);
+
+            XMapWindow(plugin.ob_display, self->innerleft);
+        }
+        else
+            XUnmapWindow(plugin.ob_display, self->innerleft);
+
+        if (self->cbwidth_l && innercornerheight > 0) {
+            XMoveResizeWindow(plugin.ob_display, self->innerbll, 0,
+                    self->client_area.height - (theme_config.grip_width
+                            - self->size.bottom), self->cbwidth_l,
+                    theme_config.grip_width - self->size.bottom);
+
+            XMapWindow(plugin.ob_display, self->innerbll);
+        }
+        else
+            XUnmapWindow(plugin.ob_display, self->innerbll);
+
+        if (self->cbwidth_r) {
+            XMoveResizeWindow(plugin.ob_display, self->innerright,
+                    self->size.left + self->client_area.width, self->size.top,
+                    self->cbwidth_r, self->client_area.height);
+
+            XMapWindow(plugin.ob_display, self->innerright);
+        }
+        else
+            XUnmapWindow(plugin.ob_display, self->innerright);
+
+        if (self->cbwidth_r && innercornerheight > 0) {
+            XMoveResizeWindow(plugin.ob_display, self->innerbrr, 0,
+                    self->client_area.height - (theme_config.grip_width
+                            - self->size.bottom), self->cbwidth_r,
+                    theme_config.grip_width - self->size.bottom);
+
+            XMapWindow(plugin.ob_display, self->innerbrr);
+        }
+        else
+            XUnmapWindow(plugin.ob_display, self->innerbrr);
+
+        if (self->cbwidth_t) {
+            XMoveResizeWindow(plugin.ob_display, self->innertop,
+                    self->size.left - self->cbwidth_l, self->size.top
+                            - self->cbwidth_t, self->client_area.width
+                            + self->cbwidth_l + self->cbwidth_r,
+                    self->cbwidth_t);
+
+            XMapWindow(plugin.ob_display, self->innertop);
+        }
+        else
+            XUnmapWindow(plugin.ob_display, self->innertop);
+
+        if (self->cbwidth_b) {
+            XMoveResizeWindow(plugin.ob_display, self->innerbottom,
+                    self->size.left - self->cbwidth_l, self->size.top
+                            + self->client_area.height, self->client_area.width
+                            + self->cbwidth_l + self->cbwidth_r,
+                    self->cbwidth_b);
+
+            XMoveResizeWindow(plugin.ob_display, self->innerblb, 0, 0,
+                    theme_config.grip_width + self->bwidth, self->cbwidth_b);
+            XMoveResizeWindow(plugin.ob_display, self->innerbrb,
+                    self->client_area.width + self->cbwidth_l + self->cbwidth_r
+                            - (theme_config.grip_width + self->bwidth), 0,
+                    theme_config.grip_width + self->bwidth, self->cbwidth_b);
+
+            XMapWindow(plugin.ob_display, self->innerbottom);
+            XMapWindow(plugin.ob_display, self->innerblb);
+            XMapWindow(plugin.ob_display, self->innerbrb);
+        }
+        else {
+            XUnmapWindow(plugin.ob_display, self->innerbottom);
+            XUnmapWindow(plugin.ob_display, self->innerblb);
+            XUnmapWindow(plugin.ob_display, self->innerbrb);
+        }
+
+        if (self->bwidth) {
+            gint titlesides;
+
+            /* height of titleleft and titleright */
+            titlesides = (!self->max_horz ? theme_config.grip_width : 0);
+
+            XMoveResizeWindow(plugin.ob_display, self->titletop,
+                    theme_config.grip_width + self->bwidth, 0,
+                    /* width + bwidth*2 - bwidth*2 - grips*2 */
+                    self->width - theme_config.grip_width * 2, self->bwidth);
+            XMoveResizeWindow(plugin.ob_display, self->titletopleft, 0, 0,
+                    theme_config.grip_width + self->bwidth, self->bwidth);
+            XMoveResizeWindow(plugin.ob_display, self->titletopright,
+                    self->client_area.width + self->size.left
+                            + self->size.right - theme_config.grip_width
+                            - self->bwidth, 0, theme_config.grip_width
+                            + self->bwidth, self->bwidth);
+
+            if (titlesides > 0) {
+                XMoveResizeWindow(plugin.ob_display, self->titleleft, 0,
+                        self->bwidth, self->bwidth, titlesides);
+                XMoveResizeWindow(plugin.ob_display, self->titleright,
+                        self->client_area.width + self->size.left
+                                + self->size.right - self->bwidth,
+                        self->bwidth, self->bwidth, titlesides);
+
+                XMapWindow(plugin.ob_display, self->titleleft);
+                XMapWindow(plugin.ob_display, self->titleright);
+            }
+            else {
+                XUnmapWindow(plugin.ob_display, self->titleleft);
+                XUnmapWindow(plugin.ob_display, self->titleright);
+            }
+
+            XMapWindow(plugin.ob_display, self->titletop);
+            XMapWindow(plugin.ob_display, self->titletopleft);
+            XMapWindow(plugin.ob_display, self->titletopright);
+
+            if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
+                XMoveResizeWindow(plugin.ob_display, self->titlebottom,
+                        (self->max_horz ? 0 : self->bwidth),
+                        theme_config.title_height + self->bwidth, self->width,
+                        self->bwidth);
+
+                XMapWindow(plugin.ob_display, self->titlebottom);
+            }
+            else
+                XUnmapWindow(plugin.ob_display, self->titlebottom);
+        }
+        else {
+            XUnmapWindow(plugin.ob_display, self->titlebottom);
+
+            XUnmapWindow(plugin.ob_display, self->titletop);
+            XUnmapWindow(plugin.ob_display, self->titletopleft);
+            XUnmapWindow(plugin.ob_display, self->titletopright);
+            XUnmapWindow(plugin.ob_display, self->titleleft);
+            XUnmapWindow(plugin.ob_display, self->titleright);
+        }
+
+        if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
+            XMoveResizeWindow(plugin.ob_display, self->title,
+                    (self->max_horz ? 0 : self->bwidth), self->bwidth,
+                    self->width, theme_config.title_height);
+
+            XMapWindow(plugin.ob_display, self->title);
+
+            if (self->decorations & OB_FRAME_DECOR_GRIPS) {
+                XMoveResizeWindow(plugin.ob_display, self->topresize,
+                        theme_config.grip_width, 0, self->width
+                                - theme_config.grip_width *2,
+                        theme_config.paddingy + 1);
+
+                XMoveWindow(plugin.ob_display, self->tltresize, 0, 0);
+                XMoveWindow(plugin.ob_display, self->tllresize, 0, 0);
+                XMoveWindow(plugin.ob_display, self->trtresize, self->width
+                        - theme_config.grip_width, 0);
+                XMoveWindow(plugin.ob_display, self->trrresize, self->width
+                        - theme_config.paddingx - 1, 0);
+
+                XMapWindow(plugin.ob_display, self->topresize);
+                XMapWindow(plugin.ob_display, self->tltresize);
+                XMapWindow(plugin.ob_display, self->tllresize);
+                XMapWindow(plugin.ob_display, self->trtresize);
+                XMapWindow(plugin.ob_display, self->trrresize);
+            }
+            else {
+                XUnmapWindow(plugin.ob_display, self->topresize);
+                XUnmapWindow(plugin.ob_display, self->tltresize);
+                XUnmapWindow(plugin.ob_display, self->tllresize);
+                XUnmapWindow(plugin.ob_display, self->trtresize);
+                XUnmapWindow(plugin.ob_display, self->trrresize);
+            }
+        }
+        else
+            XUnmapWindow(plugin.ob_display, self->title);
+    }
+
+    if ((self->decorations & OB_FRAME_DECOR_TITLEBAR))
+        /* layout the title bar elements */
+        layout_title(self);
+
+    if (!is_fake) {
+        gint sidebwidth = self->max_horz ? 0 : self->bwidth;
+
+        if (self->bwidth && self->size.bottom) {
+            XMoveResizeWindow(plugin.ob_display, self->handlebottom,
+                    theme_config.grip_width + self->bwidth + sidebwidth,
+                    self->size.top + self->client_area.height
+                            + self->size.bottom - self->bwidth, self->width
+                            - (theme_config.grip_width + sidebwidth) * 2,
+                    self->bwidth);
+
+            if (sidebwidth) {
+                XMoveResizeWindow(plugin.ob_display, self->lgripleft, 0,
+                        self->size.top + self->client_area.height
+                                + self->size.bottom
+                                - (!self->max_horz ? theme_config.grip_width
+                                        : self->size.bottom - self->cbwidth_b),
+                        self->bwidth,
+                        (!self->max_horz ? theme_config.grip_width
+                                : self->size.bottom - self->cbwidth_b));
+                XMoveResizeWindow(plugin.ob_display, self->rgripright,
+                        self->size.left + self->client_area.width
+                                + self->size.right - self->bwidth,
+                        self->size.top + self->client_area.height
+                                + self->size.bottom
+                                - (!self->max_horz ? theme_config.grip_width
+                                        : self->size.bottom - self->cbwidth_b),
+                        self->bwidth,
+                        (!self->max_horz ? theme_config.grip_width
+                                : self->size.bottom - self->cbwidth_b));
+
+                XMapWindow(plugin.ob_display, self->lgripleft);
+                XMapWindow(plugin.ob_display, self->rgripright);
+            }
+            else {
+                XUnmapWindow(plugin.ob_display, self->lgripleft);
+                XUnmapWindow(plugin.ob_display, self->rgripright);
+            }
+
+            XMoveResizeWindow(plugin.ob_display, self->lgripbottom, sidebwidth,
+                    self->size.top + self->client_area.height
+                            + self->size.bottom - self->bwidth,
+                    theme_config.grip_width + self->bwidth, self->bwidth);
+            XMoveResizeWindow(plugin.ob_display, self->rgripbottom,
+                    self->size.left + self->client_area.width
+                            + self->size.right - self->bwidth - sidebwidth
+                            - theme_config.grip_width, self->size.top
+                            + self->client_area.height + self->size.bottom
+                            - self->bwidth, theme_config.grip_width
+                            + self->bwidth, self->bwidth);
+
+            XMapWindow(plugin.ob_display, self->handlebottom);
+            XMapWindow(plugin.ob_display, self->lgripbottom);
+            XMapWindow(plugin.ob_display, self->rgripbottom);
+
+            if (self->decorations & OB_FRAME_DECOR_HANDLE
+                    && theme_config.handle_height > 0) {
+                XMoveResizeWindow(plugin.ob_display, self->handletop,
+                        theme_config.grip_width + self->bwidth + sidebwidth,
+                        FRAME_HANDLE_Y(self), self->width - (theme_config.grip_width
+                                + sidebwidth) * 2, self->bwidth);
+                XMapWindow(plugin.ob_display, self->handletop);
+
+                if (self->decorations & OB_FRAME_DECOR_GRIPS) {
+                    XMoveResizeWindow(plugin.ob_display, self->handleleft,
+                            theme_config.grip_width, 0, self->bwidth,
+                            theme_config.handle_height);
+                    XMoveResizeWindow(plugin.ob_display, self->handleright,
+                            self->width - theme_config.grip_width
+                                    - self->bwidth, 0, self->bwidth,
+                            theme_config.handle_height);
+
+                    XMoveResizeWindow(plugin.ob_display, self->lgriptop,
+                            sidebwidth,
+                            FRAME_HANDLE_Y(self), theme_config.grip_width
+                                    + self->bwidth, self->bwidth);
+                    XMoveResizeWindow(plugin.ob_display, self->rgriptop,
+                            self->size.left + self->client_area.width
+                                    + self->size.right - self->bwidth
+                                    - sidebwidth - theme_config.grip_width,
+                            FRAME_HANDLE_Y(self), theme_config.grip_width
+                                    + self->bwidth, self->bwidth);
+
+                    XMapWindow(plugin.ob_display, self->handleleft);
+                    XMapWindow(plugin.ob_display, self->handleright);
+                    XMapWindow(plugin.ob_display, self->lgriptop);
+                    XMapWindow(plugin.ob_display, self->rgriptop);
+                }
+                else {
+                    XUnmapWindow(plugin.ob_display, self->handleleft);
+                    XUnmapWindow(plugin.ob_display, self->handleright);
+                    XUnmapWindow(plugin.ob_display, self->lgriptop);
+                    XUnmapWindow(plugin.ob_display, self->rgriptop);
+                }
+            }
+            else {
+                XUnmapWindow(plugin.ob_display, self->handleleft);
+                XUnmapWindow(plugin.ob_display, self->handleright);
+                XUnmapWindow(plugin.ob_display, self->lgriptop);
+                XUnmapWindow(plugin.ob_display, self->rgriptop);
+
+                XUnmapWindow(plugin.ob_display, self->handletop);
+            }
+        }
+        else {
+            XUnmapWindow(plugin.ob_display, self->handleleft);
+            XUnmapWindow(plugin.ob_display, self->handleright);
+            XUnmapWindow(plugin.ob_display, self->lgriptop);
+            XUnmapWindow(plugin.ob_display, self->rgriptop);
+
+            XUnmapWindow(plugin.ob_display, self->handletop);
+
+            XUnmapWindow(plugin.ob_display, self->handlebottom);
+            XUnmapWindow(plugin.ob_display, self->lgripleft);
+            XUnmapWindow(plugin.ob_display, self->rgripright);
+            XUnmapWindow(plugin.ob_display, self->lgripbottom);
+            XUnmapWindow(plugin.ob_display, self->rgripbottom);
+        }
+
+        if (self->decorations & OB_FRAME_DECOR_HANDLE
+                && theme_config.handle_height > 0) {
+            XMoveResizeWindow(plugin.ob_display, self->handle, sidebwidth,
+            FRAME_HANDLE_Y(self) + self->bwidth, self->width,
+                    theme_config.handle_height);
+            XMapWindow(plugin.ob_display, self->handle);
+
+            if (self->decorations & OB_FRAME_DECOR_GRIPS) {
+                XMoveResizeWindow(plugin.ob_display, self->lgrip, 0, 0,
+                        theme_config.grip_width, theme_config.handle_height);
+                XMoveResizeWindow(plugin.ob_display, self->rgrip, self->width
+                        - theme_config.grip_width, 0, theme_config.grip_width,
+                        theme_config.handle_height);
+
+                XMapWindow(plugin.ob_display, self->lgrip);
+                XMapWindow(plugin.ob_display, self->rgrip);
+            }
+            else {
+                XUnmapWindow(plugin.ob_display, self->lgrip);
+                XUnmapWindow(plugin.ob_display, self->rgrip);
+            }
+        }
+        else {
+            XUnmapWindow(plugin.ob_display, self->lgrip);
+            XUnmapWindow(plugin.ob_display, self->rgrip);
+
+            XUnmapWindow(plugin.ob_display, self->handle);
+        }
+
+        if (self->bwidth && !self->max_horz && (self->client_area.height
+                + self->size.top + self->size.bottom) > theme_config.grip_width
+                * 2) {
+            XMoveResizeWindow(plugin.ob_display, self->left, 0, self->bwidth
+                    + theme_config.grip_width, self->bwidth,
+                    self->client_area.height + self->size.top
+                            + self->size.bottom - theme_config.grip_width * 2);
+
+            XMapWindow(plugin.ob_display, self->left);
+        }
+        else
+            XUnmapWindow(plugin.ob_display, self->left);
+
+        if (self->bwidth && !self->max_horz && (self->client_area.height
+                + self->size.top + self->size.bottom) > theme_config.grip_width
+                * 2) {
+            XMoveResizeWindow(plugin.ob_display, self->right,
+                    self->client_area.width + self->cbwidth_l + self->cbwidth_r
+                            + self->bwidth, self->bwidth
+                            + theme_config.grip_width, self->bwidth,
+                    self->client_area.height + self->size.top
+                            + self->size.bottom - theme_config.grip_width * 2);
+
+            XMapWindow(plugin.ob_display, self->right);
+        }
+        else
+            XUnmapWindow(plugin.ob_display, self->right);
+
+        XMoveResizeWindow(plugin.ob_display, self->backback, self->size.left,
+                self->size.top, self->client_area.width,
+                self->client_area.height);
+    }
+
+    /* shading can change without being moved or resized */
+    RECT_SET_SIZE(self->area, self->client_area.width + self->size.left
+            + self->size.right, (self->shaded ? theme_config.title_height
+            + self->bwidth * 2 : self->client_area.height + self->size.top
+            + self->size.bottom));
+
+    if ((is_resize) && !is_fake) {
+        /* find the new coordinates, done after setting the frame.size, for
+         frame_client_gravity. */
+        self->area.x = self->client_area.x;
+        self->area.y = self->client_area.y;
+        frame_client_gravity(OBDEFAULTFRAME(_self)->client, &self->area.x, &self->area.y);
+    }
+
+    if (!is_fake) {
+        if (!frame_iconify_animating(self))
+            /* move and resize the top level frame.
+             shading can change without being moved or resized.
+
+             but don't do this during an iconify animation. it will be
+             reflected afterwards.
+             */
+            XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
+                    self->area.y, self->area.width, self->area.height);
+
+        /* when the client has StaticGravity, it likes to move around.
+         also this correctly positions the client when it maps.
+         this also needs to be run when the frame's decorations sizes change!
+         */
+        if (!is_resize)
+            XMoveResizeWindow(plugin.ob_display, self->client->window,
+                    self->size.left, self->size.top, self->client_area.width,
+                    self->client_area.height);
+
+        if (is_resize) {
+            self->need_render = TRUE;
+            frame_update_skin(self);
+            frame_adjust_shape(self);
+        }
+
+        if (!STRUT_EQUAL(self->size, oldsize)) {
+            gulong vals[4];
+            vals[0] = self->size.left;
+            vals[1] = self->size.right;
+            vals[2] = self->size.top;
+            vals[3] = self->size.bottom;
+            OBT_PROP_SETA32(self->client->window, NET_FRAME_EXTENTS, CARDINAL,
+                    vals, 4);
+            OBT_PROP_SETA32(self->client->window, KDE_NET_WM_FRAME_STRUT,
+                    CARDINAL, vals, 4);
+        }
+
+        /* if this occurs while we are focus cycling, the indicator needs to
+         match the changes */
+        if (plugin.focus_cycle_target == self->client)
+            focus_cycle_draw_indicator(self->client);
+    }
+    if (is_resize && (self->decorations & OB_FRAME_DECOR_TITLEBAR))
+        XResizeWindow(plugin.ob_display, self->label, self->label_width,
+                theme_config.label_height);
+}
+
+void frame_set_hover_flag(gpointer self, ObFrameButton button)
+{
+    if (OBDEFAULTFRAME(self)->hover_flag != button) {
+        OBDEFAULTFRAME(self)->hover_flag = button;
+        frame_update_skin(self);
+    }
+}
+
+void frame_set_press_flag(gpointer self, ObFrameButton button)
+{
+    if (OBDEFAULTFRAME(self)->press_flag != button) {
+        OBDEFAULTFRAME(self)->press_flag = button;
+        frame_update_skin(self);
+    }
+}
+
+Window frame_get_window(gpointer self)
+{
+    return OBDEFAULTFRAME(self)->window;
+}
+
+Strut frame_get_size(gpointer self)
+{
+    return OBDEFAULTFRAME(self)->size;
+}
+
+gint frame_get_decorations(gpointer self)
+{
+    return OBDEFAULTFRAME(self)->decorations;
+}
+
+gboolean frame_is_visible(gpointer self)
+{
+    return OBDEFAULTFRAME(self)->visible;
+}
+
+gboolean frame_is_max_horz(gpointer self)
+{
+    return OBDEFAULTFRAME(self)->max_horz;
+}
+
+gboolean frame_is_max_vert(gpointer self)
+{
+    return OBDEFAULTFRAME(self)->max_vert;
+}
+
+gulong frame_animate_iconify_time_left(gpointer _self, const GTimeVal *now)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    glong sec, usec;
+    sec = self->iconify_animation_end.tv_sec - now->tv_sec;
+    usec = self->iconify_animation_end.tv_usec - now->tv_usec;
+    if (usec < 0) {
+        usec += G_USEC_PER_SEC;
+        sec--;
+    }
+    /* no negative values */
+    return MAX(sec * G_USEC_PER_SEC + usec, 0);
+}
+
+gboolean frame_animate_iconify(gpointer p)
+{
+    ObDefaultFrame *self = p;
+    gint x, y, w, h;
+    gint iconx, icony, iconw;
+    GTimeVal now;
+    gulong time;
+    gboolean iconifying;
+
+    if (self->client->icon_geometry.width == 0) {
+        /* there is no icon geometry set so just go straight down */
+        Rect *a =
+                screen_physical_area_monitor(screen_find_monitor(&self->area));
+        iconx = self->area.x + self->area.width / 2 + 32;
+        icony = a->y + a->width;
+        iconw = 64;
+        g_free(a);
+    }
+    else {
+        iconx = self->client->icon_geometry.x;
+        icony = self->client->icon_geometry.y;
+        iconw = self->client->icon_geometry.width;
+    }
+
+    iconifying = self->iconify_animation_going > 0;
+
+    /* how far do we have left to go ? */
+    g_get_current_time(&now);
+    time = frame_animate_iconify_time_left(self, &now);
+
+    if (time == 0 || iconifying) {
+        /* start where the frame is supposed to be */
+        x = self->area.x;
+        y = self->area.y;
+        w = self->area.width;
+        h = self->area.height;
+    }
+    else {
+        /* start at the icon */
+        x = iconx;
+        y = icony;
+        w = iconw;
+        h = self->size.top; /* just the titlebar */
+    }
+
+    if (time > 0) {
+        glong dx, dy, dw;
+        glong elapsed;
+
+        dx = self->area.x - iconx;
+        dy = self->area.y - icony;
+        dw = self->area.width - self->bwidth * 2 - iconw;
+        /* if restoring, we move in the opposite direction */
+        if (!iconifying) {
+            dx = -dx;
+            dy = -dy;
+            dw = -dw;
+        }
+
+        elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
+        x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        h = self->size.top; /* just the titlebar */
+    }
+
+    if (time == 0)
+        frame_end_iconify_animation(self);
+    else {
+        XMoveResizeWindow(plugin.ob_display, self->window, x, y, w, h);
+        XFlush(plugin.ob_display);
+    }
+
+    return time > 0; /* repeat until we're out of time */
+}
+
+void frame_adjust_cursors(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    if ((self->functions & OB_CLIENT_FUNC_RESIZE) != (self->functions
+            & OB_CLIENT_FUNC_RESIZE) || self->max_horz != self->max_horz
+            || self->max_vert != self->max_vert || self->shaded != self->shaded) {
+        gboolean r = (self->functions & OB_CLIENT_FUNC_RESIZE)
+                && !(self->max_horz && self->max_vert);
+        gboolean topbot = !self->max_vert;
+        gboolean sh = self->shaded;
+        XSetWindowAttributes a;
+
+        /* these ones turn off when max vert, and some when shaded */
+        a.cursor = ob_cursor(r && topbot && !sh ? OB_CURSOR_NORTH
+                : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->topresize, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->titletop, CWCursor, &a);
+        a.cursor = ob_cursor(r && topbot ? OB_CURSOR_SOUTH : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->handle, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->handletop, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->handlebottom,
+                CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerbottom, CWCursor,
+                &a);
+
+        /* these ones change when shaded */
+        a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_WEST : OB_CURSOR_NORTHWEST)
+                : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->titleleft, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->tltresize, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->tllresize, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->titletopleft,
+                CWCursor, &a);
+        a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_EAST : OB_CURSOR_NORTHEAST)
+                : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->titleright, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->trtresize, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->trrresize, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->titletopright,
+                CWCursor, &a);
+
+        /* these ones are pretty static */
+        a.cursor = ob_cursor(r ? OB_CURSOR_WEST : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->left, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerleft, CWCursor,
+                &a);
+        a.cursor = ob_cursor(r ? OB_CURSOR_EAST : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->right, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerright, CWCursor,
+                &a);
+        a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHWEST : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->lgrip, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->handleleft, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->lgripleft, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->lgriptop, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->lgripbottom, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerbll, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerblb, CWCursor, &a);
+        a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHEAST : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->rgrip, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->handleright, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->rgripright, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->rgriptop, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->rgripbottom, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerbrr, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerbrb, CWCursor, &a);
+    }
+}
+
+void frame_adjust_client_area(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    /* adjust the window which is there to prevent flashing on unmap */
+    XMoveResizeWindow(plugin.ob_display, self->backfront, 0, 0,
+            self->client_area.width, self->client_area.height);
+}
+
+void frame_adjust_state(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->need_render = TRUE;
+    frame_update_skin(self);
+}
+
+void frame_adjust_focus(gpointer _self, gboolean hilite)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->focused = hilite;
+    self->need_render = TRUE;
+    frame_update_skin(self);
+    XFlush(plugin.ob_display);
+}
+
+void frame_adjust_title(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->need_render = TRUE;
+    frame_update_skin(self);
+}
+
+void frame_adjust_icon(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->need_render = TRUE;
+    frame_update_skin(self);
+}
+
+/* is there anything present between us and the label? */
+static gboolean is_button_present(ObDefaultFrame *_self, const gchar *lc,
+        gint dir)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
+        if (*lc == ' ')
+            continue; /* it was invalid */
+        if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
+            return TRUE;
+        if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
+            return TRUE;
+        if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
+            return TRUE;
+        if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
+            return TRUE;
+        if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
+            return TRUE;
+        if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
+            return TRUE;
+        if (*lc == 'L')
+            return FALSE;
+    }
+    return FALSE;
+}
+
+void flash_done(gpointer data)
+{
+    ObDefaultFrame *self = data;
+
+    if (self->focused != self->flash_on)
+        frame_adjust_focus(self, self->focused);
+}
+
+gboolean flash_timeout(gpointer data)
+{
+    ObDefaultFrame *self = data;
+    GTimeVal now;
+
+    g_get_current_time(&now);
+    if (now.tv_sec > self->flash_end.tv_sec
+            || (now.tv_sec == self->flash_end.tv_sec && now.tv_usec
+                    >= self->flash_end.tv_usec))
+        self->flashing = FALSE;
+
+    if (!self->flashing)
+        return FALSE; /* we are done */
+
+    self->flash_on = !self->flash_on;
+    if (!self->focused) {
+        frame_adjust_focus(self, self->flash_on);
+        self->focused = FALSE;
+    }
+
+    return TRUE; /* go again */
+}
+
+void layout_title(ObDefaultFrame * self)
+{
+    gchar *lc;
+    gint i;
+
+    const gint bwidth = theme_config.button_size + theme_config.paddingx + 1;
+    /* position of the left most button */
+    const gint left = theme_config.paddingx + 1;
+    /* position of the right most button */
+    const gint right = self->width;
+
+    /* turn them all off */
+    self->icon_on = self->desk_on = self->shade_on = self->iconify_on
+            = self->max_on = self->close_on = self->label_on = FALSE;
+    self->label_width = self->width - (theme_config.paddingx + 1) * 2;
+    self->leftmost = self->rightmost = OB_FRAME_CONTEXT_NONE;
+
+    /* figure out what's being show, find each element's position, and the
+     width of the label
+
+     do the ones before the label, then after the label,
+     i will be +1 the first time through when working to the left,
+     and -1 the second time through when working to the right */
+    for (i = 1; i >= -1; i-=2) {
+        gint x;
+        ObFrameContext *firstcon;
+
+        if (i > 0) {
+            x = left;
+            lc = plugin.config_title_layout;
+            firstcon = &self->leftmost;
+        }
+        else {
+            x = right;
+            lc = plugin.config_title_layout
+                    + strlen(plugin.config_title_layout)-1;
+            firstcon = &self->rightmost;
+        }
+
+        /* stop at the end of the string (or the label, which calls break) */
+        for (; *lc != '\0' && lc >= plugin.config_title_layout; lc+=i) {
+            if (*lc == 'L') {
+                if (i > 0) {
+                    self->label_on = TRUE;
+                    self->label_x = x;
+                }
+                break; /* break the for loop, do other side of label */
+            }
+            else if (*lc == 'N') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_ICON;
+                if ((self->icon_on = is_button_present(self, lc, i))) {
+                    /* icon is bigger than buttons */
+                    self->label_width -= bwidth + 2;
+                    if (i > 0)
+                        self->icon_x = x;
+                    x += i * (bwidth + 2);
+                    if (i < 0)
+                        self->icon_x = x;
+                }
+            }
+            else if (*lc == 'D') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
+                if ((self->desk_on = is_button_present(self, lc, i))) {
+                    self->label_width -= bwidth;
+                    if (i > 0)
+                        self->desk_x = x;
+                    x += i * bwidth;
+                    if (i < 0)
+                        self->desk_x = x;
+                }
+            }
+            else if (*lc == 'S') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_SHADE;
+                if ((self->shade_on = is_button_present(self, lc, i))) {
+                    self->label_width -= bwidth;
+                    if (i > 0)
+                        self->shade_x = x;
+                    x += i * bwidth;
+                    if (i < 0)
+                        self->shade_x = x;
+                }
+            }
+            else if (*lc == 'I') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_ICONIFY;
+                if ((self->iconify_on = is_button_present(self, lc, i))) {
+                    self->label_width -= bwidth;
+                    if (i > 0)
+                        self->iconify_x = x;
+                    x += i * bwidth;
+                    if (i < 0)
+                        self->iconify_x = x;
+                }
+            }
+            else if (*lc == 'M') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
+                if ((self->max_on = is_button_present(self, lc, i))) {
+                    self->label_width -= bwidth;
+                    if (i > 0)
+                        self->max_x = x;
+                    x += i * bwidth;
+                    if (i < 0)
+                        self->max_x = x;
+                }
+            }
+            else if (*lc == 'C') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_CLOSE;
+                if ((self->close_on = is_button_present(self, lc, i))) {
+                    self->label_width -= bwidth;
+                    if (i > 0)
+                        self->close_x = x;
+                    x += i * bwidth;
+                    if (i < 0)
+                        self->close_x = x;
+                }
+            }
+            else
+                continue; /* don't set firstcon */
+            firstcon = NULL;
+        }
+    }
+
+    /* position and map the elements */
+    if (self->icon_on) {
+        XMapWindow(plugin.ob_display, self->icon);
+        XMoveWindow(plugin.ob_display, self->icon, self->icon_x,
+                theme_config.paddingy);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->icon);
+
+    if (self->desk_on) {
+        XMapWindow(plugin.ob_display, self->desk);
+        XMoveWindow(plugin.ob_display, self->desk, self->desk_x,
+                theme_config.paddingy + 1);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->desk);
+
+    if (self->shade_on) {
+        XMapWindow(plugin.ob_display, self->shade);
+        XMoveWindow(plugin.ob_display, self->shade, self->shade_x,
+                theme_config.paddingy + 1);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->shade);
+
+    if (self->iconify_on) {
+        XMapWindow(plugin.ob_display, self->iconify);
+        XMoveWindow(plugin.ob_display, self->iconify, self->iconify_x,
+                theme_config.paddingy + 1);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->iconify);
+
+    if (self->max_on) {
+        XMapWindow(plugin.ob_display, self->max);
+        XMoveWindow(plugin.ob_display, self->max, self->max_x,
+                theme_config.paddingy + 1);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->max);
+
+    if (self->close_on) {
+        XMapWindow(plugin.ob_display, self->close);
+        XMoveWindow(plugin.ob_display, self->close, self->close_x,
+                theme_config.paddingy + 1);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->close);
+
+    if (self->label_on) {
+        self->label_width = MAX(1, self->label_width); /* no lower than 1 */
+        XMapWindow(plugin.ob_display, self->label);
+        XMoveWindow(plugin.ob_display, self->label, self->label_x,
+                theme_config.paddingy);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->label);
+}
+
+ObFramePlugin plugin = { 0, //gpointer handler;
+        "libdefault.la", //gchar * filename;
+        "Default", //gchar * name;
+        init, //gint (*init) (Display * display, gint screen);
+        0, frame_new, //gpointer (*frame_new) (struct _ObClient *c);
+        frame_free, //void (*frame_free) (gpointer self);
+        frame_show, //void (*frame_show) (gpointer self);
+        frame_hide, //void (*frame_hide) (gpointer self);
+        frame_adjust_theme, //void (*frame_adjust_theme) (gpointer self);
+        frame_adjust_shape, //void (*frame_adjust_shape) (gpointer self);
+        frame_grab, //void (*frame_adjust_area) (gpointer self, gboolean moved, gboolean resized, gboolean fake);
+        frame_ungrab, frame_context, //void (*frame_adjust_state) (gpointer self);
+        frame_set_is_visible, frame_set_is_focus, frame_set_is_max_vert,
+                frame_set_is_max_horz, frame_set_is_shaded,
+
+        frame_flash_start, frame_flash_stop, frame_begin_iconify_animation,
+                frame_end_iconify_animation, frame_iconify_animating,
+
+        frame_set_decorations,
+        /* This give the window area */
+        frame_get_window_area, frame_set_client_area,
+        /* Draw the frame */
+        frame_update_layout, frame_update_skin,
+
+        frame_set_hover_flag, frame_set_press_flag,
+
+        frame_get_window,
+
+        frame_get_size, frame_get_decorations,
+
+        frame_is_visible, frame_is_max_horz, frame_is_max_vert,
+
+        load_theme_config,
+
+        /* This fields are fill by openbox. */
+        0, //Display * ob_display;
+        0, //gint ob_screen;
+        0, //RrInstance *ob_rr_inst;
+        //     0, //RrTheme    *ob_rr_theme;
+                0, //gboolean config_theme_keepborder;
+        0, //struct _ObClient *focus_cycle_target;
+        0, //gchar *config_title_layout;
+        FALSE, //gboolean moveresize_in_progress;
+        0, //struct _ObMainLoop *ob_main_loop;
+};
+
+ObFramePlugin * get_info()
+{
+    return &plugin;
+}
diff --git a/engines/default/plugin.h b/engines/default/plugin.h
new file mode 100644 (file)
index 0000000..b2c3a7d
--- /dev/null
@@ -0,0 +1,225 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_plugin.h for the Openbox window manager
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+#ifndef FRAME_DEFAULT_PLUGIN_H_
+#define FRAME_DEFAULT_PLUGIN_H_
+
+#include "config.h"
+#include "render/render.h"
+#include "openbox/engine_interface.h"
+
+ObFrameThemeConfig theme_config;
+
+struct _ObDefaultFrame
+{
+    /* PUBLIC : */
+
+    /* PRIVATE: */
+    /* You are free to add what you want here */
+
+    Window window;
+
+    gboolean visible;
+
+    gboolean max_horz; /* when maxed some decorations are hidden */
+    gboolean max_vert; /* when maxed some decorations are hidden */
+
+    struct _ObClient *client;
+    guint decorations;
+
+    Strut size;
+    Rect area;
+    Rect client_area;
+
+    gint bwidth;
+
+    ObFrameButton hover_flag;
+    ObFrameButton press_flag;
+
+    gint iconify_animation_going;
+    ObStyle style;
+
+    guint functions;
+
+    Window title;
+    Window label;
+    Window max;
+    Window close;
+    Window desk;
+    Window shade;
+    Window icon;
+    Window iconify;
+    Window handle;
+    Window lgrip;
+    Window rgrip;
+
+    /* These are borders of the frame and its elements */
+    Window titleleft;
+    Window titletop;
+    Window titletopleft;
+    Window titletopright;
+    Window titleright;
+    Window titlebottom;
+    Window left;
+    Window right;
+    Window handleleft;
+    Window handletop;
+    Window handleright;
+    Window handlebottom;
+    Window lgriptop;
+    Window lgripleft;
+    Window lgripbottom;
+    Window rgriptop;
+    Window rgripright;
+    Window rgripbottom;
+    Window innerleft; /*!< For drawing the inner client border */
+    Window innertop; /*!< For drawing the inner client border */
+    Window innerright; /*!< For drawing the inner client border */
+    Window innerbottom; /*!< For drawing the inner client border */
+    Window innerblb;
+    Window innerbll;
+    Window innerbrb;
+    Window innerbrr;
+    Window backback; /*!< A colored window shown while resizing */
+    Window backfront; /*!< An undrawn-in window, to prevent flashing on unmap */
+
+    /* These are resize handles inside the titlebar */
+    Window topresize;
+    Window tltresize;
+    Window tllresize;
+    Window trtresize;
+    Window trrresize;
+
+    Colormap colormap;
+
+    RrAppearance *a_unfocused_title;
+    RrAppearance *a_focused_title;
+    RrAppearance *a_unfocused_label;
+    RrAppearance *a_focused_label;
+    RrAppearance *a_icon;
+    RrAppearance *a_unfocused_handle;
+    RrAppearance *a_focused_handle;
+
+    gint icon_on; /* if the window icon button is on */
+    gint label_on; /* if the window title is on */
+    gint iconify_on; /* if the window iconify button is on */
+    gint desk_on; /* if the window all-desktops button is on */
+    gint shade_on; /* if the window shade button is on */
+    gint max_on; /* if the window maximize button is on */
+    gint close_on; /* if the window close button is on */
+
+    gint width; /* width of the titlebar and handle */
+    gint label_width; /* width of the label in the titlebar */
+    gint icon_x; /* x-position of the window icon button */
+    gint label_x; /* x-position of the window title */
+    gint iconify_x; /* x-position of the window iconify button */
+    gint desk_x; /* x-position of the window all-desktops button */
+    gint shade_x; /* x-position of the window shade button */
+    gint max_x; /* x-position of the window maximize button */
+    gint close_x; /* x-position of the window close button */
+
+    gint cbwidth_l; /* client border width */
+    gint cbwidth_t; /* client border width */
+    gint cbwidth_r; /* client border width */
+    gint cbwidth_b; /* client border width */
+    gboolean shaded; /* decorations adjust when shaded */
+
+    /* the leftmost and rightmost elements in the titlebar */
+    ObFrameContext leftmost;
+    ObFrameContext rightmost;
+
+    gboolean focused;
+    gboolean need_render;
+
+    gboolean flashing;
+    gboolean flash_on;
+    GTimeVal flash_end;
+
+    GTimeVal iconify_animation_end;
+
+};
+
+typedef struct _ObDefaultFrame ObDefaultFrame;
+
+/* Function use for interface */
+gint init(Display *, gint);
+gpointer frame_new(struct _ObClient *c);
+void frame_free(gpointer self);
+void frame_show(gpointer self);
+gint frame_hide(gpointer self);
+void frame_adjust_theme(gpointer self);
+void frame_adjust_shape(gpointer self);
+
+void frame_grab(gpointer self, GHashTable *);
+void frame_ungrab(gpointer self, GHashTable *);
+
+ObFrameContext frame_context(gpointer, Window, gint, gint);
+
+void frame_set_is_visible(gpointer, gboolean);
+void frame_set_is_focus(gpointer, gboolean);
+void frame_set_is_max_vert(gpointer, gboolean);
+void frame_set_is_max_horz(gpointer, gboolean);
+void frame_set_is_shaded(gpointer, gboolean);
+
+void frame_update_layout(gpointer, gboolean, gboolean);
+void frame_adjust_client_area(gpointer self);
+void frame_adjust_state(gpointer self);
+void frame_adjust_focus(gpointer self, gboolean hilite);
+void frame_adjust_title(gpointer self);
+void frame_adjust_icon(gpointer self);
+
+static gulong frame_animate_iconify_time_left(gpointer _self,
+        const GTimeVal *now);
+
+ObFrameContext frame_context(gpointer, Window win, gint x, gint y);
+//void frame_client_gravity(gpointer self, gint *x, gint *y);
+//void frame_frame_gravity(gpointer self, gint *x, gint *y);
+//void frame_rect_to_frame(gpointer self, Rect *r);
+//void frame_rect_to_client(gpointer self, Rect *r);
+void frame_flash_start(gpointer self);
+void frame_flash_stop(gpointer self);
+void frame_begin_iconify_animation(gpointer self, gboolean iconifying);
+void frame_end_iconify_animation(gpointer self);
+gboolean frame_iconify_animating(gpointer _self);
+
+void frame_set_hover_flag(gpointer, ObFrameButton);
+void frame_set_press_flag(gpointer, ObFrameButton);
+
+Window frame_get_window(gpointer);
+
+Strut frame_get_size(gpointer self);
+Rect frame_get_area(gpointer self);
+gint frame_get_decorations(gpointer self);
+
+gboolean frame_is_visible(gpointer self);
+gboolean frame_is_max_horz(gpointer self);
+gboolean frame_is_max_vert(gpointer self);
+
+void flash_done(gpointer data);
+gboolean flash_timeout(gpointer data);
+
+void layout_title(ObDefaultFrame *);
+void set_theme_statics(gpointer self);
+void free_theme_statics(gpointer self);
+gboolean frame_animate_iconify(gpointer self);
+void frame_adjust_cursors(gpointer self);
+
+/* Global for renderframe.c only */
+extern ObFramePlugin plugin;
+#define OBDEFAULTFRAME(x) ((ObDefaultFrame *)(x))
+
+#endif /*FRAME_DEFAULT_PLUGIN_H_*/
diff --git a/engines/default/render.c b/engines/default/render.c
new file mode 100644 (file)
index 0000000..43fe0de
--- /dev/null
@@ -0,0 +1,385 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_render.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+#include "render.h"
+#include "plugin.h"
+
+#include "openbox/engine_interface.h"
+#include "openbox/client.h"
+#include "openbox/screen.h"
+
+#include "render/theme.h"
+
+static void framerender_label(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_icon(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_max(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_iconify(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_desk(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_shade(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_close(ObDefaultFrame *self, RrAppearance *a);
+
+void frame_update_skin(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    if (plugin.frame_iconify_animating(self))
+        return; /* delay redrawing until the animation is done */
+    if (!self->visible)
+        return;
+
+    {
+        gulong px;
+
+        px = (self->focused ? RrColorPixel(theme_config.cb_focused_color)
+                : RrColorPixel(theme_config.cb_unfocused_color));
+
+        XSetWindowBackground(plugin.ob_display, self->backback, px);
+        XClearWindow(plugin.ob_display, self->backback);
+        XSetWindowBackground(plugin.ob_display, self->innerleft, px);
+        XClearWindow(plugin.ob_display, self->innerleft);
+        XSetWindowBackground(plugin.ob_display, self->innertop, px);
+        XClearWindow(plugin.ob_display, self->innertop);
+        XSetWindowBackground(plugin.ob_display, self->innerright, px);
+        XClearWindow(plugin.ob_display, self->innerright);
+        XSetWindowBackground(plugin.ob_display, self->innerbottom, px);
+        XClearWindow(plugin.ob_display, self->innerbottom);
+        XSetWindowBackground(plugin.ob_display, self->innerbll, px);
+        XClearWindow(plugin.ob_display, self->innerbll);
+        XSetWindowBackground(plugin.ob_display, self->innerbrr, px);
+        XClearWindow(plugin.ob_display, self->innerbrr);
+        XSetWindowBackground(plugin.ob_display, self->innerblb, px);
+        XClearWindow(plugin.ob_display, self->innerblb);
+        XSetWindowBackground(plugin.ob_display, self->innerbrb, px);
+        XClearWindow(plugin.ob_display, self->innerbrb);
+
+        px
+                = (self->focused ? RrColorPixel(theme_config.frame_focused_border_color)
+                        : RrColorPixel(theme_config.frame_unfocused_border_color));
+
+        XSetWindowBackground(plugin.ob_display, self->left, px);
+        XClearWindow(plugin.ob_display, self->left);
+        XSetWindowBackground(plugin.ob_display, self->right, px);
+        XClearWindow(plugin.ob_display, self->right);
+
+        XSetWindowBackground(plugin.ob_display, self->titleleft, px);
+        XClearWindow(plugin.ob_display, self->titleleft);
+        XSetWindowBackground(plugin.ob_display, self->titletop, px);
+        XClearWindow(plugin.ob_display, self->titletop);
+        XSetWindowBackground(plugin.ob_display, self->titletopleft, px);
+        XClearWindow(plugin.ob_display, self->titletopleft);
+        XSetWindowBackground(plugin.ob_display, self->titletopright, px);
+        XClearWindow(plugin.ob_display, self->titletopright);
+        XSetWindowBackground(plugin.ob_display, self->titleright, px);
+        XClearWindow(plugin.ob_display, self->titleright);
+
+        XSetWindowBackground(plugin.ob_display, self->handleleft, px);
+        XClearWindow(plugin.ob_display, self->handleleft);
+        XSetWindowBackground(plugin.ob_display, self->handletop, px);
+        XClearWindow(plugin.ob_display, self->handletop);
+        XSetWindowBackground(plugin.ob_display, self->handleright, px);
+        XClearWindow(plugin.ob_display, self->handleright);
+        XSetWindowBackground(plugin.ob_display, self->handlebottom, px);
+        XClearWindow(plugin.ob_display, self->handlebottom);
+
+        XSetWindowBackground(plugin.ob_display, self->lgripleft, px);
+        XClearWindow(plugin.ob_display, self->lgripleft);
+        XSetWindowBackground(plugin.ob_display, self->lgriptop, px);
+        XClearWindow(plugin.ob_display, self->lgriptop);
+        XSetWindowBackground(plugin.ob_display, self->lgripbottom, px);
+        XClearWindow(plugin.ob_display, self->lgripbottom);
+
+        XSetWindowBackground(plugin.ob_display, self->rgripright, px);
+        XClearWindow(plugin.ob_display, self->rgripright);
+        XSetWindowBackground(plugin.ob_display, self->rgriptop, px);
+        XClearWindow(plugin.ob_display, self->rgriptop);
+        XSetWindowBackground(plugin.ob_display, self->rgripbottom, px);
+        XClearWindow(plugin.ob_display, self->rgripbottom);
+
+        /* don't use the separator color for shaded windows */
+        if (!self->shaded)
+            px
+                    = (self->focused ? RrColorPixel(theme_config.title_separator_focused_color)
+                            : RrColorPixel(theme_config.title_separator_unfocused_color));
+
+        XSetWindowBackground(plugin.ob_display, self->titlebottom, px);
+        XClearWindow(plugin.ob_display, self->titlebottom);
+    }
+
+    if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
+        RrAppearance *t, *l, *m, *n, *i, *d, *s, *c, *clear;
+        if (self->focused) {
+
+            t = self->a_focused_title;
+            l = self->a_focused_label;
+
+            m
+                    = (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE) ? theme_config.a_disabled_focused_max
+                            : (self->max_vert || self->max_horz ? (self->press_flag
+                                    == OB_BUTTON_MAX ? theme_config.a_toggled_focused_pressed_max
+                                    : (self->hover_flag == OB_BUTTON_MAX ? theme_config.a_toggled_hover_focused_max
+                                            : theme_config.a_toggled_focused_unpressed_max))
+                                    : (self->press_flag == OB_BUTTON_MAX ? theme_config.a_focused_pressed_max
+                                            : (self->hover_flag
+                                                    == OB_BUTTON_MAX ? theme_config.a_hover_focused_max
+                                                    : theme_config.a_focused_unpressed_max))));
+            n = self->a_icon;
+            i
+                    = (!(self->decorations & OB_FRAME_DECOR_ICONIFY) ? theme_config.a_disabled_focused_iconify
+                            : (self->press_flag == OB_BUTTON_ICONIFY ? theme_config.a_focused_pressed_iconify
+                                    : (self->hover_flag == OB_BUTTON_ICONIFY ? theme_config.a_hover_focused_iconify
+                                            : theme_config.a_focused_unpressed_iconify)));
+            d
+                    = (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS) ? theme_config.a_disabled_focused_desk
+                            : (self->client->desktop == DESKTOP_ALL ? (self->press_flag
+                                    == OB_BUTTON_DESK ? theme_config.a_toggled_focused_pressed_desk
+                                    : (self->hover_flag == OB_BUTTON_DESK ? theme_config.a_toggled_hover_focused_desk
+                                            : theme_config.a_toggled_focused_unpressed_desk))
+                                    : (self->press_flag == OB_BUTTON_DESK ? theme_config.a_focused_pressed_desk
+                                            : (self->hover_flag
+                                                    == OB_BUTTON_DESK ? theme_config.a_hover_focused_desk
+                                                    : theme_config.a_focused_unpressed_desk))));
+            s
+                    = (!(self->decorations & OB_FRAME_DECOR_SHADE) ? theme_config.a_disabled_focused_shade
+                            : (self->shaded ? (self->press_flag
+                                    == OB_BUTTON_SHADE ? theme_config.a_toggled_focused_pressed_shade
+                                    : (self->hover_flag == OB_BUTTON_SHADE ? theme_config.a_toggled_hover_focused_shade
+                                            : theme_config.a_toggled_focused_unpressed_shade))
+                                    : (self->press_flag == OB_BUTTON_SHADE ? theme_config.a_focused_pressed_shade
+                                            : (self->hover_flag
+                                                    == OB_BUTTON_SHADE ? theme_config.a_hover_focused_shade
+                                                    : theme_config.a_focused_unpressed_shade))));
+            c
+                    = (!(self->decorations & OB_FRAME_DECOR_CLOSE) ? theme_config.a_disabled_focused_close
+                            : (self->press_flag == OB_BUTTON_CLOSE ? theme_config.a_focused_pressed_close
+                                    : (self->hover_flag == OB_BUTTON_CLOSE ? theme_config.a_hover_focused_close
+                                            : theme_config.a_focused_unpressed_close)));
+        }
+        else {
+            t = self->a_unfocused_title;
+            l = self->a_unfocused_label;
+            m
+                    = (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE) ? theme_config.a_disabled_unfocused_max
+                            : (self->max_vert || self->max_horz ? (self->press_flag
+                                    == OB_BUTTON_MAX ? theme_config.a_toggled_unfocused_pressed_max
+                                    : (self->hover_flag == OB_BUTTON_MAX ? theme_config.a_toggled_hover_unfocused_max
+                                            : theme_config.a_toggled_unfocused_unpressed_max))
+                                    : (self->press_flag == OB_BUTTON_MAX ? theme_config.a_unfocused_pressed_max
+                                            : (self->hover_flag
+                                                    == OB_BUTTON_MAX ? theme_config.a_hover_unfocused_max
+                                                    : theme_config.a_unfocused_unpressed_max))));
+            n = self->a_icon;
+            i
+                    = (!(self->decorations & OB_FRAME_DECOR_ICONIFY) ? theme_config.a_disabled_unfocused_iconify
+                            : (self->press_flag == OB_BUTTON_ICONIFY ? theme_config.a_unfocused_pressed_iconify
+                                    : (self->hover_flag == OB_BUTTON_ICONIFY ? theme_config.a_hover_unfocused_iconify
+                                            : theme_config.a_unfocused_unpressed_iconify)));
+            d
+                    = (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS) ? theme_config.a_disabled_unfocused_desk
+                            : (self->client->desktop == DESKTOP_ALL ? (self->press_flag
+                                    == OB_BUTTON_DESK ? theme_config.a_toggled_unfocused_pressed_desk
+                                    : (self->hover_flag == OB_BUTTON_DESK ? theme_config.a_toggled_hover_unfocused_desk
+                                            : theme_config.a_toggled_unfocused_unpressed_desk))
+                                    : (self->hover_flag == OB_BUTTON_DESK ? theme_config.a_unfocused_pressed_desk
+                                            : (self->hover_flag
+                                                    == OB_BUTTON_DESK ? theme_config.a_hover_unfocused_desk
+                                                    : theme_config.a_unfocused_unpressed_desk))));
+            s
+                    = (!(self->decorations & OB_FRAME_DECOR_SHADE) ? theme_config.a_disabled_unfocused_shade
+                            : (self->shaded ? (self->press_flag
+                                    == OB_BUTTON_SHADE ? theme_config.a_toggled_unfocused_pressed_shade
+                                    : (self->hover_flag == OB_BUTTON_SHADE ? theme_config.a_toggled_hover_unfocused_shade
+                                            : theme_config.a_toggled_unfocused_unpressed_shade))
+                                    : (self->press_flag == OB_BUTTON_SHADE ? theme_config.a_unfocused_pressed_shade
+                                            : (self->hover_flag
+                                                    == OB_BUTTON_SHADE ? theme_config.a_hover_unfocused_shade
+                                                    : theme_config.a_unfocused_unpressed_shade))));
+            c
+                    = (!(self->decorations & OB_FRAME_DECOR_CLOSE) ? theme_config.a_disabled_unfocused_close
+                            : (self->press_flag == OB_BUTTON_CLOSE ? theme_config.a_unfocused_pressed_close
+                                    : (self->hover_flag == OB_BUTTON_CLOSE ? theme_config.a_hover_unfocused_close
+                                            : theme_config.a_unfocused_unpressed_close)));
+        }
+        clear = theme_config.a_clear;
+
+        RrPaint(t, self->title, self->width, theme_config.title_height);
+
+        clear->surface.parent = t;
+        clear->surface.parenty = 0;
+
+        clear->surface.parentx = theme_config.grip_width;
+
+        RrPaint(clear, self->topresize, self->width - theme_config.grip_width
+                * 2, theme_config.paddingy + 1);
+
+        clear->surface.parentx = 0;
+
+        if (theme_config.grip_width > 0)
+            RrPaint(clear, self->tltresize, theme_config.grip_width,
+                    theme_config.paddingy + 1);
+        if (theme_config.title_height > 0)
+            RrPaint(clear, self->tllresize, theme_config.paddingx + 1,
+                    theme_config.title_height);
+
+        clear->surface.parentx = self->width - theme_config.grip_width;
+
+        if (theme_config.grip_width > 0)
+            RrPaint(clear, self->trtresize, theme_config.grip_width,
+                    theme_config.paddingy + 1);
+
+        clear->surface.parentx = self->width - (theme_config.paddingx + 1);
+
+        if (theme_config.title_height > 0)
+            RrPaint(clear, self->trrresize, theme_config.paddingx + 1,
+                    theme_config.title_height);
+
+        /* set parents for any parent relative guys */
+        l->surface.parent = t;
+        l->surface.parentx = self->label_x;
+        l->surface.parenty = theme_config.paddingy;
+
+        m->surface.parent = t;
+        m->surface.parentx = self->max_x;
+        m->surface.parenty = theme_config.paddingy + 1;
+
+        n->surface.parent = t;
+        n->surface.parentx = self->icon_x;
+        n->surface.parenty = theme_config.paddingy;
+
+        i->surface.parent = t;
+        i->surface.parentx = self->iconify_x;
+        i->surface.parenty = theme_config.paddingy + 1;
+
+        d->surface.parent = t;
+        d->surface.parentx = self->desk_x;
+        d->surface.parenty = theme_config.paddingy + 1;
+
+        s->surface.parent = t;
+        s->surface.parentx = self->shade_x;
+        s->surface.parenty = theme_config.paddingy + 1;
+
+        c->surface.parent = t;
+        c->surface.parentx = self->close_x;
+        c->surface.parenty = theme_config.paddingy + 1;
+
+        framerender_label(self, l);
+        framerender_max(self, m);
+        framerender_icon(self, n);
+        framerender_iconify(self, i);
+        framerender_desk(self, d);
+        framerender_shade(self, s);
+        framerender_close(self, c);
+    }
+
+    if (self->decorations & OB_FRAME_DECOR_HANDLE && theme_config.handle_height
+            > 0) {
+        RrAppearance *h, *g;
+
+        h = (self->focused ? self->a_focused_handle : self->a_unfocused_handle);
+
+        RrPaint(h, self->handle, self->width, theme_config.handle_height);
+
+        if (self->decorations & OB_FRAME_DECOR_GRIPS) {
+            g = (self->focused ? theme_config.a_focused_grip
+                    : theme_config.a_unfocused_grip);
+
+            if (g->surface.grad == RR_SURFACE_PARENTREL)
+                g->surface.parent = h;
+
+            g->surface.parentx = 0;
+            g->surface.parenty = 0;
+
+            RrPaint(g, self->lgrip, theme_config.grip_width,
+                    theme_config.handle_height);
+
+            g->surface.parentx = self->width - theme_config.grip_width;
+            g->surface.parenty = 0;
+
+            RrPaint(g, self->rgrip, theme_config.grip_width,
+                    theme_config.handle_height);
+        }
+    }
+
+    XFlush(plugin.ob_display);
+}
+
+static void framerender_label(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->label_on)
+        return;
+    /* set the texture's text! */
+    a->texture[0].data.text.string = self->client->title;
+    RrPaint(a, self->label, self->label_width, theme_config.label_height);
+}
+
+static void framerender_icon(ObDefaultFrame *self, RrAppearance *a)
+{
+    const ObClientIcon *icon;
+
+    if (!self->icon_on)
+        return;
+
+    icon = client_icon(self->client, theme_config.button_size + 2,
+            theme_config.button_size + 2);
+    if (icon) {
+        a->texture[0].type = RR_TEXTURE_RGBA;
+        a->texture[0].data.rgba.width = icon->width;
+        a->texture[0].data.rgba.height = icon->height;
+        a->texture[0].data.rgba.alpha = 0xff;
+        a->texture[0].data.rgba.data = icon->data;
+    }
+    else
+        a->texture[0].type = RR_TEXTURE_NONE;
+
+    RrPaint(a, self->icon, theme_config.button_size + 2,
+            theme_config.button_size + 2);
+}
+
+static void framerender_max(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->max_on)
+        return;
+    RrPaint(a, self->max, theme_config.button_size, theme_config.button_size);
+}
+
+static void framerender_iconify(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->iconify_on)
+        return;
+    RrPaint(a, self->iconify, theme_config.button_size,
+            theme_config.button_size);
+}
+
+static void framerender_desk(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->desk_on)
+        return;
+    RrPaint(a, self->desk, theme_config.button_size, theme_config.button_size);
+}
+
+static void framerender_shade(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->shade_on)
+        return;
+    RrPaint(a, self->shade, theme_config.button_size, theme_config.button_size);
+}
+
+static void framerender_close(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->close_on)
+        return;
+    RrPaint(a, self->close, theme_config.button_size, theme_config.button_size);
+}
diff --git a/engines/default/render.h b/engines/default/render.h
new file mode 100644 (file)
index 0000000..29bdc6a
--- /dev/null
@@ -0,0 +1,26 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_default_render.h for the Openbox window manager
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#ifndef FRAME_DEFAULT_RENDER_H_
+#define FRAME_DEFAULT_RENDER_H_
+
+#include "plugin.h"
+
+void frame_update_skin(gpointer self);
+
+#endif
diff --git a/engines/minimal/frame_minimal_config.c b/engines/minimal/frame_minimal_config.c
new file mode 100644 (file)
index 0000000..283df34
--- /dev/null
@@ -0,0 +1,1430 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_minimal_config.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#include "frame_minimal_config.h"
+#include "frame_minimal_plugin.h"
+
+#include "render/render.h"
+#include "render/color.h"
+#include "render/font.h"
+#include "render/mask.h"
+#include "render/icon.h"
+#include "parser/parse.h"
+
+#include <X11/Xlib.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+static XrmDatabase loaddb(const gchar *name, gchar **path);
+static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value);
+static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value);
+static gboolean read_color(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrColor **value);
+static gboolean read_mask(const RrInstance *inst, const gchar *path,
+        ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value);
+static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrAppearance *value, gboolean allow_trans);
+static int parse_inline_number(const char *p);
+static RrPixel32* read_c_image(gint width, gint height, const guint8 *data);
+static void set_default_appearance(RrAppearance *a);
+
+gint load_theme_config(const RrInstance *inst, const gchar *name,
+        const gchar * path, XrmDatabase db, RrFont *active_window_font,
+        RrFont *inactive_window_font, RrFont *menu_title_font,
+        RrFont *menu_item_font, RrFont *osd_font)
+{
+    RrJustify winjust, mtitlejust;
+    gchar *str;
+    ObFrameThemeConfig * theme = &theme_config;
+    gboolean userdef;
+
+    //theme = g_new0(ObFrameTheme, 1);
+
+    theme->inst = inst;
+    theme->name = g_strdup(name ? name : DEFAULT_THEME);
+
+    theme->a_disabled_focused_max = RrAppearanceNew(inst, 1);
+    theme->a_disabled_unfocused_max = RrAppearanceNew(inst, 1);
+    theme->a_hover_focused_max = RrAppearanceNew(inst, 1);
+    theme->a_hover_unfocused_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_focused_unpressed_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_unfocused_unpressed_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_hover_focused_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_hover_unfocused_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_focused_pressed_max = RrAppearanceNew(inst, 1);
+    theme->a_toggled_unfocused_pressed_max = RrAppearanceNew(inst, 1);
+    theme->a_focused_unpressed_max = RrAppearanceNew(inst, 1);
+    theme->a_focused_pressed_max = RrAppearanceNew(inst, 1);
+    theme->a_unfocused_unpressed_max = RrAppearanceNew(inst, 1);
+    theme->a_unfocused_pressed_max = RrAppearanceNew(inst, 1);
+    theme->a_focused_grip = RrAppearanceNew(inst, 0);
+    theme->a_unfocused_grip = RrAppearanceNew(inst, 0);
+    theme->a_focused_title = RrAppearanceNew(inst, 0);
+    theme->a_unfocused_title = RrAppearanceNew(inst, 0);
+    theme->a_focused_label = RrAppearanceNew(inst, 1);
+    theme->a_unfocused_label = RrAppearanceNew(inst, 1);
+    theme->a_icon = RrAppearanceNew(inst, 1);
+    theme->a_focused_handle = RrAppearanceNew(inst, 0);
+    theme->a_unfocused_handle = RrAppearanceNew(inst, 0);
+    theme->a_menu = RrAppearanceNew(inst, 0);
+    theme->a_menu_title = RrAppearanceNew(inst, 0);
+    theme->a_menu_text_title = RrAppearanceNew(inst, 1);
+    theme->a_menu_normal = RrAppearanceNew(inst, 0);
+    theme->a_menu_selected = RrAppearanceNew(inst, 0);
+    theme->a_menu_disabled = RrAppearanceNew(inst, 0);
+    theme->a_menu_disabled_selected = RrAppearanceNew(inst, 0);
+    theme->a_menu_text_normal = RrAppearanceNew(inst, 1);
+    theme->a_menu_text_selected = RrAppearanceNew(inst, 1);
+    theme->a_menu_text_disabled = RrAppearanceNew(inst, 1);
+    theme->a_menu_text_disabled_selected = RrAppearanceNew(inst, 1);
+    theme->a_menu_bullet_normal = RrAppearanceNew(inst, 1);
+    theme->a_menu_bullet_selected = RrAppearanceNew(inst, 1);
+    theme->a_clear = RrAppearanceNew(inst, 0);
+    theme->a_clear_tex = RrAppearanceNew(inst, 1);
+    theme->osd_hilite_bg = RrAppearanceNew(inst, 0);
+    theme->osd_hilite_label = RrAppearanceNew(inst, 1);
+    theme->osd_hilite_fg = RrAppearanceNew(inst, 0);
+    theme->osd_unhilite_fg = RrAppearanceNew(inst, 0);
+
+    /* load the font stuff */
+    if (active_window_font) {
+        theme->win_font_focused = active_window_font;
+        RrFontRef(active_window_font);
+    }
+    else
+        theme->win_font_focused = RrFontOpenDefault(inst);
+
+    if (inactive_window_font) {
+        theme->win_font_unfocused = inactive_window_font;
+        RrFontRef(inactive_window_font);
+    }
+    else
+        theme->win_font_unfocused = RrFontOpenDefault(inst);
+
+    winjust = RR_JUSTIFY_LEFT;
+    str = "center";
+    if (!g_ascii_strcasecmp(str, "right"))
+        winjust = RR_JUSTIFY_RIGHT;
+    else if (!g_ascii_strcasecmp(str, "center"))
+        winjust = RR_JUSTIFY_CENTER;
+
+    if (menu_title_font) {
+        theme->menu_title_font = menu_title_font;
+        RrFontRef(menu_title_font);
+    }
+    else
+        theme->menu_title_font = RrFontOpenDefault(inst);
+
+    mtitlejust = RR_JUSTIFY_LEFT;
+    str = "center";
+    if (!g_ascii_strcasecmp(str, "right"))
+        mtitlejust = RR_JUSTIFY_RIGHT;
+    else if (!g_ascii_strcasecmp(str, "center"))
+        mtitlejust = RR_JUSTIFY_CENTER;
+
+    if (menu_item_font) {
+        theme->menu_font = menu_item_font;
+        RrFontRef(menu_item_font);
+    }
+    else
+        theme->menu_font = RrFontOpenDefault(inst);
+
+    if (osd_font) {
+        theme->osd_font = osd_font;
+        RrFontRef(osd_font);
+    }
+    else
+        theme->osd_font = RrFontOpenDefault(inst);
+
+    /* load direct dimensions */
+    theme->menu_overlap = 0;
+    theme->handle_height = 6;
+    theme->paddingx = 3;
+    theme->paddingy = theme->paddingx;
+    theme->fbwidth = 1;
+    /* menu border width inherits from the frame border width */
+    theme->mbwidth = theme->fbwidth;
+    /* osd border width inherits from the frame border width */
+    theme->obwidth = theme->fbwidth;
+    theme->cbwidthx = theme->paddingx;
+    theme->cbwidthy = theme->cbwidthx;
+
+    /* load colors */
+    theme->frame_focused_border_color = RrColorNew(inst, 0, 0, 0);
+    /* title separator focused color inherits from focused boder color */
+    theme->title_separator_focused_color = RrColorNew(inst,
+            theme->frame_focused_border_color->r,
+            theme->frame_focused_border_color->g,
+            theme->frame_focused_border_color->b);
+    /* unfocused border color inherits from frame focused border color */
+    theme->frame_unfocused_border_color = RrColorNew(inst,
+            theme->frame_focused_border_color->r,
+            theme->frame_focused_border_color->g,
+            theme->frame_focused_border_color->b);
+    /* title separator unfocused color inherits from unfocused boder color */
+    theme->title_separator_unfocused_color = RrColorNew(inst,
+            theme->frame_unfocused_border_color->r,
+            theme->frame_unfocused_border_color->g,
+            theme->frame_unfocused_border_color->b);
+
+    /* menu border color inherits from frame focused border color */
+    theme->menu_border_color = RrColorNew(inst,
+            theme->frame_focused_border_color->r,
+            theme->frame_focused_border_color->g,
+            theme->frame_focused_border_color->b);
+    /* osd border color inherits from frame focused border color */
+    theme->osd_border_color = RrColorNew(inst,
+            theme->frame_focused_border_color->r,
+            theme->frame_focused_border_color->g,
+            theme->frame_focused_border_color->b);
+    theme->cb_focused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
+    theme->cb_unfocused_color = RrColorNew(inst, 0x44, 0x44, 0x44);
+    theme->title_focused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
+    theme->osd_color = RrColorNew(inst, theme->title_focused_color->r,
+            theme->title_focused_color->g, theme->title_focused_color->b);
+    theme->title_unfocused_color = RrColorNew(inst, 0x44, 0x44, 0x44);
+    theme->titlebut_focused_unpressed_color
+            = RrColorNew(inst, 0xff, 0xff, 0xff);
+    theme->titlebut_unfocused_unpressed_color = RrColorNew(inst, 0x44, 0x44,
+            0x44);
+    theme->titlebut_focused_pressed_color = RrColorNew(inst,
+            theme->titlebut_focused_unpressed_color->r,
+            theme->titlebut_focused_unpressed_color->g,
+            theme->titlebut_focused_unpressed_color->b);
+    theme->titlebut_unfocused_pressed_color = RrColorNew(inst,
+            theme->titlebut_unfocused_unpressed_color->r,
+            theme->titlebut_unfocused_unpressed_color->g,
+            theme->titlebut_unfocused_unpressed_color->b);
+    theme->titlebut_disabled_focused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
+    theme->titlebut_disabled_unfocused_color = RrColorNew(inst, 0, 0, 0);
+    theme->titlebut_hover_focused_color = RrColorNew(inst,
+            theme->titlebut_focused_unpressed_color->r,
+            theme->titlebut_focused_unpressed_color->g,
+            theme->titlebut_focused_unpressed_color->b);
+    theme->titlebut_hover_unfocused_color = RrColorNew(inst,
+            theme->titlebut_unfocused_unpressed_color->r,
+            theme->titlebut_unfocused_unpressed_color->g,
+            theme->titlebut_unfocused_unpressed_color->b);
+    theme->titlebut_toggled_focused_unpressed_color = RrColorNew(inst,
+            theme->titlebut_focused_pressed_color->r,
+            theme->titlebut_focused_pressed_color->g,
+            theme->titlebut_focused_pressed_color->b);
+    theme->titlebut_toggled_unfocused_unpressed_color = RrColorNew(inst,
+            theme->titlebut_unfocused_pressed_color->r,
+            theme->titlebut_unfocused_pressed_color->g,
+            theme->titlebut_unfocused_pressed_color->b);
+    theme->titlebut_toggled_hover_focused_color = RrColorNew(inst,
+            theme->titlebut_toggled_focused_unpressed_color->r,
+            theme->titlebut_toggled_focused_unpressed_color->g,
+            theme->titlebut_toggled_focused_unpressed_color->b);
+    theme->titlebut_toggled_hover_unfocused_color = RrColorNew(inst,
+            theme->titlebut_toggled_unfocused_unpressed_color->r,
+            theme->titlebut_toggled_unfocused_unpressed_color->g,
+            theme->titlebut_toggled_unfocused_unpressed_color->b);
+    theme->titlebut_toggled_focused_pressed_color = RrColorNew(inst,
+            theme->titlebut_focused_pressed_color->r,
+            theme->titlebut_focused_pressed_color->g,
+            theme->titlebut_focused_pressed_color->b);
+    theme->titlebut_toggled_unfocused_pressed_color = RrColorNew(inst,
+            theme->titlebut_unfocused_pressed_color->r,
+            theme->titlebut_unfocused_pressed_color->g,
+            theme->titlebut_unfocused_pressed_color->b);
+    theme->menu_title_color = RrColorNew(inst, 0, 0, 0);
+    theme->menu_color = RrColorNew(inst, 0xff, 0xff, 0xff);
+    theme->menu_disabled_color = RrColorNew(inst, 0, 0, 0);
+    theme->menu_disabled_selected_color = RrColorNew(inst,
+            theme->menu_disabled_color->r, theme->menu_disabled_color->g,
+            theme->menu_disabled_color->b);
+    theme->menu_selected_color = RrColorNew(inst, 0, 0, 0);
+
+    /* load the image masks */
+
+    /* maximize button masks */
+    userdef = TRUE;
+    if (!read_mask(inst, path, theme, "max.xbm", &theme->max_mask)) {
+        guchar data[] = { 0x3f, 0x3f, 0x21, 0x21, 0x21, 0x3f };
+        theme->max_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+        userdef = FALSE;
+    }
+    if (!read_mask(inst, path, theme, "max_toggled.xbm",
+            &theme->max_toggled_mask)) {
+        if (userdef)
+            theme->max_toggled_mask = RrPixmapMaskCopy(theme->max_mask);
+        else {
+            guchar data[] = { 0x3e, 0x22, 0x2f, 0x29, 0x39, 0x0f };
+            theme->max_toggled_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+        }
+    }
+
+    theme->max_pressed_mask = RrPixmapMaskCopy(theme->max_mask);
+    theme->max_disabled_mask = RrPixmapMaskCopy(theme->max_mask);
+    theme->max_hover_mask = RrPixmapMaskCopy(theme->max_mask);
+    theme->max_toggled_pressed_mask = RrPixmapMaskCopy(theme->max_toggled_mask);
+    theme->max_toggled_hover_mask = RrPixmapMaskCopy(theme->max_toggled_mask);
+
+    /* iconify button masks */
+    if (!read_mask(inst, path, theme, "iconify.xbm", &theme->iconify_mask)) {
+        guchar data[] = { 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f };
+        theme->iconify_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+    }
+    theme->iconify_pressed_mask = RrPixmapMaskCopy(theme->iconify_mask);
+    theme->iconify_disabled_mask = RrPixmapMaskCopy(theme->iconify_mask);
+    theme->iconify_hover_mask = RrPixmapMaskCopy(theme->iconify_mask);
+
+    /* all desktops button masks */
+    userdef = TRUE;
+    if (!read_mask(inst, path, theme, "desk.xbm", &theme->desk_mask)) {
+        guchar data[] = { 0x33, 0x33, 0x00, 0x00, 0x33, 0x33 };
+        theme->desk_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+        userdef = FALSE;
+    }
+    if (!read_mask(inst, path, theme, "desk_toggled.xbm",
+            &theme->desk_toggled_mask)) {
+        if (userdef)
+            theme->desk_toggled_mask = RrPixmapMaskCopy(theme->desk_mask);
+        else {
+            guchar data[] = { 0x00, 0x1e, 0x1a, 0x16, 0x1e, 0x00 };
+            theme->desk_toggled_mask
+                    = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+        }
+    }
+    theme->desk_pressed_mask = RrPixmapMaskCopy(theme->desk_mask);
+    theme->desk_disabled_mask = RrPixmapMaskCopy(theme->desk_mask);
+    theme->desk_hover_mask = RrPixmapMaskCopy(theme->desk_mask);
+    theme->desk_toggled_pressed_mask
+            = RrPixmapMaskCopy(theme->desk_toggled_mask);
+    theme->desk_toggled_hover_mask = RrPixmapMaskCopy(theme->desk_toggled_mask);
+
+    /* shade button masks */
+    if (!read_mask(inst, path, theme, "shade.xbm", &theme->shade_mask)) {
+        guchar data[] = { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 };
+        theme->shade_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+    }
+    theme->shade_toggled_mask = RrPixmapMaskCopy(theme->shade_mask);
+    theme->shade_pressed_mask = RrPixmapMaskCopy(theme->shade_mask);
+    theme->shade_disabled_mask = RrPixmapMaskCopy(theme->shade_mask);
+    theme->shade_hover_mask = RrPixmapMaskCopy(theme->shade_mask);
+    theme->shade_toggled_pressed_mask
+            = RrPixmapMaskCopy(theme->shade_toggled_mask);
+    theme->shade_toggled_hover_mask
+            = RrPixmapMaskCopy(theme->shade_toggled_mask);
+
+    /* close button masks */
+    if (!read_mask(inst, path, theme, "close.xbm", &theme->close_mask)) {
+        guchar data[] = { 0x33, 0x3f, 0x1e, 0x1e, 0x3f, 0x33 };
+        theme->close_mask = RrPixmapMaskNew(inst, 6, 6, (gchar*)data);
+    }
+    theme->close_pressed_mask = RrPixmapMaskCopy(theme->close_mask);
+    theme->close_disabled_mask = RrPixmapMaskCopy(theme->close_mask);
+    theme->close_hover_mask = RrPixmapMaskCopy(theme->close_mask);
+
+    /* submenu bullet mask */
+    if (!read_mask(inst, path, theme, "bullet.xbm", &theme->menu_bullet_mask)) {
+        guchar data[] = { 0x01, 0x03, 0x07, 0x0f, 0x07, 0x03, 0x01 };
+        theme->menu_bullet_mask = RrPixmapMaskNew(inst, 4, 7, (gchar*)data);
+    }
+
+    /* setup the default window icon */
+    theme->def_win_icon = read_c_image(OB_DEFAULT_ICON_WIDTH,
+            OB_DEFAULT_ICON_HEIGHT, OB_DEFAULT_ICON_pixel_data);
+
+    /* the toggled hover mask = the toggled unpressed mask (i.e. no change) */
+    theme->max_toggled_hover_mask = RrPixmapMaskCopy(theme->max_toggled_mask);
+    theme->desk_toggled_hover_mask = RrPixmapMaskCopy(theme->desk_toggled_mask);
+    theme->shade_toggled_hover_mask
+            = RrPixmapMaskCopy(theme->shade_toggled_mask);
+    /* the toggled pressed mask = the toggled unpressed mask (i.e. no change)*/
+    theme->max_toggled_pressed_mask = RrPixmapMaskCopy(theme->max_toggled_mask);
+    theme->desk_toggled_pressed_mask
+            = RrPixmapMaskCopy(theme->desk_toggled_mask);
+    theme->shade_toggled_pressed_mask
+            = RrPixmapMaskCopy(theme->shade_toggled_mask);
+
+    /* read the decoration textures */
+    set_default_appearance(theme->a_focused_title);
+    set_default_appearance(theme->a_unfocused_title);
+    set_default_appearance(theme->a_focused_label);
+    set_default_appearance(theme->a_unfocused_label);
+    set_default_appearance(theme->a_focused_handle);
+    set_default_appearance(theme->a_unfocused_handle);
+    set_default_appearance(theme->a_focused_grip);
+    set_default_appearance(theme->a_unfocused_grip);
+    set_default_appearance(theme->a_menu);
+    set_default_appearance(theme->a_menu_title);
+    set_default_appearance(theme->a_menu_selected);
+    theme->a_menu_disabled_selected = RrAppearanceCopy(theme->a_menu_selected);
+
+    /* read appearances for non-decorations (on-screen-display) */
+    if (!read_appearance(db, inst, "osd.bg", theme->osd_hilite_bg, FALSE)) {
+        RrAppearanceFree(theme->osd_hilite_bg);
+        theme->osd_hilite_bg = RrAppearanceCopy(theme->a_focused_title);
+    }
+    if (!read_appearance(db, inst, "osd.label.bg", theme->osd_hilite_label,
+            TRUE)) {
+        RrAppearanceFree(theme->osd_hilite_label);
+        theme->osd_hilite_label = RrAppearanceCopy(theme->a_focused_label);
+    }
+    /* osd_hilite_fg can't be parentrel */
+    if (!read_appearance(db, inst, "osd.hilight.bg", theme->osd_hilite_fg,
+            FALSE)) {
+        RrAppearanceFree(theme->osd_hilite_fg);
+        if (theme->a_focused_label->surface.grad != RR_SURFACE_PARENTREL)
+            theme->osd_hilite_fg = RrAppearanceCopy(theme->a_focused_label);
+        else
+            theme->osd_hilite_fg = RrAppearanceCopy(theme->a_focused_title);
+    }
+    /* osd_unhilite_fg can't be parentrel either */
+    if (!read_appearance(db, inst, "osd.unhilight.bg", theme->osd_unhilite_fg,
+            FALSE)) {
+        RrAppearanceFree(theme->osd_unhilite_fg);
+        if (theme->a_unfocused_label->surface.grad != RR_SURFACE_PARENTREL)
+            theme->osd_unhilite_fg=RrAppearanceCopy(theme->a_unfocused_label);
+        else
+            theme->osd_unhilite_fg=RrAppearanceCopy(theme->a_unfocused_title);
+    }
+
+    /* read buttons textures */
+    set_default_appearance(theme->a_disabled_focused_max);
+    set_default_appearance(theme->a_disabled_unfocused_max);
+    set_default_appearance(theme->a_focused_pressed_max);
+    set_default_appearance(theme->a_unfocused_pressed_max);
+    if (!read_appearance(db, inst, "window.active.button.toggled.unpressed.bg",
+            theme->a_toggled_focused_unpressed_max, TRUE) && !read_appearance(
+            db, inst, "window.active.button.toggled.bg",
+            theme->a_toggled_focused_unpressed_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_focused_unpressed_max);
+        theme->a_toggled_focused_unpressed_max
+                = RrAppearanceCopy(theme->a_focused_pressed_max);
+    }
+    if (!read_appearance(db, inst,
+            "window.inactive.button.toggled.unpressed.bg",
+            theme->a_toggled_unfocused_unpressed_max, TRUE)
+            && !read_appearance(db, inst, "window.inactive.button.toggled.bg",
+                    theme->a_toggled_unfocused_unpressed_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_unfocused_unpressed_max);
+        theme->a_toggled_unfocused_unpressed_max
+                = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    }
+    if (!read_appearance(db, inst, "window.active.button.toggled.hover.bg",
+            theme->a_toggled_hover_focused_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_hover_focused_max);
+        theme->a_toggled_hover_focused_max
+                = RrAppearanceCopy(theme->a_toggled_focused_unpressed_max);
+    }
+    if (!read_appearance(db, inst, "window.inactive.button.toggled.hover.bg",
+            theme->a_toggled_hover_unfocused_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_hover_unfocused_max);
+        theme->a_toggled_hover_unfocused_max
+                = RrAppearanceCopy(theme->a_toggled_unfocused_unpressed_max);
+    }
+    if (!read_appearance(db, inst, "window.active.button.toggled.pressed.bg",
+            theme->a_toggled_focused_pressed_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_focused_pressed_max);
+        theme->a_toggled_focused_pressed_max
+                = RrAppearanceCopy(theme->a_focused_pressed_max);
+    }
+    if (!read_appearance(db, inst, "window.inactive.button.toggled.pressed.bg",
+            theme->a_toggled_unfocused_pressed_max, TRUE)) {
+        RrAppearanceFree(theme->a_toggled_unfocused_pressed_max);
+        theme->a_toggled_unfocused_pressed_max
+                = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    }
+    set_default_appearance(theme->a_focused_unpressed_max);
+    set_default_appearance(theme->a_unfocused_unpressed_max);
+    if (!read_appearance(db, inst, "window.active.button.hover.bg",
+            theme->a_hover_focused_max, TRUE)) {
+        RrAppearanceFree(theme->a_hover_focused_max);
+        theme->a_hover_focused_max
+                = RrAppearanceCopy(theme->a_focused_unpressed_max);
+    }
+    if (!read_appearance(db, inst, "window.inactive.button.hover.bg",
+            theme->a_hover_unfocused_max, TRUE)) {
+        RrAppearanceFree(theme->a_hover_unfocused_max);
+        theme->a_hover_unfocused_max
+                = RrAppearanceCopy(theme->a_unfocused_unpressed_max);
+    }
+
+    theme->a_disabled_focused_close
+            = RrAppearanceCopy(theme->a_disabled_focused_max);
+    theme->a_disabled_unfocused_close
+            = RrAppearanceCopy(theme->a_disabled_unfocused_max);
+    theme->a_hover_focused_close = RrAppearanceCopy(theme->a_hover_focused_max);
+    theme->a_hover_unfocused_close
+            = RrAppearanceCopy(theme->a_hover_unfocused_max);
+    theme->a_unfocused_unpressed_close
+            = RrAppearanceCopy(theme->a_unfocused_unpressed_max);
+    theme->a_unfocused_pressed_close
+            = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    theme->a_focused_unpressed_close
+            = RrAppearanceCopy(theme->a_focused_unpressed_max);
+    theme->a_focused_pressed_close
+            = RrAppearanceCopy(theme->a_focused_pressed_max);
+    theme->a_disabled_focused_desk
+            = RrAppearanceCopy(theme->a_disabled_focused_max);
+    theme->a_disabled_unfocused_desk
+            = RrAppearanceCopy(theme->a_disabled_unfocused_max);
+    theme->a_hover_focused_desk = RrAppearanceCopy(theme->a_hover_focused_max);
+    theme->a_hover_unfocused_desk
+            = RrAppearanceCopy(theme->a_hover_unfocused_max);
+    theme->a_toggled_hover_focused_desk
+            = RrAppearanceCopy(theme->a_toggled_hover_focused_max);
+    theme->a_toggled_hover_unfocused_desk
+            = RrAppearanceCopy(theme->a_toggled_hover_unfocused_max);
+    theme->a_toggled_focused_unpressed_desk
+            = RrAppearanceCopy(theme->a_toggled_focused_unpressed_max);
+    theme->a_toggled_unfocused_unpressed_desk
+            = RrAppearanceCopy(theme->a_toggled_unfocused_unpressed_max);
+    theme->a_toggled_focused_pressed_desk
+            = RrAppearanceCopy(theme->a_toggled_focused_pressed_max);
+    theme->a_toggled_unfocused_pressed_desk
+            = RrAppearanceCopy(theme->a_toggled_unfocused_pressed_max);
+    theme->a_unfocused_unpressed_desk
+            = RrAppearanceCopy(theme->a_unfocused_unpressed_max);
+    theme->a_unfocused_pressed_desk
+            = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    theme->a_focused_unpressed_desk
+            = RrAppearanceCopy(theme->a_focused_unpressed_max);
+    theme->a_focused_pressed_desk
+            = RrAppearanceCopy(theme->a_focused_pressed_max);
+    theme->a_disabled_focused_shade
+            = RrAppearanceCopy(theme->a_disabled_focused_max);
+    theme->a_disabled_unfocused_shade
+            = RrAppearanceCopy(theme->a_disabled_unfocused_max);
+    theme->a_hover_focused_shade = RrAppearanceCopy(theme->a_hover_focused_max);
+    theme->a_hover_unfocused_shade
+            = RrAppearanceCopy(theme->a_hover_unfocused_max);
+    theme->a_toggled_hover_focused_shade
+            = RrAppearanceCopy(theme->a_toggled_hover_focused_max);
+    theme->a_toggled_hover_unfocused_shade
+            = RrAppearanceCopy(theme->a_toggled_hover_unfocused_max);
+    theme->a_toggled_focused_unpressed_shade
+            = RrAppearanceCopy(theme->a_toggled_focused_unpressed_max);
+    theme->a_toggled_unfocused_unpressed_shade
+            = RrAppearanceCopy(theme->a_toggled_unfocused_unpressed_max);
+    theme->a_toggled_focused_pressed_shade
+            = RrAppearanceCopy(theme->a_toggled_focused_pressed_max);
+    theme->a_toggled_unfocused_pressed_shade
+            = RrAppearanceCopy(theme->a_toggled_unfocused_pressed_max);
+    theme->a_unfocused_unpressed_shade
+            = RrAppearanceCopy(theme->a_unfocused_unpressed_max);
+    theme->a_unfocused_pressed_shade
+            = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    theme->a_focused_unpressed_shade
+            = RrAppearanceCopy(theme->a_focused_unpressed_max);
+    theme->a_focused_pressed_shade
+            = RrAppearanceCopy(theme->a_focused_pressed_max);
+    theme->a_disabled_focused_iconify
+            = RrAppearanceCopy(theme->a_disabled_focused_max);
+    theme->a_disabled_unfocused_iconify
+            = RrAppearanceCopy(theme->a_disabled_focused_max);
+    theme->a_hover_focused_iconify
+            = RrAppearanceCopy(theme->a_hover_focused_max);
+    theme->a_hover_unfocused_iconify
+            = RrAppearanceCopy(theme->a_hover_unfocused_max);
+    theme->a_unfocused_unpressed_iconify
+            = RrAppearanceCopy(theme->a_unfocused_unpressed_max);
+    theme->a_unfocused_pressed_iconify
+            = RrAppearanceCopy(theme->a_unfocused_pressed_max);
+    theme->a_focused_unpressed_iconify
+            = RrAppearanceCopy(theme->a_focused_unpressed_max);
+    theme->a_focused_pressed_iconify
+            = RrAppearanceCopy(theme->a_focused_pressed_max);
+
+    theme->a_icon->surface.grad
+            = theme->a_clear->surface.grad
+                    = theme->a_clear_tex->surface.grad
+                            = theme->a_menu_text_title->surface.grad
+                                    = theme->a_menu_normal->surface.grad
+                                            = theme->a_menu_disabled->surface.grad
+                                                    = theme->a_menu_text_normal->surface.grad
+                                                            = theme->a_menu_text_selected->surface.grad
+                                                                    = theme->a_menu_text_disabled->surface.grad
+                                                                            = theme->a_menu_text_disabled_selected->surface.grad
+                                                                                    = theme->a_menu_bullet_normal->surface.grad
+                                                                                            = theme->a_menu_bullet_selected->surface.grad
+                                                                                                    = RR_SURFACE_PARENTREL;
+
+    /* set up the textures */
+    theme->a_focused_label->texture[0].type = RR_TEXTURE_TEXT;
+    theme->a_focused_label->texture[0].data.text.justify = winjust;
+    theme->a_focused_label->texture[0].data.text.font=theme->win_font_focused;
+    theme->a_focused_label->texture[0].data.text.color
+            = theme->title_focused_color;
+
+    if (read_string(db, "window.active.label.text.font", &str)) {
+        char *p;
+        gint i = 0;
+        gint j;
+        if (strstr(str, "shadow=y")) {
+            if ((p = strstr(str, "shadowoffset=")))
+                i = parse_inline_number(p + strlen("shadowoffset="));
+            else
+                i = 1;
+            theme->a_focused_label->texture[0].data.text.shadow_offset_x = i;
+            theme->a_focused_label->texture[0].data.text.shadow_offset_y = i;
+        }
+        if ((p = strstr(str, "shadowtint="))) {
+            i = parse_inline_number(p + strlen("shadowtint="));
+            j = (i > 0 ? 0 : 255);
+            i = ABS(i*255/100);
+
+            theme->title_focused_shadow_color = RrColorNew(inst, j, j, j);
+            theme->title_focused_shadow_alpha = i;
+        }
+        else {
+            theme->title_focused_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->title_focused_shadow_alpha = 50;
+        }
+    }
+
+    theme->a_focused_label->texture[0].data.text.shadow_color
+            = theme->title_focused_shadow_color;
+    theme->a_focused_label->texture[0].data.text.shadow_alpha
+            = theme->title_focused_shadow_alpha;
+
+    theme->osd_hilite_label->texture[0].type = RR_TEXTURE_TEXT;
+    theme->osd_hilite_label->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
+    theme->osd_hilite_label->texture[0].data.text.font = theme->osd_font;
+    theme->osd_hilite_label->texture[0].data.text.color = theme->osd_color;
+
+    if (read_string(db, "osd.label.text.font", &str)) {
+        char *p;
+        gint i = 0;
+        gint j;
+        if (strstr(str, "shadow=y")) {
+            if ((p = strstr(str, "shadowoffset=")))
+                i = parse_inline_number(p + strlen("shadowoffset="));
+            else
+                i = 1;
+            theme->a_focused_label->texture[0].data.text.shadow_offset_x = i;
+            theme->a_focused_label->texture[0].data.text.shadow_offset_y = i;
+            theme->osd_hilite_label->texture[0].data.text.shadow_offset_x = i;
+            theme->osd_hilite_label->texture[0].data.text.shadow_offset_y = i;
+        }
+        if ((p = strstr(str, "shadowtint="))) {
+            i = parse_inline_number(p + strlen("shadowtint="));
+            j = (i > 0 ? 0 : 255);
+            i = ABS(i*255/100);
+
+            theme->title_focused_shadow_color = RrColorNew(inst, j, j, j);
+            theme->title_focused_shadow_alpha = i;
+            theme->osd_shadow_color = RrColorNew(inst, j, j, j);
+            theme->osd_shadow_alpha = i;
+        }
+        else {
+            theme->title_focused_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->title_focused_shadow_alpha = 50;
+            theme->osd_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->osd_shadow_alpha = 50;
+        }
+    }
+    else {
+        /* inherit the font settings from the focused label */
+        theme->osd_hilite_label->texture[0].data.text.shadow_offset_x
+                = theme->a_focused_label->texture[0].data.text.shadow_offset_x;
+        theme->osd_hilite_label->texture[0].data.text.shadow_offset_y
+                = theme->a_focused_label->texture[0].data.text.shadow_offset_y;
+        if (theme->title_focused_shadow_color)
+            theme->osd_shadow_color = RrColorNew(inst,
+                    theme->title_focused_shadow_color->r,
+                    theme->title_focused_shadow_color->g,
+                    theme->title_focused_shadow_color->b);
+        else
+            theme->osd_shadow_color = RrColorNew(inst, 0, 0, 0);
+        theme->osd_shadow_alpha = theme->title_focused_shadow_alpha;
+    }
+
+    theme->osd_hilite_label->texture[0].data.text.shadow_color
+            = theme->osd_shadow_color;
+    theme->osd_hilite_label->texture[0].data.text.shadow_alpha
+            = theme->osd_shadow_alpha;
+
+    theme->a_unfocused_label->texture[0].type = RR_TEXTURE_TEXT;
+    theme->a_unfocused_label->texture[0].data.text.justify = winjust;
+    theme->a_unfocused_label->texture[0].data.text.font
+            = theme->win_font_unfocused;
+    theme->a_unfocused_label->texture[0].data.text.color
+            = theme->title_unfocused_color;
+
+    if (read_string(db, "window.inactive.label.text.font", &str)) {
+        char *p;
+        gint i = 0;
+        gint j;
+        if (strstr(str, "shadow=y")) {
+            if ((p = strstr(str, "shadowoffset=")))
+                i = parse_inline_number(p + strlen("shadowoffset="));
+            else
+                i = 1;
+            theme->a_unfocused_label->texture[0].data.text.shadow_offset_x = i;
+            theme->a_unfocused_label->texture[0].data.text.shadow_offset_y = i;
+        }
+        if ((p = strstr(str, "shadowtint="))) {
+            i = parse_inline_number(p + strlen("shadowtint="));
+            j = (i > 0 ? 0 : 255);
+            i = ABS(i*255/100);
+
+            theme->title_unfocused_shadow_color = RrColorNew(inst, j, j, j);
+            theme->title_unfocused_shadow_alpha = i;
+        }
+        else {
+            theme->title_unfocused_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->title_unfocused_shadow_alpha = 50;
+        }
+    }
+
+    theme->a_unfocused_label->texture[0].data.text.shadow_color
+            = theme->title_unfocused_shadow_color;
+    theme->a_unfocused_label->texture[0].data.text.shadow_alpha
+            = theme->title_unfocused_shadow_alpha;
+
+    theme->a_menu_text_title->texture[0].type = RR_TEXTURE_TEXT;
+    theme->a_menu_text_title->texture[0].data.text.justify = mtitlejust;
+    theme->a_menu_text_title->texture[0].data.text.font
+            = theme->menu_title_font;
+    theme->a_menu_text_title->texture[0].data.text.color
+            = theme->menu_title_color;
+
+    if (read_string(db, "menu.title.text.font", &str)) {
+        char *p;
+        gint i = 0;
+        gint j;
+        if (strstr(str, "shadow=y")) {
+            if ((p = strstr(str, "shadowoffset=")))
+                i = parse_inline_number(p + strlen("shadowoffset="));
+            else
+                i = 1;
+            theme->a_menu_text_title->texture[0].data.text.shadow_offset_x = i;
+            theme->a_menu_text_title->texture[0].data.text.shadow_offset_y = i;
+        }
+        if ((p = strstr(str, "shadowtint="))) {
+            i = parse_inline_number(p + strlen("shadowtint="));
+            j = (i > 0 ? 0 : 255);
+            i = ABS(i*255/100);
+
+            theme->menu_title_shadow_color = RrColorNew(inst, j, j, j);
+            theme->menu_title_shadow_alpha = i;
+        }
+        else {
+            theme->menu_title_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->menu_title_shadow_alpha = 50;
+        }
+    }
+
+    theme->a_menu_text_title->texture[0].data.text.shadow_color
+            = theme->menu_title_shadow_color;
+    theme->a_menu_text_title->texture[0].data.text.shadow_alpha
+            = theme->menu_title_shadow_alpha;
+
+    theme->a_menu_text_normal->texture[0].type
+            = theme->a_menu_text_selected->texture[0].type
+                    = theme->a_menu_text_disabled->texture[0].type
+                            = theme->a_menu_text_disabled_selected->texture[0].type
+                                    = RR_TEXTURE_TEXT;
+    theme->a_menu_text_normal->texture[0].data.text.justify
+            = theme->a_menu_text_selected->texture[0].data.text.justify
+                    = theme->a_menu_text_disabled->texture[0].data.text.justify
+                            = theme->a_menu_text_disabled_selected->texture[0].data.text.justify
+                                    = RR_JUSTIFY_LEFT;
+    theme->a_menu_text_normal->texture[0].data.text.font
+            = theme->a_menu_text_selected->texture[0].data.text.font
+                    = theme->a_menu_text_disabled->texture[0].data.text.font
+                            = theme->a_menu_text_disabled_selected->texture[0].data.text.font
+                                    = theme->menu_font;
+    theme->a_menu_text_normal->texture[0].data.text.color = theme->menu_color;
+    theme->a_menu_text_selected->texture[0].data.text.color
+            = theme->menu_selected_color;
+    theme->a_menu_text_disabled->texture[0].data.text.color
+            = theme->menu_disabled_color;
+    theme->a_menu_text_disabled_selected->texture[0].data.text.color
+            = theme->menu_disabled_selected_color;
+
+    if (read_string(db, "menu.items.font", &str)) {
+        char *p;
+        gint i = 0;
+        gint j;
+        if (strstr(str, "shadow=y")) {
+            if ((p = strstr(str, "shadowoffset=")))
+                i = parse_inline_number(p + strlen("shadowoffset="));
+            else
+                i = 1;
+            theme->a_menu_text_normal->
+            texture[0].data.text.shadow_offset_x = i;
+            theme->a_menu_text_normal->
+            texture[0].data.text.shadow_offset_y = i;
+            theme->a_menu_text_selected->
+            texture[0].data.text.shadow_offset_x = i;
+            theme->a_menu_text_selected->
+            texture[0].data.text.shadow_offset_y = i;
+            theme->a_menu_text_disabled->
+            texture[0].data.text.shadow_offset_x = i;
+            theme->a_menu_text_disabled->
+            texture[0].data.text.shadow_offset_y = i;
+            theme->a_menu_text_disabled_selected->
+            texture[0].data.text.shadow_offset_x = i;
+            theme->a_menu_text_disabled_selected->
+            texture[0].data.text.shadow_offset_y = i;
+        }
+        if ((p = strstr(str, "shadowtint="))) {
+            i = parse_inline_number(p + strlen("shadowtint="));
+            j = (i > 0 ? 0 : 255);
+            i = ABS(i*255/100);
+
+            theme->menu_text_normal_shadow_color = RrColorNew(inst, j, j, j);
+            theme->menu_text_selected_shadow_color = RrColorNew(inst, j, j, j);
+            theme->menu_text_disabled_shadow_color = RrColorNew(inst, j, j, j);
+            theme->menu_text_normal_shadow_alpha = i;
+            theme->menu_text_selected_shadow_alpha = i;
+            theme->menu_text_disabled_shadow_alpha = i;
+            theme->menu_text_disabled_selected_shadow_alpha = i;
+        }
+        else {
+            theme->menu_text_normal_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->menu_text_selected_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->menu_text_disabled_shadow_color = RrColorNew(inst, 0, 0, 0);
+            theme->menu_text_normal_shadow_alpha = 50;
+            theme->menu_text_selected_shadow_alpha = 50;
+            theme->menu_text_disabled_selected_shadow_alpha = 50;
+        }
+    }
+
+    theme->a_menu_text_normal->texture[0].data.text.shadow_color
+            = theme->menu_text_normal_shadow_color;
+    theme->a_menu_text_normal->texture[0].data.text.shadow_alpha
+            = theme->menu_text_normal_shadow_alpha;
+    theme->a_menu_text_selected->texture[0].data.text.shadow_color
+            = theme->menu_text_selected_shadow_color;
+    theme->a_menu_text_selected->texture[0].data.text.shadow_alpha
+            = theme->menu_text_selected_shadow_alpha;
+    theme->a_menu_text_disabled->texture[0].data.text.shadow_color
+            = theme->menu_text_disabled_shadow_color;
+    theme->a_menu_text_disabled->texture[0].data.text.shadow_alpha
+            = theme->menu_text_disabled_shadow_alpha;
+    theme->a_menu_text_disabled_selected->texture[0].data.text.shadow_color
+            = theme->menu_text_disabled_shadow_color;
+    theme->a_menu_text_disabled_selected->texture[0].data.text.shadow_alpha
+            = theme->menu_text_disabled_shadow_alpha;
+
+    theme->a_disabled_focused_max->texture[0].type
+            = theme->a_disabled_unfocused_max->texture[0].type
+                    = theme->a_hover_focused_max->texture[0].type
+                            = theme->a_hover_unfocused_max->texture[0].type
+                                    = theme->a_toggled_hover_focused_max->texture[0].type
+                                            = theme->a_toggled_hover_unfocused_max->texture[0].type
+                                                    = theme->a_toggled_focused_unpressed_max->texture[0].type
+                                                            = theme->a_toggled_unfocused_unpressed_max->texture[0].type
+                                                                    = theme->a_toggled_focused_pressed_max->texture[0].type
+                                                                            = theme->a_toggled_unfocused_pressed_max->texture[0].type
+                                                                                    = theme->a_focused_unpressed_max->texture[0].type
+                                                                                            = theme->a_focused_pressed_max->texture[0].type
+                                                                                                    = theme->a_unfocused_unpressed_max->texture[0].type
+                                                                                                            = theme->a_unfocused_pressed_max->texture[0].type
+                                                                                                                    = theme->a_disabled_focused_close->texture[0].type
+                                                                                                                            = theme->a_disabled_unfocused_close->texture[0].type
+                                                                                                                                    = theme->a_hover_focused_close->texture[0].type
+                                                                                                                                            = theme->a_hover_unfocused_close->texture[0].type
+                                                                                                                                                    = theme->a_focused_unpressed_close->texture[0].type
+                                                                                                                                                            = theme->a_focused_pressed_close->texture[0].type
+                                                                                                                                                                    = theme->a_unfocused_unpressed_close->texture[0].type
+                                                                                                                                                                            = theme->a_unfocused_pressed_close->texture[0].type
+                                                                                                                                                                                    = theme->a_disabled_focused_desk->texture[0].type
+                                                                                                                                                                                            = theme->a_disabled_unfocused_desk->texture[0].type
+                                                                                                                                                                                                    = theme->a_hover_focused_desk->texture[0].type
+                                                                                                                                                                                                            = theme->a_hover_unfocused_desk->texture[0].type
+                                                                                                                                                                                                                    = theme->a_toggled_hover_focused_desk->texture[0].type
+                                                                                                                                                                                                                            = theme->a_toggled_hover_unfocused_desk->texture[0].type
+                                                                                                                                                                                                                                    = theme->a_toggled_focused_unpressed_desk->texture[0].type
+                                                                                                                                                                                                                                            = theme->a_toggled_unfocused_unpressed_desk->texture[0].type
+                                                                                                                                                                                                                                                    = theme->a_toggled_focused_pressed_desk->texture[0].type
+                                                                                                                                                                                                                                                            = theme->a_toggled_unfocused_pressed_desk->texture[0].type
+                                                                                                                                                                                                                                                                    = theme->a_focused_unpressed_desk->texture[0].type
+                                                                                                                                                                                                                                                                            = theme->a_focused_pressed_desk->texture[0].type
+                                                                                                                                                                                                                                                                                    = theme->a_unfocused_unpressed_desk->texture[0].type
+                                                                                                                                                                                                                                                                                            = theme->a_unfocused_pressed_desk->texture[0].type
+                                                                                                                                                                                                                                                                                                    = theme->a_disabled_focused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                            = theme->a_disabled_unfocused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                    = theme->a_hover_focused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                            = theme->a_hover_unfocused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                    = theme->a_toggled_hover_focused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                            = theme->a_toggled_hover_unfocused_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                    = theme->a_toggled_focused_unpressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                            = theme->a_toggled_unfocused_unpressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                    = theme->a_toggled_focused_pressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                            = theme->a_toggled_unfocused_pressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_focused_unpressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_focused_pressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_unfocused_unpressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_unfocused_pressed_shade->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_disabled_focused_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_disabled_unfocused_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_hover_focused_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_hover_unfocused_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_focused_unpressed_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_focused_pressed_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_unfocused_unpressed_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_unfocused_pressed_iconify->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    = theme->a_menu_bullet_normal->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            = theme->a_menu_bullet_selected->texture[0].type
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    = RR_TEXTURE_MASK;
+
+    theme->a_disabled_focused_max->texture[0].data.mask.mask
+            = theme->a_disabled_unfocused_max->texture[0].data.mask.mask
+                    = theme->max_disabled_mask;
+    theme->a_hover_focused_max->texture[0].data.mask.mask
+            = theme->a_hover_unfocused_max->texture[0].data.mask.mask
+                    = theme->max_hover_mask;
+    theme->a_focused_pressed_max->texture[0].data.mask.mask
+            = theme->a_unfocused_pressed_max->texture[0].data.mask.mask
+                    = theme->max_pressed_mask;
+    theme->a_focused_unpressed_max->texture[0].data.mask.mask
+            = theme->a_unfocused_unpressed_max->texture[0].data.mask.mask
+                    = theme->max_mask;
+    theme->a_toggled_hover_focused_max->texture[0].data.mask.mask
+            = theme->a_toggled_hover_unfocused_max->texture[0].data.mask.mask
+                    = theme->max_toggled_hover_mask;
+    theme->a_toggled_focused_unpressed_max->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_unpressed_max->texture[0].data.mask.mask
+                    = theme->max_toggled_mask;
+    theme->a_toggled_focused_pressed_max->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_pressed_max->texture[0].data.mask.mask
+                    = theme->max_toggled_pressed_mask;
+    theme->a_disabled_focused_close->texture[0].data.mask.mask
+            = theme->a_disabled_unfocused_close->texture[0].data.mask.mask
+                    = theme->close_disabled_mask;
+    theme->a_hover_focused_close->texture[0].data.mask.mask
+            = theme->a_hover_unfocused_close->texture[0].data.mask.mask
+                    = theme->close_hover_mask;
+    theme->a_focused_pressed_close->texture[0].data.mask.mask
+            = theme->a_unfocused_pressed_close->texture[0].data.mask.mask
+                    = theme->close_pressed_mask;
+    theme->a_focused_unpressed_close->texture[0].data.mask.mask
+            = theme->a_unfocused_unpressed_close->texture[0].data.mask.mask
+                    = theme->close_mask;
+    theme->a_disabled_focused_desk->texture[0].data.mask.mask
+            = theme->a_disabled_unfocused_desk->texture[0].data.mask.mask
+                    = theme->desk_disabled_mask;
+    theme->a_hover_focused_desk->texture[0].data.mask.mask
+            = theme->a_hover_unfocused_desk->texture[0].data.mask.mask
+                    = theme->desk_hover_mask;
+    theme->a_focused_pressed_desk->texture[0].data.mask.mask
+            = theme->a_unfocused_pressed_desk->texture[0].data.mask.mask
+                    = theme->desk_pressed_mask;
+    theme->a_focused_unpressed_desk->texture[0].data.mask.mask
+            = theme->a_unfocused_unpressed_desk->texture[0].data.mask.mask
+                    = theme->desk_mask;
+    theme->a_toggled_hover_focused_desk->texture[0].data.mask.mask
+            = theme->a_toggled_hover_unfocused_desk->texture[0].data.mask.mask
+                    = theme->desk_toggled_hover_mask;
+    theme->a_toggled_focused_unpressed_desk->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_unpressed_desk->texture[0].data.mask.mask
+                    = theme->desk_toggled_mask;
+    theme->a_toggled_focused_pressed_desk->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_pressed_desk->texture[0].data.mask.mask
+                    = theme->desk_toggled_pressed_mask;
+    theme->a_disabled_focused_shade->texture[0].data.mask.mask
+            = theme->a_disabled_unfocused_shade->texture[0].data.mask.mask
+                    = theme->shade_disabled_mask;
+    theme->a_hover_focused_shade->texture[0].data.mask.mask
+            = theme->a_hover_unfocused_shade->texture[0].data.mask.mask
+                    = theme->shade_hover_mask;
+    theme->a_focused_pressed_shade->texture[0].data.mask.mask
+            = theme->a_unfocused_pressed_shade->texture[0].data.mask.mask
+                    = theme->shade_pressed_mask;
+    theme->a_focused_unpressed_shade->texture[0].data.mask.mask
+            = theme->a_unfocused_unpressed_shade->texture[0].data.mask.mask
+                    = theme->shade_mask;
+    theme->a_toggled_hover_focused_shade->texture[0].data.mask.mask
+            = theme->a_toggled_hover_unfocused_shade->texture[0].data.mask.mask
+                    = theme->shade_toggled_hover_mask;
+    theme->a_toggled_focused_unpressed_shade->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_unpressed_shade->texture[0].data.mask.mask
+                    = theme->shade_toggled_mask;
+    theme->a_toggled_focused_pressed_shade->texture[0].data.mask.mask
+            = theme->a_toggled_unfocused_pressed_shade->texture[0].data.mask.mask
+                    = theme->shade_toggled_pressed_mask;
+    theme->a_disabled_focused_iconify->texture[0].data.mask.mask
+            = theme->a_disabled_unfocused_iconify->texture[0].data.mask.mask
+                    = theme->iconify_disabled_mask;
+    theme->a_hover_focused_iconify->texture[0].data.mask.mask
+            = theme->a_hover_unfocused_iconify->texture[0].data.mask.mask
+                    = theme->iconify_hover_mask;
+    theme->a_focused_pressed_iconify->texture[0].data.mask.mask
+            = theme->a_unfocused_pressed_iconify->texture[0].data.mask.mask
+                    = theme->iconify_pressed_mask;
+    theme->a_focused_unpressed_iconify->texture[0].data.mask.mask
+            = theme->a_unfocused_unpressed_iconify->texture[0].data.mask.mask
+                    = theme->iconify_mask;
+    theme->a_menu_bullet_normal->texture[0].data.mask.mask
+            = theme->a_menu_bullet_selected->texture[0].data.mask.mask
+                    = theme->menu_bullet_mask;
+    theme->a_disabled_focused_max->texture[0].data.mask.color
+            = theme->a_disabled_focused_close->texture[0].data.mask.color
+                    = theme->a_disabled_focused_desk->texture[0].data.mask.color
+                            = theme->a_disabled_focused_shade->texture[0].data.mask.color
+                                    = theme->a_disabled_focused_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_disabled_focused_color;
+    theme->a_disabled_unfocused_max->texture[0].data.mask.color
+            = theme->a_disabled_unfocused_close->texture[0].data.mask.color
+                    = theme->a_disabled_unfocused_desk->texture[0].data.mask.color
+                            = theme->a_disabled_unfocused_shade->texture[0].data.mask.color
+                                    = theme->a_disabled_unfocused_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_disabled_unfocused_color;
+    theme->a_hover_focused_max->texture[0].data.mask.color
+            = theme->a_hover_focused_close->texture[0].data.mask.color
+                    = theme->a_hover_focused_desk->texture[0].data.mask.color
+                            = theme->a_hover_focused_shade->texture[0].data.mask.color
+                                    = theme->a_hover_focused_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_hover_focused_color;
+    theme->a_hover_unfocused_max->texture[0].data.mask.color
+            = theme->a_hover_unfocused_close->texture[0].data.mask.color
+                    = theme->a_hover_unfocused_desk->texture[0].data.mask.color
+                            = theme->a_hover_unfocused_shade->texture[0].data.mask.color
+                                    = theme->a_hover_unfocused_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_hover_unfocused_color;
+    theme->a_toggled_hover_focused_max->texture[0].data.mask.color
+            = theme->a_toggled_hover_focused_desk->texture[0].data.mask.color
+                    = theme->a_toggled_hover_focused_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_hover_focused_color;
+    theme->a_toggled_hover_unfocused_max->texture[0].data.mask.color
+            = theme->a_toggled_hover_unfocused_desk->texture[0].data.mask.color
+                    = theme->a_toggled_hover_unfocused_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_hover_unfocused_color;
+    theme->a_toggled_focused_unpressed_max->texture[0].data.mask.color
+            = theme->a_toggled_focused_unpressed_desk->texture[0].data.mask.color
+                    = theme->a_toggled_focused_unpressed_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_focused_unpressed_color;
+    theme->a_toggled_unfocused_unpressed_max->texture[0].data.mask.color
+            = theme->a_toggled_unfocused_unpressed_desk->texture[0].data.mask.color
+                    = theme->a_toggled_unfocused_unpressed_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_unfocused_unpressed_color;
+    theme->a_toggled_focused_pressed_max->texture[0].data.mask.color
+            = theme->a_toggled_focused_pressed_desk->texture[0].data.mask.color
+                    = theme->a_toggled_focused_pressed_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_focused_pressed_color;
+    theme->a_toggled_unfocused_pressed_max->texture[0].data.mask.color
+            = theme->a_toggled_unfocused_pressed_desk->texture[0].data.mask.color
+                    = theme->a_toggled_unfocused_pressed_shade->texture[0].data.mask.color
+                            = theme->titlebut_toggled_unfocused_pressed_color;
+    theme->a_focused_unpressed_max->texture[0].data.mask.color
+            = theme->a_focused_unpressed_close->texture[0].data.mask.color
+                    = theme->a_focused_unpressed_desk->texture[0].data.mask.color
+                            = theme->a_focused_unpressed_shade->texture[0].data.mask.color
+                                    = theme->a_focused_unpressed_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_focused_unpressed_color;
+    theme->a_focused_pressed_max->texture[0].data.mask.color
+            = theme->a_focused_pressed_close->texture[0].data.mask.color
+                    = theme->a_focused_pressed_desk->texture[0].data.mask.color
+                            = theme->a_focused_pressed_shade->texture[0].data.mask.color
+                                    = theme->a_focused_pressed_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_focused_pressed_color;
+    theme->a_unfocused_unpressed_max->texture[0].data.mask.color
+            = theme->a_unfocused_unpressed_close->texture[0].data.mask.color
+                    = theme->a_unfocused_unpressed_desk->texture[0].data.mask.color
+                            = theme->a_unfocused_unpressed_shade->texture[0].data.mask.color
+                                    = theme->a_unfocused_unpressed_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_unfocused_unpressed_color;
+    theme->a_unfocused_pressed_max->texture[0].data.mask.color
+            = theme->a_unfocused_pressed_close->texture[0].data.mask.color
+                    = theme->a_unfocused_pressed_desk->texture[0].data.mask.color
+                            = theme->a_unfocused_pressed_shade->texture[0].data.mask.color
+                                    = theme->a_unfocused_pressed_iconify->texture[0].data.mask.color
+                                            = theme->titlebut_unfocused_pressed_color;
+    theme->a_menu_bullet_normal->texture[0].data.mask.color = theme->menu_color;
+    theme->a_menu_bullet_selected->texture[0].data.mask.color
+            = theme->menu_selected_color;
+
+    /* set the font heights */
+    theme->win_font_height = RrFontHeight(theme->win_font_focused,
+            theme->a_focused_label->texture[0].data.text.shadow_offset_y);
+    theme->win_font_height = MAX(theme->win_font_height, RrFontHeight(
+            theme->win_font_focused,
+            theme->a_unfocused_label->texture[0].data.text.shadow_offset_y));
+    theme->menu_title_font_height = RrFontHeight(theme->menu_title_font,
+            theme->a_menu_text_title->texture[0].data.text.shadow_offset_y);
+    theme->menu_font_height = RrFontHeight(theme->menu_font,
+            theme->a_menu_text_normal->texture[0].data.text.shadow_offset_y);
+
+    /* calculate some last extents */
+    {
+        gint ft, fb, fl, fr, ut, ub, ul, ur;
+
+        RrMargins(theme->a_focused_label, &fl, &ft, &fr, &fb);
+        RrMargins(theme->a_unfocused_label, &ul, &ut, &ur, &ub);
+        theme->label_height = theme->win_font_height + MAX(ft + fb, ut + ub);
+        theme->label_height += theme->label_height % 2;
+
+        /* this would be nice I think, since padding.width can now be 0,
+         but it breaks frame.c horribly and I don't feel like fixing that
+         right now, so if anyone complains, here is how to keep text from
+         going over the title's bevel/border with a padding.width of 0 and a
+         bevelless/borderless label
+         RrMargins(theme->a_focused_title, &fl, &ft, &fr, &fb);
+         RrMargins(theme->a_unfocused_title, &ul, &ut, &ur, &ub);
+         theme->title_height = theme->label_height +
+         MAX(MAX(theme->padding * 2, ft + fb),
+         MAX(theme->padding * 2, ut + ub));
+         */
+        theme->title_height = theme->label_height + theme->paddingy * 2;
+
+        RrMargins(theme->a_menu_title, &ul, &ut, &ur, &ub);
+        theme->menu_title_label_height = theme->menu_title_font_height+ut+ub;
+        theme->menu_title_height = theme->menu_title_label_height
+                + theme->paddingy * 2;
+    }
+    theme->button_size = theme->label_height - 2;
+    theme->grip_width = 25;
+
+    return 1;
+}
+
+static XrmDatabase loaddb(const gchar *name, gchar **path)
+{
+    GSList *it;
+    XrmDatabase db = NULL;
+    gchar *s;
+
+    if (name[0] == '/') {
+        s = g_build_filename(name, "openbox-3", "themerc", NULL);
+        if ((db = XrmGetFileDatabase(s)))
+            *path = g_path_get_dirname(s);
+        g_free(s);
+    }
+    else {
+        /* XXX backwards compatibility, remove me sometime later */
+        s = g_build_filename(g_get_home_dir(), ".themes", name, "openbox-3",
+                "themerc", NULL);
+        if ((db = XrmGetFileDatabase(s)))
+            *path = g_path_get_dirname(s);
+        g_free(s);
+
+        for (it = parse_xdg_data_dir_paths(); !db && it; it = g_slist_next(it)) {
+            s = g_build_filename(it->data, "themes", name, "openbox-3",
+                    "themerc", NULL);
+            if ((db = XrmGetFileDatabase(s)))
+                *path = g_path_get_dirname(s);
+            g_free(s);
+        }
+    }
+
+    if (db == NULL) {
+        s = g_build_filename(name, "themerc", NULL);
+        if ((db = XrmGetFileDatabase(s)))
+            *path = g_path_get_dirname(s);
+        g_free(s);
+    }
+
+    return db;
+}
+
+static gchar *create_class_name(const gchar *rname)
+{
+    gchar *rclass = g_strdup(rname);
+    gchar *p = rclass;
+
+    while (TRUE) {
+        *p = toupper(*p);
+        p = strchr(p+1, '.');
+        if (p == NULL)
+            break;
+        ++p;
+        if (*p == '\0')
+            break;
+    }
+    return rclass;
+}
+
+static gboolean read_int(XrmDatabase db, const gchar *rname, gint *value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype, *end;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        *value = (gint)strtol(retvalue.addr, &end, 10);
+        if (end != retvalue.addr)
+            ret = TRUE;
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        *value = retvalue.addr;
+        ret = TRUE;
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_color(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrColor **value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        RrColor *c = RrColorParse(inst, retvalue.addr);
+        if (c != NULL) {
+            *value = c;
+            ret = TRUE;
+        }
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+static gboolean read_mask(const RrInstance *inst, const gchar *path,
+        ObFrameThemeConfig *theme, const gchar *maskname, RrPixmapMask **value)
+{
+    gboolean ret = FALSE;
+    gchar *s;
+    gint hx, hy; /* ignored */
+    guint w, h;
+    guchar *b;
+
+    s = g_build_filename(path, maskname, NULL);
+    if (XReadBitmapFileData(s, &w, &h, &b, &hx, &hy) == BitmapSuccess) {
+        ret = TRUE;
+        *value = RrPixmapMaskNew(inst, w, h, (gchar*)b);
+        XFree(b);
+    }
+    g_free(s);
+
+    return ret;
+}
+
+static void parse_appearance(gchar *tex, RrSurfaceColorType *grad,
+        RrReliefType *relief, RrBevelType *bevel, gboolean *interlaced,
+        gboolean *border, gboolean allow_trans)
+{
+    gchar *t;
+
+    /* convert to all lowercase */
+    for (t = tex; *t != '\0'; ++t)
+        *t = g_ascii_tolower(*t);
+
+    if (allow_trans && strstr(tex, "parentrelative") != NULL) {
+        *grad = RR_SURFACE_PARENTREL;
+    }
+    else {
+        if (strstr(tex, "gradient") != NULL) {
+            if (strstr(tex, "crossdiagonal") != NULL)
+                *grad = RR_SURFACE_CROSS_DIAGONAL;
+            else if (strstr(tex, "pyramid") != NULL)
+                *grad = RR_SURFACE_PYRAMID;
+            else if (strstr(tex, "mirrorhorizontal") != NULL)
+                *grad = RR_SURFACE_MIRROR_HORIZONTAL;
+            else if (strstr(tex, "horizontal") != NULL)
+                *grad = RR_SURFACE_HORIZONTAL;
+            else if (strstr(tex, "splitvertical") != NULL)
+                *grad = RR_SURFACE_SPLIT_VERTICAL;
+            else if (strstr(tex, "vertical") != NULL)
+                *grad = RR_SURFACE_VERTICAL;
+            else
+                *grad = RR_SURFACE_DIAGONAL;
+        }
+        else {
+            *grad = RR_SURFACE_SOLID;
+        }
+    }
+
+    if (strstr(tex, "sunken") != NULL)
+        *relief = RR_RELIEF_SUNKEN;
+    else if (strstr(tex, "flat") != NULL)
+        *relief = RR_RELIEF_FLAT;
+    else if (strstr(tex, "raised") != NULL)
+        *relief = RR_RELIEF_RAISED;
+    else
+        *relief = (*grad == RR_SURFACE_PARENTREL) ? RR_RELIEF_FLAT
+                : RR_RELIEF_RAISED;
+
+    *border = FALSE;
+    if (*relief == RR_RELIEF_FLAT) {
+        if (strstr(tex, "border") != NULL)
+            *border = TRUE;
+    }
+    else {
+        if (strstr(tex, "bevel2") != NULL)
+            *bevel = RR_BEVEL_2;
+        else
+            *bevel = RR_BEVEL_1;
+    }
+
+    if (strstr(tex, "interlaced") != NULL)
+        *interlaced = TRUE;
+    else
+        *interlaced = FALSE;
+}
+
+static gboolean read_appearance(XrmDatabase db, const RrInstance *inst,
+        const gchar *rname, RrAppearance *value, gboolean allow_trans)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *cname, *ctoname, *bcname, *icname, *hname, *sname;
+    gchar *csplitname, *ctosplitname;
+    gchar *rettype;
+    XrmValue retvalue;
+    gint i;
+
+    cname = g_strconcat(rname, ".color", NULL);
+    ctoname = g_strconcat(rname, ".colorTo", NULL);
+    bcname = g_strconcat(rname, ".border.color", NULL);
+    icname = g_strconcat(rname, ".interlace.color", NULL);
+    hname = g_strconcat(rname, ".highlight", NULL);
+    sname = g_strconcat(rname, ".shadow", NULL);
+    csplitname = g_strconcat(rname, ".color.splitTo", NULL);
+    ctosplitname = g_strconcat(rname, ".colorTo.splitTo", NULL);
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        parse_appearance(retvalue.addr, &value->surface.grad,
+                &value->surface.relief, &value->surface.bevel,
+                &value->surface.interlaced, &value->surface.border, allow_trans);
+        if (!read_color(db, inst, cname, &value->surface.primary))
+            value->surface.primary = RrColorNew(inst, 0, 0, 0);
+        if (!read_color(db, inst, ctoname, &value->surface.secondary))
+            value->surface.secondary = RrColorNew(inst, 0, 0, 0);
+        if (value->surface.border)
+            if (!read_color(db, inst, bcname, &value->surface.border_color))
+                value->surface.border_color = RrColorNew(inst, 0, 0, 0);
+        if (value->surface.interlaced)
+            if (!read_color(db, inst, icname, &value->surface.interlace_color))
+                value->surface.interlace_color = RrColorNew(inst, 0, 0, 0);
+        if (read_int(db, hname, &i) && i >= 0)
+            value->surface.bevel_light_adjust = i;
+        if (read_int(db, sname, &i) && i >= 0 && i <= 256)
+            value->surface.bevel_dark_adjust = i;
+
+        if (value->surface.grad == RR_SURFACE_SPLIT_VERTICAL) {
+            gint r, g, b;
+
+            if (!read_color(db, inst, csplitname, &value->surface.split_primary)) {
+                r = value->surface.primary->r;
+                r += r >> 2;
+                g = value->surface.primary->g;
+                g += g >> 2;
+                b = value->surface.primary->b;
+                b += b >> 2;
+                if (r > 0xFF)
+                    r = 0xFF;
+                if (g > 0xFF)
+                    g = 0xFF;
+                if (b > 0xFF)
+                    b = 0xFF;
+                value->surface.split_primary = RrColorNew(inst, r, g, b);
+            }
+
+            if (!read_color(db, inst, ctosplitname,
+                    &value->surface.split_secondary)) {
+                r = value->surface.secondary->r;
+                r += r >> 4;
+                g = value->surface.secondary->g;
+                g += g >> 4;
+                b = value->surface.secondary->b;
+                b += b >> 4;
+                if (r > 0xFF)
+                    r = 0xFF;
+                if (g > 0xFF)
+                    g = 0xFF;
+                if (b > 0xFF)
+                    b = 0xFF;
+                value->surface.split_secondary = RrColorNew(inst, r, g, b);
+            }
+        }
+
+        ret = TRUE;
+    }
+
+    g_free(ctosplitname);
+    g_free(csplitname);
+    g_free(sname);
+    g_free(hname);
+    g_free(icname);
+    g_free(bcname);
+    g_free(ctoname);
+    g_free(cname);
+    g_free(rclass);
+    return ret;
+}
+
+static int parse_inline_number(const char *p)
+{
+    int neg = 1;
+    int res = 0;
+    if (*p == '-') {
+        neg = -1;
+        ++p;
+    }
+    for (; isdigit(*p); ++p)
+        res = res * 10 + *p - '0';
+    res *= neg;
+    return res;
+}
+
+static void set_default_appearance(RrAppearance *a)
+{
+    a->surface.grad = RR_SURFACE_SOLID;
+    a->surface.relief = RR_RELIEF_FLAT;
+    a->surface.bevel = RR_BEVEL_1;
+    a->surface.interlaced = FALSE;
+    a->surface.border = FALSE;
+    a->surface.primary = RrColorNew(a->inst, 0, 0, 0);
+    a->surface.secondary = RrColorNew(a->inst, 0, 0, 0);
+}
+
+/* Reads the output from gimp's C-Source file format into valid RGBA data for
+ an RrTextureRGBA. */
+static RrPixel32* read_c_image(gint width, gint height, const guint8 *data)
+{
+    RrPixel32 *im, *p;
+    gint i;
+
+    p = im = g_memdup(data, width * height * sizeof(RrPixel32));
+
+    for (i = 0; i < width * height; ++i) {
+        guchar a = ((*p >> 24) & 0xff);
+        guchar b = ((*p >> 16) & 0xff);
+        guchar g = ((*p >> 8) & 0xff);
+        guchar r = ((*p >> 0) & 0xff);
+
+        *p = ((r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset) + (b
+                << RrDefaultBlueOffset) + (a << RrDefaultAlphaOffset));
+        p++;
+    }
+
+    return im;
+}
diff --git a/engines/minimal/frame_minimal_config.h b/engines/minimal/frame_minimal_config.h
new file mode 100644 (file)
index 0000000..8e832bd
--- /dev/null
@@ -0,0 +1,251 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_minimal_config.h for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+#ifndef FRAME_MINIMAL_CONFIG_H_
+#define FRAME_MINIMAL_CONFIG_H_
+
+#include <X11/Xresource.h>
+#include "render/render.h"
+
+G_BEGIN_DECLS
+
+/* This store frame layout configuration. */
+struct _ObFrameThemeConfig
+{
+    const RrInstance *inst;
+
+    /* style settings - fonts */
+    RrFont *win_font_focused;
+    RrFont *win_font_unfocused;
+    RrFont *menu_title_font;
+    RrFont *menu_font;
+    RrFont *osd_font;
+
+    /* style settings - geometry */
+    gint paddingx;
+    gint paddingy;
+    gint handle_height;
+    gint fbwidth; /*!< frame border width */
+    gint mbwidth; /*!< menu border width */
+    gint obwidth; /*!< osd border width */
+    gint cbwidthx;
+    gint cbwidthy;
+    gint menu_overlap;
+    /* these ones are calculated, not set directly by the theme file */
+    gint win_font_height;
+    gint menu_title_font_height;
+    gint menu_font_height;
+    gint label_height;
+    gint title_height;
+    gint button_size;
+    gint grip_width;
+    gint menu_title_label_height;
+    gint menu_title_height;
+
+    /* style settings - colors */
+    RrColor *menu_border_color;
+    RrColor *osd_border_color;
+    RrColor *frame_focused_border_color;
+    RrColor *frame_unfocused_border_color;
+    RrColor *title_separator_focused_color;
+    RrColor *title_separator_unfocused_color;
+    RrColor *cb_focused_color;
+    RrColor *cb_unfocused_color;
+    RrColor *title_focused_color;
+    RrColor *title_unfocused_color;
+    RrColor *titlebut_disabled_focused_color;
+    RrColor *titlebut_disabled_unfocused_color;
+    RrColor *titlebut_hover_focused_color;
+    RrColor *titlebut_hover_unfocused_color;
+    RrColor *titlebut_toggled_hover_focused_color;
+    RrColor *titlebut_toggled_hover_unfocused_color;
+    RrColor *titlebut_toggled_focused_pressed_color;
+    RrColor *titlebut_toggled_unfocused_pressed_color;
+    RrColor *titlebut_toggled_focused_unpressed_color;
+    RrColor *titlebut_toggled_unfocused_unpressed_color;
+    RrColor *titlebut_focused_pressed_color;
+    RrColor *titlebut_unfocused_pressed_color;
+    RrColor *titlebut_focused_unpressed_color;
+    RrColor *titlebut_unfocused_unpressed_color;
+    RrColor *menu_title_color;
+    RrColor *menu_color;
+    RrColor *menu_selected_color;
+    RrColor *menu_disabled_color;
+    RrColor *menu_disabled_selected_color;
+    RrColor *title_focused_shadow_color;
+    gchar title_focused_shadow_alpha;
+    RrColor *title_unfocused_shadow_color;
+    gchar title_unfocused_shadow_alpha;
+    RrColor *osd_color;
+    RrColor *osd_shadow_color;
+    gchar osd_shadow_alpha;
+    RrColor *menu_title_shadow_color;
+    gchar menu_title_shadow_alpha;
+    RrColor *menu_text_normal_shadow_color;
+    gchar menu_text_normal_shadow_alpha;
+    RrColor *menu_text_selected_shadow_color;
+    gchar menu_text_selected_shadow_alpha;
+    RrColor *menu_text_disabled_shadow_color;
+    gchar menu_text_disabled_shadow_alpha;
+    RrColor *menu_text_disabled_selected_shadow_color;
+    gchar menu_text_disabled_selected_shadow_alpha;
+
+    /* style settings - pics */
+    RrPixel32 *def_win_icon; /* 48x48 RGBA */
+
+    /* style settings - masks */
+    RrPixmapMask *max_mask;
+    RrPixmapMask *max_hover_mask;
+    RrPixmapMask *max_pressed_mask;
+    RrPixmapMask *max_toggled_mask;
+    RrPixmapMask *max_toggled_hover_mask;
+    RrPixmapMask *max_toggled_pressed_mask;
+    RrPixmapMask *max_disabled_mask;
+    RrPixmapMask *iconify_mask;
+    RrPixmapMask *iconify_hover_mask;
+    RrPixmapMask *iconify_pressed_mask;
+    RrPixmapMask *iconify_disabled_mask;
+    RrPixmapMask *desk_mask;
+    RrPixmapMask *desk_hover_mask;
+    RrPixmapMask *desk_pressed_mask;
+    RrPixmapMask *desk_toggled_mask;
+    RrPixmapMask *desk_toggled_hover_mask;
+    RrPixmapMask *desk_toggled_pressed_mask;
+    RrPixmapMask *desk_disabled_mask;
+    RrPixmapMask *shade_mask;
+    RrPixmapMask *shade_hover_mask;
+    RrPixmapMask *shade_pressed_mask;
+    RrPixmapMask *shade_toggled_mask;
+    RrPixmapMask *shade_toggled_hover_mask;
+    RrPixmapMask *shade_toggled_pressed_mask;
+    RrPixmapMask *shade_disabled_mask;
+    RrPixmapMask *close_mask;
+    RrPixmapMask *close_hover_mask;
+    RrPixmapMask *close_disabled_mask;
+    RrPixmapMask *close_pressed_mask;
+
+    RrPixmapMask *menu_bullet_mask; /* submenu pointer */
+#if 0
+    RrPixmapMask *menu_toggle_mask; /* menu boolean */
+#endif
+
+    /* global appearances */
+    RrAppearance *a_disabled_focused_max;
+    RrAppearance *a_disabled_unfocused_max;
+    RrAppearance *a_hover_focused_max;
+    RrAppearance *a_hover_unfocused_max;
+    RrAppearance *a_focused_unpressed_max;
+    RrAppearance *a_focused_pressed_max;
+    RrAppearance *a_unfocused_unpressed_max;
+    RrAppearance *a_unfocused_pressed_max;
+    RrAppearance *a_toggled_hover_focused_max;
+    RrAppearance *a_toggled_hover_unfocused_max;
+    RrAppearance *a_toggled_focused_unpressed_max;
+    RrAppearance *a_toggled_focused_pressed_max;
+    RrAppearance *a_toggled_unfocused_unpressed_max;
+    RrAppearance *a_toggled_unfocused_pressed_max;
+    RrAppearance *a_disabled_focused_close;
+    RrAppearance *a_disabled_unfocused_close;
+    RrAppearance *a_hover_focused_close;
+    RrAppearance *a_hover_unfocused_close;
+    RrAppearance *a_focused_unpressed_close;
+    RrAppearance *a_focused_pressed_close;
+    RrAppearance *a_unfocused_unpressed_close;
+    RrAppearance *a_unfocused_pressed_close;
+    RrAppearance *a_disabled_focused_desk;
+    RrAppearance *a_disabled_unfocused_desk;
+    RrAppearance *a_hover_focused_desk;
+    RrAppearance *a_hover_unfocused_desk;
+    RrAppearance *a_focused_unpressed_desk;
+    RrAppearance *a_focused_pressed_desk;
+    RrAppearance *a_unfocused_unpressed_desk;
+    RrAppearance *a_unfocused_pressed_desk;
+    RrAppearance *a_toggled_hover_focused_desk;
+    RrAppearance *a_toggled_hover_unfocused_desk;
+    RrAppearance *a_toggled_focused_unpressed_desk;
+    RrAppearance *a_toggled_focused_pressed_desk;
+    RrAppearance *a_toggled_unfocused_unpressed_desk;
+    RrAppearance *a_toggled_unfocused_pressed_desk;
+    RrAppearance *a_disabled_focused_shade;
+    RrAppearance *a_disabled_unfocused_shade;
+    RrAppearance *a_hover_focused_shade;
+    RrAppearance *a_hover_unfocused_shade;
+    RrAppearance *a_focused_unpressed_shade;
+    RrAppearance *a_focused_pressed_shade;
+    RrAppearance *a_unfocused_unpressed_shade;
+    RrAppearance *a_unfocused_pressed_shade;
+    RrAppearance *a_toggled_hover_focused_shade;
+    RrAppearance *a_toggled_hover_unfocused_shade;
+    RrAppearance *a_toggled_focused_unpressed_shade;
+    RrAppearance *a_toggled_focused_pressed_shade;
+    RrAppearance *a_toggled_unfocused_unpressed_shade;
+    RrAppearance *a_toggled_unfocused_pressed_shade;
+    RrAppearance *a_disabled_focused_iconify;
+    RrAppearance *a_disabled_unfocused_iconify;
+    RrAppearance *a_hover_focused_iconify;
+    RrAppearance *a_hover_unfocused_iconify;
+    RrAppearance *a_focused_unpressed_iconify;
+    RrAppearance *a_focused_pressed_iconify;
+    RrAppearance *a_unfocused_unpressed_iconify;
+    RrAppearance *a_unfocused_pressed_iconify;
+    RrAppearance *a_focused_grip;
+    RrAppearance *a_unfocused_grip;
+    RrAppearance *a_focused_title;
+    RrAppearance *a_unfocused_title;
+    RrAppearance *a_focused_label;
+    RrAppearance *a_unfocused_label;
+    /* always parentrelative, so no focused/unfocused */
+    RrAppearance *a_icon;
+    RrAppearance *a_focused_handle;
+    RrAppearance *a_unfocused_handle;
+    RrAppearance *a_menu_text_title;
+    RrAppearance *a_menu_title;
+    RrAppearance *a_menu;
+    RrAppearance *a_menu_normal;
+    RrAppearance *a_menu_selected;
+    RrAppearance *a_menu_disabled;
+    RrAppearance *a_menu_disabled_selected;
+    RrAppearance *a_menu_text_normal;
+    RrAppearance *a_menu_text_disabled;
+    RrAppearance *a_menu_text_disabled_selected;
+    RrAppearance *a_menu_text_selected;
+    RrAppearance *a_menu_bullet_normal;
+    RrAppearance *a_menu_bullet_selected;
+    RrAppearance *a_clear; /* clear with no texture */
+    RrAppearance *a_clear_tex; /* clear with a texture */
+
+    RrAppearance *osd_hilite_bg; /* can never be parent relative */
+    RrAppearance *osd_hilite_fg; /* can never be parent relative */
+    RrAppearance *osd_hilite_label; /* can be parent relative */
+    RrAppearance *osd_unhilite_fg; /* can never be parent relative */
+
+    gchar *name;
+};
+
+typedef struct _ObFrameThemeConfig ObFrameThemeConfig;
+
+/*! The font values are all optional. If a NULL is used for any of them, then
+ the default font will be used. */
+gint load_theme_config(const RrInstance *inst, const gchar *name,
+        const gchar * path, XrmDatabase db, RrFont *active_window_font,
+        RrFont *inactive_window_font, RrFont *menu_title_font,
+        RrFont *menu_item_font, RrFont *osd_font);
+
+G_END_DECLS
+
+#endif /*FRAME_MINIMAL_CONFIG_H_*/
diff --git a/engines/minimal/frame_minimal_plugin.c b/engines/minimal/frame_minimal_plugin.c
new file mode 100644 (file)
index 0000000..862e4fd
--- /dev/null
@@ -0,0 +1,1895 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_minimal_plugin.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#include "frame_minimal_plugin.h"
+#include "frame_minimal_render.h"
+
+#include "openbox/frame.h"
+#include "openbox/client.h"
+#include "openbox/openbox.h"
+#include "openbox/extensions.h"
+#include "openbox/prop.h"
+#include "openbox/grab.h"
+#include "openbox/config.h"
+#include "openbox/mainloop.h"
+#include "openbox/focus_cycle.h"
+#include "openbox/focus_cycle_indicator.h"
+#include "openbox/moveresize.h"
+#include "openbox/screen.h"
+#include "render/theme.h"
+
+typedef enum
+{
+    OB_FLAG_MAX = 1 << 0,
+    OB_FLAG_CLOSE = 1 << 1,
+    OB_FLAG_DESK = 1 << 2,
+    OB_FLAG_SHADE = 1 << 3,
+    OB_FLAG_ICONIFY = 1 << 4
+} ObFrameFlags;
+
+#define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
+                         ButtonPressMask | ButtonReleaseMask | \
+                         SubstructureRedirectMask | FocusChangeMask)
+#define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
+                           ButtonMotionMask | PointerMotionMask | \
+                           EnterWindowMask | LeaveWindowMask)
+
+#define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
+#define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
+
+#define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_b)
+
+Window createWindow(Window parent, Visual *visual, gulong mask,
+        XSetWindowAttributes *attrib)
+{
+    return XCreateWindow(plugin.ob_display, parent, 0, 0, 1, 1, 0, (visual ? 32
+            : RrDepth(plugin.ob_rr_inst)), InputOutput, (visual ? visual
+            : RrVisual(plugin.ob_rr_inst)), mask, attrib);
+
+}
+
+Visual *check_32bit_client(ObClient *c)
+{
+    XWindowAttributes wattrib;
+    Status ret;
+
+    /* we're already running at 32 bit depth, yay. we don't need to use their
+     visual */
+    if (RrDepth(plugin.ob_rr_inst) == 32)
+        return NULL;
+
+    ret = XGetWindowAttributes(plugin.ob_display, c->window, &wattrib);
+    g_assert(ret != BadDrawable);
+    g_assert(ret != BadWindow);
+
+    if (wattrib.depth == 32)
+        return wattrib.visual;
+    return NULL;
+}
+
+/* Not used */
+gint init(Display * display, gint screen)
+{
+    plugin.ob_display = display;
+    plugin.ob_screen = screen;
+}
+
+/* init a new frame */
+gpointer frame_new(struct _ObClient * client)
+{
+    XSetWindowAttributes attrib;
+    gulong mask;
+    ObDefaultFrame *self;
+    Visual *visual;
+
+    self = g_new0(ObDefaultFrame, 1);
+    self->client = client;
+
+    visual = check_32bit_client(client);
+
+    /* create the non-visible decor windows */
+
+    mask = 0;
+    if (visual) {
+        /* client has a 32-bit visual */
+        mask |= CWColormap | CWBackPixel | CWBorderPixel;
+        /* create a colormap with the visual */
+        OBDEFAULTFRAME(self)->colormap = attrib.colormap = XCreateColormap(
+                plugin.ob_display, RootWindow(plugin.ob_display,
+                        plugin.ob_screen), visual, AllocNone);
+        attrib.background_pixel = BlackPixel(plugin.ob_display,
+                plugin.ob_screen);
+        attrib.border_pixel = BlackPixel(plugin.ob_display, plugin.ob_screen);
+    }
+    self->window = createWindow(
+            RootWindow(plugin.ob_display, plugin.ob_screen), visual, mask,
+            &attrib);
+
+    /* create the visible decor windows */
+
+    mask = 0;
+    if (visual) {
+        /* client has a 32-bit visual */
+        mask |= CWColormap | CWBackPixel | CWBorderPixel;
+        attrib.colormap = RrColormap(plugin.ob_rr_inst);
+    }
+
+    self->backback = createWindow(self->window, NULL, mask, &attrib);
+    self->backfront = createWindow(self->backback, NULL, mask, &attrib);
+
+    mask |= CWEventMask;
+    attrib.event_mask = ELEMENT_EVENTMASK;
+    self->innerleft = createWindow(self->window, NULL, mask, &attrib);
+    self->innertop = createWindow(self->window, NULL, mask, &attrib);
+    self->innerright = createWindow(self->window, NULL, mask, &attrib);
+    self->innerbottom = createWindow(self->window, NULL, mask, &attrib);
+
+    self->innerblb = createWindow(self->innerbottom, NULL, mask, &attrib);
+    self->innerbrb = createWindow(self->innerbottom, NULL, mask, &attrib);
+    self->innerbll = createWindow(self->innerleft, NULL, mask, &attrib);
+    self->innerbrr = createWindow(self->innerright, NULL, mask, &attrib);
+
+    self->title = createWindow(self->window, NULL, mask, &attrib);
+    self->titleleft = createWindow(self->window, NULL, mask, &attrib);
+    self->titletop = createWindow(self->window, NULL, mask, &attrib);
+    self->titletopleft = createWindow(self->window, NULL, mask, &attrib);
+    self->titletopright = createWindow(self->window, NULL, mask, &attrib);
+    self->titleright = createWindow(self->window, NULL, mask, &attrib);
+    self->titlebottom = createWindow(self->window, NULL, mask, &attrib);
+
+    self->topresize = createWindow(self->title, NULL, mask, &attrib);
+    self->tltresize = createWindow(self->title, NULL, mask, &attrib);
+    self->tllresize = createWindow(self->title, NULL, mask, &attrib);
+    self->trtresize = createWindow(self->title, NULL, mask, &attrib);
+    self->trrresize = createWindow(self->title, NULL, mask, &attrib);
+
+    self->left = createWindow(self->window, NULL, mask, &attrib);
+    self->right = createWindow(self->window, NULL, mask, &attrib);
+
+    self->label = createWindow(self->title, NULL, mask, &attrib);
+    self->max = createWindow(self->title, NULL, mask, &attrib);
+    self->close = createWindow(self->title, NULL, mask, &attrib);
+    self->desk = createWindow(self->title, NULL, mask, &attrib);
+    self->shade = createWindow(self->title, NULL, mask, &attrib);
+    self->icon = createWindow(self->title, NULL, mask, &attrib);
+    self->iconify = createWindow(self->title, NULL, mask, &attrib);
+
+    self->handle = createWindow(self->window, NULL, mask, &attrib);
+    self->lgrip = createWindow(self->handle, NULL, mask, &attrib);
+    self->rgrip = createWindow(self->handle, NULL, mask, &attrib);
+
+    self->handleleft = createWindow(self->handle, NULL, mask, &attrib);
+    self->handleright = createWindow(self->handle, NULL, mask, &attrib);
+
+    self->handletop = createWindow(self->window, NULL, mask, &attrib);
+    self->handlebottom = createWindow(self->window, NULL, mask, &attrib);
+    self->lgripleft = createWindow(self->window, NULL, mask, &attrib);
+    self->lgriptop = createWindow(self->window, NULL, mask, &attrib);
+    self->lgripbottom = createWindow(self->window, NULL, mask, &attrib);
+    self->rgripright = createWindow(self->window, NULL, mask, &attrib);
+    self->rgriptop = createWindow(self->window, NULL, mask, &attrib);
+    self->rgripbottom = createWindow(self->window, NULL, mask, &attrib);
+
+    self->focused = FALSE;
+
+    /* the other stuff is shown based on decor settings */
+    XMapWindow(plugin.ob_display, self->label);
+    XMapWindow(plugin.ob_display, self->backback);
+    XMapWindow(plugin.ob_display, self->backfront);
+
+    self->max_press = self->close_press = self->desk_press
+            = self->iconify_press = self->shade_press = FALSE;
+    self->max_hover = self->close_hover = self->desk_hover
+            = self->iconify_hover = self->shade_hover = FALSE;
+
+    set_theme_statics(self);
+
+    return (ObFrame*)self;
+}
+
+void set_theme_statics(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    /* set colors/appearance/sizes for stuff that doesn't change */
+    XResizeWindow(plugin.ob_display, self->max, theme_config.button_size,
+            theme_config.button_size);
+    XResizeWindow(plugin.ob_display, self->iconify, theme_config.button_size,
+            theme_config.button_size);
+    XResizeWindow(plugin.ob_display, self->icon, theme_config.button_size + 2,
+            theme_config.button_size + 2);
+    XResizeWindow(plugin.ob_display, self->close, theme_config.button_size,
+            theme_config.button_size);
+    XResizeWindow(plugin.ob_display, self->desk, theme_config.button_size,
+            theme_config.button_size);
+    XResizeWindow(plugin.ob_display, self->shade, theme_config.button_size,
+            theme_config.button_size);
+    XResizeWindow(plugin.ob_display, self->tltresize, theme_config.grip_width,
+            theme_config.paddingy + 1);
+    XResizeWindow(plugin.ob_display, self->trtresize, theme_config.grip_width,
+            theme_config.paddingy + 1);
+    XResizeWindow(plugin.ob_display, self->tllresize,
+            theme_config.paddingx + 1, theme_config.title_height);
+    XResizeWindow(plugin.ob_display, self->trrresize,
+            theme_config.paddingx + 1, theme_config.title_height);
+
+    /* set up the dynamic appearances */
+    self->a_unfocused_title = RrAppearanceCopy(theme_config.a_unfocused_title);
+    self->a_focused_title = RrAppearanceCopy(theme_config.a_focused_title);
+    self->a_unfocused_label = RrAppearanceCopy(theme_config.a_unfocused_label);
+    self->a_focused_label = RrAppearanceCopy(theme_config.a_focused_label);
+    self->a_unfocused_handle
+            = RrAppearanceCopy(theme_config.a_unfocused_handle);
+    self->a_focused_handle = RrAppearanceCopy(theme_config.a_focused_handle);
+    self->a_icon = RrAppearanceCopy(theme_config.a_icon);
+}
+
+void free_theme_statics(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    RrAppearanceFree(self->a_unfocused_title);
+    RrAppearanceFree(self->a_focused_title);
+    RrAppearanceFree(self->a_unfocused_label);
+    RrAppearanceFree(self->a_focused_label);
+    RrAppearanceFree(self->a_unfocused_handle);
+    RrAppearanceFree(self->a_focused_handle);
+    RrAppearanceFree(self->a_icon);
+}
+
+void frame_free(gpointer self)
+{
+    free_theme_statics(OBDEFAULTFRAME(self));
+    XDestroyWindow(plugin.ob_display, OBDEFAULTFRAME(self)->window);
+    if (OBDEFAULTFRAME(self)->colormap)
+        XFreeColormap(plugin.ob_display, OBDEFAULTFRAME(self)->colormap);
+    g_free(self);
+}
+
+void frame_show(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    if (!self->visible) {
+        self->visible = TRUE;
+        framerender_frame(self);
+        /* Grab the server to make sure that the frame window is mapped before
+         the client gets its MapNotify, i.e. to make sure the client is
+         _visible_ when it gets MapNotify. */
+        grab_server(TRUE);
+        XMapWindow(plugin.ob_display, self->client->window);
+        XMapWindow(plugin.ob_display, self->window);
+        grab_server(FALSE);
+    }
+}
+
+void frame_hide(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    if (self->visible) {
+        self->visible = FALSE;
+        if (!frame_iconify_animating(self))
+            XUnmapWindow(plugin.ob_display, self->window);
+        /* we unmap the client itself so that we can get MapRequest
+         events, and because the ICCCM tells us to! */
+        XUnmapWindow(plugin.ob_display, self->client->window);
+        self->client->ignore_unmaps += 1;
+    }
+}
+
+void frame_adjust_theme(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    free_theme_statics(self);
+    set_theme_statics(self);
+}
+
+void frame_adjust_shape(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+#ifdef SHAPE
+    gint num;
+    XRectangle xrect[2];
+
+    if (!self->client->shaped)
+    {
+        /* clear the shape on the frame window */
+        XShapeCombineMask(plugin.ob_display, self->window, ShapeBounding,
+                self->size.left,
+                self->size.top,
+                None, ShapeSet);
+    }
+    else
+    {
+        /* make the frame's shape match the clients */
+        XShapeCombineShape(plugin.ob_display, self->window, ShapeBounding,
+                self->size.left,
+                self->size.top,
+                self->client->window,
+                ShapeBounding, ShapeSet);
+
+        num = 0;
+        if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
+        {
+            xrect[0].x = 0;
+            xrect[0].y = 0;
+            xrect[0].width = self->area.width;
+            xrect[0].height = self->size.top;
+            ++num;
+        }
+
+        if (self->decorations & OB_FRAME_DECOR_HANDLE &&
+                theme_config.handle_height> 0)
+        {
+            xrect[1].x = 0;
+            xrect[1].y = FRAME_HANDLE_Y(self);
+            xrect[1].width = self->area.width;
+            xrect[1].height = theme_config.handle_height +
+            self->bwidth * 2;
+            ++num;
+        }
+
+        XShapeCombineRectangles(plugin.ob_display, self->window,
+                ShapeBounding, 0, 0, xrect, num,
+                ShapeUnion, Unsorted);
+    }
+#endif
+}
+
+void frame_adjust_area(gpointer _self, gboolean moved, gboolean resized,
+        gboolean fake)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    Strut oldsize;
+
+    oldsize = self->size;
+
+    if (resized) {
+        /* do this before changing the frame's status like max_horz max_vert */
+        frame_adjust_cursors(self);
+
+        self->functions = self->client->functions;
+        self->decorations = self->client->decorations;
+        self->max_horz = self->client->max_horz;
+        self->max_vert = self->client->max_vert;
+        self->shaded = self->client->shaded;
+
+        if (self->decorations & OB_FRAME_DECOR_BORDER
+                || (self->client->undecorated && plugin.config_theme_keepborder))
+            self->bwidth = theme_config.fbwidth;
+        else
+            self->bwidth = 0;
+
+        if (self->decorations & OB_FRAME_DECOR_BORDER) {
+            self->cbwidth_l = self->cbwidth_r = theme_config.cbwidthx;
+            self->cbwidth_t = self->cbwidth_b = theme_config.cbwidthy;
+        }
+        else
+            self->cbwidth_l = self->cbwidth_t = self->cbwidth_r
+                    = self->cbwidth_b = 0;
+
+        if (self->max_horz) {
+            self->cbwidth_l = self->cbwidth_r = 0;
+            self->width = self->client->area.width;
+            if (self->max_vert)
+                self->cbwidth_b = 0;
+        }
+        else
+            self->width = self->client->area.width + self->cbwidth_l
+                    + self->cbwidth_r;
+
+        /* some elements are sized based of the width, so don't let them have
+         negative values */
+        self->width = MAX(self->width, (theme_config.grip_width + self->bwidth)
+                * 2 + 1);
+
+        STRUT_SET(self->size, self->cbwidth_l + (!self->max_horz ? self->bwidth
+                : 0), self->cbwidth_t + self->bwidth, self->cbwidth_r
+                + (!self->max_horz ? self->bwidth : 0), self->cbwidth_b
+                + (!self->max_horz || !self->max_vert ? self->bwidth : 0));
+
+        if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
+            self->size.top += theme_config.title_height + self->bwidth;
+        if (self->decorations & OB_FRAME_DECOR_HANDLE
+                && theme_config.handle_height > 0) {
+            self->size.bottom += theme_config.handle_height + self->bwidth;
+        }
+
+        /* position/size and map/unmap all the windows */
+
+        if (!fake) {
+            gint innercornerheight = theme_config.grip_width
+                    - self->size.bottom;
+
+            if (self->cbwidth_l) {
+                XMoveResizeWindow(plugin.ob_display, self->innerleft,
+                        self->size.left - self->cbwidth_l, self->size.top,
+                        self->cbwidth_l, self->client->area.height);
+
+                XMapWindow(plugin.ob_display, self->innerleft);
+            }
+            else
+                XUnmapWindow(plugin.ob_display, self->innerleft);
+
+            if (self->cbwidth_l && innercornerheight > 0) {
+                XMoveResizeWindow(plugin.ob_display, self->innerbll, 0,
+                        self->client->area.height - (theme_config.grip_width
+                                - self->size.bottom), self->cbwidth_l,
+                        theme_config.grip_width - self->size.bottom);
+
+                XMapWindow(plugin.ob_display, self->innerbll);
+            }
+            else
+                XUnmapWindow(plugin.ob_display, self->innerbll);
+
+            if (self->cbwidth_r) {
+                XMoveResizeWindow(plugin.ob_display, self->innerright,
+                        self->size.left + self->client->area.width,
+                        self->size.top, self->cbwidth_r,
+                        self->client->area.height);
+
+                XMapWindow(plugin.ob_display, self->innerright);
+            }
+            else
+                XUnmapWindow(plugin.ob_display, self->innerright);
+
+            if (self->cbwidth_r && innercornerheight > 0) {
+                XMoveResizeWindow(plugin.ob_display, self->innerbrr, 0,
+                        self->client->area.height - (theme_config.grip_width
+                                - self->size.bottom), self->cbwidth_r,
+                        theme_config.grip_width - self->size.bottom);
+
+                XMapWindow(plugin.ob_display, self->innerbrr);
+            }
+            else
+                XUnmapWindow(plugin.ob_display, self->innerbrr);
+
+            if (self->cbwidth_t) {
+                XMoveResizeWindow(plugin.ob_display, self->innertop,
+                        self->size.left - self->cbwidth_l, self->size.top
+                                - self->cbwidth_t, self->client->area.width
+                                + self->cbwidth_l + self->cbwidth_r,
+                        self->cbwidth_t);
+
+                XMapWindow(plugin.ob_display, self->innertop);
+            }
+            else
+                XUnmapWindow(plugin.ob_display, self->innertop);
+
+            if (self->cbwidth_b) {
+                XMoveResizeWindow(plugin.ob_display, self->innerbottom,
+                        self->size.left - self->cbwidth_l, self->size.top
+                                + self->client->area.height,
+                        self->client->area.width + self->cbwidth_l
+                                + self->cbwidth_r, self->cbwidth_b);
+
+                XMoveResizeWindow(plugin.ob_display, self->innerblb, 0, 0,
+                        theme_config.grip_width + self->bwidth, self->cbwidth_b);
+                XMoveResizeWindow(plugin.ob_display, self->innerbrb,
+                        self->client->area.width + self->cbwidth_l
+                                + self->cbwidth_r - (theme_config.grip_width
+                                + self->bwidth), 0, theme_config.grip_width
+                                + self->bwidth, self->cbwidth_b);
+
+                XMapWindow(plugin.ob_display, self->innerbottom);
+                XMapWindow(plugin.ob_display, self->innerblb);
+                XMapWindow(plugin.ob_display, self->innerbrb);
+            }
+            else {
+                XUnmapWindow(plugin.ob_display, self->innerbottom);
+                XUnmapWindow(plugin.ob_display, self->innerblb);
+                XUnmapWindow(plugin.ob_display, self->innerbrb);
+            }
+
+            if (self->bwidth) {
+                gint titlesides;
+
+                /* height of titleleft and titleright */
+                titlesides = (!self->max_horz ? theme_config.grip_width : 0);
+
+                XMoveResizeWindow(plugin.ob_display, self->titletop,
+                        theme_config.grip_width + self->bwidth, 0,
+                        /* width + bwidth*2 - bwidth*2 - grips*2 */
+                        self->width - theme_config.grip_width * 2, self->bwidth);
+                XMoveResizeWindow(plugin.ob_display, self->titletopleft, 0, 0,
+                        theme_config.grip_width + self->bwidth, self->bwidth);
+                XMoveResizeWindow(plugin.ob_display, self->titletopright,
+                        self->client->area.width + self->size.left
+                                + self->size.right - theme_config.grip_width
+                                - self->bwidth, 0, theme_config.grip_width
+                                + self->bwidth, self->bwidth);
+
+                if (titlesides > 0) {
+                    XMoveResizeWindow(plugin.ob_display, self->titleleft, 0,
+                            self->bwidth, self->bwidth, titlesides);
+                    XMoveResizeWindow(plugin.ob_display, self->titleright,
+                            self->client->area.width + self->size.left
+                                    + self->size.right - self->bwidth,
+                            self->bwidth, self->bwidth, titlesides);
+
+                    XMapWindow(plugin.ob_display, self->titleleft);
+                    XMapWindow(plugin.ob_display, self->titleright);
+                }
+                else {
+                    XUnmapWindow(plugin.ob_display, self->titleleft);
+                    XUnmapWindow(plugin.ob_display, self->titleright);
+                }
+
+                XMapWindow(plugin.ob_display, self->titletop);
+                XMapWindow(plugin.ob_display, self->titletopleft);
+                XMapWindow(plugin.ob_display, self->titletopright);
+
+                if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
+                    XMoveResizeWindow(plugin.ob_display, self->titlebottom,
+                            (self->max_horz ? 0 : self->bwidth),
+                            theme_config.title_height + self->bwidth,
+                            self->width, self->bwidth);
+
+                    XMapWindow(plugin.ob_display, self->titlebottom);
+                }
+                else
+                    XUnmapWindow(plugin.ob_display, self->titlebottom);
+            }
+            else {
+                XUnmapWindow(plugin.ob_display, self->titlebottom);
+
+                XUnmapWindow(plugin.ob_display, self->titletop);
+                XUnmapWindow(plugin.ob_display, self->titletopleft);
+                XUnmapWindow(plugin.ob_display, self->titletopright);
+                XUnmapWindow(plugin.ob_display, self->titleleft);
+                XUnmapWindow(plugin.ob_display, self->titleright);
+            }
+
+            if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
+                XMoveResizeWindow(plugin.ob_display, self->title,
+                        (self->max_horz ? 0 : self->bwidth), self->bwidth,
+                        self->width, theme_config.title_height);
+
+                XMapWindow(plugin.ob_display, self->title);
+
+                if (self->decorations & OB_FRAME_DECOR_GRIPS) {
+                    XMoveResizeWindow(plugin.ob_display, self->topresize,
+                            theme_config.grip_width, 0, self->width
+                                    - theme_config.grip_width *2,
+                            theme_config.paddingy + 1);
+
+                    XMoveWindow(plugin.ob_display, self->tltresize, 0, 0);
+                    XMoveWindow(plugin.ob_display, self->tllresize, 0, 0);
+                    XMoveWindow(plugin.ob_display, self->trtresize, self->width
+                            - theme_config.grip_width, 0);
+                    XMoveWindow(plugin.ob_display, self->trrresize, self->width
+                            - theme_config.paddingx - 1, 0);
+
+                    XMapWindow(plugin.ob_display, self->topresize);
+                    XMapWindow(plugin.ob_display, self->tltresize);
+                    XMapWindow(plugin.ob_display, self->tllresize);
+                    XMapWindow(plugin.ob_display, self->trtresize);
+                    XMapWindow(plugin.ob_display, self->trrresize);
+                }
+                else {
+                    XUnmapWindow(plugin.ob_display, self->topresize);
+                    XUnmapWindow(plugin.ob_display, self->tltresize);
+                    XUnmapWindow(plugin.ob_display, self->tllresize);
+                    XUnmapWindow(plugin.ob_display, self->trtresize);
+                    XUnmapWindow(plugin.ob_display, self->trrresize);
+                }
+            }
+            else
+                XUnmapWindow(plugin.ob_display, self->title);
+        }
+
+        if ((self->decorations & OB_FRAME_DECOR_TITLEBAR))
+            /* layout the title bar elements */
+            layout_title(self);
+
+        if (!fake) {
+            gint sidebwidth = self->max_horz ? 0 : self->bwidth;
+
+            if (self->bwidth && self->size.bottom) {
+                XMoveResizeWindow(plugin.ob_display, self->handlebottom,
+                        theme_config.grip_width + self->bwidth + sidebwidth,
+                        self->size.top + self->client->area.height
+                                + self->size.bottom - self->bwidth, self->width
+                                - (theme_config.grip_width + sidebwidth) * 2,
+                        self->bwidth);
+
+                if (sidebwidth) {
+                    XMoveResizeWindow(
+                            plugin.ob_display,
+                            self->lgripleft,
+                            0,
+                            self->size.top + self->client->area.height
+                                    + self->size.bottom
+                                    - (!self->max_horz ? theme_config.grip_width
+                                            : self->size.bottom
+                                                    - self->cbwidth_b),
+                            self->bwidth,
+                            (!self->max_horz ? theme_config.grip_width
+                                    : self->size.bottom - self->cbwidth_b));
+                    XMoveResizeWindow(
+                            plugin.ob_display,
+                            self->rgripright,
+                            self->size.left + self->client->area.width
+                                    + self->size.right - self->bwidth,
+                            self->size.top + self->client->area.height
+                                    + self->size.bottom
+                                    - (!self->max_horz ? theme_config.grip_width
+                                            : self->size.bottom
+                                                    - self->cbwidth_b),
+                            self->bwidth,
+                            (!self->max_horz ? theme_config.grip_width
+                                    : self->size.bottom - self->cbwidth_b));
+
+                    XMapWindow(plugin.ob_display, self->lgripleft);
+                    XMapWindow(plugin.ob_display, self->rgripright);
+                }
+                else {
+                    XUnmapWindow(plugin.ob_display, self->lgripleft);
+                    XUnmapWindow(plugin.ob_display, self->rgripright);
+                }
+
+                XMoveResizeWindow(plugin.ob_display, self->lgripbottom,
+                        sidebwidth, self->size.top + self->client->area.height
+                                + self->size.bottom - self->bwidth,
+                        theme_config.grip_width + self->bwidth, self->bwidth);
+                XMoveResizeWindow(plugin.ob_display, self->rgripbottom,
+                        self->size.left + self->client->area.width
+                                + self->size.right - self->bwidth - sidebwidth
+                                - theme_config.grip_width, self->size.top
+                                + self->client->area.height + self->size.bottom
+                                - self->bwidth, theme_config.grip_width
+                                + self->bwidth, self->bwidth);
+
+                XMapWindow(plugin.ob_display, self->handlebottom);
+                XMapWindow(plugin.ob_display, self->lgripbottom);
+                XMapWindow(plugin.ob_display, self->rgripbottom);
+
+                if (self->decorations & OB_FRAME_DECOR_HANDLE
+                        && theme_config.handle_height > 0) {
+                    XMoveResizeWindow(
+                            plugin.ob_display,
+                            self->handletop,
+                            theme_config.grip_width + self->bwidth + sidebwidth,
+                            FRAME_HANDLE_Y(self), self->width
+                                    - (theme_config.grip_width + sidebwidth)
+                                            * 2, self->bwidth);
+                    XMapWindow(plugin.ob_display, self->handletop);
+
+                    if (self->decorations & OB_FRAME_DECOR_GRIPS) {
+                        XMoveResizeWindow(plugin.ob_display, self->handleleft,
+                                theme_config.grip_width, 0, self->bwidth,
+                                theme_config.handle_height);
+                        XMoveResizeWindow(plugin.ob_display, self->handleright,
+                                self->width - theme_config.grip_width
+                                        - self->bwidth, 0, self->bwidth,
+                                theme_config.handle_height);
+
+                        XMoveResizeWindow(plugin.ob_display, self->lgriptop,
+                                sidebwidth,
+                                FRAME_HANDLE_Y(self), theme_config.grip_width
+                                        + self->bwidth, self->bwidth);
+                        XMoveResizeWindow(plugin.ob_display, self->rgriptop,
+                                self->size.left + self->client->area.width
+                                        + self->size.right - self->bwidth
+                                        - sidebwidth - theme_config.grip_width,
+                                FRAME_HANDLE_Y(self), theme_config.grip_width
+                                        + self->bwidth, self->bwidth);
+
+                        XMapWindow(plugin.ob_display, self->handleleft);
+                        XMapWindow(plugin.ob_display, self->handleright);
+                        XMapWindow(plugin.ob_display, self->lgriptop);
+                        XMapWindow(plugin.ob_display, self->rgriptop);
+                    }
+                    else {
+                        XUnmapWindow(plugin.ob_display, self->handleleft);
+                        XUnmapWindow(plugin.ob_display, self->handleright);
+                        XUnmapWindow(plugin.ob_display, self->lgriptop);
+                        XUnmapWindow(plugin.ob_display, self->rgriptop);
+                    }
+                }
+                else {
+                    XUnmapWindow(plugin.ob_display, self->handleleft);
+                    XUnmapWindow(plugin.ob_display, self->handleright);
+                    XUnmapWindow(plugin.ob_display, self->lgriptop);
+                    XUnmapWindow(plugin.ob_display, self->rgriptop);
+
+                    XUnmapWindow(plugin.ob_display, self->handletop);
+                }
+            }
+            else {
+                XUnmapWindow(plugin.ob_display, self->handleleft);
+                XUnmapWindow(plugin.ob_display, self->handleright);
+                XUnmapWindow(plugin.ob_display, self->lgriptop);
+                XUnmapWindow(plugin.ob_display, self->rgriptop);
+
+                XUnmapWindow(plugin.ob_display, self->handletop);
+
+                XUnmapWindow(plugin.ob_display, self->handlebottom);
+                XUnmapWindow(plugin.ob_display, self->lgripleft);
+                XUnmapWindow(plugin.ob_display, self->rgripright);
+                XUnmapWindow(plugin.ob_display, self->lgripbottom);
+                XUnmapWindow(plugin.ob_display, self->rgripbottom);
+            }
+
+            if (self->decorations & OB_FRAME_DECOR_HANDLE
+                    && theme_config.handle_height > 0) {
+                XMoveResizeWindow(plugin.ob_display, self->handle, sidebwidth,
+                FRAME_HANDLE_Y(self) + self->bwidth, self->width,
+                        theme_config.handle_height);
+                XMapWindow(plugin.ob_display, self->handle);
+
+                if (self->decorations & OB_FRAME_DECOR_GRIPS) {
+                    XMoveResizeWindow(plugin.ob_display, self->lgrip, 0, 0,
+                            theme_config.grip_width, theme_config.handle_height);
+                    XMoveResizeWindow(plugin.ob_display, self->rgrip,
+                            self->width - theme_config.grip_width, 0,
+                            theme_config.grip_width, theme_config.handle_height);
+
+                    XMapWindow(plugin.ob_display, self->lgrip);
+                    XMapWindow(plugin.ob_display, self->rgrip);
+                }
+                else {
+                    XUnmapWindow(plugin.ob_display, self->lgrip);
+                    XUnmapWindow(plugin.ob_display, self->rgrip);
+                }
+            }
+            else {
+                XUnmapWindow(plugin.ob_display, self->lgrip);
+                XUnmapWindow(plugin.ob_display, self->rgrip);
+
+                XUnmapWindow(plugin.ob_display, self->handle);
+            }
+
+            if (self->bwidth && !self->max_horz && (self->client->area.height
+                    + self->size.top + self->size.bottom)
+                    > theme_config.grip_width * 2) {
+                XMoveResizeWindow(plugin.ob_display, self->left, 0,
+                        self->bwidth + theme_config.grip_width, self->bwidth,
+                        self->client->area.height + self->size.top
+                                + self->size.bottom - theme_config.grip_width
+                                * 2);
+
+                XMapWindow(plugin.ob_display, self->left);
+            }
+            else
+                XUnmapWindow(plugin.ob_display, self->left);
+
+            if (self->bwidth && !self->max_horz && (self->client->area.height
+                    + self->size.top + self->size.bottom)
+                    > theme_config.grip_width * 2) {
+                XMoveResizeWindow(plugin.ob_display, self->right,
+                        self->client->area.width + self->cbwidth_l
+                                + self->cbwidth_r + self->bwidth, self->bwidth
+                                + theme_config.grip_width, self->bwidth,
+                        self->client->area.height + self->size.top
+                                + self->size.bottom - theme_config.grip_width
+                                * 2);
+
+                XMapWindow(plugin.ob_display, self->right);
+            }
+            else
+                XUnmapWindow(plugin.ob_display, self->right);
+
+            XMoveResizeWindow(plugin.ob_display, self->backback,
+                    self->size.left, self->size.top, self->client->area.width,
+                    self->client->area.height);
+        }
+    }
+
+    /* shading can change without being moved or resized */
+    RECT_SET_SIZE(self->area, self->client->area.width + self->size.left
+            + self->size.right,
+            (self->client->shaded ? theme_config.title_height + self->bwidth
+                    * 2 : self->client->area.height + self->size.top
+                    + self->size.bottom));
+
+    if ((moved || resized) && !fake) {
+        /* find the new coordinates, done after setting the frame.size, for
+         frame_client_gravity. */
+        self->area.x = self->client->area.x;
+        self->area.y = self->client->area.y;
+        frame_client_gravity(self, &self->area.x, &self->area.y);
+    }
+
+    if (!fake) {
+        if (!frame_iconify_animating(self))
+            /* move and resize the top level frame.
+             shading can change without being moved or resized.
+
+             but don't do this during an iconify animation. it will be
+             reflected afterwards.
+             */
+            XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
+                    self->area.y, self->area.width, self->area.height);
+
+        /* when the client has StaticGravity, it likes to move around.
+         also this correctly positions the client when it maps.
+         this also needs to be run when the frame's decorations sizes change!
+         */
+        XMoveWindow(plugin.ob_display, self->client->window, self->size.left,
+                self->size.top);
+
+        if (resized) {
+            self->need_render = TRUE;
+            framerender_frame(self);
+            frame_adjust_shape(self);
+        }
+
+        if (!STRUT_EQUAL(self->size, oldsize)) {
+            gulong vals[4];
+            vals[0] = self->size.left;
+            vals[1] = self->size.right;
+            vals[2] = self->size.top;
+            vals[3] = self->size.bottom;
+            PROP_SETA32(self->client->window, net_frame_extents, cardinal,
+                    vals, 4);
+            PROP_SETA32(self->client->window, kde_net_wm_frame_strut, cardinal,
+                    vals, 4);
+        }
+
+        /* if this occurs while we are focus cycling, the indicator needs to
+         match the changes */
+        if (plugin.focus_cycle_target == self->client)
+            focus_cycle_draw_indicator(self->client);
+    }
+    if (resized && (self->decorations & OB_FRAME_DECOR_TITLEBAR))
+        XResizeWindow(plugin.ob_display, self->label, self->label_width,
+                theme_config.label_height);
+
+}
+
+void frame_adjust_cursors(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    if ((self->functions & OB_CLIENT_FUNC_RESIZE) != (self->client->functions
+            & OB_CLIENT_FUNC_RESIZE) || self->max_horz
+            != self->client->max_horz || self->max_vert
+            != self->client->max_vert || self->shaded != self->client->shaded) {
+        gboolean r = (self->client->functions & OB_CLIENT_FUNC_RESIZE)
+                && !(self->client->max_horz && self->client->max_vert);
+        gboolean topbot = !self->client->max_vert;
+        gboolean sh = self->client->shaded;
+        XSetWindowAttributes a;
+
+        /* these ones turn off when max vert, and some when shaded */
+        a.cursor = ob_cursor(r && topbot && !sh ? OB_CURSOR_NORTH
+                : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->topresize, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->titletop, CWCursor, &a);
+        a.cursor = ob_cursor(r && topbot ? OB_CURSOR_SOUTH : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->handle, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->handletop, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->handlebottom,
+                CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerbottom, CWCursor,
+                &a);
+
+        /* these ones change when shaded */
+        a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_WEST : OB_CURSOR_NORTHWEST)
+                : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->titleleft, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->tltresize, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->tllresize, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->titletopleft,
+                CWCursor, &a);
+        a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_EAST : OB_CURSOR_NORTHEAST)
+                : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->titleright, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->trtresize, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->trrresize, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->titletopright,
+                CWCursor, &a);
+
+        /* these ones are pretty static */
+        a.cursor = ob_cursor(r ? OB_CURSOR_WEST : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->left, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerleft, CWCursor,
+                &a);
+        a.cursor = ob_cursor(r ? OB_CURSOR_EAST : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->right, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerright, CWCursor,
+                &a);
+        a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHWEST : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->lgrip, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->handleleft, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->lgripleft, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->lgriptop, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->lgripbottom, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerbll, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerblb, CWCursor, &a);
+        a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHEAST : OB_CURSOR_NONE);
+        XChangeWindowAttributes(plugin.ob_display, self->rgrip, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->handleright, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->rgripright, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->rgriptop, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->rgripbottom, CWCursor,
+                &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerbrr, CWCursor, &a);
+        XChangeWindowAttributes(plugin.ob_display, self->innerbrb, CWCursor, &a);
+    }
+}
+
+void frame_adjust_client_area(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    /* adjust the window which is there to prevent flashing on unmap */
+    XMoveResizeWindow(plugin.ob_display, self->backfront, 0, 0,
+            self->client->area.width, self->client->area.height);
+}
+
+void frame_adjust_state(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->need_render = TRUE;
+    framerender_frame(self);
+}
+
+void frame_adjust_focus(gpointer _self, gboolean hilite)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->focused = hilite;
+    self->need_render = TRUE;
+    framerender_frame(self);
+    XFlush(plugin.ob_display);
+}
+
+void frame_adjust_title(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->need_render = TRUE;
+    framerender_frame(self);
+}
+
+void frame_adjust_icon(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->need_render = TRUE;
+    framerender_frame(self);
+}
+
+void frame_grab_client(gpointer _self, GHashTable * window_map)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    /* DO NOT map the client window here. we used to do that, but it is bogus.
+     we need to set up the client's dimensions and everything before we
+     send a mapnotify or we create race conditions.
+     */
+
+    /* reparent the client to the frame */
+    XReparentWindow(plugin.ob_display, self->client->window, self->window, 0, 0);
+
+    /*
+     When reparenting the client window, it is usually not mapped yet, since
+     this occurs from a MapRequest. However, in the case where Openbox is
+     starting up, the window is already mapped, so we'll see an unmap event
+     for it.
+     */
+    if (ob_state() == OB_STATE_STARTING)
+        ++self->client->ignore_unmaps;
+
+    /* select the event mask on the client's parent (to receive config/map
+     req's) the ButtonPress is to catch clicks on the client border */
+    XSelectInput(plugin.ob_display, self->window, FRAME_EVENTMASK);
+
+    /* set all the windows for the frame in the window_map */
+    g_hash_table_insert(window_map, &self->window, self->client);
+    g_hash_table_insert(window_map, &self->backback, self->client);
+    g_hash_table_insert(window_map, &self->backfront, self->client);
+    g_hash_table_insert(window_map, &self->innerleft, self->client);
+    g_hash_table_insert(window_map, &self->innertop, self->client);
+    g_hash_table_insert(window_map, &self->innerright, self->client);
+    g_hash_table_insert(window_map, &self->innerbottom, self->client);
+    g_hash_table_insert(window_map, &self->title, self->client);
+    g_hash_table_insert(window_map, &self->label, self->client);
+    g_hash_table_insert(window_map, &self->max, self->client);
+    g_hash_table_insert(window_map, &self->close, self->client);
+    g_hash_table_insert(window_map, &self->desk, self->client);
+    g_hash_table_insert(window_map, &self->shade, self->client);
+    g_hash_table_insert(window_map, &self->icon, self->client);
+    g_hash_table_insert(window_map, &self->iconify, self->client);
+    g_hash_table_insert(window_map, &self->handle, self->client);
+    g_hash_table_insert(window_map, &self->lgrip, self->client);
+    g_hash_table_insert(window_map, &self->rgrip, self->client);
+    g_hash_table_insert(window_map, &self->topresize, self->client);
+    g_hash_table_insert(window_map, &self->tltresize, self->client);
+    g_hash_table_insert(window_map, &self->tllresize, self->client);
+    g_hash_table_insert(window_map, &self->trtresize, self->client);
+    g_hash_table_insert(window_map, &self->trrresize, self->client);
+    g_hash_table_insert(window_map, &self->left, self->client);
+    g_hash_table_insert(window_map, &self->right, self->client);
+    g_hash_table_insert(window_map, &self->titleleft, self->client);
+    g_hash_table_insert(window_map, &self->titletop, self->client);
+    g_hash_table_insert(window_map, &self->titletopleft, self->client);
+    g_hash_table_insert(window_map, &self->titletopright, self->client);
+    g_hash_table_insert(window_map, &self->titleright, self->client);
+    g_hash_table_insert(window_map, &self->titlebottom, self->client);
+    g_hash_table_insert(window_map, &self->handleleft, self->client);
+    g_hash_table_insert(window_map, &self->handletop, self->client);
+    g_hash_table_insert(window_map, &self->handleright, self->client);
+    g_hash_table_insert(window_map, &self->handlebottom, self->client);
+    g_hash_table_insert(window_map, &self->lgripleft, self->client);
+    g_hash_table_insert(window_map, &self->lgriptop, self->client);
+    g_hash_table_insert(window_map, &self->lgripbottom, self->client);
+    g_hash_table_insert(window_map, &self->rgripright, self->client);
+    g_hash_table_insert(window_map, &self->rgriptop, self->client);
+    g_hash_table_insert(window_map, &self->rgripbottom, self->client);
+}
+
+void frame_release_client(gpointer _self, GHashTable * window_map)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    XEvent ev;
+    gboolean reparent = TRUE;
+
+    /* if there was any animation going on, kill it */
+    ob_main_loop_timeout_remove_data(plugin.ob_main_loop,
+            frame_animate_iconify, self, FALSE);
+
+    /* check if the app has already reparented its window away */
+    while (XCheckTypedWindowEvent(plugin.ob_display, self->client->window,
+            ReparentNotify, &ev)) {
+        /* This check makes sure we don't catch our own reparent action to
+         our frame window. This doesn't count as the app reparenting itself
+         away of course.
+
+         Reparent events that are generated by us are just discarded here.
+         They are of no consequence to us anyhow.
+         */
+        if (ev.xreparent.parent != self->window) {
+            reparent = FALSE;
+            XPutBackEvent(plugin.ob_display, &ev);
+            break;
+        }
+    }
+
+    if (reparent) {
+        /* according to the ICCCM - if the client doesn't reparent itself,
+         then we will reparent the window to root for them */
+        XReparentWindow(plugin.ob_display, self->client->window, RootWindow(
+                plugin.ob_display, plugin.ob_screen), self->client->area.x,
+                self->client->area.y);
+    }
+
+    /* remove all the windows for the frame from the window_map */
+    g_hash_table_remove(window_map, &self->window);
+    g_hash_table_remove(window_map, &self->backback);
+    g_hash_table_remove(window_map, &self->backfront);
+    g_hash_table_remove(window_map, &self->innerleft);
+    g_hash_table_remove(window_map, &self->innertop);
+    g_hash_table_remove(window_map, &self->innerright);
+    g_hash_table_remove(window_map, &self->innerbottom);
+    g_hash_table_remove(window_map, &self->title);
+    g_hash_table_remove(window_map, &self->label);
+    g_hash_table_remove(window_map, &self->max);
+    g_hash_table_remove(window_map, &self->close);
+    g_hash_table_remove(window_map, &self->desk);
+    g_hash_table_remove(window_map, &self->shade);
+    g_hash_table_remove(window_map, &self->icon);
+    g_hash_table_remove(window_map, &self->iconify);
+    g_hash_table_remove(window_map, &self->handle);
+    g_hash_table_remove(window_map, &self->lgrip);
+    g_hash_table_remove(window_map, &self->rgrip);
+    g_hash_table_remove(window_map, &self->topresize);
+    g_hash_table_remove(window_map, &self->tltresize);
+    g_hash_table_remove(window_map, &self->tllresize);
+    g_hash_table_remove(window_map, &self->trtresize);
+    g_hash_table_remove(window_map, &self->trrresize);
+    g_hash_table_remove(window_map, &self->left);
+    g_hash_table_remove(window_map, &self->right);
+    g_hash_table_remove(window_map, &self->titleleft);
+    g_hash_table_remove(window_map, &self->titletop);
+    g_hash_table_remove(window_map, &self->titletopleft);
+    g_hash_table_remove(window_map, &self->titletopright);
+    g_hash_table_remove(window_map, &self->titleright);
+    g_hash_table_remove(window_map, &self->titlebottom);
+    g_hash_table_remove(window_map, &self->handleleft);
+    g_hash_table_remove(window_map, &self->handletop);
+    g_hash_table_remove(window_map, &self->handleright);
+    g_hash_table_remove(window_map, &self->handlebottom);
+    g_hash_table_remove(window_map, &self->lgripleft);
+    g_hash_table_remove(window_map, &self->lgriptop);
+    g_hash_table_remove(window_map, &self->lgripbottom);
+    g_hash_table_remove(window_map, &self->rgripright);
+    g_hash_table_remove(window_map, &self->rgriptop);
+    g_hash_table_remove(window_map, &self->rgripbottom);
+
+    ob_main_loop_timeout_remove_data(plugin.ob_main_loop, flash_timeout, self,
+            TRUE);
+}
+
+/* is there anything present between us and the label? */
+static gboolean is_button_present(ObDefaultFrame *_self, const gchar *lc,
+        gint dir)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    for (; *lc != '\0' && lc >= plugin.config_title_layout; lc += dir) {
+        if (*lc == ' ')
+            continue; /* it was invalid */
+        if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
+            return TRUE;
+        if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
+            return TRUE;
+        if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
+            return TRUE;
+        if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
+            return TRUE;
+        if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
+            return TRUE;
+        if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
+            return TRUE;
+        if (*lc == 'L')
+            return FALSE;
+    }
+    return FALSE;
+}
+
+void layout_title(ObDefaultFrame * self)
+{
+    gchar *lc;
+    gint i;
+
+    const gint bwidth = theme_config.button_size + theme_config.paddingx + 1;
+    /* position of the left most button */
+    const gint left = theme_config.paddingx + 1;
+    /* position of the right most button */
+    const gint right = self->width;
+
+    /* turn them all off */
+    self->icon_on = self->desk_on = self->shade_on = self->iconify_on
+            = self->max_on = self->close_on = self->label_on = FALSE;
+    self->label_width = self->width - (theme_config.paddingx + 1) * 2;
+    self->leftmost = self->rightmost = OB_FRAME_CONTEXT_NONE;
+
+    /* figure out what's being show, find each element's position, and the
+     width of the label
+
+     do the ones before the label, then after the label,
+     i will be +1 the first time through when working to the left,
+     and -1 the second time through when working to the right */
+    for (i = 1; i >= -1; i-=2) {
+        gint x;
+        ObFrameContext *firstcon;
+
+        if (i > 0) {
+            x = left;
+            lc = plugin.config_title_layout;
+            firstcon = &self->leftmost;
+        }
+        else {
+            x = right;
+            lc = plugin.config_title_layout
+                    + strlen(plugin.config_title_layout)-1;
+            firstcon = &self->rightmost;
+        }
+
+        /* stop at the end of the string (or the label, which calls break) */
+        for (; *lc != '\0' && lc >= plugin.config_title_layout; lc+=i) {
+            if (*lc == 'L') {
+                if (i > 0) {
+                    self->label_on = TRUE;
+                    self->label_x = x;
+                }
+                break; /* break the for loop, do other side of label */
+            }
+            else if (*lc == 'N') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_ICON;
+                if ((self->icon_on = is_button_present(self, lc, i))) {
+                    /* icon is bigger than buttons */
+                    self->label_width -= bwidth + 2;
+                    if (i > 0)
+                        self->icon_x = x;
+                    x += i * (bwidth + 2);
+                    if (i < 0)
+                        self->icon_x = x;
+                }
+            }
+            else if (*lc == 'D') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
+                if ((self->desk_on = is_button_present(self, lc, i))) {
+                    self->label_width -= bwidth;
+                    if (i > 0)
+                        self->desk_x = x;
+                    x += i * bwidth;
+                    if (i < 0)
+                        self->desk_x = x;
+                }
+            }
+            else if (*lc == 'S') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_SHADE;
+                if ((self->shade_on = is_button_present(self, lc, i))) {
+                    self->label_width -= bwidth;
+                    if (i > 0)
+                        self->shade_x = x;
+                    x += i * bwidth;
+                    if (i < 0)
+                        self->shade_x = x;
+                }
+            }
+            else if (*lc == 'I') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_ICONIFY;
+                if ((self->iconify_on = is_button_present(self, lc, i))) {
+                    self->label_width -= bwidth;
+                    if (i > 0)
+                        self->iconify_x = x;
+                    x += i * bwidth;
+                    if (i < 0)
+                        self->iconify_x = x;
+                }
+            }
+            else if (*lc == 'M') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
+                if ((self->max_on = is_button_present(self, lc, i))) {
+                    self->label_width -= bwidth;
+                    if (i > 0)
+                        self->max_x = x;
+                    x += i * bwidth;
+                    if (i < 0)
+                        self->max_x = x;
+                }
+            }
+            else if (*lc == 'C') {
+                if (firstcon)
+                    *firstcon = OB_FRAME_CONTEXT_CLOSE;
+                if ((self->close_on = is_button_present(self, lc, i))) {
+                    self->label_width -= bwidth;
+                    if (i > 0)
+                        self->close_x = x;
+                    x += i * bwidth;
+                    if (i < 0)
+                        self->close_x = x;
+                }
+            }
+            else
+                continue; /* don't set firstcon */
+            firstcon = NULL;
+        }
+    }
+
+    /* position and map the elements */
+    if (self->icon_on) {
+        XMapWindow(plugin.ob_display, self->icon);
+        XMoveWindow(plugin.ob_display, self->icon, self->icon_x,
+                theme_config.paddingy);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->icon);
+
+    if (self->desk_on) {
+        XMapWindow(plugin.ob_display, self->desk);
+        XMoveWindow(plugin.ob_display, self->desk, self->desk_x,
+                theme_config.paddingy + 1);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->desk);
+
+    if (self->shade_on) {
+        XMapWindow(plugin.ob_display, self->shade);
+        XMoveWindow(plugin.ob_display, self->shade, self->shade_x,
+                theme_config.paddingy + 1);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->shade);
+
+    if (self->iconify_on) {
+        XMapWindow(plugin.ob_display, self->iconify);
+        XMoveWindow(plugin.ob_display, self->iconify, self->iconify_x,
+                theme_config.paddingy + 1);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->iconify);
+
+    if (self->max_on) {
+        XMapWindow(plugin.ob_display, self->max);
+        XMoveWindow(plugin.ob_display, self->max, self->max_x,
+                theme_config.paddingy + 1);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->max);
+
+    if (self->close_on) {
+        XMapWindow(plugin.ob_display, self->close);
+        XMoveWindow(plugin.ob_display, self->close, self->close_x,
+                theme_config.paddingy + 1);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->close);
+
+    if (self->label_on) {
+        self->label_width = MAX(1, self->label_width); /* no lower than 1 */
+        XMapWindow(plugin.ob_display, self->label);
+        XMoveWindow(plugin.ob_display, self->label, self->label_x,
+                theme_config.paddingy);
+    }
+    else
+        XUnmapWindow(plugin.ob_display, self->label);
+}
+
+ObFrameContext frame_context(gpointer _self, Window win, gint x, gint y)
+{
+    ObDefaultFrame * self = OBDEFAULTFRAME(_self);
+
+    /* when the user clicks in the corners of the titlebar and the client
+     is fully maximized, then treat it like they clicked in the
+     button that is there */
+    if (self->max_horz && self->max_vert && (win == self->title || win
+            == self->titletop || win == self->titleleft || win
+            == self->titletopleft || win == self->titleright || win
+            == self->titletopright)) {
+        /* get the mouse coords in reference to the whole frame */
+        gint fx = x;
+        gint fy = y;
+
+        /* these windows are down a border width from the top of the frame */
+        if (win == self->title || win == self->titleleft || win
+                == self->titleright)
+            fy += self->bwidth;
+
+        /* title is a border width in from the edge */
+        if (win == self->title)
+            fx += self->bwidth;
+        /* titletop is a bit to the right */
+        else if (win == self->titletop)
+            fx += theme_config.grip_width + self->bwidth;
+        /* titletopright is way to the right edge */
+        else if (win == self->titletopright)
+            fx += self->area.width - (theme_config.grip_width + self->bwidth);
+        /* titleright is even more way to the right edge */
+        else if (win == self->titleright)
+            fx += self->area.width - self->bwidth;
+
+        /* figure out if we're over the area that should be considered a
+         button */
+        if (fy < self->bwidth + theme_config.paddingy + 1
+                + theme_config.button_size) {
+            if (fx < (self->bwidth + theme_config.paddingx + 1
+                    + theme_config.button_size)) {
+                if (self->leftmost != OB_FRAME_CONTEXT_NONE)
+                    return self->leftmost;
+            }
+            else if (fx >= (self->area.width - (self->bwidth
+                    + theme_config.paddingx + 1 + theme_config.button_size))) {
+                if (self->rightmost != OB_FRAME_CONTEXT_NONE)
+                    return self->rightmost;
+            }
+        }
+
+        /* there is no resizing maximized windows so make them the titlebar
+         context */
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    }
+    else if (self->max_vert
+            && (win == self->titletop || win == self->topresize))
+        /* can't resize vertically when max vert */
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    else if (self->shaded && (win == self->titletop || win == self->topresize))
+        /* can't resize vertically when shaded */
+        return OB_FRAME_CONTEXT_TITLEBAR;
+
+    if (win == self->window)
+        return OB_FRAME_CONTEXT_FRAME;
+    if (win == self->label)
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    if (win == self->handle)
+        return OB_FRAME_CONTEXT_BOTTOM;
+    if (win == self->handletop)
+        return OB_FRAME_CONTEXT_BOTTOM;
+    if (win == self->handlebottom)
+        return OB_FRAME_CONTEXT_BOTTOM;
+    if (win == self->handleleft)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->lgrip)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->lgripleft)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->lgriptop)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->lgripbottom)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->handleright)
+        return OB_FRAME_CONTEXT_BRCORNER;
+    if (win == self->rgrip)
+        return OB_FRAME_CONTEXT_BRCORNER;
+    if (win == self->rgripright)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->rgriptop)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->rgripbottom)
+        return OB_FRAME_CONTEXT_BLCORNER;
+    if (win == self->title)
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    if (win == self->titlebottom)
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    if (win == self->titleleft)
+        return OB_FRAME_CONTEXT_TLCORNER;
+    if (win == self->titletopleft)
+        return OB_FRAME_CONTEXT_TLCORNER;
+    if (win == self->titleright)
+        return OB_FRAME_CONTEXT_TRCORNER;
+    if (win == self->titletopright)
+        return OB_FRAME_CONTEXT_TRCORNER;
+    if (win == self->titletop)
+        return OB_FRAME_CONTEXT_TOP;
+    if (win == self->topresize)
+        return OB_FRAME_CONTEXT_TOP;
+    if (win == self->tltresize)
+        return OB_FRAME_CONTEXT_TLCORNER;
+    if (win == self->tllresize)
+        return OB_FRAME_CONTEXT_TLCORNER;
+    if (win == self->trtresize)
+        return OB_FRAME_CONTEXT_TRCORNER;
+    if (win == self->trrresize)
+        return OB_FRAME_CONTEXT_TRCORNER;
+    if (win == self->left)
+        return OB_FRAME_CONTEXT_LEFT;
+    if (win == self->right)
+        return OB_FRAME_CONTEXT_RIGHT;
+    if (win == self->innertop)
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    if (win == self->innerleft)
+        return OB_FRAME_CONTEXT_LEFT;
+    if (win == self->innerbottom)
+        return OB_FRAME_CONTEXT_BOTTOM;
+    if (win == self->innerright)
+        return OB_FRAME_CONTEXT_RIGHT;
+    if (win == self->max)
+        return OB_FRAME_CONTEXT_MAXIMIZE;
+    if (win == self->iconify)
+        return OB_FRAME_CONTEXT_ICONIFY;
+    if (win == self->close)
+        return OB_FRAME_CONTEXT_CLOSE;
+    if (win == self->icon)
+        return OB_FRAME_CONTEXT_ICON;
+    if (win == self->desk)
+        return OB_FRAME_CONTEXT_ALLDESKTOPS;
+    if (win == self->shade)
+        return OB_FRAME_CONTEXT_SHADE;
+
+    return OB_FRAME_CONTEXT_NONE;
+}
+
+void frame_client_gravity(gpointer _self, gint *x, gint *y)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    /* horizontal */
+    switch (self->client->gravity) {
+    default:
+    case NorthWestGravity:
+    case SouthWestGravity:
+    case WestGravity:
+        break;
+
+    case NorthGravity:
+    case SouthGravity:
+    case CenterGravity:
+        /* the middle of the client will be the middle of the frame */
+        *x -= (self->size.right - self->size.left) / 2;
+        break;
+
+    case NorthEastGravity:
+    case SouthEastGravity:
+    case EastGravity:
+        /* the right side of the client will be the right side of the frame */
+        *x -= self->size.right + self->size.left - self->client->border_width
+                * 2;
+        break;
+
+    case ForgetGravity:
+    case StaticGravity:
+        /* the client's position won't move */
+        *x -= self->size.left - self->client->border_width;
+        break;
+    }
+
+    /* vertical */
+    switch (self->client->gravity) {
+    default:
+    case NorthWestGravity:
+    case NorthEastGravity:
+    case NorthGravity:
+        break;
+
+    case CenterGravity:
+    case EastGravity:
+    case WestGravity:
+        /* the middle of the client will be the middle of the frame */
+        *y -= (self->size.bottom - self->size.top) / 2;
+        break;
+
+    case SouthWestGravity:
+    case SouthEastGravity:
+    case SouthGravity:
+        /* the bottom of the client will be the bottom of the frame */
+        *y -= self->size.bottom + self->size.top - self->client->border_width
+                * 2;
+        break;
+
+    case ForgetGravity:
+    case StaticGravity:
+        /* the client's position won't move */
+        *y -= self->size.top - self->client->border_width;
+        break;
+    }
+}
+
+void frame_frame_gravity(gpointer _self, gint *x, gint *y)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    /* horizontal */
+    switch (self->client->gravity) {
+    default:
+    case NorthWestGravity:
+    case WestGravity:
+    case SouthWestGravity:
+        break;
+    case NorthGravity:
+    case CenterGravity:
+    case SouthGravity:
+        /* the middle of the client will be the middle of the frame */
+        *x += (self->size.right - self->size.left) / 2;
+        break;
+    case NorthEastGravity:
+    case EastGravity:
+    case SouthEastGravity:
+        /* the right side of the client will be the right side of the frame */
+        *x += self->size.right + self->size.left - self->client->border_width
+                * 2;
+        break;
+    case StaticGravity:
+    case ForgetGravity:
+        /* the client's position won't move */
+        *x += self->size.left - self->client->border_width;
+        break;
+    }
+
+    /* vertical */
+    switch (self->client->gravity) {
+    default:
+    case NorthWestGravity:
+    case NorthGravity:
+    case NorthEastGravity:
+        break;
+    case WestGravity:
+    case CenterGravity:
+    case EastGravity:
+        /* the middle of the client will be the middle of the frame */
+        *y += (self->size.bottom - self->size.top) / 2;
+        break;
+    case SouthWestGravity:
+    case SouthGravity:
+    case SouthEastGravity:
+        /* the bottom of the client will be the bottom of the frame */
+        *y += self->size.bottom + self->size.top - self->client->border_width
+                * 2;
+        break;
+    case StaticGravity:
+    case ForgetGravity:
+        /* the client's position won't move */
+        *y += self->size.top - self->client->border_width;
+        break;
+    }
+}
+
+void frame_rect_to_frame(gpointer _self, Rect *r)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    r->width += self->size.left + self->size.right;
+    r->height += self->size.top + self->size.bottom;
+    frame_client_gravity(self, &r->x, &r->y);
+}
+
+void frame_rect_to_client(gpointer _self, Rect *r)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    r->width -= self->size.left + self->size.right;
+    r->height -= self->size.top + self->size.bottom;
+    frame_frame_gravity(self, &r->x, &r->y);
+}
+
+void flash_done(gpointer data)
+{
+    ObDefaultFrame *self = data;
+
+    if (self->focused != self->flash_on)
+        frame_adjust_focus(self, self->focused);
+}
+
+gboolean flash_timeout(gpointer data)
+{
+    ObDefaultFrame *self = data;
+    GTimeVal now;
+
+    g_get_current_time(&now);
+    if (now.tv_sec > self->flash_end.tv_sec
+            || (now.tv_sec == self->flash_end.tv_sec && now.tv_usec
+                    >= self->flash_end.tv_usec))
+        self->flashing = FALSE;
+
+    if (!self->flashing)
+        return FALSE; /* we are done */
+
+    self->flash_on = !self->flash_on;
+    if (!self->focused) {
+        frame_adjust_focus(self, self->flash_on);
+        self->focused = FALSE;
+    }
+
+    return TRUE; /* go again */
+}
+
+void frame_flash_start(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->flash_on = self->focused;
+
+    if (!self->flashing)
+        ob_main_loop_timeout_add(plugin.ob_main_loop, G_USEC_PER_SEC * 0.6,
+                flash_timeout, self, g_direct_equal, flash_done);
+    g_get_current_time(&self->flash_end);
+    g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
+
+    self->flashing = TRUE;
+}
+
+void frame_flash_stop(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    self->flashing = FALSE;
+}
+
+static gulong frame_animate_iconify_time_left(gpointer _self,
+        const GTimeVal *now)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    glong sec, usec;
+    sec = self->iconify_animation_end.tv_sec - now->tv_sec;
+    usec = self->iconify_animation_end.tv_usec - now->tv_usec;
+    if (usec < 0) {
+        usec += G_USEC_PER_SEC;
+        sec--;
+    }
+    /* no negative values */
+    return MAX(sec * G_USEC_PER_SEC + usec, 0);
+}
+
+gboolean frame_animate_iconify(gpointer p)
+{
+    ObDefaultFrame *self = p;
+    gint x, y, w, h;
+    gint iconx, icony, iconw;
+    GTimeVal now;
+    gulong time;
+    gboolean iconifying;
+
+    if (self->client->icon_geometry.width == 0) {
+        /* there is no icon geometry set so just go straight down */
+        Rect *a =
+                screen_physical_area_monitor(screen_find_monitor(&self->area));
+        iconx = self->area.x + self->area.width / 2 + 32;
+        icony = a->y + a->width;
+        iconw = 64;
+        g_free(a);
+    }
+    else {
+        iconx = self->client->icon_geometry.x;
+        icony = self->client->icon_geometry.y;
+        iconw = self->client->icon_geometry.width;
+    }
+
+    iconifying = self->iconify_animation_going > 0;
+
+    /* how far do we have left to go ? */
+    g_get_current_time(&now);
+    time = frame_animate_iconify_time_left(self, &now);
+
+    if (time == 0 || iconifying) {
+        /* start where the frame is supposed to be */
+        x = self->area.x;
+        y = self->area.y;
+        w = self->area.width;
+        h = self->area.height;
+    }
+    else {
+        /* start at the icon */
+        x = iconx;
+        y = icony;
+        w = iconw;
+        h = self->size.top; /* just the titlebar */
+    }
+
+    if (time > 0) {
+        glong dx, dy, dw;
+        glong elapsed;
+
+        dx = self->area.x - iconx;
+        dy = self->area.y - icony;
+        dw = self->area.width - self->bwidth * 2 - iconw;
+        /* if restoring, we move in the opposite direction */
+        if (!iconifying) {
+            dx = -dx;
+            dy = -dy;
+            dw = -dw;
+        }
+
+        elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
+        x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
+        h = self->size.top; /* just the titlebar */
+    }
+
+    if (time == 0)
+        frame_end_iconify_animation(self);
+    else {
+        XMoveResizeWindow(plugin.ob_display, self->window, x, y, w, h);
+        XFlush(plugin.ob_display);
+    }
+
+    return time > 0; /* repeat until we're out of time */
+}
+
+void frame_end_iconify_animation(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    /* see if there is an animation going */
+    if (self->iconify_animation_going == 0)
+        return;
+
+    if (!self->visible)
+        XUnmapWindow(plugin.ob_display, self->window);
+    else {
+        /* Send a ConfigureNotify when the animation is done, this fixes
+         KDE's pager showing the window in the wrong place.  since the
+         window is mapped at a different location and is then moved, we
+         need to send the synthetic configurenotify, since apps may have
+         read the position when the client mapped, apparently. */
+        client_reconfigure(self->client, TRUE);
+    }
+
+    /* we're not animating any more ! */
+    self->iconify_animation_going = 0;
+
+    XMoveResizeWindow(plugin.ob_display, self->window, self->area.x,
+            self->area.y, self->area.width, self->area.height);
+    /* we delay re-rendering until after we're done animating */
+    framerender_frame(self);
+    XFlush(plugin.ob_display);
+}
+
+void frame_begin_iconify_animation(gpointer _self, gboolean iconifying)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    gulong time;
+    gboolean new_anim = FALSE;
+    gboolean set_end = TRUE;
+    GTimeVal now;
+
+    /* if there is no titlebar, just don't animate for now
+     XXX it would be nice tho.. */
+    if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
+        return;
+
+    /* get the current time */
+    g_get_current_time(&now);
+
+    /* get how long until the end */
+    time = FRAME_ANIMATE_ICONIFY_TIME;
+    if (self->iconify_animation_going) {
+        if (!!iconifying != (self->iconify_animation_going > 0)) {
+            /* animation was already going on in the opposite direction */
+            time = time - frame_animate_iconify_time_left(self, &now);
+        }
+        else
+            /* animation was already going in the same direction */
+            set_end = FALSE;
+    }
+    else
+        new_anim = TRUE;
+    self->iconify_animation_going = iconifying ? 1 : -1;
+
+    /* set the ending time */
+    if (set_end) {
+        self->iconify_animation_end.tv_sec = now.tv_sec;
+        self->iconify_animation_end.tv_usec = now.tv_usec;
+        g_time_val_add(&self->iconify_animation_end, time);
+    }
+
+    if (new_anim) {
+        ob_main_loop_timeout_remove_data(plugin.ob_main_loop,
+                frame_animate_iconify, self, FALSE);
+        ob_main_loop_timeout_add(plugin.ob_main_loop,
+        FRAME_ANIMATE_ICONIFY_STEP_TIME, frame_animate_iconify, self,
+                g_direct_equal, NULL);
+
+        /* do the first step */
+        frame_animate_iconify(self);
+
+        /* show it during the animation even if it is not "visible" */
+        if (!self->visible)
+            XMapWindow(plugin.ob_display, self->window);
+    }
+}
+
+gboolean frame_iconify_animating(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    return self->iconify_animation_going != 0;
+}
+
+ObFramePlugin plugin = { 0, //gpointer handler;
+        "libminimal.la", //gchar * filename;
+        "minimal", //gchar * name;
+        init, //gint (*init) (Display * display, gint screen);
+        0, frame_new, //gpointer (*frame_new) (struct _ObClient *c);
+        frame_free, //void (*frame_free) (gpointer self);
+        frame_show, //void (*frame_show) (gpointer self);
+        frame_hide, //void (*frame_hide) (gpointer self);
+        frame_adjust_theme, //void (*frame_adjust_theme) (gpointer self);
+        frame_adjust_shape, //void (*frame_adjust_shape) (gpointer self);
+        frame_adjust_area, //void (*frame_adjust_area) (gpointer self, gboolean moved, gboolean resized, gboolean fake);
+        frame_adjust_client_area, //void (*frame_adjust_client_area) (gpointer self);
+        frame_adjust_state, //void (*frame_adjust_state) (gpointer self);
+        frame_adjust_focus, //void (*frame_adjust_focus) (gpointer self, gboolean hilite);
+        frame_adjust_title, //void (*frame_adjust_title) (gpointer self);
+        frame_adjust_icon, //void (*frame_adjust_icon) (gpointer self);
+        frame_grab_client, //void (*frame_grab_client) (gpointer self);
+        frame_release_client, //void (*frame_release_client) (gpointer self);
+        //      frame_context_from_string, //ObFrameContext (*frame_context_from_string) (const gchar *name);
+        frame_context, //ObFrameContext (*frame_context) (struct _ObClient *self, Window win, gint x, gint y);
+        frame_client_gravity, //void (*frame_client_gravity) (gpointer self, gint *x, gint *y);
+        frame_frame_gravity, //void (*frame_frame_gravity) (gpointer self, gint *x, gint *y);
+        frame_rect_to_frame, //void (*frame_rect_to_frame) (gpointer self, Rect *r);
+        frame_rect_to_client, //void (*frame_rect_to_client) (gpointer self, Rect *r);
+        frame_flash_start, //void (*frame_flash_start) (gpointer self);
+        frame_flash_stop, //void (*frame_flash_stop) (gpointer self);
+        frame_begin_iconify_animation, //void (*frame_begin_iconify_animation) (gpointer self, gboolean iconifying);
+        frame_end_iconify_animation, //void (*frame_end_iconify_animation) (gpointer self);
+        frame_iconify_animating, // gboolean (*frame_iconify_animating)(gpointer p);
+        load_theme_config,
+
+        /* This fields are fill by openbox. */
+        0, //Display * ob_display;
+        0, //gint ob_screen;
+        0, //RrInstance *ob_rr_inst;
+        //     0, //RrTheme    *ob_rr_theme;
+                0, //gboolean config_theme_keepborder;
+        0, //struct _ObClient *focus_cycle_target;
+        0, //gchar *config_title_layout;
+        FALSE, //gboolean moveresize_in_progress;
+        0, //struct _ObMainLoop *ob_main_loop;
+};
+
+ObFramePlugin * get_info()
+{
+    return &plugin;
+}
diff --git a/engines/minimal/frame_minimal_plugin.h b/engines/minimal/frame_minimal_plugin.h
new file mode 100644 (file)
index 0000000..1ceec26
--- /dev/null
@@ -0,0 +1,207 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_minimal_plugin.h for the Openbox window manager
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+#ifndef FRAME_DEFAULT_PLUGIN_H_
+#define FRAME_DEFAULT_PLUGIN_H_
+
+#include "frame_minimal_config.h"
+
+#include "render/render.h"
+#include "openbox/engine_interface.h"
+
+ObFrameThemeConfig theme_config;
+
+struct _ObDefaultFrame
+{
+    // PUBLIC :
+    struct _ObClient *client;
+
+    Window window;
+
+    Strut size;
+    Rect area;
+    gint bwidth; /* border width */
+    guint decorations;
+
+    gboolean visible;
+
+    gboolean max_horz; /* when maxed some decorations are hidden */
+    gboolean max_vert; /* when maxed some decorations are hidden */
+
+    gboolean max_press;
+    gboolean close_press;
+    gboolean desk_press;
+    gboolean shade_press;
+    gboolean iconify_press;
+
+    gboolean max_hover;
+    gboolean close_hover;
+    gboolean desk_hover;
+    gboolean shade_hover;
+    gboolean iconify_hover;
+
+    gint iconify_animation_going;
+
+    /* PRIVATE: */
+    /* You are free to add what you want here */
+
+    ObStyle style;
+
+    guint functions;
+
+    Window title;
+    Window label;
+    Window max;
+    Window close;
+    Window desk;
+    Window shade;
+    Window icon;
+    Window iconify;
+    Window handle;
+    Window lgrip;
+    Window rgrip;
+
+    /* These are borders of the frame and its elements */
+    Window titleleft;
+    Window titletop;
+    Window titletopleft;
+    Window titletopright;
+    Window titleright;
+    Window titlebottom;
+    Window left;
+    Window right;
+    Window handleleft;
+    Window handletop;
+    Window handleright;
+    Window handlebottom;
+    Window lgriptop;
+    Window lgripleft;
+    Window lgripbottom;
+    Window rgriptop;
+    Window rgripright;
+    Window rgripbottom;
+    Window innerleft; /*!< For drawing the inner client border */
+    Window innertop; /*!< For drawing the inner client border */
+    Window innerright; /*!< For drawing the inner client border */
+    Window innerbottom; /*!< For drawing the inner client border */
+    Window innerblb;
+    Window innerbll;
+    Window innerbrb;
+    Window innerbrr;
+    Window backback; /*!< A colored window shown while resizing */
+    Window backfront; /*!< An undrawn-in window, to prevent flashing on unmap */
+
+    /* These are resize handles inside the titlebar */
+    Window topresize;
+    Window tltresize;
+    Window tllresize;
+    Window trtresize;
+    Window trrresize;
+
+    Colormap colormap;
+
+    RrAppearance *a_unfocused_title;
+    RrAppearance *a_focused_title;
+    RrAppearance *a_unfocused_label;
+    RrAppearance *a_focused_label;
+    RrAppearance *a_icon;
+    RrAppearance *a_unfocused_handle;
+    RrAppearance *a_focused_handle;
+
+    gint icon_on; /* if the window icon button is on */
+    gint label_on; /* if the window title is on */
+    gint iconify_on; /* if the window iconify button is on */
+    gint desk_on; /* if the window all-desktops button is on */
+    gint shade_on; /* if the window shade button is on */
+    gint max_on; /* if the window maximize button is on */
+    gint close_on; /* if the window close button is on */
+
+    gint width; /* width of the titlebar and handle */
+    gint label_width; /* width of the label in the titlebar */
+    gint icon_x; /* x-position of the window icon button */
+    gint label_x; /* x-position of the window title */
+    gint iconify_x; /* x-position of the window iconify button */
+    gint desk_x; /* x-position of the window all-desktops button */
+    gint shade_x; /* x-position of the window shade button */
+    gint max_x; /* x-position of the window maximize button */
+    gint close_x; /* x-position of the window close button */
+
+    gint cbwidth_l; /* client border width */
+    gint cbwidth_t; /* client border width */
+    gint cbwidth_r; /* client border width */
+    gint cbwidth_b; /* client border width */
+    gboolean shaded; /* decorations adjust when shaded */
+
+    /* the leftmost and rightmost elements in the titlebar */
+    ObFrameContext leftmost;
+    ObFrameContext rightmost;
+
+    gboolean focused;
+    gboolean need_render;
+
+    gboolean flashing;
+    gboolean flash_on;
+    GTimeVal flash_end;
+
+    GTimeVal iconify_animation_end;
+
+};
+
+typedef struct _ObDefaultFrame ObDefaultFrame;
+
+/* Function use for interface */
+gint init(Display *, gint);
+gpointer frame_new(struct _ObClient *c);
+void frame_free(gpointer self);
+void frame_show(gpointer self);
+void frame_hide(gpointer self);
+void frame_adjust_theme(gpointer self);
+void frame_adjust_shape(gpointer self);
+void frame_adjust_area(gpointer self, gboolean moved, gboolean resized,
+        gboolean fake);
+void frame_adjust_client_area(gpointer self);
+void frame_adjust_state(gpointer self);
+void frame_adjust_focus(gpointer self, gboolean hilite);
+void frame_adjust_title(gpointer self);
+void frame_adjust_icon(gpointer self);
+void frame_grab_client(gpointer self, GHashTable *);
+void frame_release_client(gpointer self, GHashTable *);
+ObFrameContext frame_context(gpointer, Window win, gint x, gint y);
+void frame_client_gravity(gpointer self, gint *x, gint *y);
+void frame_frame_gravity(gpointer self, gint *x, gint *y);
+void frame_rect_to_frame(gpointer self, Rect *r);
+void frame_rect_to_client(gpointer self, Rect *r);
+void frame_flash_start(gpointer self);
+void frame_flash_stop(gpointer self);
+void frame_begin_iconify_animation(gpointer self, gboolean iconifying);
+void frame_end_iconify_animation(gpointer self);
+gboolean frame_iconify_animating(gpointer _self);
+
+void flash_done(gpointer data);
+gboolean flash_timeout(gpointer data);
+
+void layout_title(ObDefaultFrame *);
+void set_theme_statics(gpointer self);
+void free_theme_statics(gpointer self);
+gboolean frame_animate_iconify(gpointer self);
+void frame_adjust_cursors(gpointer self);
+
+/* Global for renderframe.c only */
+extern ObFramePlugin plugin;
+#define OBDEFAULTFRAME(x) ((ObDefaultFrame *)(x))
+
+#endif /*FRAME_DEFAULT_PLUGIN_H_*/
diff --git a/engines/minimal/frame_minimal_render.c b/engines/minimal/frame_minimal_render.c
new file mode 100644 (file)
index 0000000..abfc4d6
--- /dev/null
@@ -0,0 +1,378 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_minimal_render.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#include "frame_minimal_plugin.h"
+#include "frame_minimal_render.h"
+
+#include "openbox/engine_interface.h"
+#include "openbox/openbox.h"
+#include "openbox/screen.h"
+#include "openbox/client.h"
+
+#include "render/theme.h"
+
+static void framerender_label(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_icon(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_max(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_iconify(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_desk(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_shade(ObDefaultFrame *self, RrAppearance *a);
+static void framerender_close(ObDefaultFrame *self, RrAppearance *a);
+
+void framerender_frame(gpointer _self)
+{
+    ObDefaultFrame * self = (ObDefaultFrame *) _self;
+    if (plugin.frame_iconify_animating(self))
+        return; /* delay redrawing until the animation is done */
+    if (!self->need_render)
+        return;
+    if (!self->visible)
+        return;
+    self->need_render = FALSE;
+
+    {
+        gulong px;
+
+        px = (self->focused ? RrColorPixel(theme_config.cb_focused_color)
+                : RrColorPixel(theme_config.cb_unfocused_color));
+
+        XSetWindowBackground(plugin.ob_display, self->backback, px);
+        XClearWindow(plugin.ob_display, self->backback);
+        XSetWindowBackground(plugin.ob_display, self->innerleft, px);
+        XClearWindow(plugin.ob_display, self->innerleft);
+        XSetWindowBackground(plugin.ob_display, self->innertop, px);
+        XClearWindow(plugin.ob_display, self->innertop);
+        XSetWindowBackground(plugin.ob_display, self->innerright, px);
+        XClearWindow(plugin.ob_display, self->innerright);
+        XSetWindowBackground(plugin.ob_display, self->innerbottom, px);
+        XClearWindow(plugin.ob_display, self->innerbottom);
+        XSetWindowBackground(plugin.ob_display, self->innerbll, px);
+        XClearWindow(plugin.ob_display, self->innerbll);
+        XSetWindowBackground(plugin.ob_display, self->innerbrr, px);
+        XClearWindow(plugin.ob_display, self->innerbrr);
+        XSetWindowBackground(plugin.ob_display, self->innerblb, px);
+        XClearWindow(plugin.ob_display, self->innerblb);
+        XSetWindowBackground(plugin.ob_display, self->innerbrb, px);
+        XClearWindow(plugin.ob_display, self->innerbrb);
+
+        px
+                = (self->focused ? RrColorPixel(theme_config.frame_focused_border_color)
+                        : RrColorPixel(theme_config.frame_unfocused_border_color));
+
+        XSetWindowBackground(plugin.ob_display, self->left, px);
+        XClearWindow(plugin.ob_display, self->left);
+        XSetWindowBackground(plugin.ob_display, self->right, px);
+        XClearWindow(plugin.ob_display, self->right);
+
+        XSetWindowBackground(plugin.ob_display, self->titleleft, px);
+        XClearWindow(plugin.ob_display, self->titleleft);
+        XSetWindowBackground(plugin.ob_display, self->titletop, px);
+        XClearWindow(plugin.ob_display, self->titletop);
+        XSetWindowBackground(plugin.ob_display, self->titletopleft, px);
+        XClearWindow(plugin.ob_display, self->titletopleft);
+        XSetWindowBackground(plugin.ob_display, self->titletopright, px);
+        XClearWindow(plugin.ob_display, self->titletopright);
+        XSetWindowBackground(plugin.ob_display, self->titleright, px);
+        XClearWindow(plugin.ob_display, self->titleright);
+
+        XSetWindowBackground(plugin.ob_display, self->handleleft, px);
+        XClearWindow(plugin.ob_display, self->handleleft);
+        XSetWindowBackground(plugin.ob_display, self->handletop, px);
+        XClearWindow(plugin.ob_display, self->handletop);
+        XSetWindowBackground(plugin.ob_display, self->handleright, px);
+        XClearWindow(plugin.ob_display, self->handleright);
+        XSetWindowBackground(plugin.ob_display, self->handlebottom, px);
+        XClearWindow(plugin.ob_display, self->handlebottom);
+
+        XSetWindowBackground(plugin.ob_display, self->lgripleft, px);
+        XClearWindow(plugin.ob_display, self->lgripleft);
+        XSetWindowBackground(plugin.ob_display, self->lgriptop, px);
+        XClearWindow(plugin.ob_display, self->lgriptop);
+        XSetWindowBackground(plugin.ob_display, self->lgripbottom, px);
+        XClearWindow(plugin.ob_display, self->lgripbottom);
+
+        XSetWindowBackground(plugin.ob_display, self->rgripright, px);
+        XClearWindow(plugin.ob_display, self->rgripright);
+        XSetWindowBackground(plugin.ob_display, self->rgriptop, px);
+        XClearWindow(plugin.ob_display, self->rgriptop);
+        XSetWindowBackground(plugin.ob_display, self->rgripbottom, px);
+        XClearWindow(plugin.ob_display, self->rgripbottom);
+
+        /* don't use the separator color for shaded windows */
+        if (!self->client->shaded)
+            px
+                    = (self->focused ? RrColorPixel(theme_config.title_separator_focused_color)
+                            : RrColorPixel(theme_config.title_separator_unfocused_color));
+
+        XSetWindowBackground(plugin.ob_display, self->titlebottom, px);
+        XClearWindow(plugin.ob_display, self->titlebottom);
+    }
+
+    if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
+        RrAppearance *t, *l, *m, *n, *i, *d, *s, *c, *clear;
+        if (self->focused) {
+
+            t = self->a_focused_title;
+            l = self->a_focused_label;
+
+            m
+                    = (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE) ? theme_config.a_disabled_focused_max
+                            : (self->client->max_vert || self->client->max_horz ? (self->max_press ? theme_config.a_toggled_focused_pressed_max
+                                    : (self->max_hover ? theme_config.a_toggled_hover_focused_max
+                                            : theme_config.a_toggled_focused_unpressed_max))
+                                    : (self->max_press ? theme_config.a_focused_pressed_max
+                                            : (self->max_hover ? theme_config.a_hover_focused_max
+                                                    : theme_config.a_focused_unpressed_max))));
+            n = self->a_icon;
+            i
+                    = (!(self->decorations & OB_FRAME_DECOR_ICONIFY) ? theme_config.a_disabled_focused_iconify
+                            : (self->iconify_press ? theme_config.a_focused_pressed_iconify
+                                    : (self->iconify_hover ? theme_config.a_hover_focused_iconify
+                                            : theme_config.a_focused_unpressed_iconify)));
+            d
+                    = (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS) ? theme_config.a_disabled_focused_desk
+                            : (self->client->desktop == DESKTOP_ALL ? (self->desk_press ? theme_config.a_toggled_focused_pressed_desk
+                                    : (self->desk_hover ? theme_config.a_toggled_hover_focused_desk
+                                            : theme_config.a_toggled_focused_unpressed_desk))
+                                    : (self->desk_press ? theme_config.a_focused_pressed_desk
+                                            : (self->desk_hover ? theme_config.a_hover_focused_desk
+                                                    : theme_config.a_focused_unpressed_desk))));
+            s
+                    = (!(self->decorations & OB_FRAME_DECOR_SHADE) ? theme_config.a_disabled_focused_shade
+                            : (self->client->shaded ? (self->shade_press ? theme_config.a_toggled_focused_pressed_shade
+                                    : (self->shade_hover ? theme_config.a_toggled_hover_focused_shade
+                                            : theme_config.a_toggled_focused_unpressed_shade))
+                                    : (self->shade_press ? theme_config.a_focused_pressed_shade
+                                            : (self->shade_hover ? theme_config.a_hover_focused_shade
+                                                    : theme_config.a_focused_unpressed_shade))));
+            c
+                    = (!(self->decorations & OB_FRAME_DECOR_CLOSE) ? theme_config.a_disabled_focused_close
+                            : (self->close_press ? theme_config.a_focused_pressed_close
+                                    : (self->close_hover ? theme_config.a_hover_focused_close
+                                            : theme_config.a_focused_unpressed_close)));
+        }
+        else {
+            t = self->a_unfocused_title;
+            l = self->a_unfocused_label;
+            m
+                    = (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE) ? theme_config.a_disabled_unfocused_max
+                            : (self->client->max_vert || self->client->max_horz ? (self->max_press ? theme_config.a_toggled_unfocused_pressed_max
+                                    : (self->max_hover ? theme_config.a_toggled_hover_unfocused_max
+                                            : theme_config.a_toggled_unfocused_unpressed_max))
+                                    : (self->max_press ? theme_config.a_unfocused_pressed_max
+                                            : (self->max_hover ? theme_config.a_hover_unfocused_max
+                                                    : theme_config.a_unfocused_unpressed_max))));
+            n = self->a_icon;
+            i
+                    = (!(self->decorations & OB_FRAME_DECOR_ICONIFY) ? theme_config.a_disabled_unfocused_iconify
+                            : (self->iconify_press ? theme_config.a_unfocused_pressed_iconify
+                                    : (self->iconify_hover ? theme_config.a_hover_unfocused_iconify
+                                            : theme_config.a_unfocused_unpressed_iconify)));
+            d
+                    = (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS) ? theme_config.a_disabled_unfocused_desk
+                            : (self->client->desktop == DESKTOP_ALL ? (self->desk_press ? theme_config.a_toggled_unfocused_pressed_desk
+                                    : (self->desk_hover ? theme_config.a_toggled_hover_unfocused_desk
+                                            : theme_config.a_toggled_unfocused_unpressed_desk))
+                                    : (self->desk_press ? theme_config.a_unfocused_pressed_desk
+                                            : (self->desk_hover ? theme_config.a_hover_unfocused_desk
+                                                    : theme_config.a_unfocused_unpressed_desk))));
+            s
+                    = (!(self->decorations & OB_FRAME_DECOR_SHADE) ? theme_config.a_disabled_unfocused_shade
+                            : (self->client->shaded ? (self->shade_press ? theme_config.a_toggled_unfocused_pressed_shade
+                                    : (self->shade_hover ? theme_config.a_toggled_hover_unfocused_shade
+                                            : theme_config.a_toggled_unfocused_unpressed_shade))
+                                    : (self->shade_press ? theme_config.a_unfocused_pressed_shade
+                                            : (self->shade_hover ? theme_config.a_hover_unfocused_shade
+                                                    : theme_config.a_unfocused_unpressed_shade))));
+            c
+                    = (!(self->decorations & OB_FRAME_DECOR_CLOSE) ? theme_config.a_disabled_unfocused_close
+                            : (self->close_press ? theme_config.a_unfocused_pressed_close
+                                    : (self->close_hover ? theme_config.a_hover_unfocused_close
+                                            : theme_config.a_unfocused_unpressed_close)));
+        }
+        clear = theme_config.a_clear;
+
+        RrPaint(t, self->title, self->width, theme_config.title_height);
+
+        clear->surface.parent = t;
+        clear->surface.parenty = 0;
+
+        clear->surface.parentx = theme_config.grip_width;
+
+        RrPaint(clear, self->topresize, self->width - theme_config.grip_width
+                * 2, theme_config.paddingy + 1);
+
+        clear->surface.parentx = 0;
+
+        if (theme_config.grip_width > 0)
+            RrPaint(clear, self->tltresize, theme_config.grip_width,
+                    theme_config.paddingy + 1);
+        if (theme_config.title_height > 0)
+            RrPaint(clear, self->tllresize, theme_config.paddingx + 1,
+                    theme_config.title_height);
+
+        clear->surface.parentx = self->width - theme_config.grip_width;
+
+        if (theme_config.grip_width > 0)
+            RrPaint(clear, self->trtresize, theme_config.grip_width,
+                    theme_config.paddingy + 1);
+
+        clear->surface.parentx = self->width - (theme_config.paddingx + 1);
+
+        if (theme_config.title_height > 0)
+            RrPaint(clear, self->trrresize, theme_config.paddingx + 1,
+                    theme_config.title_height);
+
+        /* set parents for any parent relative guys */
+        l->surface.parent = t;
+        l->surface.parentx = self->label_x;
+        l->surface.parenty = theme_config.paddingy;
+
+        m->surface.parent = t;
+        m->surface.parentx = self->max_x;
+        m->surface.parenty = theme_config.paddingy + 1;
+
+        n->surface.parent = t;
+        n->surface.parentx = self->icon_x;
+        n->surface.parenty = theme_config.paddingy;
+
+        i->surface.parent = t;
+        i->surface.parentx = self->iconify_x;
+        i->surface.parenty = theme_config.paddingy + 1;
+
+        d->surface.parent = t;
+        d->surface.parentx = self->desk_x;
+        d->surface.parenty = theme_config.paddingy + 1;
+
+        s->surface.parent = t;
+        s->surface.parentx = self->shade_x;
+        s->surface.parenty = theme_config.paddingy + 1;
+
+        c->surface.parent = t;
+        c->surface.parentx = self->close_x;
+        c->surface.parenty = theme_config.paddingy + 1;
+
+        framerender_label(self, l);
+        framerender_max(self, m);
+        framerender_icon(self, n);
+        framerender_iconify(self, i);
+        framerender_desk(self, d);
+        framerender_shade(self, s);
+        framerender_close(self, c);
+    }
+
+    if (self->decorations & OB_FRAME_DECOR_HANDLE && theme_config.handle_height
+            > 0) {
+        RrAppearance *h, *g;
+
+        h = (self->focused ? self->a_focused_handle : self->a_unfocused_handle);
+
+        RrPaint(h, self->handle, self->width, theme_config.handle_height);
+
+        if (self->decorations & OB_FRAME_DECOR_GRIPS) {
+            g = (self->focused ? theme_config.a_focused_grip
+                    : theme_config.a_unfocused_grip);
+
+            if (g->surface.grad == RR_SURFACE_PARENTREL)
+                g->surface.parent = h;
+
+            g->surface.parentx = 0;
+            g->surface.parenty = 0;
+
+            RrPaint(g, self->lgrip, theme_config.grip_width,
+                    theme_config.handle_height);
+
+            g->surface.parentx = self->width - theme_config.grip_width;
+            g->surface.parenty = 0;
+
+            RrPaint(g, self->rgrip, theme_config.grip_width,
+                    theme_config.handle_height);
+        }
+    }
+
+    XFlush(plugin.ob_display);
+}
+
+static void framerender_label(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->label_on)
+        return;
+    /* set the texture's text! */
+    a->texture[0].data.text.string = self->client->title;
+    RrPaint(a, self->label, self->label_width, theme_config.label_height);
+}
+
+static void framerender_icon(ObDefaultFrame *self, RrAppearance *a)
+{
+    const ObClientIcon *icon;
+
+    if (!self->icon_on)
+        return;
+
+    icon = client_icon(self->client, theme_config.button_size + 2,
+            theme_config.button_size + 2);
+    if (icon) {
+        a->texture[0].type = RR_TEXTURE_RGBA;
+        a->texture[0].data.rgba.width = icon->width;
+        a->texture[0].data.rgba.height = icon->height;
+        a->texture[0].data.rgba.alpha = 0xff;
+        a->texture[0].data.rgba.data = icon->data;
+    }
+    else
+        a->texture[0].type = RR_TEXTURE_NONE;
+
+    RrPaint(a, self->icon, theme_config.button_size + 2,
+            theme_config.button_size + 2);
+}
+
+static void framerender_max(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->max_on)
+        return;
+    RrPaint(a, self->max, theme_config.button_size, theme_config.button_size);
+}
+
+static void framerender_iconify(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->iconify_on)
+        return;
+    RrPaint(a, self->iconify, theme_config.button_size,
+            theme_config.button_size);
+}
+
+static void framerender_desk(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->desk_on)
+        return;
+    RrPaint(a, self->desk, theme_config.button_size, theme_config.button_size);
+}
+
+static void framerender_shade(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->shade_on)
+        return;
+    RrPaint(a, self->shade, theme_config.button_size, theme_config.button_size);
+}
+
+static void framerender_close(ObDefaultFrame *self, RrAppearance *a)
+{
+    if (!self->close_on)
+        return;
+    RrPaint(a, self->close, theme_config.button_size, theme_config.button_size);
+}
diff --git a/engines/minimal/frame_minimal_render.h b/engines/minimal/frame_minimal_render.h
new file mode 100644 (file)
index 0000000..7996540
--- /dev/null
@@ -0,0 +1,26 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ frame_minimal_render.h for the Openbox window manager
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#ifndef FRAME_MINIMAL_RENDER_H_
+#define __framerender_h
+
+#include "frame_minimal_plugin.h"
+
+void framerender_frame(gpointer self);
+
+#endif
index 7975d4ebd1f1996f5b61613e3581b942b9bdd5e4..a4e0a1286eea01e61a04b368d2555a338a2a5e31 100644 (file)
@@ -17,7 +17,7 @@
 */
 
 #include "misc.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "obt/parse.h"
 
 #include <glib.h>
index a37e3a26e093606100ea82581e368bcf7bb4fff1..fdc01ca8a0b4d31359b5197424674d62f022336b 100644 (file)
@@ -1,7 +1,7 @@
 #include "openbox/actions.h"
 #include "openbox/misc.h"
 #include "openbox/client.h"
-#include "openbox/frame.h"
+#include "openbox/engine_interface.h"
 #include "openbox/screen.h"
 #include <glib.h>
 
index 63a7fbcd20d10c235282ce5e6fe99888e9dec06b..dce885a3a95988599b37ff9bfa97521534140a49 100644 (file)
@@ -1,7 +1,7 @@
 #include "openbox/actions.h"
 #include "openbox/misc.h"
 #include "openbox/client.h"
-#include "openbox/frame.h"
+#include "openbox/engine_interface.h"
 #include "openbox/screen.h"
 #include "openbox/focus.h"
 #include <glib.h>
index ccdff545d5702d02c4a470e98df31b3249c7e823..3f72bac7394cfbcd8d2270195573477cc8b1236f 100644 (file)
@@ -1,7 +1,7 @@
 #include "openbox/actions.h"
 #include "openbox/client.h"
 #include "openbox/screen.h"
-#include "openbox/frame.h"
+#include "openbox/engine_interface.h"
 #include <stdlib.h> /* for atoi */
 
 typedef struct {
index d355dafdc5c30ea0535c1b239a2a62275899e364..faeeb0fedc2e05d1d1db5816d7561ac05c78ca7f 100644 (file)
@@ -1,7 +1,9 @@
 #include "openbox/actions.h"
 #include "openbox/client.h"
 #include "openbox/screen.h"
-#include "openbox/frame.h"
+#include "openbox/engine_interface.h"
+#include "openbox/openbox.h"
+
 #include <stdlib.h> /* for atoi */
 
 enum {
@@ -124,27 +126,29 @@ static gboolean run_func(ObActionsData *data, gpointer options)
         y = c->area.y;
         client_try_configure(c, &x, &y, &w, &h, &lw, &lh, TRUE);
 
+        Strut c_size = render_plugin->frame_get_size(c->frame);
+        Rect c_area = render_plugin->frame_get_window_area(c->frame);
         /* get the frame's size */
-        w += c->frame->size.left + c->frame->size.right;
-        h += c->frame->size.top + c->frame->size.bottom;
+        w += c_size.left + c_size.right;
+        h += c_size.top + c_size.bottom;
 
         x = o->x;
         if (o->xcenter) x = (area->width - w) / 2;
-        else if (x == G_MININT) x = c->frame->area.x - carea->x;
+        else if (x == G_MININT) x = c_area.x - carea->x;
         else if (o->xopposite) x = area->width - w;
         x += area->x;
 
         y = o->y;
         if (o->ycenter) y = (area->height - h) / 2;
-        else if (y == G_MININT) y = c->frame->area.y - carea->y;
+        else if (y == G_MININT) y = c_area.y - carea->y;
         else if (o->yopposite) y = area->height - h;
         y += area->y;
 
         /* get the client's size back */
-        w -= c->frame->size.left + c->frame->size.right;
-        h -= c->frame->size.top + c->frame->size.bottom;
+        w -= c_size.left + c_size.right;
+        h -= c_size.top + c_size.bottom;
 
-        frame_frame_gravity(c->frame, &x, &y); /* get the client coords */
+        frame_frame_gravity(c, &x, &y); /* get the client coords */
         client_try_configure(c, &x, &y, &w, &h, &lw, &lh, TRUE);
         /* force it on screen if its moving to another monitor */
         client_find_onscreen(c, &x, &y, w, h, mon != cmon);
index f360ddd03da63309ea0da0ddc26a989b350a7e8e..7875e1315a822be29f0628b4b3fa4fdb500ff71f 100644 (file)
@@ -1,7 +1,7 @@
 #include "openbox/actions.h"
 #include "openbox/misc.h"
 #include "openbox/client.h"
-#include "openbox/frame.h"
+#include "openbox/engine_interface.h"
 #include "openbox/geom.h"
 #include <glib.h>
 
index 47f45f5b2de4aadcfb3dbcc88870d67ae86bf701..3590c1d1d1a155b87df6fa3b64ff883597e9b489 100644 (file)
@@ -1,7 +1,10 @@
 #include "openbox/actions.h"
 #include "openbox/moveresize.h"
 #include "openbox/client.h"
-#include "openbox/frame.h"
+#include "openbox/engine_interface.h"
+
+#include "openbox/openbox.h"
+
 #include "obt/prop.h"
 
 typedef struct {
@@ -64,21 +67,23 @@ static gboolean run_func(ObActionsData *data, gpointer options)
         ObClient *c = data->client;
         guint32 corner;
 
+        Strut c_size = render_plugin->frame_get_size(c->frame);
+        Rect c_area = render_plugin->frame_get_window_area(c->frame);
         if (!data->button)
             corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD);
         else if (o->corner_specified)
             corner = o->corner; /* it was specified in the binding */
         else
             corner = pick_corner(data->x, data->y,
-                                 c->frame->area.x, c->frame->area.y,
+                                 c_area.x, c_area.y,
                                  /* use the client size because the frame
                                     can be differently sized (shaded
                                     windows) and we want this based on the
                                     clients size */
-                                 c->area.width + c->frame->size.left +
-                                 c->frame->size.right,
-                                 c->area.height + c->frame->size.top +
-                                 c->frame->size.bottom, c->shaded);
+                                 c->area.width + c_size.left +
+                                 c_size.right,
+                                 c->area.height + c_size.top +
+                                 c_size.bottom, c->shaded);
 
         moveresize_start(c, data->x, data->y, data->button, corner);
     }
index 5742e1fcff0a963e589aa370de47e6d11377c135..0887e18607471e176172a52816ad9bc9b4a02be5 100644 (file)
@@ -1,7 +1,7 @@
 #include "openbox/actions.h"
 #include "openbox/client.h"
 #include "openbox/screen.h"
-#include "openbox/frame.h"
+#include "openbox/engine_interface.h"
 #include <stdlib.h> /* for atoi */
 
 typedef struct {
index dd1f5e72b92c8535f1e29516d5f82a1b2ed13f45..c6b57814c7eda9663be76e6cf21ff8f2822d0e8c 100644 (file)
@@ -25,7 +25,7 @@
 #include "moveresize.h"
 #include "ping.h"
 #include "place.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "session.h"
 #include "event.h"
 #include "grab.h"
@@ -42,6 +42,7 @@
 #include "gettext.h"
 #include "obt/display.h"
 #include "obt/prop.h"
+#include "window.h"
 
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
@@ -228,9 +229,8 @@ void client_manage(Window window, ObPrompt *prompt)
         XChangeSaveSet(obt_display, window, SetModeInsert);
 
     /* create the decoration frame for the client window */
-    self->frame = frame_new(self);
-
-    frame_grab_client(self->frame);
+    self->frame = render_plugin->frame_new(self);
+    render_plugin->frame_grab(self->frame, window_map);
 
     /* we've grabbed everything and set everything that we need to at mapping
        time now */
@@ -274,8 +274,13 @@ void client_manage(Window window, ObPrompt *prompt)
 
     /* adjust the frame to the client's size before showing or placing
        the window */
-    frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
-    frame_adjust_client_area(self->frame);
+    render_plugin->frame_set_client_area (self->frame, self->area);
+    render_plugin->frame_set_hover_flag (self->frame, OB_BUTTON_NONE);
+    render_plugin->frame_set_press_flag (self->frame, OB_BUTTON_NONE);
+    render_plugin->frame_set_is_focus (self->frame, FALSE);
+    render_plugin->frame_set_decorations (self->frame, self->decorations);
+    render_plugin->frame_update_layout (self->frame, FALSE, TRUE);
+    render_plugin->frame_update_skin (self->frame);
 
     /* where the frame was placed is where the window was originally */
     place = self->area;
@@ -355,9 +360,10 @@ void client_manage(Window window, ObPrompt *prompt)
     {
         Rect *a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &place);
 
+        Strut size = render_plugin->frame_get_size(self->frame);
         /* get the size of the frame */
-        place.width += self->frame->size.left + self->frame->size.right;
-        place.height += self->frame->size.top + self->frame->size.bottom;
+        place.width += size.left + size.right;
+        place.height += size.top + size.bottom;
 
         /* fit the window inside the area */
         place.width = MIN(place.width, a->width);
@@ -366,8 +372,8 @@ void client_manage(Window window, ObPrompt *prompt)
         ob_debug("setting window size to %dx%d", place.width, place.height);
 
         /* get the size of the client back */
-        place.width -= self->frame->size.left + self->frame->size.right;
-        place.height -= self->frame->size.top + self->frame->size.bottom;
+        place.width -= size.left + size.right;
+        place.height -= size.top + size.bottom;
 
         g_free(a);
     }
@@ -404,7 +410,7 @@ void client_manage(Window window, ObPrompt *prompt)
                       self->window, map_time, launch_time,
                       event_last_user_time);
 
-        if (menu_frame_visible || moveresize_in_progress) {
+        if (menu_frame_visible || render_plugin->moveresize_in_progress) {
             activate = FALSE;
             raise = TRUE;
             ob_debug_type(OB_DEBUG_FOCUS,
@@ -551,7 +557,7 @@ void client_manage(Window window, ObPrompt *prompt)
     g_free(settings);
 
     ob_debug("Managed window 0x%lx plate 0x%x (%s)",
-             window, self->frame->window, self->class);
+             window, render_plugin->frame_get_window(self->frame), self->class);
 }
 
 
@@ -575,12 +581,13 @@ ObClient *client_fake_manage(Window window)
     client_setup_decor_and_functions(self, FALSE);
 
     /* create the decoration frame for the client window and adjust its size */
-    self->frame = frame_new(self);
-    frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
+    self->frame = render_plugin->frame_new(self);
+    render_plugin->frame_set_decorations (self->frame, self->decorations);
+    render_plugin->frame_update_layout (self->frame, FALSE, FALSE);
 
     ob_debug("gave extents left %d right %d top %d bottom %d",
-             self->frame->size.left, self->frame->size.right,
-             self->frame->size.top, self->frame->size.bottom);
+             render_plugin->frame_get_size(self->frame).left, render_plugin->frame_get_size(self->frame).right,
+             render_plugin->frame_get_size(self->frame).top, render_plugin->frame_get_size(self->frame).bottom);
 
     /* free the ObAppSettings shallow copy */
     g_free(settings);
@@ -601,7 +608,7 @@ void client_unmanage(ObClient *self)
     gulong ignore_start;
 
     ob_debug("Unmanaging window: 0x%x plate 0x%x (%s) (%s)",
-             self->window, self->frame->window,
+             self->window, render_plugin->frame_get_window(self->frame),
              self->class, self->title ? self->title : "");
 
     g_assert(self != NULL);
@@ -614,7 +621,7 @@ void client_unmanage(ObClient *self)
     if (!config_focus_under_mouse)
         ignore_start = event_start_ignore_all_enters();
 
-    frame_hide(self->frame);
+    self->ignore_unmaps += render_plugin->frame_hide(self->frame);
     /* flush to send the hide to the server quickly */
     XFlush(obt_display);
 
@@ -700,8 +707,8 @@ void client_unmanage(ObClient *self)
     }
 
     /* reparent the window out of the frame, and free the frame */
-    frame_release_client(self->frame);
-    frame_free(self->frame);
+    render_plugin->frame_ungrab(self->frame, window_map);
+    render_plugin->frame_free(self->frame);
     self->frame = NULL;
 
     if (ob_state() != OB_STATE_EXITING) {
@@ -750,7 +757,7 @@ void client_fake_unmanage(ObClient *self)
 {
     /* this is all that got allocated to get the decorations */
 
-    frame_free(self->frame);
+    render_plugin->frame_free(self->frame);
     g_free(self);
 }
 
@@ -877,6 +884,9 @@ static void client_restore_session_state(ObClient *self)
     self->max_horz = self->session->max_horz;
     self->max_vert = self->session->max_vert;
     self->undecorated = self->session->undecorated;
+
+    render_plugin->frame_set_is_max_horz (self->frame, self->max_horz);
+    render_plugin->frame_set_is_max_vert (self->frame, self->max_vert);
 }
 
 static gboolean client_restore_session_stacking(ObClient *self)
@@ -927,14 +937,16 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
     gboolean found_mon;
 
     RECT_SET(desired, *x, *y, w, h);
-    frame_rect_to_frame(self->frame, &desired);
+    frame_rect_to_frame(self, &desired);
 
     /* get where the frame would be */
-    frame_client_gravity(self->frame, x, y);
+    frame_client_gravity(self, x, y);
+
+    Strut size = render_plugin->frame_get_size(self->frame);
 
     /* get the requested size of the window with decorations */
-    fw = self->frame->size.left + w + self->frame->size.right;
-    fh = self->frame->size.top + h + self->frame->size.bottom;
+    fw = size.left + w + size.right;
+    fh = size.top + h + size.bottom;
 
     /* If rudeness wasn't requested, then still be rude in a given direction
        if the client is not moving, only resizing in that direction */
@@ -943,9 +955,10 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
         Point newtl, newtr, newbl, newbr;
         gboolean stationary_l, stationary_r, stationary_t, stationary_b;
 
-        POINT_SET(oldtl, self->frame->area.x, self->frame->area.y);
-        POINT_SET(oldbr, self->frame->area.x + self->frame->area.width - 1,
-                  self->frame->area.y + self->frame->area.height - 1);
+        Rect area = render_plugin->frame_get_window_area(self->frame);
+        POINT_SET(oldtl, area.x, area.y);
+        POINT_SET(oldbr, area.x + area.width - 1,
+                  area.y + area.height - 1);
         POINT_SET(oldtr, oldbr.x, oldtl.y);
         POINT_SET(oldbl, oldtl.x, oldbr.y);
 
@@ -1031,7 +1044,7 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
     }
 
     /* get where the client should be */
-    frame_frame_gravity(self->frame, x, y);
+    frame_frame_gravity(self, x, y);
 
     return ox != *x || oy != *y;
 }
@@ -1797,6 +1810,8 @@ static void client_change_allowed_actions(ObClient *self)
                                                          self->max_vert)) {
         if (self->frame) client_maximize(self, FALSE, 0);
         else self->max_vert = self->max_horz = FALSE;
+        render_plugin->frame_set_is_max_horz (self->frame, self->max_horz);
+        render_plugin->frame_set_is_max_vert (self->frame, self->max_vert);
     }
 }
 
@@ -1931,7 +1946,7 @@ void client_update_title(ObClient *self)
     self->title = visible;
 
     if (self->frame)
-        frame_adjust_title(self->frame);
+    render_plugin->frame_update_layout (self->frame, FALSE, FALSE);
 
     /* update the icon title */
     data = NULL;
@@ -2152,9 +2167,10 @@ void client_update_icons(ObClient *self)
         OBT_PROP_SETA32(self->window, NET_WM_ICON, CARDINAL, data, 48*48+2);
         g_free(data);
     } else if (self->frame)
+        render_plugin->frame_update_skin (self->frame);
         /* don't draw the icon empty if we're just setting one now anyways,
            we'll get the property change any second */
-        frame_adjust_icon(self->frame);
+        //frame_adjust_icon(self->frame);
 }
 
 void client_update_icon_geometry(ObClient *self)
@@ -2332,7 +2348,7 @@ static void client_change_state(ObClient *self)
     OBT_PROP_SETA32(self->window, NET_WM_STATE, ATOM, netstate, num);
 
     if (self->frame)
-        frame_adjust_state(self->frame);
+    render_plugin->frame_update_layout (self->frame, FALSE, FALSE);
 }
 
 ObClient *client_search_focus_tree(ObClient *self)
@@ -2514,7 +2530,7 @@ gboolean client_show(ObClient *self)
            should be going to something under the window */
         mouse_replay_pointer();
 
-        frame_show(self->frame);
+        render_plugin->frame_show(self->frame);
         show = TRUE;
 
         /* According to the ICCCM (sec 4.1.3.1) when a window is not visible,
@@ -2559,7 +2575,7 @@ gboolean client_hide(ObClient *self)
            should be going to the window */
         mouse_replay_pointer();
 
-        frame_hide(self->frame);
+        self->ignore_unmaps += render_plugin->frame_hide(self->frame);
         hide = TRUE;
 
         /* According to the ICCCM (sec 4.1.3.1) when a window is not visible,
@@ -2640,6 +2656,7 @@ static void client_apply_startup_state(ObClient *self,
     /* save the area, and make it where it should be for the premax stuff */
     oldarea = self->area;
     RECT_SET(self->area, x, y, w, h);
+    render_plugin->frame_set_client_area (self->frame, self->area);
 
     /* apply the states. these are in a carefully crafted order.. */
 
@@ -2672,6 +2689,11 @@ static void client_apply_startup_state(ObClient *self,
        not, so this needs to be called even if we have fullscreened/maxed
     */
     self->area = oldarea;
+    render_plugin->frame_set_client_area (self->frame, self->area);
+    render_plugin->frame_set_decorations (self->frame, self->decorations);
+    render_plugin->frame_update_layout (self->frame, FALSE, FALSE);
+    render_plugin->frame_set_is_max_horz (self->frame, self->max_horz);
+    render_plugin->frame_set_is_max_vert (self->frame, self->max_vert);
     client_configure(self, x, y, w, h, FALSE, TRUE, FALSE);
 
     /* set the desktop hint, to make sure that it always exists */
@@ -2749,15 +2771,16 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
                           gboolean user)
 {
     Rect desired = {*x, *y, *w, *h};
-    frame_rect_to_frame(self->frame, &desired);
+    frame_rect_to_frame(self, &desired);
 
     /* make the frame recalculate its dimentions n shit without changing
        anything visible for real, this way the constraints below can work with
        the updated frame dimensions. */
-    frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
+    render_plugin->frame_set_decorations (self->frame, self->decorations);
+    render_plugin->frame_update_layout (self->frame, FALSE, TRUE);
 
     /* gets the frame's position */
-    frame_client_gravity(self->frame, x, y);
+    frame_client_gravity(self, x, y);
 
     /* these positions are frame positions, not client positions */
 
@@ -2787,14 +2810,15 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
         a = screen_area(self->desktop, i,
                         (self->max_horz && self->max_vert ? NULL : &desired));
 
+        Strut size = render_plugin->frame_get_size(self->frame);
         /* set the size and position if maximized */
         if (self->max_horz) {
             *x = a->x;
-            *w = a->width - self->frame->size.left - self->frame->size.right;
+            *w = a->width - size.left - size.right;
         }
         if (self->max_vert) {
             *y = a->y;
-            *h = a->height - self->frame->size.top - self->frame->size.bottom;
+            *h = a->height - size.top - size.bottom;
         }
 
         user = FALSE; /* ignore if the client can't be moved/resized when it
@@ -2804,7 +2828,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h,
     }
 
     /* gets the client's position */
-    frame_frame_gravity(self->frame, x, y);
+    frame_frame_gravity(self, x, y);
 
     /* work within the prefered sizes given by the window */
     if (!(*w == self->area.width && *h == self->area.height)) {
@@ -2921,11 +2945,14 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
     gboolean send_resize_client;
     gboolean moved = FALSE, resized = FALSE, rootmoved = FALSE;
     gboolean fmoved, fresized;
-    guint fdecor = self->frame->decorations;
-    gboolean fhorz = self->frame->max_horz;
-    gboolean fvert = self->frame->max_vert;
+    guint fdecor = render_plugin->frame_get_decorations(self->frame);
+    gboolean fhorz = render_plugin->frame_is_max_horz(self->frame);
+    gboolean fvert = render_plugin->frame_is_max_vert(self->frame);
     gint logicalw, logicalh;
 
+    Strut size = render_plugin->frame_get_size(self->frame);
+    Rect area = render_plugin->frame_get_window_area(self->frame);
+
     /* find the new x, y, width, and height (and logical size) */
     client_try_configure(self, &x, &y, &w, &h, &logicalw, &logicalh, user);
 
@@ -2939,9 +2966,11 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
 
     oldw = self->area.width;
     oldh = self->area.height;
-    oldframe = self->frame->area;
+    oldframe = render_plugin->frame_get_window_area(self->frame);
     RECT_SET(self->area, x, y, w, h);
 
+    render_plugin->frame_set_client_area (self->frame, self->area);
+
     /* for app-requested resizes, always resize if 'resized' is true.
        for user-requested ones, only resize if final is true, or when
        resizing in redraw mode */
@@ -2951,10 +2980,8 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
 
     /* if the client is enlarging, then resize the client before the frame */
     if (send_resize_client && (w > oldw || h > oldh)) {
-        XMoveResizeWindow(obt_display, self->window,
-                          self->frame->size.left, self->frame->size.top,
-                          MAX(w, oldw), MAX(h, oldh));
-        frame_adjust_client_area(self->frame);
+        render_plugin->frame_set_decorations (self->frame, self->decorations);
+        render_plugin->frame_update_layout (self->frame, FALSE, FALSE);
     }
 
     /* find the frame's dimensions and move/resize it */
@@ -2978,7 +3005,8 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
            would change what window gets the event */
         mouse_replay_pointer();
 
-        frame_adjust_area(self->frame, fmoved, fresized, FALSE);
+        render_plugin->frame_set_decorations (self->frame, self->decorations);
+        render_plugin->frame_update_layout (self->frame, TRUE, FALSE);
 
         if (!user)
             event_end_ignore_all_enters(ignore_start);
@@ -2990,9 +3018,9 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
         /* we have reset the client to 0 border width, so don't include
            it in these coords */
         POINT_SET(self->root_pos,
-                  self->frame->area.x + self->frame->size.left -
+                  area.x + size.left -
                   self->border_width,
-                  self->frame->area.y + self->frame->size.top -
+                  area.y + size.top -
                   self->border_width);
         if (self->root_pos.x != oldrx || self->root_pos.y != oldry)
             rootmoved = TRUE;
@@ -3042,16 +3070,16 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
        in the direction that is growing
      */
     if (send_resize_client && (w <= oldw || h <= oldh)) {
-        frame_adjust_client_area(self->frame);
-        XMoveResizeWindow(obt_display, self->window,
-                          self->frame->size.left, self->frame->size.top, w, h);
+      render_plugin->frame_set_decorations (self->frame, self->decorations);
+      render_plugin->frame_update_layout (self->frame, FALSE, FALSE);
     }
 
     XFlush(obt_display);
 
     /* if it moved between monitors, then this can affect the stacking
        layer of this window or others - for fullscreen windows */
-    if (screen_find_monitor(&self->frame->area) !=
+    Rect current_frame = render_plugin->frame_get_window_area(self->frame);
+    if (screen_find_monitor(&current_frame) !=
         screen_find_monitor(&oldframe))
     {
         client_calc_layer(self);
@@ -3157,7 +3185,7 @@ static void client_iconify_recursive(ObClient *self,
     if (changed) {
         client_change_state(self);
         if (config_animate_iconify && !hide_animation)
-            frame_begin_iconify_animation(self->frame, iconic);
+        render_plugin->frame_begin_iconify_animation(self->frame, iconic);
         /* do this after starting the animation so it doesn't flash */
         client_showhide(self);
     }
@@ -3243,6 +3271,9 @@ void client_maximize(ObClient *self, gboolean max, gint dir)
     if (dir == 0 || dir == 2) /* vert */
         self->max_vert = max;
 
+    render_plugin->frame_set_is_max_horz (self->frame, self->max_horz);
+    render_plugin->frame_set_is_max_vert (self->frame, self->max_vert);
+
     client_change_state(self); /* change the state hints on the client */
 
     client_setup_decor_and_functions(self, FALSE);
@@ -3259,7 +3290,8 @@ void client_shade(ObClient *self, gboolean shade)
     client_change_state(self);
     client_change_wm_state(self); /* the window is being hidden/shown */
     /* resize the frame to just the titlebar */
-    frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
+    render_plugin->frame_set_is_shaded (self->frame, self->shaded);
+    render_plugin->frame_update_layout(self->frame, FALSE, FALSE);
 }
 
 static void client_ping_event(ObClient *self, gboolean dead)
@@ -3386,9 +3418,9 @@ void client_hilite(ObClient *self, gboolean hilite)
     self->demands_attention = hilite && !client_focused(self);
     if (self->frame != NULL) { /* if we're mapping, just set the state */
         if (self->demands_attention)
-            frame_flash_start(self->frame);
+        render_plugin->frame_flash_start(self->frame);
         else
-            frame_flash_stop(self->frame);
+        render_plugin->frame_flash_stop(self->frame);
         client_change_state(self);
     }
 }
@@ -3411,7 +3443,8 @@ static void client_set_desktop_recursive(ObClient *self,
         self->desktop = target;
         OBT_PROP_SET32(self->window, NET_WM_DESKTOP, CARDINAL, target);
         /* the frame can display the current desktop state */
-        frame_adjust_state(self->frame);
+        render_plugin->frame_set_decorations (self->frame, self->decorations);
+        render_plugin->frame_update_layout(self->frame, FALSE, FALSE);
         /* 'move' the window to the new desktop */
         if (!donthide)
             client_hide(self);
@@ -3685,7 +3718,7 @@ gboolean client_can_focus(ObClient *self)
     /* choose the correct target */
     self = client_focus_target(self);
 
-    if (!self->frame->visible)
+    if (!render_plugin->frame_is_visible(self->frame))
         return FALSE;
 
     if (!(self->can_focus || self->focus_notify))
@@ -3771,7 +3804,7 @@ static void client_present(ObClient *self, gboolean here, gboolean raise,
             client_set_desktop(self, screen_desktop, FALSE, TRUE);
         else
             screen_set_desktop(self->desktop, FALSE);
-    } else if (!self->frame->visible)
+    } else if (!render_plugin->frame_is_visible(self->frame))
         /* if its not visible for other reasons, then don't mess
            with it */
         return;
@@ -3908,7 +3941,8 @@ void client_set_undecorated(ObClient *self, gboolean undecorated)
 
 guint client_monitor(ObClient *self)
 {
-    return screen_find_monitor(&self->frame->area);
+    Rect area = render_plugin->frame_get_window_area(self->frame);
+    return screen_find_monitor(&area);
 }
 
 ObClient *client_direct_parent(ObClient *self)
@@ -4103,10 +4137,13 @@ void client_find_edge_directional(ObClient *self, ObDirection dir,
     Rect dock_area;
     gint edge;
 
+    Strut size = render_plugin->frame_get_size(self->frame);
+    Rect area = render_plugin->frame_get_window_area(self->frame);
+
     a = screen_area(self->desktop, SCREEN_AREA_ALL_MONITORS,
-                    &self->frame->area);
+                    &area);
     mon = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR,
-                      &self->frame->area);
+                      &area);
 
     switch (dir) {
     case OB_DIRECTION_NORTH:
@@ -4154,7 +4191,7 @@ void client_find_edge_directional(ObClient *self, ObDirection dir,
 
         ob_debug("trying window %s", cur->title);
 
-        detect_edge(cur->frame->area, dir, my_head, my_size, my_edge_start,
+        detect_edge(render_plugin->frame_get_window_area(cur->frame), dir, my_head, my_size, my_edge_start,
                     my_edge_size, dest, near_edge);
     }
     dock_get_area(&dock_area);
@@ -4171,30 +4208,33 @@ void client_find_move_directional(ObClient *self, ObDirection dir,
     gint e, e_start, e_size;
     gboolean near;
 
+
+    Rect area = render_plugin->frame_get_window_area(self->frame);
+
     switch (dir) {
     case OB_DIRECTION_EAST:
-        head = RECT_RIGHT(self->frame->area);
-        size = self->frame->area.width;
-        e_start = RECT_TOP(self->frame->area);
-        e_size = self->frame->area.height;
+        head = RECT_RIGHT(area);
+        size = area.width;
+        e_start = RECT_TOP(area);
+        e_size = area.height;
         break;
     case OB_DIRECTION_WEST:
-        head = RECT_LEFT(self->frame->area);
-        size = self->frame->area.width;
-        e_start = RECT_TOP(self->frame->area);
-        e_size = self->frame->area.height;
+        head = RECT_LEFT(area);
+        size = area.width;
+        e_start = RECT_TOP(area);
+        e_size = area.height;
         break;
     case OB_DIRECTION_NORTH:
-        head = RECT_TOP(self->frame->area);
-        size = self->frame->area.height;
-        e_start = RECT_LEFT(self->frame->area);
-        e_size = self->frame->area.width;
+        head = RECT_TOP(area);
+        size = area.height;
+        e_start = RECT_LEFT(area);
+        e_size = area.width;
         break;
     case OB_DIRECTION_SOUTH:
-        head = RECT_BOTTOM(self->frame->area);
-        size = self->frame->area.height;
-        e_start = RECT_LEFT(self->frame->area);
-        e_size = self->frame->area.width;
+        head = RECT_BOTTOM(area);
+        size = area.height;
+        e_start = RECT_LEFT(area);
+        e_size = area.width;
         break;
     default:
         g_assert_not_reached();
@@ -4202,33 +4242,33 @@ void client_find_move_directional(ObClient *self, ObDirection dir,
 
     client_find_edge_directional(self, dir, head, size,
                                  e_start, e_size, &e, &near);
-    *x = self->frame->area.x;
-    *y = self->frame->area.y;
+    *x = area.x;
+    *y = area.y;
     switch (dir) {
     case OB_DIRECTION_EAST:
-        if (near) e -= self->frame->area.width;
+        if (near) e -= area.width;
         else      e++;
         *x = e;
         break;
     case OB_DIRECTION_WEST:
         if (near) e++;
-        else      e -= self->frame->area.width;
+        else      e -= area.width;
         *x = e;
         break;
     case OB_DIRECTION_NORTH:
         if (near) e++;
-        else      e -= self->frame->area.height;
+        else      e -= area.height;
         *y = e;
         break;
     case OB_DIRECTION_SOUTH:
-        if (near) e -= self->frame->area.height;
+        if (near) e -= area.height;
         else      e++;
         *y = e;
         break;
     default:
         g_assert_not_reached();
     }
-    frame_frame_gravity(self->frame, x, y);
+    frame_frame_gravity(self, x, y);
 }
 
 void client_find_resize_directional(ObClient *self, ObDirection side,
@@ -4240,33 +4280,36 @@ void client_find_resize_directional(ObClient *self, ObDirection side,
     gboolean near;
     ObDirection dir;
 
+    Rect area = render_plugin->frame_get_window_area(self->frame);
+    Strut size = render_plugin->frame_get_size(self->frame);
+
     switch (side) {
     case OB_DIRECTION_EAST:
-        head = RECT_RIGHT(self->frame->area) +
+        head = RECT_RIGHT(area) +
             (self->size_inc.width - 1) * (grow ? 1 : -1);
-        e_start = RECT_TOP(self->frame->area);
-        e_size = self->frame->area.height;
+        e_start = RECT_TOP(area);
+        e_size = area.height;
         dir = grow ? OB_DIRECTION_EAST : OB_DIRECTION_WEST;
         break;
     case OB_DIRECTION_WEST:
-        head = RECT_LEFT(self->frame->area) -
+        head = RECT_LEFT(area) -
             (self->size_inc.width - 1) * (grow ? 1 : -1);
-        e_start = RECT_TOP(self->frame->area);
-        e_size = self->frame->area.height;
+        e_start = RECT_TOP(area);
+        e_size = area.height;
         dir = grow ? OB_DIRECTION_WEST : OB_DIRECTION_EAST;
         break;
     case OB_DIRECTION_NORTH:
-        head = RECT_TOP(self->frame->area) -
+        head = RECT_TOP(area) -
             (self->size_inc.height - 1) * (grow ? 1 : -1);
-        e_start = RECT_LEFT(self->frame->area);
-        e_size = self->frame->area.width;
+        e_start = RECT_LEFT(area);
+        e_size = area.width;
         dir = grow ? OB_DIRECTION_NORTH : OB_DIRECTION_SOUTH;
         break;
     case OB_DIRECTION_SOUTH:
-        head = RECT_BOTTOM(self->frame->area) +
+        head = RECT_BOTTOM(area) +
             (self->size_inc.height - 1) * (grow ? 1 : -1);
-        e_start = RECT_LEFT(self->frame->area);
-        e_size = self->frame->area.width;
+        e_start = RECT_LEFT(area);
+        e_size = area.width;
         dir = grow ? OB_DIRECTION_SOUTH : OB_DIRECTION_NORTH;
         break;
     default:
@@ -4277,39 +4320,39 @@ void client_find_resize_directional(ObClient *self, ObDirection side,
     client_find_edge_directional(self, dir, head, 1,
                                  e_start, e_size, &e, &near);
     ob_debug("edge %d", e);
-    *x = self->frame->area.x;
-    *y = self->frame->area.y;
-    *w = self->frame->area.width;
-    *h = self->frame->area.height;
+    *x = area.x;
+    *y = area.y;
+    *w = area.width;
+    *h = area.height;
     switch (side) {
     case OB_DIRECTION_EAST:
         if (grow == near) --e;
-        delta = e - RECT_RIGHT(self->frame->area);
+        delta = e - RECT_RIGHT(area);
         *w += delta;
         break;
     case OB_DIRECTION_WEST:
         if (grow == near) ++e;
-        delta = RECT_LEFT(self->frame->area) - e;
+        delta = RECT_LEFT(area) - e;
         *x -= delta;
         *w += delta;
         break;
     case OB_DIRECTION_NORTH:
         if (grow == near) ++e;
-        delta = RECT_TOP(self->frame->area) - e;
+        delta = RECT_TOP(area) - e;
         *y -= delta;
         *h += delta;
         break;
     case OB_DIRECTION_SOUTH:
         if (grow == near) --e;
-        delta = e - RECT_BOTTOM(self->frame->area);
+        delta = e - RECT_BOTTOM(area);
         *h += delta;
         break;
     default:
         g_assert_not_reached();
     }
-    frame_frame_gravity(self->frame, x, y);
-    *w -= self->frame->size.left + self->frame->size.right;
-    *h -= self->frame->size.top + self->frame->size.bottom;
+    frame_frame_gravity(self, x, y);
+    *w -= size.left + size.right;
+    *h -= size.top + size.bottom;
 }
 
 ObClient* client_under_pointer(void)
@@ -4322,15 +4365,15 @@ ObClient* client_under_pointer(void)
         for (it = stacking_list; it; it = g_list_next(it)) {
             if (WINDOW_IS_CLIENT(it->data)) {
                 ObClient *c = WINDOW_AS_CLIENT(it->data);
-                if (c->frame->visible &&
+                if (render_plugin->frame_is_visible(c->frame) &&
                     /* check the desktop, this is done during desktop
                        switching and windows are shown/hidden status is not
                        reliable */
                     (c->desktop == screen_desktop ||
                      c->desktop == DESKTOP_ALL) &&
                     /* ignore all animating windows */
-                    !frame_iconify_animating(c->frame) &&
-                    RECT_CONTAINS(c->frame->area, x, y))
+                    !(render_plugin->frame_iconify_animating(c->frame)) &&
+                    RECT_CONTAINS(render_plugin->frame_get_window_area(c->frame), x, y))
                 {
                     ret = c;
                     break;
index 04f50e857fb31d6e34fe0d0c8cfbe989ec3ec473..c7617e47cf6b10d4b59708863d31fbbe7e266b94 100644 (file)
@@ -24,7 +24,7 @@
 #include "client.h"
 #include "client_menu.h"
 #include "openbox.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "moveresize.h"
 #include "event.h"
 #include "gettext.h"
@@ -296,21 +296,24 @@ static void client_menu_place(ObMenuFrame *frame, gint *x, gint *y,
     gint dx, dy;
 
     if (!mouse && frame->client) {
-        *x = frame->client->frame->area.x;
+
+    Strut size = render_plugin->frame_get_size(frame->client->frame);
+    Rect area = render_plugin->frame_get_window_area(frame->client->frame);
+
+        *x = area.x;
 
         /* try below the titlebar */
-        *y = frame->client->frame->area.y + frame->client->frame->size.top -
-            frame->client->frame->bwidth;
+        *y = area.y + size.top;
         menu_frame_move_on_screen(frame, *x, *y, &dx, &dy);
         if (dy != 0) {
             /* try above the titlebar */
-            *y = frame->client->frame->area.y + frame->client->frame->bwidth -
+            *y = area.y -
                 frame->area.height;
             menu_frame_move_on_screen(frame, *x, *y, &dx, &dy);
         }
         if (dy != 0) {
             /* didnt fit either way, use move on screen's values */
-            *y = frame->client->frame->area.y + frame->client->frame->size.top;
+            *y = area.y + size.top;
             menu_frame_move_on_screen(frame, *x, *y, &dx, &dy);
         }
 
diff --git a/openbox/engine_interface.c b/openbox/engine_interface.c
new file mode 100644 (file)
index 0000000..b271762
--- /dev/null
@@ -0,0 +1,420 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ keyboard.c for the Openbox window manager
+ Copyright (c) 2006        Mikael Magnusson
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+
+#include "engine_interface.h"
+#include "config.h"
+#include "debug.h"
+#include "openbox.h"
+#include "obt/paths.h"
+
+#define SHARED_SUFFIX ".la"
+#define PLUGIN_PATH "/.config/openbox/engines/"
+
+gchar *create_class_name(const gchar *rname);
+
+/* Load XrmDatabase */
+XrmDatabase loaddb(const gchar *name, gchar **path);
+
+/* Read string in XrmDatabase */
+gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value);
+
+ObFramePlugin * init_frame_plugin(const gchar *name, gboolean allow_fallback,
+        RrFont *active_window_font, RrFont *inactive_window_font,
+        RrFont *menu_title_font, RrFont *menu_item_font, RrFont *osd_font)
+{
+    XrmDatabase db = NULL;
+    gchar *path;
+
+    if (name) {
+        db = loaddb(name, &path);
+        if (db == NULL) {
+            g_message("Unable to load the theme '%s'", name);
+            if (allow_fallback)
+                //g_message("Falling back to the default theme '%s'", DEFAULT_THEME);
+                /* fallback to the default theme */
+                name = NULL;
+        }
+    }
+    if (name == NULL) {
+        if (allow_fallback) {
+            //db = loaddb(DEFAULT_THEME, &path);
+            db = NULL;
+            if (db == NULL) {
+                //g_message("Unable to load the theme '%s'", DEFAULT_THEME);
+                return 0;
+            }
+        }
+        else
+            return 0;
+    }
+
+    gchar * plugin_filename;
+    if (!read_string(db, "frame.theme.engine", &plugin_filename)) {
+        plugin_filename = "libdefault.la";
+    }
+    ob_debug("Try to init : %s", plugin_filename);
+    gchar * absolute_plugin_filename = g_build_filename(g_get_home_dir(),
+            ".config", "openbox", "engines", plugin_filename, NULL);
+    ObFramePlugin * p = load_frame_plugin(absolute_plugin_filename);
+    g_free(absolute_plugin_filename);
+
+    update_frame_plugin(p);
+
+    (p->load_theme_config)(ob_rr_inst, name, path, db, active_window_font,
+            inactive_window_font, menu_title_font, menu_item_font, osd_font);
+
+    g_free(path);
+    XrmDestroyDatabase(db);
+
+    return p;
+}
+
+void update_frame_plugin(ObFramePlugin * self)
+{
+    self->ob_display = obt_display;
+    self->ob_screen = ob_screen;
+    self->ob_rr_inst = ob_rr_inst;
+    self->config_theme_keepborder = config_theme_keepborder;
+    self->config_title_layout = config_title_layout;
+    self->ob_main_loop = ob_main_loop;
+}
+
+ObFramePlugin * load_frame_plugin(const gchar * filename)
+{
+    GModule *module;
+    gpointer func;
+
+    if (!(module = g_module_open(filename, G_MODULE_BIND_LOCAL))) {
+        ob_debug_type(OB_DEBUG_SM, "Failed to load plugin (%s): %s\n",
+                filename, g_module_error());
+        exit(1);
+    }
+
+    if (g_module_symbol(module, "get_info", &func)) {
+        ObFramePlugin *plugin = (ObFramePlugin *) ((ObFramePluginFunc) func)();
+        return plugin;
+    }
+    else {
+        ob_debug_type(OB_DEBUG_SM,
+                "Failed to get \"get_info\" function (%s): %s\n", filename,
+                g_module_error());
+        exit(1);
+    }
+
+    ob_debug_type(OB_DEBUG_SM, "Invalid plugin (%s)\n", filename);
+    g_module_close(module);
+    exit(1);
+}
+/*
+ static gboolean scan_plugin_func(const gchar * path, const gchar * basename,
+ gpointer data)
+ {
+ if (!str_has_suffix_nocase(basename, SHARED_SUFFIX))
+ return FALSE;
+
+ if (!g_file_test(path, G_FILE_TEST_IS_REGULAR))
+ return FALSE;
+
+ add_plugin(path);
+
+ return FALSE;
+ }
+
+ static void scan_plugins(const gchar * path)
+ {
+ dir_foreach(path, scan_plugin_func, NULL, NULL);
+ }
+ */
+gboolean read_string(XrmDatabase db, const gchar *rname, gchar **value)
+{
+    gboolean ret = FALSE;
+    gchar *rclass = create_class_name(rname);
+    gchar *rettype;
+    XrmValue retvalue;
+
+    if (XrmGetResource(db, rname, rclass, &rettype, &retvalue) && retvalue.addr
+            != NULL) {
+        *value = retvalue.addr;
+        ret = TRUE;
+    }
+
+    g_free(rclass);
+    return ret;
+}
+
+XrmDatabase loaddb(const gchar *name, gchar **path)
+{
+    GSList *it;
+    XrmDatabase db = NULL;
+    gchar *s;
+
+    if (name[0] == '/') {
+        s = g_build_filename(name, "openbox-3", "themerc", NULL);
+        if ((db = XrmGetFileDatabase(s)))
+            *path = g_path_get_dirname(s);
+        g_free(s);
+    }
+    else {
+        ObtPaths *p;
+
+        p = obt_paths_new();
+        /* XXX backwards compatibility, remove me sometime later */
+        s = g_build_filename(g_get_home_dir(), ".themes", name, "openbox-3",
+                "themerc", NULL);
+        if ((db = XrmGetFileDatabase(s)))
+            *path = g_path_get_dirname(s);
+        g_free(s);
+
+        for (it = obt_paths_data_dirs(p); !db && it; it = g_slist_next(it)) {
+            s = g_build_filename(it->data, "themes", name, "openbox-3",
+                    "themerc", NULL);
+            if ((db = XrmGetFileDatabase(s)))
+                *path = g_path_get_dirname(s);
+            g_free(s);
+        }
+    }
+
+    if (db == NULL) {
+        s = g_build_filename(name, "themerc", NULL);
+        if ((db = XrmGetFileDatabase(s)))
+            *path = g_path_get_dirname(s);
+        g_free(s);
+    }
+
+    return db;
+}
+
+gchar *create_class_name(const gchar *rname)
+{
+    gchar *rclass = g_strdup(rname);
+    gchar *p = rclass;
+
+    while (TRUE) {
+        *p = toupper(*p);
+        p = strchr(p+1, '.');
+        if (p == NULL)
+            break;
+        ++p;
+        if (*p == '\0')
+            break;
+    }
+    return rclass;
+}
+
+ObFrameContext frame_context_from_string(const gchar *name)
+{
+    if (!g_ascii_strcasecmp("Desktop", name))
+        return OB_FRAME_CONTEXT_DESKTOP;
+    else if (!g_ascii_strcasecmp("Root", name))
+        return OB_FRAME_CONTEXT_ROOT;
+    else if (!g_ascii_strcasecmp("Client", name))
+        return OB_FRAME_CONTEXT_CLIENT;
+    else if (!g_ascii_strcasecmp("Titlebar", name))
+        return OB_FRAME_CONTEXT_TITLEBAR;
+    else if (!g_ascii_strcasecmp("Frame", name))
+        return OB_FRAME_CONTEXT_FRAME;
+    else if (!g_ascii_strcasecmp("TLCorner", name))
+        return OB_FRAME_CONTEXT_TLCORNER;
+    else if (!g_ascii_strcasecmp("TRCorner", name))
+        return OB_FRAME_CONTEXT_TRCORNER;
+    else if (!g_ascii_strcasecmp("BLCorner", name))
+        return OB_FRAME_CONTEXT_BLCORNER;
+    else if (!g_ascii_strcasecmp("BRCorner", name))
+        return OB_FRAME_CONTEXT_BRCORNER;
+    else if (!g_ascii_strcasecmp("Top", name))
+        return OB_FRAME_CONTEXT_TOP;
+    else if (!g_ascii_strcasecmp("Bottom", name))
+        return OB_FRAME_CONTEXT_BOTTOM;
+    else if (!g_ascii_strcasecmp("Handle", name))
+        return OB_FRAME_CONTEXT_BOTTOM;
+    else if (!g_ascii_strcasecmp("Left", name))
+        return OB_FRAME_CONTEXT_LEFT;
+    else if (!g_ascii_strcasecmp("Right", name))
+        return OB_FRAME_CONTEXT_RIGHT;
+    else if (!g_ascii_strcasecmp("Maximize", name))
+        return OB_FRAME_CONTEXT_MAXIMIZE;
+    else if (!g_ascii_strcasecmp("AllDesktops", name))
+        return OB_FRAME_CONTEXT_ALLDESKTOPS;
+    else if (!g_ascii_strcasecmp("Shade", name))
+        return OB_FRAME_CONTEXT_SHADE;
+    else if (!g_ascii_strcasecmp("Iconify", name))
+        return OB_FRAME_CONTEXT_ICONIFY;
+    else if (!g_ascii_strcasecmp("Icon", name))
+        return OB_FRAME_CONTEXT_ICON;
+    else if (!g_ascii_strcasecmp("Close", name))
+        return OB_FRAME_CONTEXT_CLOSE;
+    else if (!g_ascii_strcasecmp("MoveResize", name))
+        return OB_FRAME_CONTEXT_MOVE_RESIZE;
+    return OB_FRAME_CONTEXT_NONE;
+}
+
+ObFrameContext plugin_frame_context(ObClient *client, Window win, gint x, gint y)
+{
+    /* this part is commun to all plugin */
+    if (render_plugin->moveresize_in_progress)
+        return OB_FRAME_CONTEXT_MOVE_RESIZE;
+    if (win == obt_root(ob_screen))
+        return OB_FRAME_CONTEXT_ROOT;
+    if (client == NULL)
+        return OB_FRAME_CONTEXT_NONE;
+    if (win == client->window) {
+        /* conceptually, this is the desktop, as far as users are
+         concerned */
+        if (client->type == OB_CLIENT_TYPE_DESKTOP)
+            return OB_FRAME_CONTEXT_DESKTOP;
+        return OB_FRAME_CONTEXT_CLIENT;
+    }
+    /* this part is specific to the plugin */
+    return render_plugin->frame_context(client->frame, win, x, y);
+
+}
+
+void frame_client_gravity(ObClient *self, gint *x, gint *y)
+{
+    Strut size = render_plugin->frame_get_size(self->frame);
+    /* horizontal */
+    switch (self->gravity) {
+    default:
+    case NorthWestGravity:
+    case SouthWestGravity:
+    case WestGravity:
+        break;
+
+    case NorthGravity:
+    case SouthGravity:
+    case CenterGravity:
+        /* the middle of the client will be the middle of the frame */
+        *x -= (size.right - size.left) / 2;
+        break;
+
+    case NorthEastGravity:
+    case SouthEastGravity:
+    case EastGravity:
+        /* the right side of the client will be the right side of the frame */
+        *x -= size.right + size.left - self->border_width * 2;
+        break;
+
+    case ForgetGravity:
+    case StaticGravity:
+        /* the client's position won't move */
+        *x -= size.left - self->border_width;
+        break;
+    }
+
+    /* vertical */
+    switch (self->gravity) {
+    default:
+    case NorthWestGravity:
+    case NorthEastGravity:
+    case NorthGravity:
+        break;
+
+    case CenterGravity:
+    case EastGravity:
+    case WestGravity:
+        /* the middle of the client will be the middle of the frame */
+        *y -= (size.bottom - size.top) / 2;
+        break;
+
+    case SouthWestGravity:
+    case SouthEastGravity:
+    case SouthGravity:
+        /* the bottom of the client will be the bottom of the frame */
+        *y -= size.bottom + size.top - self->border_width * 2;
+        break;
+
+    case ForgetGravity:
+    case StaticGravity:
+        /* the client's position won't move */
+        *y -= size.top - self->border_width;
+        break;
+    }
+}
+
+void frame_frame_gravity(ObClient *self, gint *x, gint *y)
+{
+    Strut size = render_plugin->frame_get_size(self->frame);
+    /* horizontal */
+    switch (self->gravity) {
+    default:
+    case NorthWestGravity:
+    case WestGravity:
+    case SouthWestGravity:
+        break;
+    case NorthGravity:
+    case CenterGravity:
+    case SouthGravity:
+        /* the middle of the client will be the middle of the frame */
+        *x += (size.right - size.left) / 2;
+        break;
+    case NorthEastGravity:
+    case EastGravity:
+    case SouthEastGravity:
+        /* the right side of the client will be the right side of the frame */
+        *x += size.right + size.left - self->border_width * 2;
+        break;
+    case StaticGravity:
+    case ForgetGravity:
+        /* the client's position won't move */
+        *x += size.left - self->border_width;
+        break;
+    }
+
+    /* vertical */
+    switch (self->gravity) {
+    default:
+    case NorthWestGravity:
+    case NorthGravity:
+    case NorthEastGravity:
+        break;
+    case WestGravity:
+    case CenterGravity:
+    case EastGravity:
+        /* the middle of the client will be the middle of the frame */
+        *y += (size.bottom - size.top) / 2;
+        break;
+    case SouthWestGravity:
+    case SouthGravity:
+    case SouthEastGravity:
+        /* the bottom of the client will be the bottom of the frame */
+        *y += size.bottom + size.top - self->border_width * 2;
+        break;
+    case StaticGravity:
+    case ForgetGravity:
+        /* the client's position won't move */
+        *y += size.top - self->border_width;
+        break;
+    }
+}
+
+void frame_rect_to_frame(ObClient * self, Rect *r)
+{
+    Strut size = render_plugin->frame_get_size(self->frame);
+    r->width += size.left + size.right;
+    r->height += size.top + size.bottom;
+    frame_client_gravity(self, &r->x, &r->y);
+}
+
+void frame_rect_to_client(ObClient * self, Rect *r)
+{
+    Strut size = render_plugin->frame_get_size(self);
+    r->width -= size.left + size.right;
+    r->height -= size.top + size.bottom;
+    frame_frame_gravity(self, &r->x, &r->y);
+}
diff --git a/openbox/engine_interface.h b/openbox/engine_interface.h
new file mode 100644 (file)
index 0000000..e7d4c67
--- /dev/null
@@ -0,0 +1,224 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ plugin.h for the Openbox window manager
+ Copyright (c) 2003-2007   Dana Jansens
+
+ 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 of the License, 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.
+
+ See the COPYING file for a copy of the GNU General Public License.
+ */
+#ifndef ENGINE_INTERFACE_H_
+#define ENGINE_INTERFACE_H_
+/* Thanks to BMP, XMMS, Audacious and glib project to enable plugin */
+#include "geom.h"
+#include "render/render.h"
+#include "render/theme.h"
+#include "obt/parse.h"
+#include "client.h"
+
+#include "obt/mainloop.h"
+
+#include <X11/Xresource.h>
+#include <gmodule.h>
+
+struct _RrTheme;
+struct _ObClient;
+
+typedef enum
+{
+    OB_FRAME_CONTEXT_NONE,
+    OB_FRAME_CONTEXT_DESKTOP,
+    OB_FRAME_CONTEXT_ROOT,
+    OB_FRAME_CONTEXT_CLIENT,
+    OB_FRAME_CONTEXT_TITLEBAR,
+    OB_FRAME_CONTEXT_FRAME,
+    OB_FRAME_CONTEXT_BLCORNER,
+    OB_FRAME_CONTEXT_BRCORNER,
+    OB_FRAME_CONTEXT_TLCORNER,
+    OB_FRAME_CONTEXT_TRCORNER,
+    OB_FRAME_CONTEXT_TOP,
+    OB_FRAME_CONTEXT_BOTTOM,
+    OB_FRAME_CONTEXT_LEFT,
+    OB_FRAME_CONTEXT_RIGHT,
+    OB_FRAME_CONTEXT_MAXIMIZE,
+    OB_FRAME_CONTEXT_ALLDESKTOPS,
+    OB_FRAME_CONTEXT_SHADE,
+    OB_FRAME_CONTEXT_ICONIFY,
+    OB_FRAME_CONTEXT_ICON,
+    OB_FRAME_CONTEXT_CLOSE,
+    /*! This is a special context, which occurs while dragging a window in
+     a move/resize */
+    OB_FRAME_CONTEXT_MOVE_RESIZE,
+    OB_FRAME_NUM_CONTEXTS
+} ObFrameContext;
+
+/*! The decorations the client window wants to be displayed on it */
+typedef enum
+{
+    OB_FRAME_DECOR_TITLEBAR = 1 << 0, /*!< Display a titlebar */
+    OB_FRAME_DECOR_HANDLE = 1 << 1, /*!< Display a handle (bottom) */
+    OB_FRAME_DECOR_GRIPS = 1 << 2, /*!< Display grips in the handle */
+    OB_FRAME_DECOR_BORDER = 1 << 3, /*!< Display a border */
+    OB_FRAME_DECOR_ICON = 1 << 4, /*!< Display the window's icon */
+    OB_FRAME_DECOR_ICONIFY = 1 << 5, /*!< Display an iconify button */
+    OB_FRAME_DECOR_MAXIMIZE = 1 << 6, /*!< Display a maximize button */
+    /*! Display a button to toggle the window's placement on
+     all desktops */
+    OB_FRAME_DECOR_ALLDESKTOPS = 1 << 7,
+    OB_FRAME_DECOR_SHADE = 1 << 8, /*!< Displays a shade button */
+    OB_FRAME_DECOR_CLOSE = 1 << 9 /*!< Display a close button */
+} ObFrameDecorations;
+
+typedef enum
+{
+    OB_BUTTON_NONE = 0,
+    OB_BUTTON_MAX = 1,
+    OB_BUTTON_CLOSE = 2,
+    OB_BUTTON_DESK = 3,
+    OB_BUTTON_SHADE = 4,
+    OB_BUTTON_ICONIFY = 5
+} ObFrameButton;
+
+typedef enum
+{
+    OB_FRAME_STATE_NORMAL,
+    OB_FRAME_STATE_INCONIFIED,
+    OB_FRAME_STATE_SHADED,
+    OB_FRAME_STATE_MAX,
+    OB_FRAME_STATE_MAX_VERT,
+    OB_FRAME_STATE_MAX_HORZ,
+    OB_FRAME_STATE_NO_BORDER
+} ObFrameState;
+
+struct _ObFramePlugin
+{
+    gpointer handler; // Currently not used.
+
+    gchar * filename;
+    gchar * name;
+
+    /* Function to init module */
+    gint (*init)(Display * display, gint screen);
+    /* Not curently used */
+    gint (*release)(void);
+
+    /* create a new frame, return the ID of frame */
+    gpointer (*frame_new)(struct _ObClient *c);
+    /* Free the frame */
+    void (*frame_free)(gpointer self);
+
+    void (*frame_show)(gpointer self);
+    gint (*frame_hide)(gpointer self);
+
+    void (*frame_adjust_theme)(gpointer self);
+    void (*frame_adjust_shape)(gpointer self);
+
+    /* Grab or Ungrab event */
+    void (*frame_grab)(gpointer self, GHashTable *);
+    void (*frame_ungrab)(gpointer self, GHashTable *);
+
+    /* Provide the context of the mouse */
+    ObFrameContext (*frame_context)(gpointer self, Window win, gint x, gint y);
+
+    void (*frame_set_is_visible)(gpointer, gboolean);
+    void (*frame_set_is_focus)(gpointer, gboolean);
+    void (*frame_set_is_max_vert)(gpointer, gboolean);
+    void (*frame_set_is_max_horz)(gpointer, gboolean);
+    void (*frame_set_is_shaded)(gpointer, gboolean);
+
+    void (*frame_flash_start)(gpointer self);
+    void (*frame_flash_stop)(gpointer self);
+    void (*frame_begin_iconify_animation)(gpointer self, gboolean iconifying);
+    void (*frame_end_iconify_animation)(gpointer self);
+    gboolean (*frame_iconify_animating)(gpointer p);
+
+    /* Set the layout wanted by client */
+    void (*frame_set_decorations)(gpointer, ObFrameDecorations);
+
+    /* get the current window area */
+    Rect (*frame_get_window_area)(gpointer);
+    /* set the requested client area */
+    void (*frame_set_client_area)(gpointer, Rect);
+    /* Draw the frame */
+    void (*frame_update_layout)(gpointer self, gboolean is_resize,
+            gboolean is_fake);
+    void (*frame_update_skin)(gpointer);
+
+    void (*frame_set_hover_flag)(gpointer, ObFrameButton);
+    void (*frame_set_press_flag)(gpointer, ObFrameButton);
+
+    Window (*frame_get_window)(gpointer);
+
+    Strut (*frame_get_size)(gpointer);
+    gint (*frame_get_decorations)(gpointer);
+
+    gboolean (*frame_is_visible)(gpointer);
+    gboolean (*frame_is_max_horz)(gpointer);
+    gboolean (*frame_is_max_vert)(gpointer);
+
+    gint (*load_theme_config)(const RrInstance *inst, const gchar *name,
+            const gchar * path, XrmDatabase db, RrFont *active_window_font,
+            RrFont *inactive_window_font, RrFont *menu_title_font,
+            RrFont *menu_item_font, RrFont *osd_font);
+
+    /* Filled by openbox-core */
+    Display * ob_display;
+    gint ob_screen;
+    RrInstance *ob_rr_inst;
+    // Not more needed
+    //struct _RrTheme * ob_rr_theme;
+    gboolean config_theme_keepborder;
+    struct _ObClient *focus_cycle_target;
+    gchar *config_title_layout;
+    gboolean moveresize_in_progress;
+    struct _ObtMainLoop *ob_main_loop;
+};
+/* Define how to draw the current windows */
+enum _ObStyle
+{
+    OBSTYLE_DECOR,
+    OBSTYLE_NODECOR,
+    OBSTYLE_SHADE,
+    OBSTYLE_ICON,
+    OBSTYLE_MAXVERT,
+    OBSTYLE_MAXHORIZ,
+    OBSTYLE_MAX,
+};
+
+typedef enum _ObStyle ObStyle;
+typedef struct _ObFramePlugin ObFramePlugin;
+typedef ObFramePlugin * (*ObFramePluginFunc)(void);
+
+#define OBFRAME(x) (ObFrame *) (x);
+
+/* initialize theme plugin, it read themerc and load
+ * the plugin needed */
+ObFramePlugin * init_frame_plugin(const gchar *name, gboolean allow_fallback,
+        RrFont *active_window_font, RrFont *inactive_window_font,
+        RrFont *menu_title_font, RrFont *menu_item_font, RrFont *osd_font);
+
+/* Update plugin data */
+void update_frame_plugin(ObFramePlugin *);
+
+/* Load modules specified in filename */
+ObFramePlugin * load_frame_plugin(const gchar * filename);
+
+/* Give context from string, it's used to parse config file */
+ObFrameContext frame_context_from_string(const gchar *name);
+ObFrameContext plugin_frame_context(ObClient *, Window, gint, gint);
+
+void frame_client_gravity(ObClient * self, gint *x, gint *y);
+void frame_frame_gravity(ObClient * self, gint *x, gint *y);
+
+void frame_rect_to_frame(ObClient * self, Rect *r);
+void frame_rect_to_client(ObClient * self, Rect *r);
+
+#endif /*FRAME_PLUGIN_H_*/
index cedac2e3f29e28d758494f8bc197e3e7905239f4..dbc7058ded80cff5f4b30eaaeb47ef07257cd9eb 100644 (file)
@@ -26,7 +26,7 @@
 #include "client.h"
 #include "config.h"
 #include "screen.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "grab.h"
 #include "menu.h"
 #include "prompt.h"
@@ -527,7 +527,9 @@ static void event_process(const XEvent *ec, gpointer data)
             /* We don't get a FocusOut for this case, because it's just moving
                from our Inferior up to us. This happens when iconifying a
                window with RevertToParent focus */
-            frame_adjust_focus(client->frame, FALSE);
+            render_plugin->frame_set_is_focus(client->frame, FALSE);
+            render_plugin->frame_update_layout (client->frame, FALSE, FALSE);
+            render_plugin->frame_update_skin(client->frame);
             /* focus_set_client(NULL) has already been called */
         }
         else if (e->xfocus.detail == NotifyPointerRoot ||
@@ -590,7 +592,9 @@ static void event_process(const XEvent *ec, gpointer data)
         }
         else if (client != focus_client) {
             focus_left_screen = FALSE;
-            frame_adjust_focus(client->frame, TRUE);
+            render_plugin->frame_set_is_focus(client->frame, TRUE);
+            render_plugin->frame_update_layout (client->frame, FALSE, FALSE);
+            render_plugin->frame_update_skin (client->frame);
             focus_set_client(client);
             client_calc_layer(client);
             client_bring_helper_windows(client);
@@ -635,7 +639,9 @@ static void event_process(const XEvent *ec, gpointer data)
         }
 
         if (client && client != focus_client) {
-            frame_adjust_focus(client->frame, FALSE);
+          render_plugin->frame_set_is_focus(client->frame, FALSE);
+          render_plugin->frame_update_layout (client->frame, FALSE, FALSE);
+          render_plugin->frame_update_skin(client->frame);
             /* focus_set_client(NULL) has already been called in this
                section or by focus_fallback */
         }
@@ -671,10 +677,11 @@ static void event_process(const XEvent *ec, gpointer data)
             gulong vals[4];
 
             /* set the frame extents on the window */
-            vals[0] = c->frame->size.left;
-            vals[1] = c->frame->size.right;
-            vals[2] = c->frame->size.top;
-            vals[3] = c->frame->size.bottom;
+            Strut size = render_plugin->frame_get_size(c->frame);
+            vals[0] = size.left;
+            vals[1] = size.right;
+            vals[2] = size.top;
+            vals[3] = size.bottom;
             OBT_PROP_SETA32(e->xclient.window, NET_FRAME_EXTENTS,
                             CARDINAL, vals, 4);
 
@@ -707,7 +714,7 @@ static void event_process(const XEvent *ec, gpointer data)
              e->type == obt_display_extension_sync_basep + XSyncAlarmNotify)
     {
         XSyncAlarmNotifyEvent *se = (XSyncAlarmNotifyEvent*)e;
-        if (se->alarm == moveresize_alarm && moveresize_in_progress)
+        if (se->alarm == moveresize_alarm && render_plugin->moveresize_in_progress)
             moveresize_event(e);
     }
 #endif
@@ -868,38 +875,38 @@ static void event_handle_client(ObClient *client, XEvent *e)
             !grab_on_keyboard())
         {
             /* use where the press occured */
-            con = frame_context(client, e->xbutton.window, px, py);
+            con = plugin_frame_context(client, e->xbutton.window, px, py);
             con = mouse_button_frame_context(con, e->xbutton.button,
                                              e->xbutton.state);
 
             if (e->type == ButtonRelease && e->xbutton.button == pb)
                 pb = 0, px = py = -1;
 
+            ObFrameButton current_button = OB_BUTTON_NONE;
+
             switch (con) {
             case OB_FRAME_CONTEXT_MAXIMIZE:
-                client->frame->max_press = (e->type == ButtonPress);
-                frame_adjust_state(client->frame);
+                current_button = OB_BUTTON_MAX;
                 break;
             case OB_FRAME_CONTEXT_CLOSE:
-                client->frame->close_press = (e->type == ButtonPress);
-                frame_adjust_state(client->frame);
+        current_button = OB_BUTTON_CLOSE;
                 break;
             case OB_FRAME_CONTEXT_ICONIFY:
-                client->frame->iconify_press = (e->type == ButtonPress);
-                frame_adjust_state(client->frame);
+        current_button = OB_BUTTON_ICONIFY;
                 break;
             case OB_FRAME_CONTEXT_ALLDESKTOPS:
-                client->frame->desk_press = (e->type == ButtonPress);
-                frame_adjust_state(client->frame);
+        current_button = OB_BUTTON_DESK;
                 break;
             case OB_FRAME_CONTEXT_SHADE:
-                client->frame->shade_press = (e->type == ButtonPress);
-                frame_adjust_state(client->frame);
+        current_button = OB_BUTTON_SHADE;
                 break;
             default:
                 /* nothing changes with clicks for any other contexts */
                 break;
             }
+
+            if (current_button)
+        render_plugin->frame_set_hover_flag (client->frame, current_button);
         }
         break;
     case MotionNotify:
@@ -907,104 +914,64 @@ static void event_handle_client(ObClient *client, XEvent *e)
            notifies, but we still get motion events */
         if (grab_on_pointer()) break;
 
-        con = frame_context(client, e->xmotion.window,
+        con = plugin_frame_context(client, e->xmotion.window,
                             e->xmotion.x, e->xmotion.y);
         switch (con) {
         case OB_FRAME_CONTEXT_TITLEBAR:
         case OB_FRAME_CONTEXT_TLCORNER:
         case OB_FRAME_CONTEXT_TRCORNER:
             /* we've left the button area inside the titlebar */
-            if (client->frame->max_hover || client->frame->desk_hover ||
-                client->frame->shade_hover || client->frame->iconify_hover ||
-                client->frame->close_hover)
-            {
-                client->frame->max_hover = FALSE;
-                client->frame->desk_hover = FALSE;
-                client->frame->shade_hover = FALSE;
-                client->frame->iconify_hover = FALSE;
-                client->frame->close_hover = FALSE;
-                frame_adjust_state(client->frame);
-            }
+            render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_NONE);
             break;
         case OB_FRAME_CONTEXT_MAXIMIZE:
-            if (!client->frame->max_hover) {
-                client->frame->max_hover = TRUE;
-                frame_adjust_state(client->frame);
-            }
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_MAX);
             break;
         case OB_FRAME_CONTEXT_ALLDESKTOPS:
-            if (!client->frame->desk_hover) {
-                client->frame->desk_hover = TRUE;
-                frame_adjust_state(client->frame);
-            }
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_DESK);
             break;
         case OB_FRAME_CONTEXT_SHADE:
-            if (!client->frame->shade_hover) {
-                client->frame->shade_hover = TRUE;
-                frame_adjust_state(client->frame);
-            }
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_SHADE);
             break;
         case OB_FRAME_CONTEXT_ICONIFY:
-            if (!client->frame->iconify_hover) {
-                client->frame->iconify_hover = TRUE;
-                frame_adjust_state(client->frame);
-            }
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_ICONIFY);
             break;
         case OB_FRAME_CONTEXT_CLOSE:
-            if (!client->frame->close_hover) {
-                client->frame->close_hover = TRUE;
-                frame_adjust_state(client->frame);
-            }
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_CLOSE);
             break;
         default:
             break;
         }
         break;
     case LeaveNotify:
-        con = frame_context(client, e->xcrossing.window,
+        con = plugin_frame_context(client, e->xcrossing.window,
                             e->xcrossing.x, e->xcrossing.y);
         switch (con) {
         case OB_FRAME_CONTEXT_TITLEBAR:
         case OB_FRAME_CONTEXT_TLCORNER:
         case OB_FRAME_CONTEXT_TRCORNER:
             /* we've left the button area inside the titlebar */
-            if (client->frame->max_hover || client->frame->desk_hover ||
-                client->frame->shade_hover || client->frame->iconify_hover ||
-                client->frame->close_hover)
-            {
-                client->frame->max_hover = FALSE;
-                client->frame->desk_hover = FALSE;
-                client->frame->shade_hover = FALSE;
-                client->frame->iconify_hover = FALSE;
-                client->frame->close_hover = FALSE;
-                frame_adjust_state(client->frame);
-            }
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_NONE);
             break;
         case OB_FRAME_CONTEXT_MAXIMIZE:
-            client->frame->max_hover = FALSE;
-            frame_adjust_state(client->frame);
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_NONE);
             break;
         case OB_FRAME_CONTEXT_ALLDESKTOPS:
-            client->frame->desk_hover = FALSE;
-            frame_adjust_state(client->frame);
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_NONE);
             break;
         case OB_FRAME_CONTEXT_SHADE:
-            client->frame->shade_hover = FALSE;
-            frame_adjust_state(client->frame);
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_NONE);
             break;
         case OB_FRAME_CONTEXT_ICONIFY:
-            client->frame->iconify_hover = FALSE;
-            frame_adjust_state(client->frame);
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_NONE);
             break;
         case OB_FRAME_CONTEXT_CLOSE:
-            client->frame->close_hover = FALSE;
-            frame_adjust_state(client->frame);
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_NONE);
             break;
         case OB_FRAME_CONTEXT_FRAME:
             /* When the mouse leaves an animating window, don't use the
                corresponding enter events. Pretend like the animating window
                doesn't even exist..! */
-            if (frame_iconify_animating(client->frame))
+            if (render_plugin->frame_iconify_animating(client->frame))
                 event_end_ignore_all_enters(event_start_ignore_all_enters());
 
             ob_debug_type(OB_DEBUG_FOCUS,
@@ -1031,28 +998,23 @@ static void event_handle_client(ObClient *client, XEvent *e)
         break;
     case EnterNotify:
     {
-        con = frame_context(client, e->xcrossing.window,
+        con = plugin_frame_context(client, e->xcrossing.window,
                             e->xcrossing.x, e->xcrossing.y);
         switch (con) {
         case OB_FRAME_CONTEXT_MAXIMIZE:
-            client->frame->max_hover = TRUE;
-            frame_adjust_state(client->frame);
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_MAX);
             break;
         case OB_FRAME_CONTEXT_ALLDESKTOPS:
-            client->frame->desk_hover = TRUE;
-            frame_adjust_state(client->frame);
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_DESK);
             break;
         case OB_FRAME_CONTEXT_SHADE:
-            client->frame->shade_hover = TRUE;
-            frame_adjust_state(client->frame);
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_SHADE);
             break;
         case OB_FRAME_CONTEXT_ICONIFY:
-            client->frame->iconify_hover = TRUE;
-            frame_adjust_state(client->frame);
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_ICONIFY);
             break;
         case OB_FRAME_CONTEXT_CLOSE:
-            client->frame->close_hover = TRUE;
-            frame_adjust_state(client->frame);
+        render_plugin->frame_set_hover_flag(client->frame, OB_BUTTON_CLOSE);
             break;
         case OB_FRAME_CONTEXT_FRAME:
             if (grab_on_keyboard())
@@ -1107,8 +1069,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
         ob_debug("ConfigureRequest for \"%s\" desktop %d wmstate %d "
                  "visibile %d",
                  client->title,
-                 screen_desktop, client->wmstate, client->frame->visible);
-        ob_debug("                     x %d y %d w %d h %d b %d",
+                 screen_desktop, client->wmstate, render_plugin->frame_is_visible(client->frame),
                  x, y, w, h, client->border_width);
 
         if (e->xconfigurerequest.value_mask & CWBorderWidth)
@@ -1202,11 +1163,13 @@ static void event_handle_client(ObClient *client, XEvent *e)
            desktop. eg. open amarok window on desktop 1, switch to desktop
            2, click amarok tray icon. it will move by its decoration size.
         */
+        Strut size = render_plugin->frame_get_size(client->frame);
+        Rect area = render_plugin->frame_get_window_area(client->frame);
         if (x != client->area.x &&
-            x == (client->frame->area.x + client->frame->size.left -
+            x == (area.x + size.left -
                   (gint)client->border_width) &&
             y != client->area.y &&
-            y == (client->frame->area.y + client->frame->size.top -
+            y == (area.y + size.top -
                   (gint)client->border_width) &&
             w == client->area.width &&
             h == client->area.height)
@@ -1265,7 +1228,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
         break;
     case ReparentNotify:
         /* this is when the client is first taken captive in the frame */
-        if (e->xreparent.parent == client->frame->window) break;
+        if (e->xreparent.parent == render_plugin->frame_get_window(client->frame)) break;
 
         /*
           This event is quite rare and is usually handled in unmapHandler.
@@ -1607,7 +1570,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
             e->type == obt_display_extension_shape_basep)
         {
             client->shaped = ((XShapeEvent*)e)->shaped;
-            frame_adjust_shape(client->frame);
+            render_plugin->frame_adjust_shape(client->frame);
         }
 #endif
     }
@@ -1906,7 +1869,7 @@ static void event_handle_user_input(ObClient *client, XEvent *e)
     /* if the keyboard interactive action uses the event then dont
        use it for bindings. likewise is moveresize uses the event. */
     if (!actions_interactive_input_event(e) && !moveresize_event(e)) {
-        if (moveresize_in_progress)
+        if (render_plugin->moveresize_in_progress)
             /* make further actions work on the client being
                moved/resized */
             client = moveresize_client;
@@ -1917,10 +1880,10 @@ static void event_handle_user_input(ObClient *client, XEvent *e)
         {
             /* the frame may not be "visible" but they can still click on it
                in the case where it is animating before disappearing */
-            if (!client || !frame_iconify_animating(client->frame))
+            if (!client || !render_plugin->frame_iconify_animating(client->frame))
                 mouse_event(client, e);
         } else
-            keyboard_event((focus_cycle_target ? focus_cycle_target :
+            keyboard_event((render_plugin->focus_cycle_target ? render_plugin->focus_cycle_target :
                             (client ? client : focus_client)), e);
     }
 }
@@ -1942,7 +1905,7 @@ static gboolean focus_delay_func(gpointer data)
     Time old = event_curtime;
 
     /* don't move focus and kill the menu or the move/resize */
-    if (menu_frame_visible || moveresize_in_progress) return FALSE;
+    if (menu_frame_visible || render_plugin->moveresize_in_progress) return FALSE;
 
     event_curtime = d->time;
     event_curserial = d->serial;
@@ -2030,7 +1993,7 @@ void event_cancel_all_key_grabs(void)
         menu_frame_hide_all();
         ob_debug("KILLED open menus");
     }
-    else if (moveresize_in_progress) {
+    else if (render_plugin->moveresize_in_progress) {
         moveresize_end(TRUE);
         ob_debug("KILLED interactive moveresize");
     }
index dbf79c9a7d2207ef899c91402222b711a4f583c9..af68c37f9ce1ccdce422ae39fa76ae9721151451 100644 (file)
@@ -20,7 +20,7 @@
 #include "focus_cycle.h"
 #include "focus_cycle_indicator.h"
 #include "client.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "focus.h"
 #include "screen.h"
 #include "openbox.h"
@@ -29,7 +29,7 @@
 #include <X11/Xlib.h>
 #include <glib.h>
 
-ObClient       *focus_cycle_target = NULL;
+//ObClient       *focus_cycle_target = NULL;
 static gboolean focus_cycle_iconic_windows;
 static gboolean focus_cycle_all_desktops;
 static gboolean focus_cycle_dock_windows;
@@ -54,7 +54,7 @@ void focus_cycle_stop(ObClient *ifclient)
 {
     /* stop focus cycling if the given client is a valid focus target,
        and so the cycling is being disrupted */
-    if (focus_cycle_target && ifclient &&
+    if (render_plugin->focus_cycle_target && ifclient &&
         focus_valid_target(ifclient, TRUE,
                            focus_cycle_iconic_windows,
                            focus_cycle_all_desktops,
@@ -80,7 +80,7 @@ ObClient* focus_cycle(gboolean forward, gboolean all_desktops,
 
     if (interactive) {
         if (cancel) {
-            focus_cycle_target = NULL;
+        render_plugin->focus_cycle_target = NULL;
             goto done_cycle;
         } else if (done)
             goto done_cycle;
@@ -97,14 +97,14 @@ ObClient* focus_cycle(gboolean forward, gboolean all_desktops,
     }
 
 
-    if (focus_cycle_target == NULL) {
+    if (render_plugin->focus_cycle_target == NULL) {
         focus_cycle_iconic_windows = TRUE;
         focus_cycle_all_desktops = all_desktops;
         focus_cycle_dock_windows = dock_windows;
         focus_cycle_desktop_windows = desktop_windows;
         start = it = g_list_find(list, focus_client);
     } else
-        start = it = g_list_find(list, focus_cycle_target);
+        start = it = g_list_find(list, render_plugin->focus_cycle_target);
 
     if (!start) /* switched desktops or something? */
         start = it = forward ? g_list_last(list) : g_list_first(list);
@@ -126,8 +126,8 @@ ObClient* focus_cycle(gboolean forward, gboolean all_desktops,
                                focus_cycle_desktop_windows))
         {
             if (interactive) {
-                if (ft != focus_cycle_target) { /* prevents flicker */
-                    focus_cycle_target = ft;
+                if (ft != render_plugin->focus_cycle_target) { /* prevents flicker */
+                    render_plugin->focus_cycle_target = ft;
                     focus_cycle_draw_indicator(showbar ? ft : NULL);
                 }
                 /* same arguments as focus_target_valid */
@@ -137,9 +137,9 @@ ObClient* focus_cycle(gboolean forward, gboolean all_desktops,
                                        focus_cycle_dock_windows,
                                        focus_cycle_desktop_windows,
                                        mode);
-                return focus_cycle_target;
-            } else if (ft != focus_cycle_target) {
-                focus_cycle_target = ft;
+                return render_plugin->focus_cycle_target;
+            } else if (ft != render_plugin->focus_cycle_target) {
+        render_plugin->focus_cycle_target = ft;
                 done = TRUE;
                 break;
             }
@@ -147,10 +147,10 @@ ObClient* focus_cycle(gboolean forward, gboolean all_desktops,
     } while (it != start);
 
 done_cycle:
-    if (done && !cancel) ret = focus_cycle_target;
+    if (done && !cancel) ret = render_plugin->focus_cycle_target;
 
     t = NULL;
-    focus_cycle_target = NULL;
+    render_plugin->focus_cycle_target = NULL;
     g_list_free(order);
     order = NULL;
 
@@ -177,9 +177,10 @@ static ObClient *focus_find_directional(ObClient *c, ObDirection dir,
     if (!client_list)
         return NULL;
 
+    Rect area = render_plugin->frame_get_window_area(c->frame);
     /* first, find the centre coords of the currently focused window */
-    my_cx = c->frame->area.x + c->frame->area.width / 2;
-    my_cy = c->frame->area.y + c->frame->area.height / 2;
+    my_cx = area.x + area.width / 2;
+    my_cy = area.y + area.height / 2;
 
     best_score = -1;
     best_client = c;
@@ -194,12 +195,13 @@ static ObClient *focus_find_directional(ObClient *c, ObDirection dir,
                                 desktop_windows))
             continue;
 
+        Rect cur_area = render_plugin->frame_get_window_area(cur->frame);
         /* find the centre coords of this window, from the
          * currently focused window's point of view */
-        his_cx = (cur->frame->area.x - my_cx)
-            + cur->frame->area.width / 2;
-        his_cy = (cur->frame->area.y - my_cy)
-            + cur->frame->area.height / 2;
+        his_cx = (cur_area.x - my_cx)
+            + cur_area.width / 2;
+        his_cy = (cur_area.y - my_cy)
+            + cur_area.height / 2;
 
         if (dir == OB_DIRECTION_NORTHEAST || dir == OB_DIRECTION_SOUTHEAST ||
             dir == OB_DIRECTION_SOUTHWEST || dir == OB_DIRECTION_NORTHWEST)
@@ -269,7 +271,7 @@ ObClient* focus_directional_cycle(ObDirection dir, gboolean dock_windows,
     ObClient *ret = NULL;
 
     if (cancel) {
-        focus_cycle_target = NULL;
+    render_plugin->focus_cycle_target = NULL;
         goto done_cycle;
     } else if (done && interactive)
         goto done_cycle;
@@ -277,7 +279,7 @@ ObClient* focus_directional_cycle(ObDirection dir, gboolean dock_windows,
     if (!focus_order)
         goto done_cycle;
 
-    if (focus_cycle_target == NULL) {
+    if (render_plugin->focus_cycle_target == NULL) {
         focus_cycle_iconic_windows = FALSE;
         focus_cycle_all_desktops = FALSE;
         focus_cycle_dock_windows = dock_windows;
@@ -286,8 +288,8 @@ ObClient* focus_directional_cycle(ObDirection dir, gboolean dock_windows,
 
     if (!first) first = focus_client;
 
-    if (focus_cycle_target)
-        ft = focus_find_directional(focus_cycle_target, dir, dock_windows,
+    if (render_plugin->focus_cycle_target)
+        ft = focus_find_directional(render_plugin->focus_cycle_target, dir, dock_windows,
                                     desktop_windows);
     else if (first)
         ft = focus_find_directional(first, dir, dock_windows, desktop_windows);
@@ -303,26 +305,26 @@ ObClient* focus_directional_cycle(ObDirection dir, gboolean dock_windows,
                 ft = it->data;
     }
 
-    if (ft && ft != focus_cycle_target) {/* prevents flicker */
-        focus_cycle_target = ft;
+    if (ft && ft != render_plugin->focus_cycle_target) {/* prevents flicker */
+    render_plugin->focus_cycle_target = ft;
         if (!interactive)
             goto done_cycle;
         focus_cycle_draw_indicator(showbar ? ft : NULL);
     }
-    if (focus_cycle_target && dialog)
+    if (render_plugin->focus_cycle_target && dialog)
         /* same arguments as focus_target_valid */
-        focus_cycle_popup_single_show(focus_cycle_target,
+        focus_cycle_popup_single_show(render_plugin->focus_cycle_target,
                                       focus_cycle_iconic_windows,
                                       focus_cycle_all_desktops,
                                       focus_cycle_dock_windows,
                                       focus_cycle_desktop_windows);
-    return focus_cycle_target;
+    return render_plugin->focus_cycle_target;
 
 done_cycle:
-    if (done && !cancel) ret = focus_cycle_target;
+    if (done && !cancel) ret = render_plugin->focus_cycle_target;
 
     first = NULL;
-    focus_cycle_target = NULL;
+    render_plugin->focus_cycle_target = NULL;
 
     focus_cycle_draw_indicator(NULL);
     focus_cycle_popup_single_hide();
index c31abc81f47abe8165030342703c28e95604e2d2..97ac8467f83943decaf5b697c880392538a63812 100644 (file)
@@ -29,7 +29,7 @@
 struct _ObClient;
 
 /*! The client which appears focused during a focus cycle operation */
-extern struct _ObClient *focus_cycle_target;
+//extern struct _ObClient *focus_cycle_target;
 
 void focus_cycle_startup(gboolean reconfig);
 void focus_cycle_shutdown(gboolean reconfig);
index 495a72305be16d2d86d1fe738e4015b2e13b46eb..4639cb1ade3c9d9fde239b046e389cd474848606 100644 (file)
@@ -21,7 +21,7 @@
 #include "focus_cycle_indicator.h"
 #include "client.h"
 #include "openbox.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "event.h"
 #include "render/render.h"
 
@@ -151,6 +151,7 @@ void focus_cycle_draw_indicator(ObClient *c)
         visible = FALSE;
     }
     else if (c) {
+        Rect area = render_plugin->frame_get_window_area(c->frame);
         /*
           if (c)
               frame_adjust_focus(c->frame, FALSE);
@@ -162,9 +163,9 @@ void focus_cycle_draw_indicator(ObClient *c)
 
         wt = wl = wr = wb = FOCUS_INDICATOR_WIDTH;
 
-        x = c->frame->area.x;
-        y = c->frame->area.y;
-        w = c->frame->area.width;
+        x = area.x;
+        y = area.y;
+        w = area.width;
         h = wt;
 
         /* kill enter events cause by this moving */
@@ -191,10 +192,10 @@ void focus_cycle_draw_indicator(ObClient *c)
         RrPaint(a_focus_indicator, focus_indicator.top.window,
                 w, h);
 
-        x = c->frame->area.x;
-        y = c->frame->area.y;
+        x = area.x;
+        y = area.y;
         w = wl;
-        h = c->frame->area.height;
+        h = area.height;
 
         XMoveResizeWindow(obt_display, focus_indicator.left.window,
                           x, y, w, h);
@@ -217,10 +218,10 @@ void focus_cycle_draw_indicator(ObClient *c)
         RrPaint(a_focus_indicator, focus_indicator.left.window,
                 w, h);
 
-        x = c->frame->area.x + c->frame->area.width - wr;
-        y = c->frame->area.y;
+        x = area.x + area.width - wr;
+        y = area.y;
         w = wr;
-        h = c->frame->area.height ;
+        h = area.height ;
 
         XMoveResizeWindow(obt_display, focus_indicator.right.window,
                           x, y, w, h);
@@ -243,9 +244,9 @@ void focus_cycle_draw_indicator(ObClient *c)
         RrPaint(a_focus_indicator, focus_indicator.right.window,
                 w, h);
 
-        x = c->frame->area.x;
-        y = c->frame->area.y + c->frame->area.height - wb;
-        w = c->frame->area.width;
+        x = area.x;
+        y = area.y + area.height - wb;
+        w = area.width;
         h = wb;
 
         XMoveResizeWindow(obt_display, focus_indicator.bottom.window,
diff --git a/openbox/frame.c b/openbox/frame.c
deleted file mode 100644 (file)
index 0975214..0000000
+++ /dev/null
@@ -1,1811 +0,0 @@
-/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
-   frame.c for the Openbox window manager
-   Copyright (c) 2006        Mikael Magnusson
-   Copyright (c) 2003-2007   Dana Jansens
-
-   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 of the License, 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.
-
-   See the COPYING file for a copy of the GNU General Public License.
-*/
-
-#include "frame.h"
-#include "client.h"
-#include "openbox.h"
-#include "grab.h"
-#include "config.h"
-#include "framerender.h"
-#include "focus_cycle.h"
-#include "focus_cycle_indicator.h"
-#include "moveresize.h"
-#include "screen.h"
-#include "render/theme.h"
-#include "obt/display.h"
-#include "obt/prop.h"
-
-#define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
-                         ButtonPressMask | ButtonReleaseMask | \
-                         SubstructureRedirectMask | FocusChangeMask)
-#define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
-                           ButtonMotionMask | PointerMotionMask | \
-                           EnterWindowMask | LeaveWindowMask)
-
-#define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
-#define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
-
-#define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_b)
-
-static void flash_done(gpointer data);
-static gboolean flash_timeout(gpointer data);
-
-static void layout_title(ObFrame *self);
-static void set_theme_statics(ObFrame *self);
-static void free_theme_statics(ObFrame *self);
-static gboolean frame_animate_iconify(gpointer self);
-static void frame_adjust_cursors(ObFrame *self);
-
-static Window createWindow(Window parent, Visual *visual,
-                           gulong mask, XSetWindowAttributes *attrib)
-{
-    return XCreateWindow(obt_display, parent, 0, 0, 1, 1, 0,
-                         (visual ? 32 : RrDepth(ob_rr_inst)), InputOutput,
-                         (visual ? visual : RrVisual(ob_rr_inst)),
-                         mask, attrib);
-
-}
-
-static Visual *check_32bit_client(ObClient *c)
-{
-    XWindowAttributes wattrib;
-    Status ret;
-
-    /* we're already running at 32 bit depth, yay. we don't need to use their
-       visual */
-    if (RrDepth(ob_rr_inst) == 32)
-        return NULL;
-
-    ret = XGetWindowAttributes(obt_display, c->window, &wattrib);
-    g_assert(ret != BadDrawable);
-    g_assert(ret != BadWindow);
-
-    if (wattrib.depth == 32)
-        return wattrib.visual;
-    return NULL;
-}
-
-ObFrame *frame_new(ObClient *client)
-{
-    XSetWindowAttributes attrib;
-    gulong mask;
-    ObFrame *self;
-    Visual *visual;
-
-    self = g_new0(ObFrame, 1);
-    self->client = client;
-
-    visual = check_32bit_client(client);
-
-    /* create the non-visible decor windows */
-
-    mask = 0;
-    if (visual) {
-        /* client has a 32-bit visual */
-        mask |= CWColormap | CWBackPixel | CWBorderPixel;
-        /* create a colormap with the visual */
-        self->colormap = attrib.colormap =
-            XCreateColormap(obt_display, obt_root(ob_screen),
-                            visual, AllocNone);
-        attrib.background_pixel = BlackPixel(obt_display, ob_screen);
-        attrib.border_pixel = BlackPixel(obt_display, ob_screen);
-    }
-    self->window = createWindow(obt_root(ob_screen), visual,
-                                mask, &attrib);
-
-    /* create the visible decor windows */
-
-    mask = 0;
-    if (visual) {
-        /* client has a 32-bit visual */
-        mask |= CWColormap | CWBackPixel | CWBorderPixel;
-        attrib.colormap = RrColormap(ob_rr_inst);
-    }
-
-    self->backback = createWindow(self->window, NULL, mask, &attrib);
-    self->backfront = createWindow(self->backback, NULL, mask, &attrib);
-
-    mask |= CWEventMask;
-    attrib.event_mask = ELEMENT_EVENTMASK;
-    self->innerleft = createWindow(self->window, NULL, mask, &attrib);
-    self->innertop = createWindow(self->window, NULL, mask, &attrib);
-    self->innerright = createWindow(self->window, NULL, mask, &attrib);
-    self->innerbottom = createWindow(self->window, NULL, mask, &attrib);
-
-    self->innerblb = createWindow(self->innerbottom, NULL, mask, &attrib);
-    self->innerbrb = createWindow(self->innerbottom, NULL, mask, &attrib);
-    self->innerbll = createWindow(self->innerleft, NULL, mask, &attrib);
-    self->innerbrr = createWindow(self->innerright, NULL, mask, &attrib);
-
-    self->title = createWindow(self->window, NULL, mask, &attrib);
-    self->titleleft = createWindow(self->window, NULL, mask, &attrib);
-    self->titletop = createWindow(self->window, NULL, mask, &attrib);
-    self->titletopleft = createWindow(self->window, NULL, mask, &attrib);
-    self->titletopright = createWindow(self->window, NULL, mask, &attrib);
-    self->titleright = createWindow(self->window, NULL, mask, &attrib);
-    self->titlebottom = createWindow(self->window, NULL, mask, &attrib);
-
-    self->topresize = createWindow(self->title, NULL, mask, &attrib);
-    self->tltresize = createWindow(self->title, NULL, mask, &attrib);
-    self->tllresize = createWindow(self->title, NULL, mask, &attrib);
-    self->trtresize = createWindow(self->title, NULL, mask, &attrib);
-    self->trrresize = createWindow(self->title, NULL, mask, &attrib);
-
-    self->left = createWindow(self->window, NULL, mask, &attrib);
-    self->right = createWindow(self->window, NULL, mask, &attrib);
-
-    self->label = createWindow(self->title, NULL, mask, &attrib);
-    self->max = createWindow(self->title, NULL, mask, &attrib);
-    self->close = createWindow(self->title, NULL, mask, &attrib);
-    self->desk = createWindow(self->title, NULL, mask, &attrib);
-    self->shade = createWindow(self->title, NULL, mask, &attrib);
-    self->icon = createWindow(self->title, NULL, mask, &attrib);
-    self->iconify = createWindow(self->title, NULL, mask, &attrib);
-
-    self->handle = createWindow(self->window, NULL, mask, &attrib);
-    self->lgrip = createWindow(self->handle, NULL, mask, &attrib);
-    self->rgrip = createWindow(self->handle, NULL, mask, &attrib);
-
-    self->handleleft = createWindow(self->handle, NULL, mask, &attrib);
-    self->handleright = createWindow(self->handle, NULL, mask, &attrib);
-
-    self->handletop = createWindow(self->window, NULL, mask, &attrib);
-    self->handlebottom = createWindow(self->window, NULL, mask, &attrib);
-    self->lgripleft = createWindow(self->window, NULL, mask, &attrib);
-    self->lgriptop = createWindow(self->window, NULL, mask, &attrib);
-    self->lgripbottom = createWindow(self->window, NULL, mask, &attrib);
-    self->rgripright = createWindow(self->window, NULL, mask, &attrib);
-    self->rgriptop = createWindow(self->window, NULL, mask, &attrib);
-    self->rgripbottom = createWindow(self->window, NULL, mask, &attrib);
-
-    self->focused = FALSE;
-
-    /* the other stuff is shown based on decor settings */
-    XMapWindow(obt_display, self->label);
-    XMapWindow(obt_display, self->backback);
-    XMapWindow(obt_display, self->backfront);
-
-    self->max_press = self->close_press = self->desk_press =
-        self->iconify_press = self->shade_press = FALSE;
-    self->max_hover = self->close_hover = self->desk_hover =
-        self->iconify_hover = self->shade_hover = FALSE;
-
-    set_theme_statics(self);
-
-    return (ObFrame*)self;
-}
-
-static void set_theme_statics(ObFrame *self)
-{
-    /* set colors/appearance/sizes for stuff that doesn't change */
-    XResizeWindow(obt_display, self->max,
-                  ob_rr_theme->button_size, ob_rr_theme->button_size);
-    XResizeWindow(obt_display, self->iconify,
-                  ob_rr_theme->button_size, ob_rr_theme->button_size);
-    XResizeWindow(obt_display, self->icon,
-                  ob_rr_theme->button_size + 2, ob_rr_theme->button_size + 2);
-    XResizeWindow(obt_display, self->close,
-                  ob_rr_theme->button_size, ob_rr_theme->button_size);
-    XResizeWindow(obt_display, self->desk,
-                  ob_rr_theme->button_size, ob_rr_theme->button_size);
-    XResizeWindow(obt_display, self->shade,
-                  ob_rr_theme->button_size, ob_rr_theme->button_size);
-    XResizeWindow(obt_display, self->tltresize,
-                  ob_rr_theme->grip_width, ob_rr_theme->paddingy + 1);
-    XResizeWindow(obt_display, self->trtresize,
-                  ob_rr_theme->grip_width, ob_rr_theme->paddingy + 1);
-    XResizeWindow(obt_display, self->tllresize,
-                  ob_rr_theme->paddingx + 1, ob_rr_theme->title_height);
-    XResizeWindow(obt_display, self->trrresize,
-                  ob_rr_theme->paddingx + 1, ob_rr_theme->title_height);
-}
-
-static void free_theme_statics(ObFrame *self)
-{
-}
-
-void frame_free(ObFrame *self)
-{
-    free_theme_statics(self);
-
-    XDestroyWindow(obt_display, self->window);
-    if (self->colormap)
-        XFreeColormap(obt_display, self->colormap);
-
-    g_free(self);
-}
-
-void frame_show(ObFrame *self)
-{
-    if (!self->visible) {
-        self->visible = TRUE;
-        framerender_frame(self);
-        /* Grab the server to make sure that the frame window is mapped before
-           the client gets its MapNotify, i.e. to make sure the client is
-           _visible_ when it gets MapNotify. */
-        grab_server(TRUE);
-        XMapWindow(obt_display, self->client->window);
-        XMapWindow(obt_display, self->window);
-        grab_server(FALSE);
-    }
-}
-
-void frame_hide(ObFrame *self)
-{
-    if (self->visible) {
-        self->visible = FALSE;
-        if (!frame_iconify_animating(self))
-            XUnmapWindow(obt_display, self->window);
-        /* we unmap the client itself so that we can get MapRequest
-           events, and because the ICCCM tells us to! */
-        XUnmapWindow(obt_display, self->client->window);
-        self->client->ignore_unmaps += 1;
-    }
-}
-
-void frame_adjust_theme(ObFrame *self)
-{
-    free_theme_statics(self);
-    set_theme_statics(self);
-}
-
-void frame_adjust_shape(ObFrame *self)
-{
-#ifdef SHAPE
-    gint num;
-    XRectangle xrect[2];
-
-    if (!self->client->shaped) {
-        /* clear the shape on the frame window */
-        XShapeCombineMask(obt_display, self->window, ShapeBounding,
-                          self->size.left,
-                          self->size.top,
-                          None, ShapeSet);
-    } else {
-        /* make the frame's shape match the clients */
-        XShapeCombineShape(obt_display, self->window, ShapeBounding,
-                           self->size.left,
-                           self->size.top,
-                           self->client->window,
-                           ShapeBounding, ShapeSet);
-
-        num = 0;
-        if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
-            xrect[0].x = 0;
-            xrect[0].y = 0;
-            xrect[0].width = self->area.width;
-            xrect[0].height = self->size.top;
-            ++num;
-        }
-
-        if (self->decorations & OB_FRAME_DECOR_HANDLE &&
-            ob_rr_theme->handle_height > 0)
-        {
-            xrect[1].x = 0;
-            xrect[1].y = FRAME_HANDLE_Y(self);
-            xrect[1].width = self->area.width;
-            xrect[1].height = ob_rr_theme->handle_height +
-                self->bwidth * 2;
-            ++num;
-        }
-
-        XShapeCombineRectangles(obt_display, self->window,
-                                ShapeBounding, 0, 0, xrect, num,
-                                ShapeUnion, Unsorted);
-    }
-#endif
-}
-
-void frame_adjust_area(ObFrame *self, gboolean moved,
-                       gboolean resized, gboolean fake)
-{
-    Strut oldsize;
-
-    oldsize = self->size;
-
-    if (resized) {
-        /* do this before changing the frame's status like max_horz max_vert */
-        frame_adjust_cursors(self);
-
-        self->functions = self->client->functions;
-        self->decorations = self->client->decorations;
-        self->max_horz = self->client->max_horz;
-        self->max_vert = self->client->max_vert;
-        self->shaded = self->client->shaded;
-
-        if (self->decorations & OB_FRAME_DECOR_BORDER ||
-            (self->client->undecorated && config_theme_keepborder))
-            self->bwidth = ob_rr_theme->fbwidth;
-        else
-            self->bwidth = 0;
-
-        if (self->decorations & OB_FRAME_DECOR_BORDER) {
-            self->cbwidth_l = self->cbwidth_r = ob_rr_theme->cbwidthx;
-            self->cbwidth_t = self->cbwidth_b = ob_rr_theme->cbwidthy;
-        } else
-            self->cbwidth_l = self->cbwidth_t =
-                self->cbwidth_r = self->cbwidth_b = 0;
-
-        if (self->max_horz) {
-            self->cbwidth_l = self->cbwidth_r = 0;
-            self->width = self->client->area.width;
-            if (self->max_vert)
-                self->cbwidth_b = 0;
-        } else
-            self->width = self->client->area.width +
-                self->cbwidth_l + self->cbwidth_r;
-
-        /* some elements are sized based of the width, so don't let them have
-           negative values */
-        self->width = MAX(self->width,
-                          (ob_rr_theme->grip_width + self->bwidth) * 2 + 1);
-
-        STRUT_SET(self->size,
-                  self->cbwidth_l + (!self->max_horz ? self->bwidth : 0),
-                  self->cbwidth_t +
-                  (!self->max_horz || !self->max_vert ||
-                   !self->client->undecorated ? self->bwidth : 0),
-                  self->cbwidth_r + (!self->max_horz ? self->bwidth : 0),
-                  self->cbwidth_b +
-                  (!self->max_horz || !self->max_vert ? self->bwidth : 0));
-
-        if (self->decorations & OB_FRAME_DECOR_TITLEBAR)
-            self->size.top += ob_rr_theme->title_height + self->bwidth;
-        if (self->decorations & OB_FRAME_DECOR_HANDLE &&
-            ob_rr_theme->handle_height > 0)
-        {
-            self->size.bottom += ob_rr_theme->handle_height + self->bwidth;
-        }
-
-        /* position/size and map/unmap all the windows */
-
-        if (!fake) {
-            gint innercornerheight =
-                ob_rr_theme->grip_width - self->size.bottom;
-
-            if (self->cbwidth_l) {
-                XMoveResizeWindow(obt_display, self->innerleft,
-                                  self->size.left - self->cbwidth_l,
-                                  self->size.top,
-                                  self->cbwidth_l, self->client->area.height);
-
-                XMapWindow(obt_display, self->innerleft);
-            } else
-                XUnmapWindow(obt_display, self->innerleft);
-
-            if (self->cbwidth_l && innercornerheight > 0) {
-                XMoveResizeWindow(obt_display, self->innerbll,
-                                  0,
-                                  self->client->area.height - 
-                                  (ob_rr_theme->grip_width -
-                                   self->size.bottom),
-                                  self->cbwidth_l,
-                                  ob_rr_theme->grip_width - self->size.bottom);
-
-                XMapWindow(obt_display, self->innerbll);
-            } else
-                XUnmapWindow(obt_display, self->innerbll);
-
-            if (self->cbwidth_r) {
-                XMoveResizeWindow(obt_display, self->innerright,
-                                  self->size.left + self->client->area.width,
-                                  self->size.top,
-                                  self->cbwidth_r, self->client->area.height);
-
-                XMapWindow(obt_display, self->innerright);
-            } else
-                XUnmapWindow(obt_display, self->innerright);
-
-            if (self->cbwidth_r && innercornerheight > 0) {
-                XMoveResizeWindow(obt_display, self->innerbrr,
-                                  0,
-                                  self->client->area.height - 
-                                  (ob_rr_theme->grip_width -
-                                   self->size.bottom),
-                                  self->cbwidth_r,
-                                  ob_rr_theme->grip_width - self->size.bottom);
-
-                XMapWindow(obt_display, self->innerbrr);
-            } else
-                XUnmapWindow(obt_display, self->innerbrr);
-
-            if (self->cbwidth_t) {
-                XMoveResizeWindow(obt_display, self->innertop,
-                                  self->size.left - self->cbwidth_l,
-                                  self->size.top - self->cbwidth_t,
-                                  self->client->area.width +
-                                  self->cbwidth_l + self->cbwidth_r,
-                                  self->cbwidth_t);
-
-                XMapWindow(obt_display, self->innertop);
-            } else
-                XUnmapWindow(obt_display, self->innertop);
-
-            if (self->cbwidth_b) {
-                XMoveResizeWindow(obt_display, self->innerbottom,
-                                  self->size.left - self->cbwidth_l,
-                                  self->size.top + self->client->area.height,
-                                  self->client->area.width +
-                                  self->cbwidth_l + self->cbwidth_r,
-                                  self->cbwidth_b);
-
-                XMoveResizeWindow(obt_display, self->innerblb,
-                                  0, 0,
-                                  ob_rr_theme->grip_width + self->bwidth,
-                                  self->cbwidth_b);
-                XMoveResizeWindow(obt_display, self->innerbrb,
-                                  self->client->area.width +
-                                  self->cbwidth_l + self->cbwidth_r -
-                                  (ob_rr_theme->grip_width + self->bwidth),
-                                  0,
-                                  ob_rr_theme->grip_width + self->bwidth,
-                                  self->cbwidth_b);
-
-                XMapWindow(obt_display, self->innerbottom);
-                XMapWindow(obt_display, self->innerblb);
-                XMapWindow(obt_display, self->innerbrb);
-            } else {
-                XUnmapWindow(obt_display, self->innerbottom);
-                XUnmapWindow(obt_display, self->innerblb);
-                XUnmapWindow(obt_display, self->innerbrb);
-            }
-
-            if (self->bwidth) {
-                gint titlesides;
-
-                /* height of titleleft and titleright */
-                titlesides = (!self->max_horz ? ob_rr_theme->grip_width : 0);
-
-                XMoveResizeWindow(obt_display, self->titletop,
-                                  ob_rr_theme->grip_width + self->bwidth, 0,
-                                  /* width + bwidth*2 - bwidth*2 - grips*2 */
-                                  self->width - ob_rr_theme->grip_width * 2,
-                                  self->bwidth);
-                XMoveResizeWindow(obt_display, self->titletopleft,
-                                  0, 0,
-                                  ob_rr_theme->grip_width + self->bwidth,
-                                  self->bwidth);
-                XMoveResizeWindow(obt_display, self->titletopright,
-                                  self->client->area.width +
-                                  self->size.left + self->size.right -
-                                  ob_rr_theme->grip_width - self->bwidth,
-                                  0,
-                                  ob_rr_theme->grip_width + self->bwidth,
-                                  self->bwidth);
-
-                if (titlesides > 0) {
-                    XMoveResizeWindow(obt_display, self->titleleft,
-                                      0, self->bwidth,
-                                      self->bwidth,
-                                      titlesides);
-                    XMoveResizeWindow(obt_display, self->titleright,
-                                      self->client->area.width +
-                                      self->size.left + self->size.right -
-                                      self->bwidth,
-                                      self->bwidth,
-                                      self->bwidth,
-                                      titlesides);
-
-                    XMapWindow(obt_display, self->titleleft);
-                    XMapWindow(obt_display, self->titleright);
-                } else {
-                    XUnmapWindow(obt_display, self->titleleft);
-                    XUnmapWindow(obt_display, self->titleright);
-                }
-
-                XMapWindow(obt_display, self->titletop);
-                XMapWindow(obt_display, self->titletopleft);
-                XMapWindow(obt_display, self->titletopright);
-
-                if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
-                    XMoveResizeWindow(obt_display, self->titlebottom,
-                                      (self->max_horz ? 0 : self->bwidth),
-                                      ob_rr_theme->title_height + self->bwidth,
-                                      self->width,
-                                      self->bwidth);
-
-                    XMapWindow(obt_display, self->titlebottom);
-                } else
-                    XUnmapWindow(obt_display, self->titlebottom);
-            } else {
-                XUnmapWindow(obt_display, self->titlebottom);
-
-                XUnmapWindow(obt_display, self->titletop);
-                XUnmapWindow(obt_display, self->titletopleft);
-                XUnmapWindow(obt_display, self->titletopright);
-                XUnmapWindow(obt_display, self->titleleft);
-                XUnmapWindow(obt_display, self->titleright);
-            }
-
-            if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
-                XMoveResizeWindow(obt_display, self->title,
-                                  (self->max_horz ? 0 : self->bwidth),
-                                  self->bwidth,
-                                  self->width, ob_rr_theme->title_height);
-
-                XMapWindow(obt_display, self->title);
-
-                if (self->decorations & OB_FRAME_DECOR_GRIPS) {
-                    XMoveResizeWindow(obt_display, self->topresize,
-                                      ob_rr_theme->grip_width,
-                                      0,
-                                      self->width - ob_rr_theme->grip_width *2,
-                                      ob_rr_theme->paddingy + 1);
-
-                    XMoveWindow(obt_display, self->tltresize, 0, 0);
-                    XMoveWindow(obt_display, self->tllresize, 0, 0);
-                    XMoveWindow(obt_display, self->trtresize,
-                                self->width - ob_rr_theme->grip_width, 0);
-                    XMoveWindow(obt_display, self->trrresize,
-                                self->width - ob_rr_theme->paddingx - 1, 0);
-
-                    XMapWindow(obt_display, self->topresize);
-                    XMapWindow(obt_display, self->tltresize);
-                    XMapWindow(obt_display, self->tllresize);
-                    XMapWindow(obt_display, self->trtresize);
-                    XMapWindow(obt_display, self->trrresize);
-                } else {
-                    XUnmapWindow(obt_display, self->topresize);
-                    XUnmapWindow(obt_display, self->tltresize);
-                    XUnmapWindow(obt_display, self->tllresize);
-                    XUnmapWindow(obt_display, self->trtresize);
-                    XUnmapWindow(obt_display, self->trrresize);
-                }
-            } else
-                XUnmapWindow(obt_display, self->title);
-        }
-
-        if ((self->decorations & OB_FRAME_DECOR_TITLEBAR))
-            /* layout the title bar elements */
-            layout_title(self);
-
-        if (!fake) {
-            gint sidebwidth = self->max_horz ? 0 : self->bwidth;
-
-            if (self->bwidth && self->size.bottom) {
-                XMoveResizeWindow(obt_display, self->handlebottom,
-                                  ob_rr_theme->grip_width +
-                                  self->bwidth + sidebwidth,
-                                  self->size.top + self->client->area.height +
-                                  self->size.bottom - self->bwidth,
-                                  self->width - (ob_rr_theme->grip_width +
-                                                 sidebwidth) * 2,
-                                  self->bwidth);
-
-
-                if (sidebwidth) {
-                    XMoveResizeWindow(obt_display, self->lgripleft,
-                                      0,
-                                      self->size.top +
-                                      self->client->area.height +
-                                      self->size.bottom -
-                                      (!self->max_horz ?
-                                       ob_rr_theme->grip_width :
-                                       self->size.bottom - self->cbwidth_b),
-                                      self->bwidth,
-                                      (!self->max_horz ?
-                                       ob_rr_theme->grip_width :
-                                       self->size.bottom - self->cbwidth_b));
-                    XMoveResizeWindow(obt_display, self->rgripright,
-                                  self->size.left +
-                                      self->client->area.width +
-                                      self->size.right - self->bwidth,
-                                      self->size.top +
-                                      self->client->area.height +
-                                      self->size.bottom -
-                                      (!self->max_horz ?
-                                       ob_rr_theme->grip_width :
-                                       self->size.bottom - self->cbwidth_b),
-                                      self->bwidth,
-                                      (!self->max_horz ?
-                                       ob_rr_theme->grip_width :
-                                       self->size.bottom - self->cbwidth_b));
-
-                    XMapWindow(obt_display, self->lgripleft);
-                    XMapWindow(obt_display, self->rgripright);
-                } else {
-                    XUnmapWindow(obt_display, self->lgripleft);
-                    XUnmapWindow(obt_display, self->rgripright);
-                }
-
-                XMoveResizeWindow(obt_display, self->lgripbottom,
-                                  sidebwidth,
-                                  self->size.top + self->client->area.height +
-                                  self->size.bottom - self->bwidth,
-                                  ob_rr_theme->grip_width + self->bwidth,
-                                  self->bwidth);
-                XMoveResizeWindow(obt_display, self->rgripbottom,
-                                  self->size.left + self->client->area.width +
-                                  self->size.right - self->bwidth - sidebwidth-
-                                  ob_rr_theme->grip_width,
-                                  self->size.top + self->client->area.height +
-                                  self->size.bottom - self->bwidth,
-                                  ob_rr_theme->grip_width + self->bwidth,
-                                  self->bwidth);
-
-                XMapWindow(obt_display, self->handlebottom);
-                XMapWindow(obt_display, self->lgripbottom);
-                XMapWindow(obt_display, self->rgripbottom);
-
-                if (self->decorations & OB_FRAME_DECOR_HANDLE &&
-                    ob_rr_theme->handle_height > 0)
-                {
-                    XMoveResizeWindow(obt_display, self->handletop,
-                                      ob_rr_theme->grip_width +
-                                      self->bwidth + sidebwidth,
-                                      FRAME_HANDLE_Y(self),
-                                      self->width - (ob_rr_theme->grip_width +
-                                                     sidebwidth) * 2,
-                                      self->bwidth);
-                    XMapWindow(obt_display, self->handletop);
-
-                    if (self->decorations & OB_FRAME_DECOR_GRIPS) {
-                        XMoveResizeWindow(obt_display, self->handleleft,
-                                          ob_rr_theme->grip_width,
-                                          0,
-                                          self->bwidth,
-                                          ob_rr_theme->handle_height);
-                        XMoveResizeWindow(obt_display, self->handleright,
-                                          self->width -
-                                          ob_rr_theme->grip_width -
-                                          self->bwidth,
-                                          0,
-                                          self->bwidth,
-                                          ob_rr_theme->handle_height);
-
-                        XMoveResizeWindow(obt_display, self->lgriptop,
-                                          sidebwidth,
-                                          FRAME_HANDLE_Y(self),
-                                          ob_rr_theme->grip_width +
-                                          self->bwidth,
-                                          self->bwidth);
-                        XMoveResizeWindow(obt_display, self->rgriptop,
-                                          self->size.left +
-                                          self->client->area.width +
-                                          self->size.right - self->bwidth -
-                                          sidebwidth - ob_rr_theme->grip_width,
-                                          FRAME_HANDLE_Y(self),
-                                          ob_rr_theme->grip_width +
-                                          self->bwidth,
-                                          self->bwidth);
-
-                        XMapWindow(obt_display, self->handleleft);
-                        XMapWindow(obt_display, self->handleright);
-                        XMapWindow(obt_display, self->lgriptop);
-                        XMapWindow(obt_display, self->rgriptop);
-                    } else {
-                        XUnmapWindow(obt_display, self->handleleft);
-                        XUnmapWindow(obt_display, self->handleright);
-                        XUnmapWindow(obt_display, self->lgriptop);
-                        XUnmapWindow(obt_display, self->rgriptop);
-                    }
-                } else {
-                    XUnmapWindow(obt_display, self->handleleft);
-                    XUnmapWindow(obt_display, self->handleright);
-                    XUnmapWindow(obt_display, self->lgriptop);
-                    XUnmapWindow(obt_display, self->rgriptop);
-
-                    XUnmapWindow(obt_display, self->handletop);
-                }
-            } else {
-                XUnmapWindow(obt_display, self->handleleft);
-                XUnmapWindow(obt_display, self->handleright);
-                XUnmapWindow(obt_display, self->lgriptop);
-                XUnmapWindow(obt_display, self->rgriptop);
-
-                XUnmapWindow(obt_display, self->handletop);
-
-                XUnmapWindow(obt_display, self->handlebottom);
-                XUnmapWindow(obt_display, self->lgripleft);
-                XUnmapWindow(obt_display, self->rgripright);
-                XUnmapWindow(obt_display, self->lgripbottom);
-                XUnmapWindow(obt_display, self->rgripbottom);
-            }
-
-            if (self->decorations & OB_FRAME_DECOR_HANDLE &&
-                ob_rr_theme->handle_height > 0)
-            {
-                XMoveResizeWindow(obt_display, self->handle,
-                                  sidebwidth,
-                                  FRAME_HANDLE_Y(self) + self->bwidth,
-                                  self->width, ob_rr_theme->handle_height);
-                XMapWindow(obt_display, self->handle);
-
-                if (self->decorations & OB_FRAME_DECOR_GRIPS) {
-                    XMoveResizeWindow(obt_display, self->lgrip,
-                                      0, 0,
-                                      ob_rr_theme->grip_width,
-                                      ob_rr_theme->handle_height);
-                    XMoveResizeWindow(obt_display, self->rgrip,
-                                      self->width - ob_rr_theme->grip_width,
-                                      0,
-                                      ob_rr_theme->grip_width,
-                                      ob_rr_theme->handle_height);
-
-                    XMapWindow(obt_display, self->lgrip);
-                    XMapWindow(obt_display, self->rgrip);
-                } else {
-                    XUnmapWindow(obt_display, self->lgrip);
-                    XUnmapWindow(obt_display, self->rgrip);
-                }
-            } else {
-                XUnmapWindow(obt_display, self->lgrip);
-                XUnmapWindow(obt_display, self->rgrip);
-
-                XUnmapWindow(obt_display, self->handle);
-            }
-
-            if (self->bwidth && !self->max_horz &&
-                (self->client->area.height + self->size.top +
-                 self->size.bottom) > ob_rr_theme->grip_width * 2)
-            {
-                XMoveResizeWindow(obt_display, self->left,
-                                  0,
-                                  self->bwidth + ob_rr_theme->grip_width,
-                                  self->bwidth,
-                                  self->client->area.height +
-                                  self->size.top + self->size.bottom -
-                                  ob_rr_theme->grip_width * 2);
-
-                XMapWindow(obt_display, self->left);
-            } else
-                XUnmapWindow(obt_display, self->left);
-
-            if (self->bwidth && !self->max_horz &&
-                (self->client->area.height + self->size.top +
-                 self->size.bottom) > ob_rr_theme->grip_width * 2)
-            {
-                XMoveResizeWindow(obt_display, self->right,
-                                  self->client->area.width + self->cbwidth_l +
-                                  self->cbwidth_r + self->bwidth,
-                                  self->bwidth + ob_rr_theme->grip_width,
-                                  self->bwidth,
-                                  self->client->area.height +
-                                  self->size.top + self->size.bottom -
-                                  ob_rr_theme->grip_width * 2);
-
-                XMapWindow(obt_display, self->right);
-            } else
-                XUnmapWindow(obt_display, self->right);
-
-            XMoveResizeWindow(obt_display, self->backback,
-                              self->size.left, self->size.top,
-                              self->client->area.width,
-                              self->client->area.height);
-        }
-    }
-
-    /* shading can change without being moved or resized */
-    RECT_SET_SIZE(self->area,
-                  self->client->area.width +
-                  self->size.left + self->size.right,
-                  (self->client->shaded ?
-                   ob_rr_theme->title_height + self->bwidth * 2:
-                   self->client->area.height +
-                   self->size.top + self->size.bottom));
-
-    if ((moved || resized) && !fake) {
-        /* find the new coordinates, done after setting the frame.size, for
-           frame_client_gravity. */
-        self->area.x = self->client->area.x;
-        self->area.y = self->client->area.y;
-        frame_client_gravity(self, &self->area.x, &self->area.y);
-    }
-
-    if (!fake) {
-        if (!frame_iconify_animating(self))
-            /* move and resize the top level frame.
-               shading can change without being moved or resized.
-
-               but don't do this during an iconify animation. it will be
-               reflected afterwards.
-            */
-            XMoveResizeWindow(obt_display, self->window,
-                              self->area.x,
-                              self->area.y,
-                              self->area.width,
-                              self->area.height);
-
-        /* when the client has StaticGravity, it likes to move around.
-           also this correctly positions the client when it maps.
-           this also needs to be run when the frame's decorations sizes change!
-        */
-        XMoveWindow(obt_display, self->client->window,
-                    self->size.left, self->size.top);
-
-        if (resized) {
-            self->need_render = TRUE;
-            framerender_frame(self);
-            frame_adjust_shape(self);
-        }
-
-        if (!STRUT_EQUAL(self->size, oldsize)) {
-            gulong vals[4];
-            vals[0] = self->size.left;
-            vals[1] = self->size.right;
-            vals[2] = self->size.top;
-            vals[3] = self->size.bottom;
-            OBT_PROP_SETA32(self->client->window, NET_FRAME_EXTENTS,
-                            CARDINAL, vals, 4);
-            OBT_PROP_SETA32(self->client->window, KDE_NET_WM_FRAME_STRUT,
-                            CARDINAL, vals, 4);
-        }
-
-        /* if this occurs while we are focus cycling, the indicator needs to
-           match the changes */
-        if (focus_cycle_target == self->client)
-            focus_cycle_draw_indicator(self->client);
-    }
-    if (resized && (self->decorations & OB_FRAME_DECOR_TITLEBAR))
-        XResizeWindow(obt_display, self->label, self->label_width,
-                      ob_rr_theme->label_height);
-
-}
-
-static void frame_adjust_cursors(ObFrame *self)
-{
-    if ((self->functions & OB_CLIENT_FUNC_RESIZE) !=
-        (self->client->functions & OB_CLIENT_FUNC_RESIZE) ||
-        self->max_horz != self->client->max_horz ||
-        self->max_vert != self->client->max_vert ||
-        self->shaded != self->client->shaded)
-    {
-        gboolean r = (self->client->functions & OB_CLIENT_FUNC_RESIZE) &&
-            !(self->client->max_horz && self->client->max_vert);
-        gboolean topbot = !self->client->max_vert;
-        gboolean sh = self->client->shaded;
-        XSetWindowAttributes a;
-
-        /* these ones turn off when max vert, and some when shaded */
-        a.cursor = ob_cursor(r && topbot && !sh ?
-                             OB_CURSOR_NORTH : OB_CURSOR_NONE);
-        XChangeWindowAttributes(obt_display, self->topresize, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->titletop, CWCursor, &a);
-        a.cursor = ob_cursor(r && topbot ? OB_CURSOR_SOUTH : OB_CURSOR_NONE);
-        XChangeWindowAttributes(obt_display, self->handle, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->handletop, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->handlebottom, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->innerbottom, CWCursor, &a);
-
-        /* these ones change when shaded */
-        a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_WEST : OB_CURSOR_NORTHWEST) :
-                             OB_CURSOR_NONE);
-        XChangeWindowAttributes(obt_display, self->titleleft, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->tltresize, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->tllresize, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->titletopleft, CWCursor, &a);
-        a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_EAST : OB_CURSOR_NORTHEAST) :
-                             OB_CURSOR_NONE);
-        XChangeWindowAttributes(obt_display, self->titleright, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->trtresize, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->trrresize, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->titletopright, CWCursor,&a);
-
-        /* these ones are pretty static */
-        a.cursor = ob_cursor(r ? OB_CURSOR_WEST : OB_CURSOR_NONE);
-        XChangeWindowAttributes(obt_display, self->left, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->innerleft, CWCursor, &a);
-        a.cursor = ob_cursor(r ? OB_CURSOR_EAST : OB_CURSOR_NONE);
-        XChangeWindowAttributes(obt_display, self->right, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->innerright, CWCursor, &a);
-        a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHWEST : OB_CURSOR_NONE);
-        XChangeWindowAttributes(obt_display, self->lgrip, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->handleleft, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->lgripleft, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->lgriptop, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->lgripbottom, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->innerbll, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->innerblb, CWCursor, &a);
-        a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHEAST : OB_CURSOR_NONE);
-        XChangeWindowAttributes(obt_display, self->rgrip, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->handleright, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->rgripright, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->rgriptop, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->rgripbottom, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->innerbrr, CWCursor, &a);
-        XChangeWindowAttributes(obt_display, self->innerbrb, CWCursor, &a);
-    }
-}
-
-void frame_adjust_client_area(ObFrame *self)
-{
-    /* adjust the window which is there to prevent flashing on unmap */
-    XMoveResizeWindow(obt_display, self->backfront, 0, 0,
-                      self->client->area.width,
-                      self->client->area.height);
-}
-
-void frame_adjust_state(ObFrame *self)
-{
-    self->need_render = TRUE;
-    framerender_frame(self);
-}
-
-void frame_adjust_focus(ObFrame *self, gboolean hilite)
-{
-    self->focused = hilite;
-    self->need_render = TRUE;
-    framerender_frame(self);
-    XFlush(obt_display);
-}
-
-void frame_adjust_title(ObFrame *self)
-{
-    self->need_render = TRUE;
-    framerender_frame(self);
-}
-
-void frame_adjust_icon(ObFrame *self)
-{
-    self->need_render = TRUE;
-    framerender_frame(self);
-}
-
-void frame_grab_client(ObFrame *self)
-{
-    /* DO NOT map the client window here. we used to do that, but it is bogus.
-       we need to set up the client's dimensions and everything before we
-       send a mapnotify or we create race conditions.
-    */
-
-    /* reparent the client to the frame */
-    XReparentWindow(obt_display, self->client->window, self->window, 0, 0);
-
-    /*
-      When reparenting the client window, it is usually not mapped yet, since
-      this occurs from a MapRequest. However, in the case where Openbox is
-      starting up, the window is already mapped, so we'll see an unmap event
-      for it.
-    */
-    if (ob_state() == OB_STATE_STARTING)
-        ++self->client->ignore_unmaps;
-
-    /* select the event mask on the client's parent (to receive config/map
-       req's) the ButtonPress is to catch clicks on the client border */
-    XSelectInput(obt_display, self->window, FRAME_EVENTMASK);
-
-    /* set all the windows for the frame in the window_map */
-    window_add(&self->window, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->backback, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->backfront, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->innerleft, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->innertop, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->innerright, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->innerbottom, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->innerblb, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->innerbll, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->innerbrb, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->innerbrr, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->title, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->label, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->max, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->close, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->desk, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->shade, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->icon, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->iconify, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->handle, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->lgrip, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->rgrip, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->topresize, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->tltresize, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->tllresize, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->trtresize, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->trrresize, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->left, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->right, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->titleleft, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->titletop, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->titletopleft, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->titletopright, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->titleright, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->titlebottom, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->handleleft, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->handletop, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->handleright, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->handlebottom, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->lgripleft, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->lgriptop, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->lgripbottom, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->rgripright, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->rgriptop, CLIENT_AS_WINDOW(self->client));
-    window_add(&self->rgripbottom, CLIENT_AS_WINDOW(self->client));
-}
-
-void frame_release_client(ObFrame *self)
-{
-    XEvent ev;
-    gboolean reparent = TRUE;
-
-    /* if there was any animation going on, kill it */
-    obt_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify,
-                                      self, FALSE);
-
-    /* check if the app has already reparented its window away */
-    while (XCheckTypedWindowEvent(obt_display, self->client->window,
-                                  ReparentNotify, &ev))
-    {
-        /* This check makes sure we don't catch our own reparent action to
-           our frame window. This doesn't count as the app reparenting itself
-           away of course.
-
-           Reparent events that are generated by us are just discarded here.
-           They are of no consequence to us anyhow.
-        */
-        if (ev.xreparent.parent != self->window) {
-            reparent = FALSE;
-            XPutBackEvent(obt_display, &ev);
-            break;
-        }
-    }
-
-    if (reparent) {
-        /* according to the ICCCM - if the client doesn't reparent itself,
-           then we will reparent the window to root for them */
-        XReparentWindow(obt_display, self->client->window, obt_root(ob_screen),
-                        self->client->area.x, self->client->area.y);
-    }
-
-    /* remove all the windows for the frame from the window_map */
-    window_remove(self->window);
-    window_remove(self->backback);
-    window_remove(self->backfront);
-    window_remove(self->innerleft);
-    window_remove(self->innertop);
-    window_remove(self->innerright);
-    window_remove(self->innerbottom);
-    window_remove(self->innerblb);
-    window_remove(self->innerbll);
-    window_remove(self->innerbrb);
-    window_remove(self->innerbrr);
-    window_remove(self->title);
-    window_remove(self->label);
-    window_remove(self->max);
-    window_remove(self->close);
-    window_remove(self->desk);
-    window_remove(self->shade);
-    window_remove(self->icon);
-    window_remove(self->iconify);
-    window_remove(self->handle);
-    window_remove(self->lgrip);
-    window_remove(self->rgrip);
-    window_remove(self->topresize);
-    window_remove(self->tltresize);
-    window_remove(self->tllresize);
-    window_remove(self->trtresize);
-    window_remove(self->trrresize);
-    window_remove(self->left);
-    window_remove(self->right);
-    window_remove(self->titleleft);
-    window_remove(self->titletop);
-    window_remove(self->titletopleft);
-    window_remove(self->titletopright);
-    window_remove(self->titleright);
-    window_remove(self->titlebottom);
-    window_remove(self->handleleft);
-    window_remove(self->handletop);
-    window_remove(self->handleright);
-    window_remove(self->handlebottom);
-    window_remove(self->lgripleft);
-    window_remove(self->lgriptop);
-    window_remove(self->lgripbottom);
-    window_remove(self->rgripright);
-    window_remove(self->rgriptop);
-    window_remove(self->rgripbottom);
-
-    obt_main_loop_timeout_remove_data(ob_main_loop, flash_timeout, self, TRUE);
-}
-
-/* is there anything present between us and the label? */
-static gboolean is_button_present(ObFrame *self, const gchar *lc, gint dir) {
-    for (; *lc != '\0' && lc >= config_title_layout; lc += dir) {
-        if (*lc == ' ') continue; /* it was invalid */
-        if (*lc == 'N' && self->decorations & OB_FRAME_DECOR_ICON)
-            return TRUE;
-        if (*lc == 'D' && self->decorations & OB_FRAME_DECOR_ALLDESKTOPS)
-            return TRUE;
-        if (*lc == 'S' && self->decorations & OB_FRAME_DECOR_SHADE)
-            return TRUE;
-        if (*lc == 'I' && self->decorations & OB_FRAME_DECOR_ICONIFY)
-            return TRUE;
-        if (*lc == 'M' && self->decorations & OB_FRAME_DECOR_MAXIMIZE)
-            return TRUE;
-        if (*lc == 'C' && self->decorations & OB_FRAME_DECOR_CLOSE)
-            return TRUE;
-        if (*lc == 'L') return FALSE;
-    }
-    return FALSE;
-}
-
-static void layout_title(ObFrame *self)
-{
-    gchar *lc;
-    gint i;
-
-    const gint bwidth = ob_rr_theme->button_size + ob_rr_theme->paddingx + 1;
-    /* position of the left most button */
-    const gint left = ob_rr_theme->paddingx + 1;
-    /* position of the right most button */
-    const gint right = self->width;
-
-    /* turn them all off */
-    self->icon_on = self->desk_on = self->shade_on = self->iconify_on =
-        self->max_on = self->close_on = self->label_on = FALSE;
-    self->label_width = self->width - (ob_rr_theme->paddingx + 1) * 2;
-    self->leftmost = self->rightmost = OB_FRAME_CONTEXT_NONE;
-
-    /* figure out what's being show, find each element's position, and the
-       width of the label
-
-       do the ones before the label, then after the label,
-       i will be +1 the first time through when working to the left,
-       and -1 the second time through when working to the right */
-    for (i = 1; i >= -1; i-=2) {
-        gint x;
-        ObFrameContext *firstcon;
-
-        if (i > 0) {
-            x = left;
-            lc = config_title_layout;
-            firstcon = &self->leftmost;
-        } else {
-            x = right;
-            lc = config_title_layout + strlen(config_title_layout)-1;
-            firstcon = &self->rightmost;
-        }
-
-        /* stop at the end of the string (or the label, which calls break) */
-        for (; *lc != '\0' && lc >= config_title_layout; lc+=i) {
-            if (*lc == 'L') {
-                if (i > 0) {
-                    self->label_on = TRUE;
-                    self->label_x = x;
-                }
-                break; /* break the for loop, do other side of label */
-            } else if (*lc == 'N') {
-                if (firstcon) *firstcon = OB_FRAME_CONTEXT_ICON;
-                if ((self->icon_on = is_button_present(self, lc, i))) {
-                    /* icon is bigger than buttons */
-                    self->label_width -= bwidth + 2;
-                    if (i > 0) self->icon_x = x;
-                    x += i * (bwidth + 2);
-                    if (i < 0) self->icon_x = x;
-                }
-            } else if (*lc == 'D') {
-                if (firstcon) *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS;
-                if ((self->desk_on = is_button_present(self, lc, i))) {
-                    self->label_width -= bwidth;
-                    if (i > 0) self->desk_x = x;
-                    x += i * bwidth;
-                    if (i < 0) self->desk_x = x;
-                }
-            } else if (*lc == 'S') {
-                if (firstcon) *firstcon = OB_FRAME_CONTEXT_SHADE;
-                if ((self->shade_on = is_button_present(self, lc, i))) {
-                    self->label_width -= bwidth;
-                    if (i > 0) self->shade_x = x;
-                    x += i * bwidth;
-                    if (i < 0) self->shade_x = x;
-                }
-            } else if (*lc == 'I') {
-                if (firstcon) *firstcon = OB_FRAME_CONTEXT_ICONIFY;
-                if ((self->iconify_on = is_button_present(self, lc, i))) {
-                    self->label_width -= bwidth;
-                    if (i > 0) self->iconify_x = x;
-                    x += i * bwidth;
-                    if (i < 0) self->iconify_x = x;
-                }
-            } else if (*lc == 'M') {
-                if (firstcon) *firstcon = OB_FRAME_CONTEXT_MAXIMIZE;
-                if ((self->max_on = is_button_present(self, lc, i))) {
-                    self->label_width -= bwidth;
-                    if (i > 0) self->max_x = x;
-                    x += i * bwidth;
-                    if (i < 0) self->max_x = x;
-                }
-            } else if (*lc == 'C') {
-                if (firstcon) *firstcon = OB_FRAME_CONTEXT_CLOSE;
-                if ((self->close_on = is_button_present(self, lc, i))) {
-                    self->label_width -= bwidth;
-                    if (i > 0) self->close_x = x;
-                    x += i * bwidth;
-                    if (i < 0) self->close_x = x;
-                }
-            } else
-                continue; /* don't set firstcon */
-            firstcon = NULL;
-        }
-    }
-
-    /* position and map the elements */
-    if (self->icon_on) {
-        XMapWindow(obt_display, self->icon);
-        XMoveWindow(obt_display, self->icon, self->icon_x,
-                    ob_rr_theme->paddingy);
-    } else
-        XUnmapWindow(obt_display, self->icon);
-
-    if (self->desk_on) {
-        XMapWindow(obt_display, self->desk);
-        XMoveWindow(obt_display, self->desk, self->desk_x,
-                    ob_rr_theme->paddingy + 1);
-    } else
-        XUnmapWindow(obt_display, self->desk);
-
-    if (self->shade_on) {
-        XMapWindow(obt_display, self->shade);
-        XMoveWindow(obt_display, self->shade, self->shade_x,
-                    ob_rr_theme->paddingy + 1);
-    } else
-        XUnmapWindow(obt_display, self->shade);
-
-    if (self->iconify_on) {
-        XMapWindow(obt_display, self->iconify);
-        XMoveWindow(obt_display, self->iconify, self->iconify_x,
-                    ob_rr_theme->paddingy + 1);
-    } else
-        XUnmapWindow(obt_display, self->iconify);
-
-    if (self->max_on) {
-        XMapWindow(obt_display, self->max);
-        XMoveWindow(obt_display, self->max, self->max_x,
-                    ob_rr_theme->paddingy + 1);
-    } else
-        XUnmapWindow(obt_display, self->max);
-
-    if (self->close_on) {
-        XMapWindow(obt_display, self->close);
-        XMoveWindow(obt_display, self->close, self->close_x,
-                    ob_rr_theme->paddingy + 1);
-    } else
-        XUnmapWindow(obt_display, self->close);
-
-    if (self->label_on) {
-        self->label_width = MAX(1, self->label_width); /* no lower than 1 */
-        XMapWindow(obt_display, self->label);
-        XMoveWindow(obt_display, self->label, self->label_x,
-                    ob_rr_theme->paddingy);
-    } else
-        XUnmapWindow(obt_display, self->label);
-}
-
-ObFrameContext frame_context_from_string(const gchar *name)
-{
-    if (!g_ascii_strcasecmp("Desktop", name))
-        return OB_FRAME_CONTEXT_DESKTOP;
-    else if (!g_ascii_strcasecmp("Root", name))
-        return OB_FRAME_CONTEXT_ROOT;
-    else if (!g_ascii_strcasecmp("Client", name))
-        return OB_FRAME_CONTEXT_CLIENT;
-    else if (!g_ascii_strcasecmp("Titlebar", name))
-        return OB_FRAME_CONTEXT_TITLEBAR;
-    else if (!g_ascii_strcasecmp("Frame", name))
-        return OB_FRAME_CONTEXT_FRAME;
-    else if (!g_ascii_strcasecmp("TLCorner", name))
-        return OB_FRAME_CONTEXT_TLCORNER;
-    else if (!g_ascii_strcasecmp("TRCorner", name))
-        return OB_FRAME_CONTEXT_TRCORNER;
-    else if (!g_ascii_strcasecmp("BLCorner", name))
-        return OB_FRAME_CONTEXT_BLCORNER;
-    else if (!g_ascii_strcasecmp("BRCorner", name))
-        return OB_FRAME_CONTEXT_BRCORNER;
-    else if (!g_ascii_strcasecmp("Top", name))
-        return OB_FRAME_CONTEXT_TOP;
-    else if (!g_ascii_strcasecmp("Bottom", name))
-        return OB_FRAME_CONTEXT_BOTTOM;
-    else if (!g_ascii_strcasecmp("Left", name))
-        return OB_FRAME_CONTEXT_LEFT;
-    else if (!g_ascii_strcasecmp("Right", name))
-        return OB_FRAME_CONTEXT_RIGHT;
-    else if (!g_ascii_strcasecmp("Maximize", name))
-        return OB_FRAME_CONTEXT_MAXIMIZE;
-    else if (!g_ascii_strcasecmp("AllDesktops", name))
-        return OB_FRAME_CONTEXT_ALLDESKTOPS;
-    else if (!g_ascii_strcasecmp("Shade", name))
-        return OB_FRAME_CONTEXT_SHADE;
-    else if (!g_ascii_strcasecmp("Iconify", name))
-        return OB_FRAME_CONTEXT_ICONIFY;
-    else if (!g_ascii_strcasecmp("Icon", name))
-        return OB_FRAME_CONTEXT_ICON;
-    else if (!g_ascii_strcasecmp("Close", name))
-        return OB_FRAME_CONTEXT_CLOSE;
-    else if (!g_ascii_strcasecmp("MoveResize", name))
-        return OB_FRAME_CONTEXT_MOVE_RESIZE;
-    return OB_FRAME_CONTEXT_NONE;
-}
-
-ObFrameContext frame_context(ObClient *client, Window win, gint x, gint y)
-{
-    ObFrame *self;
-
-    if (moveresize_in_progress)
-        return OB_FRAME_CONTEXT_MOVE_RESIZE;
-
-    if (win == obt_root(ob_screen))
-        return OB_FRAME_CONTEXT_ROOT ;
-    if (client == NULL) return OB_FRAME_CONTEXT_NONE;
-    if (win == client->window) {
-        /* conceptually, this is the desktop, as far as users are
-           concerned */
-        if (client->type == OB_CLIENT_TYPE_DESKTOP)
-            return OB_FRAME_CONTEXT_DESKTOP;
-        return OB_FRAME_CONTEXT_CLIENT;
-    }
-
-    self = client->frame;
-
-    /* when the user clicks in the corners of the titlebar and the client
-       is fully maximized, then treat it like they clicked in the
-       button that is there */
-    if (self->max_horz && self->max_vert &&
-        (win == self->title || win == self->titletop ||
-         win == self->titleleft || win == self->titletopleft ||
-         win == self->titleright || win == self->titletopright))
-    {
-        /* get the mouse coords in reference to the whole frame */
-        gint fx = x;
-        gint fy = y;
-
-        /* these windows are down a border width from the top of the frame */
-        if (win == self->title ||
-            win == self->titleleft || win == self->titleright)
-            fy += self->bwidth;
-
-        /* title is a border width in from the edge */
-        if (win == self->title)
-            fx += self->bwidth;
-        /* titletop is a bit to the right */
-        else if (win == self->titletop)
-            fx += ob_rr_theme->grip_width + self->bwidth;
-        /* titletopright is way to the right edge */
-        else if (win == self->titletopright)
-            fx += self->area.width - (ob_rr_theme->grip_width + self->bwidth);
-        /* titleright is even more way to the right edge */
-        else if (win == self->titleright)
-            fx += self->area.width - self->bwidth;
-
-        /* figure out if we're over the area that should be considered a
-           button */
-        if (fy < self->bwidth + ob_rr_theme->paddingy + 1 +
-            ob_rr_theme->button_size)
-        {
-            if (fx < (self->bwidth + ob_rr_theme->paddingx + 1 +
-                      ob_rr_theme->button_size))
-            {
-                if (self->leftmost != OB_FRAME_CONTEXT_NONE)
-                    return self->leftmost;
-            }
-            else if (fx >= (self->area.width -
-                            (self->bwidth + ob_rr_theme->paddingx + 1 +
-                             ob_rr_theme->button_size)))
-            {
-                if (self->rightmost != OB_FRAME_CONTEXT_NONE)
-                    return self->rightmost;
-            }
-        }
-
-        /* there is no resizing maximized windows so make them the titlebar
-           context */
-        return OB_FRAME_CONTEXT_TITLEBAR;
-    }
-    else if (self->max_vert &&
-             (win == self->titletop || win == self->topresize))
-        /* can't resize vertically when max vert */
-        return OB_FRAME_CONTEXT_TITLEBAR;
-    else if (self->shaded &&
-             (win == self->titletop || win == self->topresize))
-        /* can't resize vertically when shaded */
-        return OB_FRAME_CONTEXT_TITLEBAR;
-
-    if (win == self->window)            return OB_FRAME_CONTEXT_FRAME;
-    if (win == self->label)             return OB_FRAME_CONTEXT_TITLEBAR;
-    if (win == self->handle)            return OB_FRAME_CONTEXT_BOTTOM;
-    if (win == self->handletop)         return OB_FRAME_CONTEXT_BOTTOM;
-    if (win == self->handlebottom)      return OB_FRAME_CONTEXT_BOTTOM;
-    if (win == self->handleleft)        return OB_FRAME_CONTEXT_BLCORNER;
-    if (win == self->lgrip)             return OB_FRAME_CONTEXT_BLCORNER;
-    if (win == self->lgripleft)         return OB_FRAME_CONTEXT_BLCORNER;
-    if (win == self->lgriptop)          return OB_FRAME_CONTEXT_BLCORNER;
-    if (win == self->lgripbottom)       return OB_FRAME_CONTEXT_BLCORNER;
-    if (win == self->handleright)       return OB_FRAME_CONTEXT_BRCORNER;
-    if (win == self->rgrip)             return OB_FRAME_CONTEXT_BRCORNER;
-    if (win == self->rgripright)        return OB_FRAME_CONTEXT_BRCORNER;
-    if (win == self->rgriptop)          return OB_FRAME_CONTEXT_BRCORNER;
-    if (win == self->rgripbottom)       return OB_FRAME_CONTEXT_BRCORNER;
-    if (win == self->title)             return OB_FRAME_CONTEXT_TITLEBAR;
-    if (win == self->titlebottom)       return OB_FRAME_CONTEXT_TITLEBAR;
-    if (win == self->titleleft)         return OB_FRAME_CONTEXT_TLCORNER;
-    if (win == self->titletopleft)      return OB_FRAME_CONTEXT_TLCORNER;
-    if (win == self->titleright)        return OB_FRAME_CONTEXT_TRCORNER;
-    if (win == self->titletopright)     return OB_FRAME_CONTEXT_TRCORNER;
-    if (win == self->titletop)          return OB_FRAME_CONTEXT_TOP;
-    if (win == self->topresize)         return OB_FRAME_CONTEXT_TOP;
-    if (win == self->tltresize)         return OB_FRAME_CONTEXT_TLCORNER;
-    if (win == self->tllresize)         return OB_FRAME_CONTEXT_TLCORNER;
-    if (win == self->trtresize)         return OB_FRAME_CONTEXT_TRCORNER;
-    if (win == self->trrresize)         return OB_FRAME_CONTEXT_TRCORNER;
-    if (win == self->left)              return OB_FRAME_CONTEXT_LEFT;
-    if (win == self->right)             return OB_FRAME_CONTEXT_RIGHT;
-    if (win == self->innertop)          return OB_FRAME_CONTEXT_TITLEBAR;
-    if (win == self->innerleft)         return OB_FRAME_CONTEXT_LEFT;
-    if (win == self->innerbottom)       return OB_FRAME_CONTEXT_BOTTOM;
-    if (win == self->innerright)        return OB_FRAME_CONTEXT_RIGHT;
-    if (win == self->innerbll)          return OB_FRAME_CONTEXT_BLCORNER;
-    if (win == self->innerblb)          return OB_FRAME_CONTEXT_BLCORNER;
-    if (win == self->innerbrr)          return OB_FRAME_CONTEXT_BRCORNER;
-    if (win == self->innerbrb)          return OB_FRAME_CONTEXT_BRCORNER;
-    if (win == self->max)               return OB_FRAME_CONTEXT_MAXIMIZE;
-    if (win == self->iconify)           return OB_FRAME_CONTEXT_ICONIFY;
-    if (win == self->close)             return OB_FRAME_CONTEXT_CLOSE;
-    if (win == self->icon)              return OB_FRAME_CONTEXT_ICON;
-    if (win == self->desk)              return OB_FRAME_CONTEXT_ALLDESKTOPS;
-    if (win == self->shade)             return OB_FRAME_CONTEXT_SHADE;
-
-    return OB_FRAME_CONTEXT_NONE;
-}
-
-void frame_client_gravity(ObFrame *self, gint *x, gint *y)
-{
-    /* horizontal */
-    switch (self->client->gravity) {
-    default:
-    case NorthWestGravity:
-    case SouthWestGravity:
-    case WestGravity:
-        break;
-
-    case NorthGravity:
-    case SouthGravity:
-    case CenterGravity:
-        /* the middle of the client will be the middle of the frame */
-        *x -= (self->size.right - self->size.left) / 2;
-        break;
-
-    case NorthEastGravity:
-    case SouthEastGravity:
-    case EastGravity:
-        /* the right side of the client will be the right side of the frame */
-        *x -= self->size.right + self->size.left -
-            self->client->border_width * 2;
-        break;
-
-    case ForgetGravity:
-    case StaticGravity:
-        /* the client's position won't move */
-        *x -= self->size.left - self->client->border_width;
-        break;
-    }
-
-    /* vertical */
-    switch (self->client->gravity) {
-    default:
-    case NorthWestGravity:
-    case NorthEastGravity:
-    case NorthGravity:
-        break;
-
-    case CenterGravity:
-    case EastGravity:
-    case WestGravity:
-        /* the middle of the client will be the middle of the frame */
-        *y -= (self->size.bottom - self->size.top) / 2;
-        break;
-
-    case SouthWestGravity:
-    case SouthEastGravity:
-    case SouthGravity:
-        /* the bottom of the client will be the bottom of the frame */
-        *y -= self->size.bottom + self->size.top -
-            self->client->border_width * 2;
-        break;
-
-    case ForgetGravity:
-    case StaticGravity:
-        /* the client's position won't move */
-        *y -= self->size.top - self->client->border_width;
-        break;
-    }
-}
-
-void frame_frame_gravity(ObFrame *self, gint *x, gint *y)
-{
-    /* horizontal */
-    switch (self->client->gravity) {
-    default:
-    case NorthWestGravity:
-    case WestGravity:
-    case SouthWestGravity:
-        break;
-    case NorthGravity:
-    case CenterGravity:
-    case SouthGravity:
-        /* the middle of the client will be the middle of the frame */
-        *x += (self->size.right - self->size.left) / 2;
-        break;
-    case NorthEastGravity:
-    case EastGravity:
-    case SouthEastGravity:
-        /* the right side of the client will be the right side of the frame */
-        *x += self->size.right + self->size.left -
-            self->client->border_width * 2;
-        break;
-    case StaticGravity:
-    case ForgetGravity:
-        /* the client's position won't move */
-        *x += self->size.left - self->client->border_width;
-        break;
-    }
-
-    /* vertical */
-    switch (self->client->gravity) {
-    default:
-    case NorthWestGravity:
-    case NorthGravity:
-    case NorthEastGravity:
-        break;
-    case WestGravity:
-    case CenterGravity:
-    case EastGravity:
-        /* the middle of the client will be the middle of the frame */
-        *y += (self->size.bottom - self->size.top) / 2;
-        break;
-    case SouthWestGravity:
-    case SouthGravity:
-    case SouthEastGravity:
-        /* the bottom of the client will be the bottom of the frame */
-        *y += self->size.bottom + self->size.top -
-            self->client->border_width * 2;
-        break;
-    case StaticGravity:
-    case ForgetGravity:
-        /* the client's position won't move */
-        *y += self->size.top - self->client->border_width;
-        break;
-    }
-}
-
-void frame_rect_to_frame(ObFrame *self, Rect *r)
-{
-    r->width += self->size.left + self->size.right;
-    r->height += self->size.top + self->size.bottom;
-    frame_client_gravity(self, &r->x, &r->y);
-}
-
-void frame_rect_to_client(ObFrame *self, Rect *r)
-{
-    r->width -= self->size.left + self->size.right;
-    r->height -= self->size.top + self->size.bottom;
-    frame_frame_gravity(self, &r->x, &r->y);
-}
-
-static void flash_done(gpointer data)
-{
-    ObFrame *self = data;
-
-    if (self->focused != self->flash_on)
-        frame_adjust_focus(self, self->focused);
-}
-
-static gboolean flash_timeout(gpointer data)
-{
-    ObFrame *self = data;
-    GTimeVal now;
-
-    g_get_current_time(&now);
-    if (now.tv_sec > self->flash_end.tv_sec ||
-        (now.tv_sec == self->flash_end.tv_sec &&
-         now.tv_usec >= self->flash_end.tv_usec))
-        self->flashing = FALSE;
-
-    if (!self->flashing)
-        return FALSE; /* we are done */
-
-    self->flash_on = !self->flash_on;
-    if (!self->focused) {
-        frame_adjust_focus(self, self->flash_on);
-        self->focused = FALSE;
-    }
-
-    return TRUE; /* go again */
-}
-
-void frame_flash_start(ObFrame *self)
-{
-    self->flash_on = self->focused;
-
-    if (!self->flashing)
-        obt_main_loop_timeout_add(ob_main_loop,
-                                  G_USEC_PER_SEC * 0.6,
-                                  flash_timeout,
-                                  self,
-                                  g_direct_equal,
-                                  flash_done);
-    g_get_current_time(&self->flash_end);
-    g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
-
-    self->flashing = TRUE;
-}
-
-void frame_flash_stop(ObFrame *self)
-{
-    self->flashing = FALSE;
-}
-
-static gulong frame_animate_iconify_time_left(ObFrame *self,
-                                              const GTimeVal *now)
-{
-    glong sec, usec;
-    sec = self->iconify_animation_end.tv_sec - now->tv_sec;
-    usec = self->iconify_animation_end.tv_usec - now->tv_usec;
-    if (usec < 0) {
-        usec += G_USEC_PER_SEC;
-        sec--;
-    }
-    /* no negative values */
-    return MAX(sec * G_USEC_PER_SEC + usec, 0);
-}
-
-static gboolean frame_animate_iconify(gpointer p)
-{
-    ObFrame *self = p;
-    gint x, y, w, h;
-    gint iconx, icony, iconw;
-    GTimeVal now;
-    gulong time;
-    gboolean iconifying;
-
-    if (self->client->icon_geometry.width == 0) {
-        /* there is no icon geometry set so just go straight down */
-        Rect *a = screen_physical_area_monitor
-            (screen_find_monitor(&self->area));
-        iconx = self->area.x + self->area.width / 2 + 32;
-        icony = a->y + a->width;
-        iconw = 64;
-        g_free(a);
-    } else {
-        iconx = self->client->icon_geometry.x;
-        icony = self->client->icon_geometry.y;
-        iconw = self->client->icon_geometry.width;
-    }
-
-    iconifying = self->iconify_animation_going > 0;
-
-    /* how far do we have left to go ? */
-    g_get_current_time(&now);
-    time = frame_animate_iconify_time_left(self, &now);
-
-    if (time == 0 || iconifying) {
-        /* start where the frame is supposed to be */
-        x = self->area.x;
-        y = self->area.y;
-        w = self->area.width;
-        h = self->area.height;
-    } else {
-        /* start at the icon */
-        x = iconx;
-        y = icony;
-        w = iconw;
-        h = self->size.top; /* just the titlebar */
-    }
-
-    if (time > 0) {
-        glong dx, dy, dw;
-        glong elapsed;
-
-        dx = self->area.x - iconx;
-        dy = self->area.y - icony;
-        dw = self->area.width - self->bwidth * 2 - iconw;
-         /* if restoring, we move in the opposite direction */
-        if (!iconifying) { dx = -dx; dy = -dy; dw = -dw; }
-
-        elapsed = FRAME_ANIMATE_ICONIFY_TIME - time;
-        x = x - (dx * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
-        y = y - (dy * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
-        w = w - (dw * elapsed) / FRAME_ANIMATE_ICONIFY_TIME;
-        h = self->size.top; /* just the titlebar */
-    }
-
-    if (time == 0)
-        frame_end_iconify_animation(self);
-    else {
-        XMoveResizeWindow(obt_display, self->window, x, y, w, h);
-        XFlush(obt_display);
-    }
-
-    return time > 0; /* repeat until we're out of time */
-}
-
-void frame_end_iconify_animation(ObFrame *self)
-{
-    /* see if there is an animation going */
-    if (self->iconify_animation_going == 0) return;
-
-    if (!self->visible)
-        XUnmapWindow(obt_display, self->window);
-    else {
-        /* Send a ConfigureNotify when the animation is done, this fixes
-           KDE's pager showing the window in the wrong place.  since the
-           window is mapped at a different location and is then moved, we
-           need to send the synthetic configurenotify, since apps may have
-           read the position when the client mapped, apparently. */
-        client_reconfigure(self->client, TRUE);
-    }
-
-    /* we're not animating any more ! */
-    self->iconify_animation_going = 0;
-
-    XMoveResizeWindow(obt_display, self->window,
-                      self->area.x, self->area.y,
-                      self->area.width, self->area.height);
-    /* we delay re-rendering until after we're done animating */
-    framerender_frame(self);
-    XFlush(obt_display);
-}
-
-void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying)
-{
-    gulong time;
-    gboolean new_anim = FALSE;
-    gboolean set_end = TRUE;
-    GTimeVal now;
-
-    /* if there is no titlebar, just don't animate for now
-       XXX it would be nice tho.. */
-    if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))
-        return;
-
-    /* get the current time */
-    g_get_current_time(&now);
-
-    /* get how long until the end */
-    time = FRAME_ANIMATE_ICONIFY_TIME;
-    if (self->iconify_animation_going) {
-        if (!!iconifying != (self->iconify_animation_going > 0)) {
-            /* animation was already going on in the opposite direction */
-            time = time - frame_animate_iconify_time_left(self, &now);
-        } else
-            /* animation was already going in the same direction */
-            set_end = FALSE;
-    } else
-        new_anim = TRUE;
-    self->iconify_animation_going = iconifying ? 1 : -1;
-
-    /* set the ending time */
-    if (set_end) {
-        self->iconify_animation_end.tv_sec = now.tv_sec;
-        self->iconify_animation_end.tv_usec = now.tv_usec;
-        g_time_val_add(&self->iconify_animation_end, time);
-    }
-
-    if (new_anim) {
-        obt_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify,
-                                          self, FALSE);
-        obt_main_loop_timeout_add(ob_main_loop,
-                                  FRAME_ANIMATE_ICONIFY_STEP_TIME,
-                                  frame_animate_iconify, self,
-                                  g_direct_equal, NULL);
-
-        /* do the first step */
-        frame_animate_iconify(self);
-
-        /* show it during the animation even if it is not "visible" */
-        if (!self->visible)
-            XMapWindow(obt_display, self->window);
-    }
-}
diff --git a/openbox/frame.h b/openbox/frame.h
deleted file mode 100644 (file)
index 02be17a..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
-   frame.h for the Openbox window manager
-   Copyright (c) 2006        Mikael Magnusson
-   Copyright (c) 2003-2007   Dana Jansens
-
-   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 of the License, 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.
-
-   See the COPYING file for a copy of the GNU General Public License.
-*/
-
-#ifndef __frame_h
-#define __frame_h
-
-#include "geom.h"
-#include "render/render.h"
-
-typedef struct _ObFrame ObFrame;
-
-struct _ObClient;
-
-typedef void (*ObFrameIconifyAnimateFunc)(gpointer data);
-
-typedef enum {
-    OB_FRAME_CONTEXT_NONE,
-    OB_FRAME_CONTEXT_DESKTOP,
-    OB_FRAME_CONTEXT_ROOT,
-    OB_FRAME_CONTEXT_CLIENT,
-    OB_FRAME_CONTEXT_TITLEBAR,
-    OB_FRAME_CONTEXT_FRAME,
-    OB_FRAME_CONTEXT_BLCORNER,
-    OB_FRAME_CONTEXT_BRCORNER,
-    OB_FRAME_CONTEXT_TLCORNER,
-    OB_FRAME_CONTEXT_TRCORNER,
-    OB_FRAME_CONTEXT_TOP,
-    OB_FRAME_CONTEXT_BOTTOM,
-    OB_FRAME_CONTEXT_LEFT,
-    OB_FRAME_CONTEXT_RIGHT,
-    OB_FRAME_CONTEXT_MAXIMIZE,
-    OB_FRAME_CONTEXT_ALLDESKTOPS,
-    OB_FRAME_CONTEXT_SHADE,
-    OB_FRAME_CONTEXT_ICONIFY,
-    OB_FRAME_CONTEXT_ICON,
-    OB_FRAME_CONTEXT_CLOSE,
-    /*! This is a special context, which occurs while dragging a window in
-      a move/resize */
-    OB_FRAME_CONTEXT_MOVE_RESIZE,
-    OB_FRAME_NUM_CONTEXTS
-} ObFrameContext;
-
-/*! The decorations the client window wants to be displayed on it */
-typedef enum {
-    OB_FRAME_DECOR_TITLEBAR    = 1 << 0, /*!< Display a titlebar */
-    OB_FRAME_DECOR_HANDLE      = 1 << 1, /*!< Display a handle (bottom) */
-    OB_FRAME_DECOR_GRIPS       = 1 << 2, /*!< Display grips in the handle */
-    OB_FRAME_DECOR_BORDER      = 1 << 3, /*!< Display a border */
-    OB_FRAME_DECOR_ICON        = 1 << 4, /*!< Display the window's icon */
-    OB_FRAME_DECOR_ICONIFY     = 1 << 5, /*!< Display an iconify button */
-    OB_FRAME_DECOR_MAXIMIZE    = 1 << 6, /*!< Display a maximize button */
-    /*! Display a button to toggle the window's placement on
-      all desktops */
-    OB_FRAME_DECOR_ALLDESKTOPS = 1 << 7,
-    OB_FRAME_DECOR_SHADE       = 1 << 8, /*!< Displays a shade button */
-    OB_FRAME_DECOR_CLOSE       = 1 << 9  /*!< Display a close button */
-} ObFrameDecorations;
-
-struct _ObFrame
-{
-    struct _ObClient *client;
-
-    Window    window;
-
-    Strut     size;
-    Rect      area;
-    gboolean  visible;
-
-    guint     functions;
-    guint     decorations;
-
-    Window    title;
-    Window    label;
-    Window    max;
-    Window    close;
-    Window    desk;
-    Window    shade;
-    Window    icon;
-    Window    iconify;
-    Window    handle;
-    Window    lgrip;
-    Window    rgrip;
-
-    /* These are borders of the frame and its elements */
-    Window    titleleft;
-    Window    titletop;
-    Window    titletopleft;
-    Window    titletopright;
-    Window    titleright;
-    Window    titlebottom;
-    Window    left;
-    Window    right;
-    Window    handleleft;
-    Window    handletop;
-    Window    handleright;
-    Window    handlebottom;
-    Window    lgriptop;
-    Window    lgripleft;
-    Window    lgripbottom;
-    Window    rgriptop;
-    Window    rgripright;
-    Window    rgripbottom;
-    Window    innerleft;    /*!< For drawing the inner client border */
-    Window    innertop;     /*!< For drawing the inner client border */
-    Window    innerright;   /*!< For drawing the inner client border */
-    Window    innerbottom;  /*!< For drawing the inner client border */
-    Window    innerblb;
-    Window    innerbll;
-    Window    innerbrb;
-    Window    innerbrr;
-    Window    backback;     /*!< A colored window shown while resizing */
-    Window    backfront;    /*!< An undrawn-in window, to prevent flashing on
-                                 unmap */
-
-    /* These are resize handles inside the titlebar */
-    Window    topresize;
-    Window    tltresize;
-    Window    tllresize;
-    Window    trtresize;
-    Window    trrresize;
-
-    Colormap  colormap;
-
-    gint      icon_on;    /* if the window icon button is on */
-    gint      label_on;   /* if the window title is on */
-    gint      iconify_on; /* if the window iconify button is on */
-    gint      desk_on;    /* if the window all-desktops button is on */
-    gint      shade_on;   /* if the window shade button is on */
-    gint      max_on;     /* if the window maximize button is on */
-    gint      close_on;   /* if the window close button is on */
-
-    gint      width;         /* width of the titlebar and handle */
-    gint      label_width;   /* width of the label in the titlebar */
-    gint      icon_x;        /* x-position of the window icon button */
-    gint      label_x;       /* x-position of the window title */
-    gint      iconify_x;     /* x-position of the window iconify button */
-    gint      desk_x;        /* x-position of the window all-desktops button */
-    gint      shade_x;       /* x-position of the window shade button */
-    gint      max_x;         /* x-position of the window maximize button */
-    gint      close_x;       /* x-position of the window close button */
-    gint      bwidth;        /* border width */
-    gint      cbwidth_l;     /* client border width */
-    gint      cbwidth_t;     /* client border width */
-    gint      cbwidth_r;     /* client border width */
-    gint      cbwidth_b;     /* client border width */
-    gboolean  max_horz;      /* when maxed some decorations are hidden */
-    gboolean  max_vert;      /* when maxed some decorations are hidden */
-    gboolean  shaded;        /* decorations adjust when shaded */
-
-    /* the leftmost and rightmost elements in the titlebar */
-    ObFrameContext leftmost;
-    ObFrameContext rightmost;
-
-    gboolean  max_press;
-    gboolean  close_press;
-    gboolean  desk_press;
-    gboolean  shade_press;
-    gboolean  iconify_press;
-    gboolean  max_hover;
-    gboolean  close_hover;
-    gboolean  desk_hover;
-    gboolean  shade_hover;
-    gboolean  iconify_hover;
-
-    gboolean  focused;
-    gboolean  need_render;
-
-    gboolean  flashing;
-    gboolean  flash_on;
-    GTimeVal  flash_end;
-
-    /*! Is the frame currently in an animation for iconify or restore.
-      0 means that it is not animating. > 0 means it is animating an iconify.
-      < 0 means it is animating a restore.
-    */
-    gint iconify_animation_going;
-    GTimeVal  iconify_animation_end;
-};
-
-ObFrame *frame_new(struct _ObClient *c);
-void frame_free(ObFrame *self);
-
-void frame_show(ObFrame *self);
-void frame_hide(ObFrame *self);
-void frame_adjust_theme(ObFrame *self);
-void frame_adjust_shape(ObFrame *self);
-void frame_adjust_area(ObFrame *self, gboolean moved,
-                       gboolean resized, gboolean fake);
-void frame_adjust_client_area(ObFrame *self);
-void frame_adjust_state(ObFrame *self);
-void frame_adjust_focus(ObFrame *self, gboolean hilite);
-void frame_adjust_title(ObFrame *self);
-void frame_adjust_icon(ObFrame *self);
-void frame_grab_client(ObFrame *self);
-void frame_release_client(ObFrame *self);
-
-ObFrameContext frame_context_from_string(const gchar *name);
-
-ObFrameContext frame_context(struct _ObClient *self, Window win,
-                             gint x, gint y);
-
-/*! Applies gravity to the client's position to find where the frame should
-  be positioned.
-  @return The proper coordinates for the frame, based on the client.
-*/
-void frame_client_gravity(ObFrame *self, gint *x, gint *y);
-
-/*! Reversly applies gravity to the frame's position to find where the client
-  should be positioned.
-    @return The proper coordinates for the client, based on the frame.
-*/
-void frame_frame_gravity(ObFrame *self, gint *x, gint *y);
-
-/*! Convert a rectangle in client coordinates/sizes to what it would be
-  for the frame, given its current decorations sizes */
-void frame_rect_to_frame(ObFrame *self, Rect *r);
-
-/*! Convert a rectangle in frame coordinates/sizes to what it would be for the
-  client, given its current decorations sizes */
-void frame_rect_to_client(ObFrame *self, Rect *r);
-
-void frame_flash_start(ObFrame *self);
-void frame_flash_stop(ObFrame *self);
-
-/*! Start an animation for iconifying or restoring a frame. The callback
-  will be called when the animation finishes. But if another animation is
-  started in the meantime, the callback will never get called. */
-void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying);
-void frame_end_iconify_animation(ObFrame *self);
-
-#define frame_iconify_animating(f) (f->iconify_animation_going != 0)
-
-#endif
diff --git a/openbox/framerender.c b/openbox/framerender.c
deleted file mode 100644 (file)
index 87706b2..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
-   framerender.c for the Openbox window manager
-   Copyright (c) 2006        Mikael Magnusson
-   Copyright (c) 2003-2007   Dana Jansens
-
-   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 of the License, 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.
-
-   See the COPYING file for a copy of the GNU General Public License.
-*/
-
-#include "frame.h"
-#include "openbox.h"
-#include "screen.h"
-#include "client.h"
-#include "framerender.h"
-#include "render/theme.h"
-
-static void framerender_label(ObFrame *self, RrAppearance *a);
-static void framerender_icon(ObFrame *self, RrAppearance *a);
-static void framerender_max(ObFrame *self, RrAppearance *a);
-static void framerender_iconify(ObFrame *self, RrAppearance *a);
-static void framerender_desk(ObFrame *self, RrAppearance *a);
-static void framerender_shade(ObFrame *self, RrAppearance *a);
-static void framerender_close(ObFrame *self, RrAppearance *a);
-
-void framerender_frame(ObFrame *self)
-{
-    if (frame_iconify_animating(self))
-        return; /* delay redrawing until the animation is done */
-    if (!self->need_render)
-        return;
-    if (!self->visible)
-        return;
-    self->need_render = FALSE;
-
-    {
-        gulong px;
-
-        px = (self->focused ?
-              RrColorPixel(ob_rr_theme->cb_focused_color) :
-              RrColorPixel(ob_rr_theme->cb_unfocused_color));
-
-        XSetWindowBackground(obt_display, self->backback, px);
-        XClearWindow(obt_display, self->backback);
-        XSetWindowBackground(obt_display, self->innerleft, px);
-        XClearWindow(obt_display, self->innerleft);
-        XSetWindowBackground(obt_display, self->innertop, px);
-        XClearWindow(obt_display, self->innertop);
-        XSetWindowBackground(obt_display, self->innerright, px);
-        XClearWindow(obt_display, self->innerright);
-        XSetWindowBackground(obt_display, self->innerbottom, px);
-        XClearWindow(obt_display, self->innerbottom);
-        XSetWindowBackground(obt_display, self->innerbll, px);
-        XClearWindow(obt_display, self->innerbll);
-        XSetWindowBackground(obt_display, self->innerbrr, px);
-        XClearWindow(obt_display, self->innerbrr);
-        XSetWindowBackground(obt_display, self->innerblb, px);
-        XClearWindow(obt_display, self->innerblb);
-        XSetWindowBackground(obt_display, self->innerbrb, px);
-        XClearWindow(obt_display, self->innerbrb);
-
-        px = (self->focused ?
-              RrColorPixel(ob_rr_theme->frame_focused_border_color) :
-              RrColorPixel(ob_rr_theme->frame_unfocused_border_color));
-
-        XSetWindowBackground(obt_display, self->left, px);
-        XClearWindow(obt_display, self->left);
-        XSetWindowBackground(obt_display, self->right, px);
-        XClearWindow(obt_display, self->right);
-
-        XSetWindowBackground(obt_display, self->titleleft, px);
-        XClearWindow(obt_display, self->titleleft);
-        XSetWindowBackground(obt_display, self->titletop, px);
-        XClearWindow(obt_display, self->titletop);
-        XSetWindowBackground(obt_display, self->titletopleft, px);
-        XClearWindow(obt_display, self->titletopleft);
-        XSetWindowBackground(obt_display, self->titletopright, px);
-        XClearWindow(obt_display, self->titletopright);
-        XSetWindowBackground(obt_display, self->titleright, px);
-        XClearWindow(obt_display, self->titleright);
-
-        XSetWindowBackground(obt_display, self->handleleft, px);
-        XClearWindow(obt_display, self->handleleft);
-        XSetWindowBackground(obt_display, self->handletop, px);
-        XClearWindow(obt_display, self->handletop);
-        XSetWindowBackground(obt_display, self->handleright, px);
-        XClearWindow(obt_display, self->handleright);
-        XSetWindowBackground(obt_display, self->handlebottom, px);
-        XClearWindow(obt_display, self->handlebottom);
-
-        XSetWindowBackground(obt_display, self->lgripleft, px);
-        XClearWindow(obt_display, self->lgripleft);
-        XSetWindowBackground(obt_display, self->lgriptop, px);
-        XClearWindow(obt_display, self->lgriptop);
-        XSetWindowBackground(obt_display, self->lgripbottom, px);
-        XClearWindow(obt_display, self->lgripbottom);
-
-        XSetWindowBackground(obt_display, self->rgripright, px);
-        XClearWindow(obt_display, self->rgripright);
-        XSetWindowBackground(obt_display, self->rgriptop, px);
-        XClearWindow(obt_display, self->rgriptop);
-        XSetWindowBackground(obt_display, self->rgripbottom, px);
-        XClearWindow(obt_display, self->rgripbottom);
-
-        /* don't use the separator color for shaded windows */
-        if (!self->client->shaded)
-            px = (self->focused ?
-                  RrColorPixel(ob_rr_theme->title_separator_focused_color) :
-                  RrColorPixel(ob_rr_theme->title_separator_unfocused_color));
-
-        XSetWindowBackground(obt_display, self->titlebottom, px);
-        XClearWindow(obt_display, self->titlebottom);
-    }
-
-    if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
-        RrAppearance *t, *l, *m, *n, *i, *d, *s, *c, *clear;
-        if (self->focused) {
-            t = ob_rr_theme->a_focused_title;
-            l = ob_rr_theme->a_focused_label;
-            m = (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE) ?
-                 ob_rr_theme->a_disabled_focused_max :
-                 (self->client->max_vert || self->client->max_horz ?
-                  (self->max_press ?
-                   ob_rr_theme->a_toggled_focused_pressed_max :
-                   (self->max_hover ?
-                    ob_rr_theme->a_toggled_hover_focused_max :
-                    ob_rr_theme->a_toggled_focused_unpressed_max)) :
-                  (self->max_press ?
-                   ob_rr_theme->a_focused_pressed_max :
-                   (self->max_hover ?
-                    ob_rr_theme->a_hover_focused_max :
-                    ob_rr_theme->a_focused_unpressed_max))));
-            n = ob_rr_theme->a_icon;
-            i = (!(self->decorations & OB_FRAME_DECOR_ICONIFY) ?
-                 ob_rr_theme->a_disabled_focused_iconify :
-                 (self->iconify_press ?
-                  ob_rr_theme->a_focused_pressed_iconify :
-                  (self->iconify_hover ?
-                   ob_rr_theme->a_hover_focused_iconify :
-                   ob_rr_theme->a_focused_unpressed_iconify)));
-            d = (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS) ?
-                 ob_rr_theme->a_disabled_focused_desk :
-                 (self->client->desktop == DESKTOP_ALL ?
-                  (self->desk_press ?
-                   ob_rr_theme->a_toggled_focused_pressed_desk :
-                   (self->desk_hover ?
-                    ob_rr_theme->a_toggled_hover_focused_desk :
-                    ob_rr_theme->a_toggled_focused_unpressed_desk)) :
-                  (self->desk_press ?
-                   ob_rr_theme->a_focused_pressed_desk :
-                   (self->desk_hover ?
-                    ob_rr_theme->a_hover_focused_desk :
-                    ob_rr_theme->a_focused_unpressed_desk))));
-            s = (!(self->decorations & OB_FRAME_DECOR_SHADE) ?
-                 ob_rr_theme->a_disabled_focused_shade :
-                 (self->client->shaded ?
-                  (self->shade_press ?
-                   ob_rr_theme->a_toggled_focused_pressed_shade :
-                   (self->shade_hover ?
-                    ob_rr_theme->a_toggled_hover_focused_shade :
-                    ob_rr_theme->a_toggled_focused_unpressed_shade)) :
-                  (self->shade_press ?
-                   ob_rr_theme->a_focused_pressed_shade :
-                   (self->shade_hover ?
-                    ob_rr_theme->a_hover_focused_shade :
-                    ob_rr_theme->a_focused_unpressed_shade))));
-            c = (!(self->decorations & OB_FRAME_DECOR_CLOSE) ?
-                 ob_rr_theme->a_disabled_focused_close :
-                 (self->close_press ?
-                  ob_rr_theme->a_focused_pressed_close :
-                  (self->close_hover ?
-                   ob_rr_theme->a_hover_focused_close :
-                   ob_rr_theme->a_focused_unpressed_close)));
-        } else {
-            t = ob_rr_theme->a_unfocused_title;
-            l = ob_rr_theme->a_unfocused_label;
-            m = (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE) ?
-                 ob_rr_theme->a_disabled_unfocused_max :
-                 (self->client->max_vert || self->client->max_horz ?
-                  (self->max_press ?
-                   ob_rr_theme->a_toggled_unfocused_pressed_max :
-                   (self->max_hover ?
-                    ob_rr_theme->a_toggled_hover_unfocused_max :
-                    ob_rr_theme->a_toggled_unfocused_unpressed_max)) :
-                  (self->max_press ?
-                   ob_rr_theme->a_unfocused_pressed_max :
-                   (self->max_hover ?
-                    ob_rr_theme->a_hover_unfocused_max :
-                    ob_rr_theme->a_unfocused_unpressed_max))));
-            n = ob_rr_theme->a_icon;
-            i = (!(self->decorations & OB_FRAME_DECOR_ICONIFY) ?
-                 ob_rr_theme->a_disabled_unfocused_iconify :
-                 (self->iconify_press ?
-                  ob_rr_theme->a_unfocused_pressed_iconify :
-                  (self->iconify_hover ?
-                   ob_rr_theme->a_hover_unfocused_iconify :
-                   ob_rr_theme->a_unfocused_unpressed_iconify)));
-            d = (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS) ?
-                 ob_rr_theme->a_disabled_unfocused_desk :
-                 (self->client->desktop == DESKTOP_ALL ?
-                  (self->desk_press ?
-                   ob_rr_theme->a_toggled_unfocused_pressed_desk :
-                   (self->desk_hover ?
-                    ob_rr_theme->a_toggled_hover_unfocused_desk :
-                    ob_rr_theme->a_toggled_unfocused_unpressed_desk)) :
-                  (self->desk_press ?
-                   ob_rr_theme->a_unfocused_pressed_desk :
-                   (self->desk_hover ?
-                    ob_rr_theme->a_hover_unfocused_desk :
-                    ob_rr_theme->a_unfocused_unpressed_desk))));
-            s = (!(self->decorations & OB_FRAME_DECOR_SHADE) ?
-                 ob_rr_theme->a_disabled_unfocused_shade :
-                 (self->client->shaded ?
-                  (self->shade_press ?
-                   ob_rr_theme->a_toggled_unfocused_pressed_shade :
-                   (self->shade_hover ?
-                    ob_rr_theme->a_toggled_hover_unfocused_shade :
-                    ob_rr_theme->a_toggled_unfocused_unpressed_shade)) :
-                  (self->shade_press ?
-                   ob_rr_theme->a_unfocused_pressed_shade :
-                   (self->shade_hover ?
-                    ob_rr_theme->a_hover_unfocused_shade :
-                    ob_rr_theme->a_unfocused_unpressed_shade))));
-            c = (!(self->decorations & OB_FRAME_DECOR_CLOSE) ?
-                 ob_rr_theme->a_disabled_unfocused_close :
-                 (self->close_press ?
-                  ob_rr_theme->a_unfocused_pressed_close :
-                  (self->close_hover ?
-                   ob_rr_theme->a_hover_unfocused_close :
-                   ob_rr_theme->a_unfocused_unpressed_close)));
-        }
-        clear = ob_rr_theme->a_clear;
-
-        RrPaint(t, self->title, self->width, ob_rr_theme->title_height);
-
-        clear->surface.parent = t;
-        clear->surface.parenty = 0;
-
-        clear->surface.parentx = ob_rr_theme->grip_width;
-
-        RrPaint(clear, self->topresize,
-                self->width - ob_rr_theme->grip_width * 2,
-                ob_rr_theme->paddingy + 1);
-
-        clear->surface.parentx = 0;
-
-        if (ob_rr_theme->grip_width > 0)
-            RrPaint(clear, self->tltresize,
-                    ob_rr_theme->grip_width, ob_rr_theme->paddingy + 1);
-        if (ob_rr_theme->title_height > 0)
-            RrPaint(clear, self->tllresize,
-                    ob_rr_theme->paddingx + 1, ob_rr_theme->title_height);
-
-        clear->surface.parentx = self->width - ob_rr_theme->grip_width;
-
-        if (ob_rr_theme->grip_width > 0)
-            RrPaint(clear, self->trtresize,
-                    ob_rr_theme->grip_width, ob_rr_theme->paddingy + 1);
-
-        clear->surface.parentx = self->width - (ob_rr_theme->paddingx + 1);
-
-        if (ob_rr_theme->title_height > 0)
-            RrPaint(clear, self->trrresize,
-                    ob_rr_theme->paddingx + 1, ob_rr_theme->title_height);
-
-        /* set parents for any parent relative guys */
-        l->surface.parent = t;
-        l->surface.parentx = self->label_x;
-        l->surface.parenty = ob_rr_theme->paddingy;
-
-        m->surface.parent = t;
-        m->surface.parentx = self->max_x;
-        m->surface.parenty = ob_rr_theme->paddingy + 1;
-
-        n->surface.parent = t;
-        n->surface.parentx = self->icon_x;
-        n->surface.parenty = ob_rr_theme->paddingy;
-
-        i->surface.parent = t;
-        i->surface.parentx = self->iconify_x;
-        i->surface.parenty = ob_rr_theme->paddingy + 1;
-
-        d->surface.parent = t;
-        d->surface.parentx = self->desk_x;
-        d->surface.parenty = ob_rr_theme->paddingy + 1;
-
-        s->surface.parent = t;
-        s->surface.parentx = self->shade_x;
-        s->surface.parenty = ob_rr_theme->paddingy + 1;
-
-        c->surface.parent = t;
-        c->surface.parentx = self->close_x;
-        c->surface.parenty = ob_rr_theme->paddingy + 1;
-
-        framerender_label(self, l);
-        framerender_max(self, m);
-        framerender_icon(self, n);
-        framerender_iconify(self, i);
-        framerender_desk(self, d);
-        framerender_shade(self, s);
-        framerender_close(self, c);
-    }
-
-    if (self->decorations & OB_FRAME_DECOR_HANDLE &&
-        ob_rr_theme->handle_height > 0)
-    {
-        RrAppearance *h, *g;
-
-        h = (self->focused ?
-             ob_rr_theme->a_focused_handle : ob_rr_theme->a_unfocused_handle);
-
-        RrPaint(h, self->handle, self->width, ob_rr_theme->handle_height);
-
-        if (self->decorations & OB_FRAME_DECOR_GRIPS) {
-            g = (self->focused ?
-                 ob_rr_theme->a_focused_grip : ob_rr_theme->a_unfocused_grip);
-
-            if (g->surface.grad == RR_SURFACE_PARENTREL)
-                g->surface.parent = h;
-
-            g->surface.parentx = 0;
-            g->surface.parenty = 0;
-
-            RrPaint(g, self->lgrip,
-                    ob_rr_theme->grip_width, ob_rr_theme->handle_height);
-
-            g->surface.parentx = self->width - ob_rr_theme->grip_width;
-            g->surface.parenty = 0;
-
-            RrPaint(g, self->rgrip,
-                    ob_rr_theme->grip_width, ob_rr_theme->handle_height);
-        }
-    }
-
-    XFlush(obt_display);
-}
-
-static void framerender_label(ObFrame *self, RrAppearance *a)
-{
-    if (!self->label_on) return;
-    /* set the texture's text! */
-    a->texture[0].data.text.string = self->client->title;
-    RrPaint(a, self->label, self->label_width, ob_rr_theme->label_height);
-}
-
-static void framerender_icon(ObFrame *self, RrAppearance *a)
-{
-    const ObClientIcon *icon;
-
-    if (!self->icon_on) return;
-
-    icon = client_icon(self->client,
-                       ob_rr_theme->button_size + 2,
-                       ob_rr_theme->button_size + 2);
-    if (icon) {
-        a->texture[0].type = RR_TEXTURE_RGBA;
-        a->texture[0].data.rgba.width = icon->width;
-        a->texture[0].data.rgba.height = icon->height;
-        a->texture[0].data.rgba.alpha = 0xff;
-        a->texture[0].data.rgba.data = icon->data;
-    } else
-        a->texture[0].type = RR_TEXTURE_NONE;
-
-    RrPaint(a, self->icon,
-            ob_rr_theme->button_size + 2, ob_rr_theme->button_size + 2);
-}
-
-static void framerender_max(ObFrame *self, RrAppearance *a)
-{
-    if (!self->max_on) return;
-    RrPaint(a, self->max, ob_rr_theme->button_size, ob_rr_theme->button_size);
-}
-
-static void framerender_iconify(ObFrame *self, RrAppearance *a)
-{
-    if (!self->iconify_on) return;
-    RrPaint(a, self->iconify,
-            ob_rr_theme->button_size, ob_rr_theme->button_size);
-}
-
-static void framerender_desk(ObFrame *self, RrAppearance *a)
-{
-    if (!self->desk_on) return;
-    RrPaint(a, self->desk, ob_rr_theme->button_size, ob_rr_theme->button_size);
-}
-
-static void framerender_shade(ObFrame *self, RrAppearance *a)
-{
-    if (!self->shade_on) return;
-    RrPaint(a, self->shade,
-            ob_rr_theme->button_size, ob_rr_theme->button_size);
-}
-
-static void framerender_close(ObFrame *self, RrAppearance *a)
-{
-    if (!self->close_on) return;
-    RrPaint(a, self->close,
-            ob_rr_theme->button_size, ob_rr_theme->button_size);
-}
diff --git a/openbox/framerender.h b/openbox/framerender.h
deleted file mode 100644 (file)
index 162fa57..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
-   framerender.h for the Openbox window manager
-   Copyright (c) 2003-2007   Dana Jansens
-
-   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 of the License, 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.
-
-   See the COPYING file for a copy of the GNU General Public License.
-*/
-
-#ifndef __framerender_h
-#define __framerender_h
-
-struct _ObFrame;
-
-void framerender_frame(struct _ObFrame *self);
-
-#endif
index 02ae6a304642ef4ce7a735ca0a55c827393f6e34..aa374c5d585a39e5e8ba33bea31c9f7fc570a8ca 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "focus.h"
 #include "screen.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "openbox.h"
 #include "event.h"
 #include "grab.h"
index 995cdbc5f0757ad0246a95bfd4023954732f20f5..5b354e227d5ba57f2f0e9b72add280ab14f76275 100644 (file)
@@ -21,7 +21,7 @@
 #define ob__keybaord_h
 
 #include "keytree.h"
-#include "frame.h"
+#include "engine_interface.h"
 
 #include <glib.h>
 #include <X11/Xlib.h>
index 071a23b2ecb5e146e003a415572d4ea88559eac8..bed0fcb624b972edf3abc058d1f9215fb316cb19 100644 (file)
@@ -23,7 +23,7 @@
 #include "event.h"
 #include "client.h"
 #include "grab.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "translate.h"
 #include "mouse.h"
 #include "gettext.h"
@@ -117,7 +117,7 @@ void mouse_grab_for_client(ObClient *client, gboolean grab)
             guint mask;
 
             if (FRAME_CONTEXT(i, client)) {
-                win = client->frame->window;
+                win = render_plugin->frame_get_window(client->frame);
                 mode = GrabModeAsync;
                 mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
             } else if (CLIENT_CONTEXT(i, client)) {
@@ -224,7 +224,7 @@ void mouse_event(ObClient *client, XEvent *e)
 
     switch (e->type) {
     case ButtonPress:
-        context = frame_context(client, e->xbutton.window,
+        context = plugin_frame_context(client, e->xbutton.window,
                                 e->xbutton.x, e->xbutton.y);
         context = mouse_button_frame_context(context, e->xbutton.button,
                                              e->xbutton.state);
@@ -273,7 +273,7 @@ void mouse_event(ObClient *client, XEvent *e)
 
     case ButtonRelease:
         /* use where the press occured in the window */
-        context = frame_context(client, e->xbutton.window, pwx, pwy);
+        context = plugin_frame_context(client, e->xbutton.window, pwx, pwy);
         context = mouse_button_frame_context(context, e->xbutton.button,
                                              e->xbutton.state);
 
@@ -338,7 +338,7 @@ void mouse_event(ObClient *client, XEvent *e)
 
     case MotionNotify:
         if (button) {
-            context = frame_context(client, e->xmotion.window, pwx, pwy);
+            context = plugin_frame_context(client, e->xmotion.window, pwx, pwy);
             context = mouse_button_frame_context(context, button, state);
 
             if (ABS(e->xmotion.x_root - px) >= config_mouse_threshold ||
index a862fe5b4a5f8ee9a0a552feb34b704db4bad967..41ba5b16aa5a115f0cc0c9416191989f667de991 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef ob__mouse_h
 #define ob__mouse_h
 
-#include "frame.h"
+#include "engine_interface.h"
 #include "misc.h"
 
 #include <X11/Xlib.h>
index ddc518adbb299d905ffc0f3bde9c12808362e761..91eb7bb6fcdceedf562b0299e63e6611afd79422 100644 (file)
 */
 
 #include "grab.h"
-#include "framerender.h"
 #include "screen.h"
 #include "client.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "openbox.h"
 #include "resist.h"
 #include "popup.h"
@@ -41,7 +40,7 @@
 /* how far windows move and resize with the keyboard arrows */
 #define KEY_DIST 8
 
-gboolean moveresize_in_progress = FALSE;
+//gboolean moveresize_in_progress = FALSE;
 ObClient *moveresize_client = NULL;
 #ifdef SYNC
 XSyncAlarm moveresize_alarm = None;
@@ -86,7 +85,7 @@ void moveresize_startup(gboolean reconfig)
 void moveresize_shutdown(gboolean reconfig)
 {
     if (!reconfig) {
-        if (moveresize_in_progress)
+        if (render_plugin->moveresize_in_progress)
             moveresize_end(FALSE);
         client_remove_destroy_notify(client_dest);
     }
@@ -99,17 +98,19 @@ static void popup_coords(ObClient *c, const gchar *format, gint a, gint b)
 {
     gchar *text;
 
+    Strut size = render_plugin->frame_get_size(c->frame);
+    Rect area = render_plugin->frame_get_window_area(c->frame);
     text = g_strdup_printf(format, a, b);
     if (config_resize_popup_pos == OB_RESIZE_POS_TOP)
         popup_position(popup, SouthGravity,
-                       c->frame->area.x
-                     + c->frame->area.width/2,
-                       c->frame->area.y - ob_rr_theme->fbwidth);
+                       area.x
+                     + area.width/2,
+                       area.y - ob_rr_theme->fbwidth);
     else if (config_resize_popup_pos == OB_RESIZE_POS_CENTER)
         popup_position(popup, CenterGravity,
-                       c->frame->area.x + c->frame->size.left +
+                       area.x + size.left +
                        c->area.width / 2,
-                       c->frame->area.y + c->frame->size.top +
+                       area.y + size.top +
                        c->area.height / 2);
     else /* Fixed */ {
         Rect *area = screen_physical_area_active();
@@ -172,7 +173,7 @@ void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
     gint up = 1;
     gint left = 1;
 
-    if (moveresize_in_progress || !c->frame->visible ||
+    if (render_plugin->moveresize_in_progress || !render_plugin->frame_is_visible(c->frame) ||
         !(mv ?
           (c->functions & OB_CLIENT_FUNC_MOVE) :
           (c->functions & OB_CLIENT_FUNC_RESIZE)))
@@ -221,7 +222,7 @@ void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
         return;
     }
 
-    frame_end_iconify_animation(c->frame);
+    render_plugin->frame_end_iconify_animation(c->frame);
 
     moving = mv;
     moveresize_client = c;
@@ -252,7 +253,7 @@ void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
     cur_w = start_cw;
     cur_h = start_ch;
 
-    moveresize_in_progress = TRUE;
+    render_plugin->moveresize_in_progress = TRUE;
 
 #ifdef SYNC
     if (config_resize_redraw && !moving && obt_display_extension_sync &&
@@ -330,7 +331,7 @@ void moveresize_end(gboolean cancel)
     /* dont edge warp after its ended */
     cancel_edge_warp();
 
-    moveresize_in_progress = FALSE;
+    render_plugin->moveresize_in_progress = FALSE;
     moveresize_client = NULL;
 }
 
@@ -348,8 +349,8 @@ static void do_move(gboolean keyboard, gint keydist)
                      TRUE, FALSE, FALSE);
     if (config_resize_popup_show == 2) /* == "Always" */
         popup_coords(moveresize_client, "%d x %d",
-                     moveresize_client->frame->area.x,
-                     moveresize_client->frame->area.y);
+                     render_plugin->frame_get_window_area(moveresize_client->frame).x,
+                     render_plugin->frame_get_window_area(moveresize_client->frame).y);
 }
 
 
@@ -480,11 +481,13 @@ static void calc_resize(gboolean keyboard, gint keydist, gint *dw, gint *dh,
         trydh = nh - oh;
     }
 
+
+    Strut size = render_plugin->frame_get_size(moveresize_client->frame);
     /* resist_size_* needs the frame size */
-    nw += moveresize_client->frame->size.left +
-        moveresize_client->frame->size.right;
-    nh += moveresize_client->frame->size.top +
-        moveresize_client->frame->size.bottom;
+    nw += size.left +
+        size.right;
+    nh += size.top +
+        size.bottom;
 
     if (keyboard) resist = keydist - 1; /* resist for one key press */
     else resist = config_resist_win;
@@ -492,10 +495,10 @@ static void calc_resize(gboolean keyboard, gint keydist, gint *dw, gint *dh,
     if (!keyboard) resist = config_resist_edge;
     resist_size_monitors(moveresize_client, resist, &nw, &nh, dir);
 
-    nw -= moveresize_client->frame->size.left +
-        moveresize_client->frame->size.right;
-    nh -= moveresize_client->frame->size.top +
-        moveresize_client->frame->size.bottom;
+    nw -= size.left +
+        size.right;
+    nh -= size.top +
+        size.bottom;
 
     *dw = nw - ow;
     *dh = nh - oh;
@@ -827,7 +830,7 @@ gboolean moveresize_event(XEvent *e)
 {
     gboolean used = FALSE;
 
-    if (!moveresize_in_progress) return FALSE;
+    if (!render_plugin->moveresize_in_progress) return FALSE;
 
     if (e->type == ButtonPress) {
         if (!button) {
index 2d0f7dced493644a2804cab6291cfba424ffaf1d..ad222558d6dd52ca01fdad47f9bdf7588a6d4bac 100644 (file)
@@ -33,7 +33,7 @@ typedef enum {
     OB_RESIZE_POS_FIXED
 } ObResizePopupPos;
 
-extern gboolean moveresize_in_progress;
+//extern gboolean moveresize_in_progress;
 extern struct _ObClient *moveresize_client;
 #ifdef SYNC
 extern XSyncAlarm moveresize_alarm;
index a6a81cef7dec11e813e67f9ac8dd5d3b23b0fd1d..55be9d79aea1ae4debc9e83d04a86c78fcc28ffd 100644 (file)
@@ -32,8 +32,7 @@
 #include "focus_cycle_indicator.h"
 #include "focus_cycle_popup.h"
 #include "moveresize.h"
-#include "frame.h"
-#include "framerender.h"
+#include "engine_interface.h"
 #include "keyboard.h"
 #include "mouse.h"
 #include "menuframe.h"
@@ -93,6 +92,7 @@ gchar       *ob_sm_id = NULL;
 gchar       *ob_sm_save_file = NULL;
 gboolean     ob_sm_restore = TRUE;
 gboolean     ob_debug_xinerama = FALSE;
+ObFramePlugin *render_plugin = NULL;
 
 static ObState   state;
 static gboolean  xsync = FALSE;
@@ -255,7 +255,14 @@ gint main(gint argc, gchar **argv)
             }
 
             /* load the theme specified in the rc file */
-            {
+              {
+                ob_debug("Entering LoadThemeConfig");
+                render_plugin = init_frame_plugin (
+                    config_theme, TRUE, config_font_activewindow,
+                    config_font_inactivewindow, config_font_menutitle,
+                    config_font_menuitem, config_font_osd);
+                ob_debug("Exiting LoadThemeConfig");
+                /* load the theme specified in the rc file */
                 RrTheme *theme;
                 if ((theme = RrThemeNew(ob_rr_inst, config_theme, TRUE,
                                         config_font_activewindow,
@@ -280,9 +287,9 @@ gint main(gint argc, gchar **argv)
                 /* update all existing windows for the new theme */
                 for (it = client_list; it; it = g_list_next(it)) {
                     ObClient *c = it->data;
-                    frame_adjust_theme(c->frame);
-                }
-            }
+                    render_plugin->frame_adjust_theme(c->frame);
+                  }
+              }
             event_startup(reconfigure);
             /* focus_backup is used for stacking, so this needs to come before
                anything that calls stacking_add */
@@ -330,7 +337,7 @@ gint main(gint argc, gchar **argv)
                     /* the new config can change the window's decorations */
                     client_setup_decor_and_functions(c, FALSE);
                     /* redraw the frames */
-                    frame_adjust_area(c->frame, TRUE, TRUE, FALSE);
+                    render_plugin->frame_update_layout (c->frame, FALSE, FALSE);
                     /* the decor sizes may have changed, so the windows may
                        end up in new positions */
                     client_reconfigure(c, FALSE);
@@ -372,9 +379,11 @@ gint main(gint argc, gchar **argv)
 
     XSync(obt_display, FALSE);
 
-    RrThemeFree(ob_rr_theme);
-    RrInstanceFree(ob_rr_inst);
-
+    if (render_plugin)
+    {
+    //RrThemeFree(render_plugin->ob_rr_theme);
+    RrInstanceFree(render_plugin->ob_rr_inst);
+    }
     session_shutdown(being_replaced);
 
     obt_display_close(obt_display);
index 47d92042e2eed946931c7a0dcb49ba3fe2a18683..bc6bf21b3359121437fa062d6f49398f5347d388 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "render/render.h"
 #include "render/theme.h"
+#include "engine_interface.h"
 #include "obt/mainloop.h"
 #include "obt/display.h"
 
@@ -46,6 +47,9 @@ extern gboolean ob_sm_restore;
 extern gboolean ob_replace_wm;
 extern gboolean ob_debug_xinerama;
 
+/* render function */
+extern ObFramePlugin *render_plugin;
+
 /* The state of execution of the window manager */
 ObState ob_state();
 
index aac40e8a099249c0620e7513269f556b766c56d8..8c1861342706cc5419aed4c11aabd2f2d899967e 100644 (file)
 #include "client.h"
 #include "group.h"
 #include "screen.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "focus.h"
 #include "config.h"
 #include "dock.h"
 #include "debug.h"
+#include "openbox.h"
 
 extern ObDock *dock;
 
@@ -148,14 +149,16 @@ static gboolean place_random(ObClient *client, gint *x, gint *y)
     Rect **areas;
     guint i;
 
+    Rect area = render_plugin->frame_get_window_area(client->frame);
+
     areas = pick_head(client);
     i = (config_place_monitor != OB_PLACE_MONITOR_ANY) ?
         0 : g_random_int_range(0, screen_num_monitors);
 
     l = areas[i]->x;
     t = areas[i]->y;
-    r = areas[i]->x + areas[i]->width - client->frame->area.width;
-    b = areas[i]->y + areas[i]->height - client->frame->area.height;
+    r = areas[i]->x + areas[i]->width - area.width;
+    b = areas[i]->y + areas[i]->height - area.height;
 
     if (r > l) *x = g_random_int_range(l, r + 1);
     else       *x = areas[i]->x;
@@ -310,7 +313,8 @@ static gboolean place_nooverlap(ObClient *c, gint *x, gint *y)
                 */
                 /* don't ignore this window, so remove it from the available
                    area */
-                spaces = area_remove(spaces, &test->frame->area);
+                Rect test_area = render_plugin->frame_get_window_area(test->frame);
+                spaces = area_remove(spaces, &test_area);
             }
 
             if (ignore < IGNORE_DOCK) {
@@ -319,11 +323,12 @@ static gboolean place_nooverlap(ObClient *c, gint *x, gint *y)
                 spaces = area_remove(spaces, &a);
             }
 
+            Rect c_area = render_plugin->frame_get_window_area(c->frame);
             for (sit = spaces; sit; sit = g_slist_next(sit)) {
                 Rect *r = sit->data;
 
-                if (r->width >= c->frame->area.width &&
-                    r->height >= c->frame->area.height &&
+                if (r->width >= c_area.width &&
+                    r->height >= c_area.height &&
                     r->width * r->height > maxsize)
                 {
                     maxsize = r->width * r->height;
@@ -338,8 +343,8 @@ static gboolean place_nooverlap(ObClient *c, gint *x, gint *y)
                 *x = r->x;
                 *y = r->y;
                 if (config_place_center) {
-                    *x += (r->width - c->frame->area.width) / 2;
-                    *y += (r->height - c->frame->area.height) / 2;
+                    *x += (r->width - c_area.width) / 2;
+                    *y += (r->height - c_area.height) / 2;
                 }
                 ret = TRUE;
             }
@@ -363,18 +368,21 @@ static gboolean place_under_mouse(ObClient *client, gint *x, gint *y)
     gint px, py;
     Rect *area;
 
+    Strut fsize = render_plugin->frame_get_size(client->frame);
+    Rect farea = render_plugin->frame_get_window_area(client->frame);
+
     if (!screen_pointer_pos(&px, &py))
         return FALSE;
     area = pick_pointer_head(client);
 
     l = area->x;
     t = area->y;
-    r = area->x + area->width - client->frame->area.width;
-    b = area->y + area->height - client->frame->area.height;
+    r = area->x + area->width - farea.width;
+    b = area->y + area->height - farea.height;
 
-    *x = px - client->area.width / 2 - client->frame->size.left;
+    *x = px - client->area.width / 2 - fsize.left;
     *x = MIN(MAX(*x, l), r);
-    *y = py - client->area.height / 2 - client->frame->size.top;
+    *y = py - client->area.height / 2 - fsize.top;
     *y = MIN(MAX(*y, t), b);
 
     return TRUE;
@@ -411,10 +419,11 @@ static gboolean place_per_app_setting(ObClient *client, gint *x, gint *y,
         g_free(areas);
     }
 
+    Rect farea = render_plugin->frame_get_window_area(client->frame);
     if (settings->position.x.center)
         *x = screen->x + screen->width / 2 - client->area.width / 2;
     else if (settings->position.x.opposite)
-        *x = screen->x + screen->width - client->frame->area.width -
+        *x = screen->x + screen->width - farea.width -
             settings->position.x.pos;
     else
         *x = screen->x + settings->position.x.pos;
@@ -422,7 +431,7 @@ static gboolean place_per_app_setting(ObClient *client, gint *x, gint *y,
     if (settings->position.y.center)
         *y = screen->y + screen->height / 2 - client->area.height / 2;
     else if (settings->position.y.opposite)
-        *y = screen->y + screen->height - client->frame->area.height -
+        *y = screen->y + screen->height - farea.height -
             settings->position.y.pos;
     else
         *y = screen->y + settings->position.y.pos;
@@ -439,23 +448,24 @@ static gboolean place_transient_splash(ObClient *client, gint *x, gint *y)
         gint l, r, t, b;
         for (it = client->parents; it; it = g_slist_next(it)) {
             ObClient *m = it->data;
+            Rect area = render_plugin->frame_get_window_area(m->frame);
             if (!m->iconic) {
                 if (first) {
-                    l = RECT_LEFT(m->frame->area);
-                    t = RECT_TOP(m->frame->area);
-                    r = RECT_RIGHT(m->frame->area);
-                    b = RECT_BOTTOM(m->frame->area);
+                    l = RECT_LEFT(area);
+                    t = RECT_TOP(area);
+                    r = RECT_RIGHT(area);
+                    b = RECT_BOTTOM(area);
                     first = FALSE;
                 } else {
-                    l = MIN(l, RECT_LEFT(m->frame->area));
-                    t = MIN(t, RECT_TOP(m->frame->area));
-                    r = MAX(r, RECT_RIGHT(m->frame->area));
-                    b = MAX(b, RECT_BOTTOM(m->frame->area));
+                    l = MIN(l, RECT_LEFT(area));
+                    t = MIN(t, RECT_TOP(area));
+                    r = MAX(r, RECT_RIGHT(area));
+                    b = MAX(b, RECT_BOTTOM(area));
                 }
             }
             if (!first) {
-                *x = ((r + 1 - l) - client->frame->area.width) / 2 + l;
-                *y = ((b + 1 - t) - client->frame->area.height) / 2 + t;
+                *x = ((r + 1 - l) - area.width) / 2 + l;
+                *y = ((b + 1 - t) - area.height) / 2 + t;
                 return TRUE;
             }
         }
@@ -465,12 +475,13 @@ static gboolean place_transient_splash(ObClient *client, gint *x, gint *y)
         client->type == OB_CLIENT_TYPE_SPLASH)
     {
         Rect **areas;
+        Rect area = render_plugin->frame_get_window_area(client->frame);
         guint i;
 
         areas = pick_head(client);
 
-        *x = (areas[0]->width - client->frame->area.width) / 2 + areas[0]->x;
-        *y = (areas[0]->height - client->frame->area.height) / 2 + areas[0]->y;
+        *x = (areas[0]->width - area.width) / 2 + areas[0]->x;
+        *y = (areas[0]->height - area.height) / 2 + areas[0]->y;
 
         for (i = 0; i < screen_num_monitors; ++i)
             g_free(areas[i]);
@@ -506,6 +517,6 @@ gboolean place_client(ObClient *client, gint *x, gint *y,
     g_assert(ret);
 
     /* get where the client should be */
-    frame_frame_gravity(client->frame, x, y);
+    frame_frame_gravity(client, x, y);
     return !userplaced;
 }
index 02c87848675c3b30fe5f455d716c1a48510b0797..bbd05c3111b7cdfb2a7e46c4b0c2584620b35b5e 100644 (file)
@@ -20,7 +20,7 @@
 #include "popup.h"
 
 #include "openbox.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "client.h"
 #include "stacking.h"
 #include "event.h"
index 3bcb95ffc4db5779f870d29b47f7fdb6fbd9f129..5e88326a437fd6f62353c5a868590b1cccaa1dfd 100644 (file)
 
 #include "resist.h"
 #include "client.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "stacking.h"
 #include "screen.h"
 #include "dock.h"
 #include "config.h"
+#include "openbox.h"
 
 #include <glib.h>
 
@@ -104,10 +105,11 @@ void resist_move_windows(ObClient *c, gint resist, gint *x, gint *y)
     GList *it;
     Rect dock_area;
 
-    if (!resist) return;
+    Rect c_area = render_plugin->frame_get_window_area(c->frame);
 
-    frame_client_gravity(c->frame, x, y);
+    if (!resist) return;
 
+    frame_client_gravity(c, x, y);
 
     for (it = stacking_list; it; it = g_list_next(it)) {
         ObClient *target;
@@ -117,20 +119,21 @@ void resist_move_windows(ObClient *c, gint resist, gint *x, gint *y)
         target = it->data;
 
         /* don't snap to self or non-visibles */
-        if (!target->frame->visible || target == c)
+        if (!render_plugin->frame_is_visible(target->frame) || target == c)
             continue;
         /* don't snap to windows set to below and skip_taskbar (desklets) */
         if (target->below && !c->below && target->skip_taskbar)
             continue;
 
-        if (resist_move_window(c->frame->area, target->frame->area,
+        Rect target_area = render_plugin->frame_get_window_area(target->frame);
+        if (resist_move_window(c_area, target_area,
                                resist, x, y))
             break;
     }
     dock_get_area(&dock_area);
-    resist_move_window(c->frame->area, dock_area, resist, x, y);
+    resist_move_window(c_area, dock_area, resist, x, y);
 
-    frame_frame_gravity(c->frame, x, y);
+    frame_frame_gravity(c, x, y);
 }
 
 void resist_move_monitors(ObClient *c, gint resist, gint *x, gint *y)
@@ -144,29 +147,31 @@ void resist_move_monitors(ObClient *c, gint resist, gint *x, gint *y)
     gint w, h; /* current size */
     Rect desired_area;
 
+    Rect c_area = render_plugin->frame_get_window_area(c->frame);
+
     if (!resist) return;
 
-    frame_client_gravity(c->frame, x, y);
+    frame_client_gravity(c, x, y);
 
-    w = c->frame->area.width;
-    h = c->frame->area.height;
+    w = c_area.width;
+    h = c_area.height;
 
     l = *x;
     t = *y;
     r = l + w - 1;
     b = t + h - 1;
 
-    cl = RECT_LEFT(c->frame->area);
-    ct = RECT_TOP(c->frame->area);
-    cr = RECT_RIGHT(c->frame->area);
-    cb = RECT_BOTTOM(c->frame->area);
+    cl = RECT_LEFT(c_area);
+    ct = RECT_TOP(c_area);
+    cr = RECT_RIGHT(c_area);
+    cb = RECT_BOTTOM(c_area);
 
     RECT_SET(desired_area, *x, *y, c->area.width, c->area.height);
 
     for (i = 0; i < screen_num_monitors; ++i) {
         parea = screen_physical_area_monitor(i);
 
-        if (!RECT_INTERSECTS_RECT(*parea, c->frame->area)) {
+        if (!RECT_INTERSECTS_RECT(*parea, c_area)) {
             g_free(parea);
             continue;
         }
@@ -205,7 +210,7 @@ void resist_move_monitors(ObClient *c, gint resist, gint *x, gint *y)
         g_free(parea);
     }
 
-    frame_frame_gravity(c->frame, x, y);
+    frame_frame_gravity(c, x, y);
 }
 
 static gboolean resist_size_window(Rect window, Rect target, gint resist,
@@ -297,6 +302,7 @@ void resist_size_windows(ObClient *c, gint resist, gint *w, gint *h,
     ObClient *target; /* target */
     Rect dock_area;
 
+    Rect c_area = render_plugin->frame_get_window_area(c->frame);
     if (!resist) return;
 
     for (it = stacking_list; it; it = g_list_next(it)) {
@@ -305,18 +311,19 @@ void resist_size_windows(ObClient *c, gint resist, gint *w, gint *h,
         target = it->data;
 
         /* don't snap to invisibles or ourself */
-        if (!target->frame->visible || target == c)
+        if (!render_plugin->frame_is_visible(target->frame) || target == c)
             continue;
         /* don't snap to windows set to below and skip_taskbar (desklets) */
         if (target->below && !c->below && target->skip_taskbar)
             continue;
 
-        if (resist_size_window(c->frame->area, target->frame->area,
+        Rect target_area = render_plugin->frame_get_window_area(target->frame);
+        if (resist_size_window(c_area, target_area,
                                resist, w, h, dir))
             break;
     }
     dock_get_area(&dock_area);
-    resist_size_window(c->frame->area, dock_area,
+    resist_size_window(c_area, dock_area,
                        resist, w, h, dir);
 }
 
@@ -332,12 +339,14 @@ void resist_size_monitors(ObClient *c, gint resist, gint *w, gint *h,
     guint i;
     Rect desired_area;
 
+    Rect c_area = render_plugin->frame_get_window_area(c->frame);
+
     if (!resist) return;
 
-    l = RECT_LEFT(c->frame->area);
-    r = RECT_RIGHT(c->frame->area);
-    t = RECT_TOP(c->frame->area);
-    b = RECT_BOTTOM(c->frame->area);
+    l = RECT_LEFT(c_area);
+    r = RECT_RIGHT(c_area);
+    t = RECT_TOP(c_area);
+    b = RECT_BOTTOM(c_area);
 
     incw = c->size_inc.width;
     inch = c->size_inc.height;
@@ -347,7 +356,7 @@ void resist_size_monitors(ObClient *c, gint resist, gint *w, gint *h,
     for (i = 0; i < screen_num_monitors; ++i) {
         parea = screen_physical_area_monitor(i);
 
-        if (!RECT_INTERSECTS_RECT(*parea, c->frame->area)) {
+        if (!RECT_INTERSECTS_RECT(*parea, c_area)) {
             g_free(parea);
             continue;
         }
@@ -373,7 +382,7 @@ void resist_size_monitors(ObClient *c, gint resist, gint *w, gint *h,
         case OB_DIRECTION_NORTH:
         case OB_DIRECTION_SOUTH:
             dlt = l;
-            drb = r + *w - c->frame->area.width;
+            drb = r + *w - c_area.width;
             if (r <= ar && drb > ar && drb <= ar + resist)
                 *w = ar - l + 1;
             else if (r <= pr && drb > pr && drb <= pr + resist)
@@ -382,7 +391,7 @@ void resist_size_monitors(ObClient *c, gint resist, gint *w, gint *h,
         case OB_DIRECTION_WEST:
         case OB_DIRECTION_NORTHWEST:
         case OB_DIRECTION_SOUTHWEST:
-            dlt = l - *w + c->frame->area.width;
+            dlt = l - *w + c_area.width;
             drb = r;
             if (l >= al && dlt < al && dlt >= al - resist)
                 *w = r - al + 1;
@@ -399,7 +408,7 @@ void resist_size_monitors(ObClient *c, gint resist, gint *w, gint *h,
         case OB_DIRECTION_WEST:
         case OB_DIRECTION_EAST:
             dlt = t;
-            drb = b + *h - c->frame->area.height;
+            drb = b + *h - c_area.height;
             if (b <= ab && drb > ab && drb <= ab + resist)
                 *h = ab - t + 1;
             else if (b <= pb && drb > pb && drb <= pb + resist)
@@ -408,7 +417,7 @@ void resist_size_monitors(ObClient *c, gint resist, gint *w, gint *h,
         case OB_DIRECTION_NORTH:
         case OB_DIRECTION_NORTHWEST:
         case OB_DIRECTION_NORTHEAST:
-            dlt = t - *h + c->frame->area.height;
+            dlt = t - *h + c_area.height;
             drb = b;
             if (t >= at && dlt < at && dlt >= at - resist)
                 *h = b - at + 1;
index 90f8b27c76cbd13c29c74c07e78ab79cf9bfd8e9..b525c57f52806ec1bdc439e32ce294f35fd1aeae 100644 (file)
@@ -27,7 +27,7 @@
 #include "screen.h"
 #include "client.h"
 #include "session.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "event.h"
 #include "focus.h"
 #include "popup.h"
@@ -571,7 +571,9 @@ static void screen_fallback_focus(void)
         if (c->can_focus) {
             /* reduce flicker by hiliting now rather than waiting for the
                server FocusIn event */
-            frame_adjust_focus(c->frame, TRUE);
+        render_plugin->frame_set_is_focus (c->frame, TRUE);
+        render_plugin->frame_update_layout (c->frame, FALSE, FALSE);
+        render_plugin->frame_update_skin (c->frame);
             /* do this here so that if you switch desktops to a window with
                helper windows then the helper windows won't flash */
             client_bring_helper_windows(c);
@@ -1226,7 +1228,9 @@ void screen_show_desktop(gboolean show, ObClient *show_only)
             if (c->can_focus) {
                 /* reduce flicker by hiliting now rather than waiting for the
                    server FocusIn event */
-                frame_adjust_focus(c->frame, TRUE);
+        render_plugin->frame_set_is_focus(c->frame, TRUE);
+        render_plugin->frame_update_layout (c->frame, FALSE, FALSE);
+        render_plugin->frame_update_skin (c->frame);
             }
         }
     }
index 3c05df49c64c0c23f470a87aa4e090ee33fb4d29..d9e8d40d7771be6f97c29b2cdf7be668a0a9ac6b 100644 (file)
@@ -22,7 +22,7 @@
 #include "focus.h"
 #include "client.h"
 #include "group.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "window.h"
 #include "event.h"
 #include "debug.h"
@@ -544,6 +544,7 @@ static gboolean stacking_occluded(ObClient *client, ObClient *sibling)
     gboolean occluded = FALSE;
     gboolean found = FALSE;
 
+    Rect client_area = render_plugin->frame_get_window_area(client->frame);
     /* no need for any looping in this case */
     if (sibling && client->layer != sibling->layer)
         return occluded;
@@ -557,7 +558,8 @@ static gboolean stacking_occluded(ObClient *client, ObClient *sibling)
                  c->desktop == client->desktop) &&
                 !client_search_transient(client, c))
             {
-                if (RECT_INTERSECTS_RECT(c->frame->area, client->frame->area))
+                Rect c_area = render_plugin->frame_get_window_area(c->frame);
+                if (RECT_INTERSECTS_RECT(c_area, client_area))
                 {
                     if (sibling != NULL) {
                         if (c == sibling) {
@@ -588,6 +590,8 @@ static gboolean stacking_occludes(ObClient *client, ObClient *sibling)
     gboolean occludes = FALSE;
     gboolean found = FALSE;
 
+    Rect client_area = render_plugin->frame_get_window_area(client->frame);
+
     /* no need for any looping in this case */
     if (sibling && client->layer != sibling->layer)
         return occludes;
@@ -600,7 +604,8 @@ static gboolean stacking_occludes(ObClient *client, ObClient *sibling)
                  c->desktop == client->desktop) &&
                 !client_search_transient(c, client))
             {
-                if (RECT_INTERSECTS_RECT(c->frame->area, client->frame->area))
+                Rect c_area = render_plugin->frame_get_window_area(c->frame);
+                if (RECT_INTERSECTS_RECT(c_area, client_area))
                 {
                     if (sibling != NULL) {
                         if (c == sibling) {
index c8951741bf44fa72713a54b697f713943eeb286d..4c6b998b78f0fc68b08868f1c27354179f5f5964 100644 (file)
 #include "config.h"
 #include "dock.h"
 #include "client.h"
-#include "frame.h"
+#include "engine_interface.h"
 #include "openbox.h"
 #include "prompt.h"
 #include "debug.h"
 #include "grab.h"
 
-static GHashTable *window_map;
+GHashTable *window_map;
 
 static guint window_hash(Window *w) { return *w; }
 static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
@@ -55,7 +55,7 @@ Window window_top(ObWindow *self)
     case OB_WINDOW_CLASS_DOCK:
         return WINDOW_AS_DOCK(self)->frame;
     case OB_WINDOW_CLASS_CLIENT:
-        return WINDOW_AS_CLIENT(self)->frame->window;
+        return render_plugin->frame_get_window(WINDOW_AS_CLIENT(self)->frame);
     case OB_WINDOW_CLASS_INTERNAL:
         return WINDOW_AS_INTERNAL(self)->window;
     case OB_WINDOW_CLASS_PROMPT:
index 24a7d07bc7d7163024941c5d9471d7417b05e770..76303b3c046bf8c3af1cc48143d0a64bad0b40cd 100644 (file)
@@ -90,4 +90,6 @@ void window_manage_all(void);
 void window_manage(Window win);
 void window_unmanage_all(void);
 
+extern GHashTable *window_map;
+
 #endif
index a6931be664923a4980c23d736592671976917766..f44d68a020b6fea970a1bda02d095e92e4e2d4c1 100644 (file)
@@ -24,6 +24,7 @@
 #include "theme.h"
 #include "icon.h"
 #include "obt/paths.h"
+#include "openbox/engine_interface.h"
 
 #include <X11/Xlib.h>
 #include <X11/Xresource.h>
@@ -46,6 +47,50 @@ static int parse_inline_number(const char *p);
 static RrPixel32* read_c_image(gint width, gint height, const guint8 *data);
 static void set_default_appearance(RrAppearance *a);
 
+gint LoadThemeConfig(ObFramePlugin * p, const RrInstance *inst,
+    const gchar *name, gboolean allow_fallback, RrFont *active_window_font,
+    RrFont *inactive_window_font, RrFont *menu_title_font,
+    RrFont *menu_item_font, RrFont *osd_font)
+  {
+    XrmDatabase db = NULL;
+    gchar *path;
+
+    if (name)
+      {
+        db = loaddb(name, &path);
+        if (db == NULL)
+          {
+            g_message("Unable to load the theme '%s'", name);
+            if (allow_fallback)
+              g_message("Falling back to the default theme '%s'", DEFAULT_THEME);
+            /* fallback to the default theme */
+            name = NULL;
+          }
+      }
+    if (name == NULL)
+      {
+        if (allow_fallback)
+          {
+            db = loaddb(DEFAULT_THEME, &path);
+            if (db == NULL)
+              {
+                g_message("Unable to load the theme '%s'", DEFAULT_THEME);
+                return 0;
+              }
+          }
+        else
+          return 0;
+      }
+
+    gint i = (p->load_theme_config)(inst, name, path, db, active_window_font,
+        inactive_window_font, menu_title_font, menu_item_font, osd_font);
+
+    g_free(path);
+    XrmDestroyDatabase(db);
+
+    return i;
+  }
+
 RrTheme* RrThemeNew(const RrInstance *inst, const gchar *name,
                     gboolean allow_fallback,
                     RrFont *active_window_font, RrFont *inactive_window_font,
index 9f51fabd905793c75a1fe61264348bb04871494a..0363050f856f4a03fe63b807525fd90d5ce07277 100644 (file)
@@ -21,6 +21,7 @@
 #define __theme_h
 
 #include "render.h"
+#include "openbox/engine_interface.h"
 
 G_BEGIN_DECLS
 
@@ -240,6 +241,14 @@ struct _RrTheme {
     gchar *name;
 };
 
+struct _ObFramePlugin;
+/*! The font values are all optional. If a NULL is used for any of them, then
+ the default font will be used. */
+gint LoadThemeConfig(struct _ObFramePlugin * p, const RrInstance *inst,
+    const gchar *name, gboolean allow_fallback, RrFont *active_window_font,
+    RrFont *inactive_window_font, RrFont *menu_title_font,
+    RrFont *menu_item_font, RrFont *osd_font);
+
 /*! The font values are all optional. If a NULL is used for any of them, then
   the default font will be used. */
 RrTheme* RrThemeNew(const RrInstance *inst, const gchar *theme,