diff -rN -u old-ion-3/de/font.c new-ion-3/de/font.c
diff -rN -u old-ion-3/modulelist.mk new-ion-3/modulelist.mk
--- old-ion-3/modulelist.mk	2005-10-06 09:34:53.000000000 +0200
+++ new-ion-3/modulelist.mk	2005-10-06 18:20:12.000000000 +0200
@@ -4,7 +4,7 @@
 
 MODULE_LIST = mod_ionws mod_floatws mod_query mod_menu \
 	      mod_dock mod_sp mod_sm mod_panews de \
-	      mod_mgmtmode mod_statusbar
+	      mod_mgmtmode mod_statusbar xftde 
 
 # Modules to -dlpreload into pwm if statically linking.
 
diff -rN -u old-ion-3/xftde/brush.c new-ion-3/xftde/brush.c
--- old-ion-3/xftde/brush.c	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/brush.c	2005-10-06 18:08:35.000000000 +0200
@@ -0,0 +1,219 @@
+/*
+ * ion/de/brush.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <string.h>
+
+#include <libtu/objp.h>
+#include <libextl/extl.h>
+
+#include <ioncore/common.h>
+#include <ioncore/rootwin.h>
+#include <ioncore/extlconv.h>
+#include <ioncore/ioncore.h>
+
+#include "brush.h"
+#include "style.h"
+#include "font.h"
+#include "colour.h"
+#include "private.h"
+
+
+/*{{{ Brush creation and releasing */
+
+
+bool debrush_init(DEBrush *brush, Window win,
+                  const char *stylename, DEStyle *style)
+{
+    brush->d=style;
+    brush->extras_fn=NULL;
+    brush->indicator_w=0;
+    brush->win=win;
+    brush->clip_set=FALSE;
+    brush->draw=NULL;
+    style->usecount++;
+
+    if(!grbrush_init(&(brush->grbrush))){
+        style->usecount--;
+        return FALSE;
+    }
+    
+    if(MATCHES("tab-frame", stylename)){
+        brush->extras_fn=debrush_tab_extras;
+        if(!style->tabbrush_data_ok)
+            destyle_create_tab_gcs(style);
+    }else if(MATCHES("tab-menuentry", stylename)){
+        brush->extras_fn=debrush_menuentry_extras;
+        brush->indicator_w=grbrush_get_text_width((GrBrush*)brush, 
+                                                  DE_SUB_IND, 
+                                                  DE_SUB_IND_LEN);
+    }
+    
+    return TRUE;
+}
+
+
+DEBrush *create_debrush(Window win, const char *stylename, DEStyle *style)
+{
+    CREATEOBJ_IMPL(DEBrush, debrush, (p, win, stylename, style));
+}
+
+
+static DEBrush *do_get_brush(Window win, WRootWin *rootwin, 
+                             const char *stylename, bool slave)
+{
+    DEStyle *style=de_get_style(rootwin, stylename);
+    DEBrush *brush;
+    
+    if(style==NULL)
+        return NULL;
+    
+    brush=create_debrush(win, stylename, style);
+    
+    /* Set background colour */
+    if(brush!=NULL && !slave){
+        grbrush_enable_transparency(&(brush->grbrush), 
+                                    GR_TRANSPARENCY_DEFAULT);
+    }
+    
+    return brush;
+}
+
+
+DEBrush *de_get_brush(Window win, WRootWin *rootwin, const char *stylename)
+{
+    return do_get_brush(win, rootwin, stylename, FALSE);
+}
+
+
+DEBrush *debrush_get_slave(DEBrush *master, WRootWin *rootwin, 
+                           const char *stylename)
+{
+    return do_get_brush(master->win, rootwin, stylename, TRUE);
+}
+
+
+void debrush_deinit(DEBrush *brush)
+{
+	destyle_unref(brush->d);
+	brush->d=NULL;
+	if(brush->draw!=NULL)
+		XftDrawDestroy(brush->draw);
+	grbrush_deinit(&(brush->grbrush));
+}
+
+
+void debrush_release(DEBrush *brush)
+{
+    destroy_obj((Obj*)brush);
+}
+
+
+XftDraw *debrush_get_draw(DEBrush *brush, Drawable d)
+{
+	if(brush->draw==NULL)
+		brush->draw=XftDrawCreate(ioncore_g.dpy, d,
+								  DefaultVisual(ioncore_g.dpy,
+									            ioncore_g.active_screen->id),
+								  DefaultColormap(ioncore_g.dpy,
+									              ioncore_g.active_screen->id));
+	else
+		XftDrawChange(brush->draw, d);
+
+	return brush->draw;
+}
+
+/*}}}*/
+
+
+/*{{{ Border widths and extra information */
+
+
+void debrush_get_border_widths(DEBrush *brush, GrBorderWidths *bdw)
+{
+    DEStyle *style=brush->d;
+    DEBorder *bd=&(style->border);
+    uint tmp;
+    
+    switch(bd->style){
+    case DEBORDER_RIDGE:
+    case DEBORDER_GROOVE:
+        tmp=bd->sh+bd->hl+bd->pad;
+        bdw->top=tmp; bdw->bottom=tmp; bdw->left=tmp; bdw->right=tmp;
+        break;
+    case DEBORDER_INLAID:
+        tmp=bd->sh+bd->pad; bdw->top=tmp; bdw->left=tmp;
+        tmp=bd->hl+bd->pad; bdw->bottom=tmp; bdw->right=tmp;
+        break;
+    case DEBORDER_ELEVATED:
+    default:
+        tmp=bd->hl+bd->pad; bdw->top=tmp; bdw->left=tmp;
+        tmp=bd->sh+bd->pad; bdw->bottom=tmp; bdw->right=tmp;
+        break;
+    }
+    
+    bdw->tb_ileft=bdw->left;
+    bdw->tb_iright=bdw->right;
+    bdw->spacing=style->spacing;
+    
+    bdw->right+=brush->indicator_w;
+    bdw->tb_iright+=brush->indicator_w;
+}
+
+
+bool debrush_get_extra(DEBrush *brush, const char *key, char type, void *data)
+{
+    DEStyle *style=brush->d;
+    while(style!=NULL){
+        if(extl_table_get(style->data_table, 's', type, key, data))
+            return TRUE;
+        style=style->based_on;
+    }
+    return FALSE;
+}
+
+
+
+/*}}}*/
+
+
+/*{{{ Class implementation */
+
+
+static DynFunTab debrush_dynfuntab[]={
+    {grbrush_release, debrush_release},
+    {grbrush_draw_border, debrush_draw_border},
+    {grbrush_draw_borderline, debrush_draw_borderline},
+    {grbrush_get_border_widths, debrush_get_border_widths},
+    {grbrush_draw_string, debrush_draw_string},
+    {debrush_do_draw_string, debrush_do_draw_string_default},
+    {grbrush_get_font_extents, debrush_get_font_extents},
+    {(DynFun*)grbrush_get_text_width, (DynFun*)debrush_get_text_width},
+    {grbrush_draw_textbox, debrush_draw_textbox},
+    {grbrush_draw_textboxes, debrush_draw_textboxes},
+    {grbrush_set_window_shape, debrush_set_window_shape},
+    {grbrush_enable_transparency, debrush_enable_transparency},
+    {grbrush_clear_area, debrush_clear_area},
+    {grbrush_fill_area, debrush_fill_area},
+    {(DynFun*)grbrush_get_extra, (DynFun*)debrush_get_extra},
+    {(DynFun*)grbrush_get_slave, (DynFun*)debrush_get_slave},
+    {grbrush_begin, debrush_begin},
+    {grbrush_end, debrush_end},
+    END_DYNFUNTAB
+};
+
+
+IMPLCLASS(DEBrush, GrBrush, debrush_deinit, debrush_dynfuntab);
+
+
+/*}}}*/
+
+
+
diff -rN -u old-ion-3/xftde/brush.h new-ion-3/xftde/brush.h
--- old-ion-3/xftde/brush.h	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/brush.h	2005-10-06 18:09:19.000000000 +0200
@@ -0,0 +1,112 @@
+/*
+ * ion/de/brush.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef ION_DE_BRUSH_H
+#define ION_DE_BRUSH_H
+
+#include <libextl/extl.h>
+
+#include <ioncore/common.h>
+#include <ioncore/gr.h>
+#include <ioncore/rectangle.h>
+#include <X11/Xft/Xft.h>
+
+INTRCLASS(DEBrush);
+
+#include "style.h"
+#include "colour.h"
+
+
+typedef void DEBrushExtrasFn(DEBrush *brush, 
+                             const WRectangle *g, DEColourGroup *cg,
+                             GrBorderWidths *bdw,
+                             GrFontExtents *fnte,
+                             const char *a1, const char *a2,
+                             bool pre);
+
+DECLCLASS(DEBrush){
+    GrBrush grbrush;
+    DEStyle *d;
+	XftDraw *draw;
+    DEBrushExtrasFn *extras_fn;
+    int indicator_w;
+    Window win;
+    bool clip_set;
+};
+
+extern DEBrush *de_get_brush(Window win, WRootWin *rootwin,
+                             const char *style);
+
+extern DEBrush *create_debrush(Window win, 
+                               const char *stylename, DEStyle *style);
+extern bool debrush_init(DEBrush *brush, Window win,
+                         const char *stylename, DEStyle *style);
+extern void debrush_deinit(DEBrush *brush);
+
+extern DEBrush *debrush_get_slave(DEBrush *brush, WRootWin *rootwin, 
+                                  const char *style);
+
+extern void debrush_release(DEBrush *brush);
+
+
+extern DEColourGroup *debrush_get_colour_group2(DEBrush *brush, 
+                                                const char *attr_p1,
+                                                const char *attr_p2);
+
+extern DEColourGroup *debrush_get_colour_group(DEBrush *brush, 
+                                               const char *attr);
+
+
+/* Begin/end */
+
+extern void debrush_begin(DEBrush *brush, const WRectangle *geom, int flags);
+extern void debrush_end(DEBrush *brush);
+
+/* Information */
+
+extern void debrush_get_border_widths(DEBrush *brush, GrBorderWidths *bdw);
+extern bool debrush_get_extra(DEBrush *brush, const char *key, char type, 
+                              void *data);
+
+/* Borders & boxes */
+
+extern void debrush_draw_border(DEBrush *brush, 
+                                const WRectangle *geom,
+                                const char *attrib);
+extern void debrush_draw_borderline(DEBrush *brush, const WRectangle *geom,
+                                    const char *attrib, GrBorderLine line);
+
+extern void debrush_draw_textbox(DEBrush *brush, const WRectangle *geom,
+                                 const char *text, const char *attr,
+                                 bool needfill);
+
+extern void debrush_draw_textboxes(DEBrush *brush, const WRectangle *geom, 
+                                   int n, const GrTextElem *elem, 
+                                   bool needfill, const char *common_attrib);
+
+extern DEBrushExtrasFn debrush_tab_extras;
+extern DEBrushExtrasFn debrush_menuentry_extras;
+
+/* Misc */
+
+extern void debrush_set_window_shape(DEBrush *brush, bool rough,
+                                     int n, const WRectangle *rects);
+
+extern void debrush_enable_transparency(DEBrush *brush, GrTransparency mode);
+
+extern void debrush_fill_area(DEBrush *brush, const WRectangle *geom, 
+                              const char *attr);
+extern void debrush_clear_area(DEBrush *brush, const WRectangle *geom);
+
+XftDraw *debrush_get_draw(DEBrush *brush, Drawable d);
+
+
+#endif /* ION_DE_BRUSH_H */
diff -rN -u old-ion-3/xftde/colour.c new-ion-3/xftde/colour.c
--- old-ion-3/xftde/colour.c	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/colour.c	2005-10-06 18:11:05.000000000 +0200
@@ -0,0 +1,58 @@
+/*
+ * ion/de/colour.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <ioncore/common.h>
+#include "colour.h"
+
+
+bool de_alloc_colour(WRootWin *rootwin, DEColour *ret, const char *name)
+{
+	if(name==NULL)
+		return FALSE;
+	return XftColorAllocName(
+			ioncore_g.dpy,
+			DefaultVisual(ioncore_g.dpy, ioncore_g.active_screen->id),
+			rootwin->default_cmap,
+			name,
+			ret
+	);
+
+}
+
+
+bool de_duplicate_colour(WRootWin *rootwin, DEColour in, DEColour *out)
+{
+	return XftColorAllocName(
+			ioncore_g.dpy,
+			DefaultVisual(ioncore_g.dpy, ioncore_g.active_screen->id),
+			rootwin->default_cmap,
+			&(in.color),
+			out
+	);
+}
+
+
+void de_free_colour_group(WRootWin *rootwin, DEColourGroup *cg)
+{
+	de_free_colour(rootwin, cg->bg);
+	de_free_colour(rootwin, cg->fg);
+	de_free_colour(rootwin, cg->hl);
+	de_free_colour(rootwin, cg->sh);
+	de_free_colour(rootwin, cg->pad);
+}
+
+
+void de_free_colour(WRootWin *rootwin, DEColour col)
+{
+	XftColorFree(ioncore_g.dpy, DefaultVisual(ioncore_g.dpy, ioncore_g.active_screen->id), rootwin->default_cmap, &col);
+
+}
+
diff -rN -u old-ion-3/xftde/colour.h new-ion-3/xftde/colour.h
--- old-ion-3/xftde/colour.h	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/colour.h	2005-10-06 18:11:44.000000000 +0200
@@ -0,0 +1,42 @@
+/*
+ * ion/de/colour.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef ION_DE_COLOUR_H
+#define ION_DE_COLOUR_H
+
+#include <ioncore/common.h>
+#include <ioncore/global.h>
+#include <ioncore/rootwin.h>
+#include <X11/Xft/Xft.h>
+
+
+INTRSTRUCT(DEColourGroup);
+
+
+typedef XftColor DEColour;
+
+
+DECLSTRUCT(DEColourGroup){
+    char *spec;
+    DEColour bg, hl, sh, fg, pad;
+};
+
+
+#define DE_BLACK(rootwin) BlackPixel(ioncore_g.dpy, rootwin->xscr)
+#define DE_WHITE(rootwin) WhitePixel(ioncore_g.dpy, rootwin->xscr)
+
+bool de_init_colour_group(WRootWin *rootwin, DEColourGroup *cg);
+bool de_alloc_colour(WRootWin *rootwin, DEColour *ret, const char *name);
+bool de_duplicate_colour(WRootWin *rootwin, DEColour in, DEColour *out);
+void de_free_colour_group(WRootWin *rootwin, DEColourGroup *cg);
+void de_free_colour(WRootWin *rootwin, DEColour col);
+
+#endif /* ION_DE_COLOUR_H */
diff -rN -u old-ion-3/xftde/draw.c new-ion-3/xftde/draw.c
--- old-ion-3/xftde/draw.c	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/draw.c	2005-10-06 18:13:25.000000000 +0200
@@ -0,0 +1,562 @@
+/*
+ * ion/de/draw.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <string.h>
+
+#include <ioncore/global.h>
+#include <ioncore/common.h>
+#include <ioncore/gr.h>
+#include "brush.h"
+#include "font.h"
+#include "private.h"
+
+#include <X11/extensions/shape.h>
+
+
+/*{{{ Colour group lookup */
+
+
+static DEColourGroup *destyle_get_colour_group2(DEStyle *style,
+                                                const char *attr_p1,
+                                                const char *attr_p2)
+{
+    int i, score, maxscore=0;
+    DEColourGroup *maxg=&(style->cgrp);
+    
+    while(style!=NULL){
+        for(i=0; i<style->n_extra_cgrps; i++){
+            score=gr_stylespec_score2(style->extra_cgrps[i].spec,
+                                      attr_p1, attr_p2);
+            if(score>maxscore){
+                maxg=&(style->extra_cgrps[i]);
+                maxscore=score;
+            }
+        }
+        style=style->based_on;
+    }
+    
+    return maxg;
+}
+
+
+DEColourGroup *debrush_get_colour_group2(DEBrush *brush, 
+                                         const char *attr_p1,
+                                         const char *attr_p2)
+{
+    return destyle_get_colour_group2(brush->d, attr_p1, attr_p2);
+}
+
+
+DEColourGroup *debrush_get_colour_group(DEBrush *brush, const char *attr)
+{
+    return destyle_get_colour_group2(brush->d, attr, NULL);
+}
+
+
+/*}}}*/
+
+
+/*{{{ Borders */
+
+
+/* Draw a border at x, y with outer width w x h. Top and left 'tl' pixels
+ * wide with color 'tlc' and bottom and right 'br' pixels with colors 'brc'.
+ */
+static void do_draw_border(Window win, GC gc, int x, int y, int w, int h,
+                           uint tl, uint br, DEColour tlc, DEColour brc)
+{
+    XPoint points[3];
+    uint i=0, a=0, b=0;
+    
+    w--;
+    h--;
+
+    XSetForeground(ioncore_g.dpy, gc, tlc.pixel);
+
+    
+    a=(br!=0);
+    b=0;
+    
+    for(i=0; i<tl; i++){
+        points[0].x=x+i;        points[0].y=y+h+1-b;
+        points[1].x=x+i;        points[1].y=y+i;
+        points[2].x=x+w+1-a;    points[2].y=y+i;
+
+        if(a<br)
+            a++;
+        if(b<br)
+            b++;
+    
+        XDrawLines(ioncore_g.dpy, win, gc, points, 3, CoordModeOrigin);
+    }
+
+    
+    XSetForeground(ioncore_g.dpy, gc, brc.pixel);
+
+    a=(tl!=0);
+    b=0;
+    
+    for(i=0; i<br; i++){
+        points[0].x=x+w-i;        points[0].y=y+b;
+        points[1].x=x+w-i;        points[1].y=y+h-i;
+        points[2].x=x+a;        points[2].y=y+h-i;
+    
+        if(a<tl)
+            a++;
+        if(b<tl)
+            b++;
+        
+        XDrawLines(ioncore_g.dpy, win, gc, points, 3, CoordModeOrigin);
+    }
+}
+
+
+static void draw_border(Window win, GC gc, WRectangle *geom,
+                        uint tl, uint br, DEColour tlc, DEColour brc)
+{
+    do_draw_border(win, gc, geom->x, geom->y, geom->w, geom->h,
+                   tl, br, tlc, brc);
+    geom->x+=tl;
+    geom->y+=tl;
+    geom->w-=tl+br;
+    geom->h-=tl+br;
+}
+
+
+void debrush_do_draw_border(DEBrush *brush, WRectangle geom, 
+                            DEColourGroup *cg)
+{
+    DEBorder *bd=&(brush->d->border);
+    GC gc=brush->d->normal_gc;
+    Window win=brush->win;
+    
+    switch(bd->style){
+    case DEBORDER_RIDGE:
+        draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
+    case DEBORDER_INLAID:
+        draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
+        draw_border(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl);
+        break;
+    case DEBORDER_GROOVE:
+        draw_border(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl);
+        draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
+        draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
+        break;
+    case DEBORDER_ELEVATED:
+    default:
+        draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
+        draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
+        break;
+    }
+}
+
+
+void debrush_draw_border(DEBrush *brush, 
+                         const WRectangle *geom,
+                         const char *attrib)
+{
+    DEColourGroup *cg=debrush_get_colour_group(brush, attrib);
+    if(cg!=NULL)
+        debrush_do_draw_border(brush, *geom, cg);
+}
+
+
+static void draw_borderline(Window win, GC gc, WRectangle *geom,
+                            uint tl, uint br, DEColour tlc, DEColour brc, 
+                            GrBorderLine line)
+{
+    if(line==GR_BORDERLINE_LEFT && geom->h>0){
+        XSetForeground(ioncore_g.dpy, gc, tlc.pixel);
+        XDrawRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y, tl, geom->h);
+        geom->x+=tl;
+    }else if(line==GR_BORDERLINE_TOP && geom->w>0){
+        XSetForeground(ioncore_g.dpy, gc, tlc.pixel);
+        XDrawRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y, geom->w, tl);
+        geom->y+=tl;
+    }else if(line==GR_BORDERLINE_RIGHT && geom->h>0){
+        XSetForeground(ioncore_g.dpy, gc, brc.pixel);
+        XDrawRectangle(ioncore_g.dpy, win, gc, geom->x+geom->w-1-br, geom->y, br, geom->h);
+        geom->w-=br;
+    }else if(line==GR_BORDERLINE_BOTTOM && geom->w>0){
+        XSetForeground(ioncore_g.dpy, gc, brc.pixel);
+        XDrawRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y+geom->h-1-br, geom->w, br);
+        geom->h-=br;
+    }
+}
+
+
+void debrush_do_draw_borderline(DEBrush *brush, WRectangle geom,
+                                DEColourGroup *cg, GrBorderLine line)
+{
+    DEBorder *bd=&(brush->d->border);
+    GC gc=brush->d->normal_gc;
+    Window win=brush->win;
+    
+    switch(bd->style){
+    case DEBORDER_RIDGE:
+        draw_borderline(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh, line);
+    case DEBORDER_INLAID:
+        draw_borderline(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad, line);
+        draw_borderline(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl, line);
+        break;
+    case DEBORDER_GROOVE:
+        draw_borderline(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl, line);
+        draw_borderline(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad, line);
+        draw_borderline(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh, line);
+        break;
+    case DEBORDER_ELEVATED:
+    default:
+        draw_borderline(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh, line);
+        draw_borderline(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad, line);
+        break;
+    }
+}
+
+
+void debrush_draw_borderline(DEBrush *brush, const WRectangle *geom,
+                             const char *attrib, GrBorderLine line)
+{
+    DEColourGroup *cg=debrush_get_colour_group(brush, attrib);
+    if(cg!=NULL)
+        debrush_do_draw_borderline(brush, *geom, cg, line);
+}
+
+
+/*}}}*/
+
+
+/*{{{ Boxes */
+
+
+static void copy_masked(DEBrush *brush, Drawable src, Drawable dst,
+                        int src_x, int src_y, int w, int h,
+                        int dst_x, int dst_y)
+{
+    
+    GC copy_gc=brush->d->copy_gc;
+    
+    XSetClipMask(ioncore_g.dpy, copy_gc, src);
+    XSetClipOrigin(ioncore_g.dpy, copy_gc, dst_x, dst_y);
+    XCopyPlane(ioncore_g.dpy, src, dst, copy_gc, src_x, src_y, w, h,
+               dst_x, dst_y, 1);
+}
+
+
+void debrush_tab_extras(DEBrush *brush, const WRectangle *g, 
+                        DEColourGroup *cg, GrBorderWidths *bdw,
+                        GrFontExtents *fnte,
+                        const char *a1, const char *a2,
+                        bool pre)
+{
+    DEStyle *d=brush->d;
+    GC tmp;
+    /* Not thread-safe, but neither is the rest of the drawing code
+     * with shared GC:s.
+     */
+    static bool swapped=FALSE;
+    
+    if(pre){
+        if(!MATCHES2("*-*-*-dragged", a1, a2))
+            return;
+        
+        tmp=d->normal_gc;
+        d->normal_gc=d->stipple_gc;
+        d->stipple_gc=tmp;
+        swapped=TRUE;
+        XClearArea(ioncore_g.dpy, brush->win, g->x, g->y, g->w, g->h, False);
+        return;
+    }
+    
+    if(MATCHES2("*-*-tagged", a1, a2)){
+        XSetForeground(ioncore_g.dpy, d->copy_gc, cg->fg.pixel);
+            
+        copy_masked(brush, d->tag_pixmap, brush->win, 0, 0,
+                    d->tag_pixmap_w, d->tag_pixmap_h,
+                    g->x+g->w-bdw->right-d->tag_pixmap_w, 
+                    g->y+bdw->top);
+    }
+
+    if(swapped){
+        tmp=d->normal_gc;
+        d->normal_gc=d->stipple_gc;
+        d->stipple_gc=tmp;
+        swapped=FALSE;
+    }
+    /*if(MATCHES2("*-*-*-dragged", a1, a2)){
+        XFillRectangle(ioncore_g.dpy, win, d->stipple_gc, 
+                       g->x, g->y, g->w, g->h);
+    }*/
+}
+
+
+void debrush_menuentry_extras(DEBrush *brush, const WRectangle *g, 
+                              DEColourGroup *cg, GrBorderWidths *bdw,
+                              GrFontExtents *fnte,
+                              const char *a1, const char *a2, 
+                              bool pre)
+{
+    int tx, ty;
+
+    if(pre)
+        return;
+    
+    if(!MATCHES2("*-*-submenu", a1, a2))
+        return;
+        
+    ty=(g->y+bdw->top+fnte->baseline
+        +(g->h-bdw->top-bdw->bottom-fnte->max_height)/2);
+    tx=g->x+g->w-bdw->right;
+
+    debrush_do_draw_string(brush, tx, ty, DE_SUB_IND, DE_SUB_IND_LEN, 
+                           FALSE, cg);
+}
+
+
+void debrush_do_draw_box(DEBrush *brush, const WRectangle *geom, 
+                         DEColourGroup *cg, bool needfill)
+{
+    GC gc=brush->d->normal_gc;
+    
+    if(TRUE/*needfill*/){
+        XSetForeground(ioncore_g.dpy, gc, cg->bg.pixel);
+        XFillRectangle(ioncore_g.dpy, brush->win, gc, geom->x, geom->y, 
+                       geom->w, geom->h);
+    }
+    
+    debrush_do_draw_border(brush, *geom, cg);
+}
+
+
+static void debrush_do_draw_textbox(DEBrush *brush, const WRectangle *geom, 
+                                    const char *text, DEColourGroup *cg, 
+                                    bool needfill,
+                                    const char *a1, const char *a2)
+{
+    uint len;
+    GrBorderWidths bdw;
+    GrFontExtents fnte;
+    uint tx, ty, tw;
+
+    grbrush_get_border_widths(&(brush->grbrush), &bdw);
+    grbrush_get_font_extents(&(brush->grbrush), &fnte);
+    
+    if(brush->extras_fn!=NULL)
+        brush->extras_fn(brush, geom, cg, &bdw, &fnte, a1, a2, TRUE);
+    
+    debrush_do_draw_box(brush, geom, cg, needfill);
+    
+    do{ /*...while(0)*/
+        if(text==NULL)
+            break;
+        
+        len=strlen(text);
+    
+        if(len==0)
+            break;
+    
+        if(brush->d->textalign!=DEALIGN_LEFT){
+            tw=grbrush_get_text_width((GrBrush*)brush, text, len);
+            
+            if(brush->d->textalign==DEALIGN_CENTER)
+                tx=geom->x+bdw.left+(geom->w-bdw.left-bdw.right-tw)/2;
+            else
+                tx=geom->x+geom->w-bdw.right-tw;
+        }else{
+            tx=geom->x+bdw.left;
+        }
+        
+        ty=(geom->y+bdw.top+fnte.baseline
+            +(geom->h-bdw.top-bdw.bottom-fnte.max_height)/2);
+        
+        debrush_do_draw_string(brush, tx, ty, text, len, FALSE, cg);
+    }while(0);
+    
+    if(brush->extras_fn!=NULL)
+        brush->extras_fn(brush, geom, cg, &bdw, &fnte, a1, a2, FALSE);
+}
+
+
+void debrush_draw_textbox(DEBrush *brush, const WRectangle *geom, 
+                          const char *text, const char *attr, 
+                          bool needfill)
+{
+    DEColourGroup *cg=debrush_get_colour_group(brush, attr);
+    if(cg!=NULL){
+        debrush_do_draw_textbox(brush, geom, text, cg, needfill, 
+                                attr, NULL);
+    }
+}
+
+
+void debrush_draw_textboxes(DEBrush *brush, const WRectangle *geom,
+                            int n, const GrTextElem *elem, 
+                            bool needfill, const char *common_attrib)
+{
+    WRectangle g=*geom;
+    DEColourGroup *cg;
+    GrBorderWidths bdw;
+    int i;
+    
+    grbrush_get_border_widths(&(brush->grbrush), &bdw);
+    
+    for(i=0; i<n; i++){
+        g.w=bdw.left+elem[i].iw+bdw.right;
+        cg=debrush_get_colour_group2(brush, common_attrib, elem[i].attr);
+        
+        if(cg!=NULL){
+            debrush_do_draw_textbox(brush, &g, elem[i].text, cg, needfill,
+                                    common_attrib, elem[i].attr);
+        }
+        
+        g.x+=g.w;
+        if(bdw.spacing>0 && needfill){
+            XClearArea(ioncore_g.dpy, brush->win, g.x, g.y,
+                       brush->d->spacing, g.h, False);
+        }
+        g.x+=bdw.spacing;
+    }
+}
+
+
+/*}}}*/
+
+
+/*{{{ Misc. */
+
+#define MAXSHAPE 16
+
+void debrush_set_window_shape(DEBrush *brush, bool rough,
+                              int n, const WRectangle *rects)
+{
+    XRectangle r[MAXSHAPE];
+    int i;
+    
+    if(n>MAXSHAPE)
+        n=MAXSHAPE;
+    
+    for(i=0; i<n; i++){
+        r[i].x=rects[i].x;
+        r[i].y=rects[i].y;
+        r[i].width=rects[i].w;
+        r[i].height=rects[i].h;
+    }
+    
+    XShapeCombineRectangles(ioncore_g.dpy, brush->win,
+                            ShapeBounding, 0, 0, r, n,
+                            ShapeSet, YXBanded);
+}
+
+
+void debrush_enable_transparency(DEBrush *brush, GrTransparency mode)
+{
+    XSetWindowAttributes attr;
+    ulong attrflags=0;
+
+    if(mode==GR_TRANSPARENCY_DEFAULT)
+        mode=brush->d->transparency_mode;
+    
+    if(mode==GR_TRANSPARENCY_YES){
+        attrflags=CWBackPixmap;
+        attr.background_pixmap=ParentRelative;
+    }else{
+        attrflags=CWBackPixel;
+        attr.background_pixel=brush->d->cgrp.bg.pixel;
+    }
+    
+    XChangeWindowAttributes(ioncore_g.dpy, brush->win, attrflags, &attr);
+    XClearWindow(ioncore_g.dpy, brush->win);
+}
+
+
+void debrush_fill_area(DEBrush *brush, const WRectangle *geom, const char *attr)
+{
+    DEColourGroup *cg=debrush_get_colour_group(brush, attr);
+    GC gc=brush->d->normal_gc;
+
+    if(cg==NULL)
+        return;
+    
+    XSetForeground(ioncore_g.dpy, gc, cg->bg.pixel);
+    XFillRectangle(ioncore_g.dpy, brush->win, gc, 
+                   geom->x, geom->y, geom->w, geom->h);
+}
+
+
+void debrush_clear_area(DEBrush *brush, const WRectangle *geom)
+{
+    XClearArea(ioncore_g.dpy, brush->win,
+               geom->x, geom->y, geom->w, geom->h, False);
+}
+
+
+/*}}}*/
+
+
+/*{{{ Clipping rectangles */
+
+/* Should actually set the clipping rectangle for all GC:s and use 
+ * window-specific GC:s to do this correctly...
+ */
+
+static void debrush_set_clipping_rectangle(DEBrush *brush, 
+                                           const WRectangle *geom)
+{
+    XRectangle rect;
+    
+    assert(!brush->clip_set);
+    
+    rect.x=geom->x;
+    rect.y=geom->y;
+    rect.width=geom->w;
+    rect.height=geom->h;
+    
+    XSetClipRectangles(ioncore_g.dpy, brush->d->normal_gc,
+                       0, 0, &rect, 1, Unsorted);
+    brush->clip_set=TRUE;
+}
+
+
+static void debrush_clear_clipping_rectangle(DEBrush *brush)
+{
+    if(brush->clip_set){
+        XSetClipMask(ioncore_g.dpy, brush->d->normal_gc, None);
+        brush->clip_set=FALSE;
+    }
+}
+
+
+/*}}}*/
+
+
+/*{{{ debrush_begin/end */
+
+
+void debrush_begin(DEBrush *brush, const WRectangle *geom, int flags)
+{
+    if(flags&GRBRUSH_AMEND)
+        flags|=GRBRUSH_NO_CLEAR_OK;
+    
+    if(!(flags&GRBRUSH_NO_CLEAR_OK))
+        debrush_clear_area(brush, geom);
+    
+    if(flags&GRBRUSH_NEED_CLIP)
+        debrush_set_clipping_rectangle(brush, geom);
+}
+
+
+void debrush_end(DEBrush *brush)
+{
+    debrush_clear_clipping_rectangle(brush);
+}
+
+
+/*}}}*/
+
diff -rN -u old-ion-3/xftde/exports.c new-ion-3/xftde/exports.c
--- old-ion-3/xftde/exports.c	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/exports.c	2005-10-06 18:54:38.000000000 +0200
@@ -0,0 +1,53 @@
+/* Automatically generated by mkexports.lua */
+#include <libextl/extl.h>
+#include <libextl/private.h>
+
+EXTL_DEFCLASS(WRootWin);
+static bool l2chnd_b_ost__WRootWin__(bool (*fn)(), ExtlL2Param *in, ExtlL2Param *out)
+{
+    if(!EXTL_CHKO1(in, 0, WRootWin)) return FALSE;
+    out[0].b=fn(in[0].o, in[1].s, in[2].t);
+    return TRUE;
+}
+static bool l2chnd_b_st___(bool (*fn)(), ExtlL2Param *in, ExtlL2Param *out)
+{
+    out[0].b=fn(in[0].s, in[1].t);
+    return TRUE;
+}
+static bool l2chnd_t_st___(ExtlTab (*fn)(), ExtlL2Param *in, ExtlL2Param *out)
+{
+    out[0].t=fn(in[0].s, in[1].t);
+    return TRUE;
+}
+static bool l2chnd_v__(void (*fn)(), ExtlL2Param *in, ExtlL2Param *out)
+{
+    fn();
+    return TRUE;
+}
+
+#define WRootWin_exports NULL
+extern void xftde_defstyle();
+extern void xftde_substyle();
+extern void xftde_reset();
+extern void xftde_defstyle_rootwin();
+
+
+static ExtlExportedFnSpec xftde_exports[] = {
+    {"defstyle", xftde_defstyle, "St", "b", (ExtlL2CallHandler*)l2chnd_b_st___, FALSE},
+    {"substyle", xftde_substyle, "St", "t", (ExtlL2CallHandler*)l2chnd_t_st___, TRUE},
+    {"reset", xftde_reset, NULL, NULL, (ExtlL2CallHandler*)l2chnd_v__, FALSE},
+    {"defstyle_rootwin", xftde_defstyle_rootwin, "oSt", "b", (ExtlL2CallHandler*)l2chnd_b_ost__WRootWin__, FALSE},
+    {NULL, NULL, NULL, NULL, NULL, FALSE}
+};
+
+bool xftde_register_exports()
+{
+    if(!extl_register_module("xftde", xftde_exports)) return FALSE;
+    return TRUE;
+}
+
+void xftde_unregister_exports()
+{
+    extl_unregister_module("xftde", xftde_exports);
+}
+
diff -rN -u old-ion-3/xftde/exports.h new-ion-3/xftde/exports.h
--- old-ion-3/xftde/exports.h	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/exports.h	2005-10-06 18:54:38.000000000 +0200
@@ -0,0 +1,11 @@
+/* Automatically generated by mkexports.lua */
+#ifndef XFTDE_EXTL_EXPORTS_H
+#define XFTDE_EXTL_EXPORTS_H
+
+#include <libextl/extl.h>
+
+extern bool xftde_register_exports();
+extern void xftde_unregister_exports();
+
+#endif /* XFTDE_EXTL_EXPORTS_H */
+
diff -rN -u old-ion-3/xftde/font.c new-ion-3/xftde/font.c
--- old-ion-3/xftde/font.c	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/font.c	2005-10-06 18:54:27.000000000 +0200
@@ -0,0 +1,236 @@
+/*
+ * ion/de/font.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <string.h>
+
+#include <libtu/objp.h>
+#include <ioncore/common.h>
+#include "font.h"
+#include "brush.h"
+
+
+/*{{{ Load/free */
+
+
+static DEFont *fonts=NULL;
+
+
+DEFont *de_load_font(const char *fontname)
+{
+	DEFont *fnt;
+	XftFont *font;
+
+	assert(fontname!=NULL);
+
+	/* There shouldn't be that many fonts... */
+	for(fnt=fonts; fnt!=NULL; fnt=fnt->next){
+		if(strcmp(fnt->pattern, fontname)==0){
+			fnt->refcount++;
+			return fnt;
+		}
+	}
+	if(strncmp(fontname, "xft:", 4)==0){
+		font=XftFontOpenName(ioncore_g.dpy, DefaultScreen(ioncore_g.dpy),
+				fontname+4);
+	}else{
+		font=XftFontOpenXlfd(ioncore_g.dpy, DefaultScreen(ioncore_g.dpy), fontname);
+	}
+
+	if(font==NULL){
+		if(strcmp(fontname, CF_FALLBACK_FONT_NAME)!=0){
+			warn(TR("Could not load font \"%s\", trying \"%s\""),
+					fontname, CF_FALLBACK_FONT_NAME);
+			return de_load_font(CF_FALLBACK_FONT_NAME);
+		}
+		return NULL;
+	}
+
+	fnt=ALLOC(DEFont);
+
+	if(fnt==NULL)
+		return NULL;
+
+	fnt->font=font;
+	fnt->pattern=scopy(fontname);
+	fnt->next=NULL;
+	fnt->prev=NULL;
+	fnt->refcount=1;
+
+	LINK_ITEM(fonts, fnt, next, prev);
+
+	return fnt;
+}
+
+
+bool de_set_font_for_style(DEStyle *style, DEFont *font)
+{
+    if(style->font!=NULL)
+        de_free_font(style->font);
+    
+    style->font=font;
+    font->refcount++;
+    
+    return TRUE;
+}
+
+
+bool de_load_font_for_style(DEStyle *style, const char *fontname)
+{
+    if(style->font!=NULL)
+        de_free_font(style->font);
+    
+    style->font=de_load_font(fontname);
+
+    if(style->font==NULL)
+        return FALSE;
+    
+    return TRUE;
+}
+
+
+void de_free_font(DEFont *font)
+{
+	if(--font->refcount!=0)
+		return;
+
+	if(font->font!=NULL)
+		XftFontClose(ioncore_g.dpy, font->font);
+	if(font->pattern!=NULL)
+		free(font->pattern);
+
+	UNLINK_ITEM(fonts, font, next, prev);
+	free(font);
+}
+
+
+/*}}}*/
+
+
+/*{{{ Lengths */
+
+
+void debrush_get_font_extents(DEBrush *brush, GrFontExtents *fnte)
+{
+    if(brush->d->font==NULL){
+        DE_RESET_FONT_EXTENTS(fnte);
+        return;
+    }
+    
+    defont_get_font_extents(brush->d->font, fnte);
+}
+
+
+void defont_get_font_extents(DEFont *font, GrFontExtents *fnte)
+{
+
+	if(font->font!=NULL){
+		fnte->max_height=font->font->ascent+font->font->descent;
+		fnte->max_width=font->font->max_advance_width;
+		fnte->baseline=font->font->ascent;
+		return;
+
+
+		return;
+	}
+
+fail:
+	DE_RESET_FONT_EXTENTS(fnte);
+}
+
+
+uint debrush_get_text_width(DEBrush *brush, const char *text, uint len)
+{
+    if(brush->d->font==NULL || text==NULL || len==0)
+        return 0;
+    
+    return defont_get_text_width(brush->d->font, text, len);
+}
+
+
+uint defont_get_text_width(DEFont *font, const char *text, uint len)
+{
+	if(font->font!=NULL){
+		XGlyphInfo extents;
+		if(ioncore_g.enc_utf8)
+			XftTextExtentsUtf8(ioncore_g.dpy, font->font, (XftChar8 *)text, len,
+					&extents);
+		else
+			XftTextExtents8(ioncore_g.dpy, font->font, (XftChar8 *)text, len,
+					&extents);
+		return extents.xOff;
+
+	}else{
+		return 0;
+	}
+}
+
+
+/*}}}*/
+
+
+/*{{{ String drawing */
+
+
+void debrush_do_draw_string_default(DEBrush *brush, 
+				      int x, int y, const char *str,
+				      int len, bool needfill, 
+				      DEColourGroup *colours)
+ {
+   Window win = brush->win;
+   GC gc=brush->d->normal_gc;
+ 	XftFont *font=brush->d->font->font;
+ 	XftDraw *draw;
+ 
+ 	if(brush->d->font==NULL)
+ 		return;
+ 
+ 	draw=debrush_get_draw(brush, win);
+ 
+ 	if(TRUE/*needfill*/){
+ 		XGlyphInfo extents;
+ 		if(ioncore_g.enc_utf8)
+ 			XftTextExtentsUtf8(ioncore_g.dpy, font, (XftChar8 *)str, len,
+ 					&extents);
+ 		else
+ 			XftTextExtents8(ioncore_g.dpy, font, (XftChar8 *)str, len, &extents);
+ 		XftDrawRect(draw, &(colours->bg), x-extents.x, y-extents.y,
+ 				extents.width, extents.height);
+ 	}
+ 
+ 	if(ioncore_g.enc_utf8)
+ 		XftDrawStringUtf8(draw, &(colours->fg), font, x, y, (XftChar8 *)str,
+ 				len);
+ 	else
+ 		XftDrawString8(draw, &(colours->fg), font, x, y, (XftChar8 *)str, len);
+  
+  }
+
+void debrush_do_draw_string(DEBrush *brush, int x, int y,
+                            const char *str, int len, bool needfill, 
+                            DEColourGroup *colours)
+{
+    CALL_DYN(debrush_do_draw_string, brush, (brush, x, y, str, len,
+                                             needfill, colours));
+}
+
+
+void debrush_draw_string(DEBrush *brush, int x, int y,
+                         const char *str, int len, bool needfill,
+                         const char *attrib)
+{
+    DEColourGroup *cg=debrush_get_colour_group(brush, attrib);
+    if(cg!=NULL)
+        debrush_do_draw_string(brush, x, y, str, len, needfill, cg);
+}
+
+
+/*}}}*/
+
diff -rN -u old-ion-3/xftde/font.h new-ion-3/xftde/font.h
--- old-ion-3/xftde/font.h	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/font.h	2005-10-06 18:17:00.000000000 +0200
@@ -0,0 +1,58 @@
+/*
+ * ion/de/font.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef ION_DE_FONT_H
+#define ION_DE_FONT_H
+
+#include <ioncore/common.h>
+#include <ioncore/gr.h>
+#include <X11/Xft/Xft.h>
+
+INTRSTRUCT(DEFont);
+
+#include "brush.h"
+#include "colour.h"
+#include "style.h"
+
+#define DE_RESET_FONT_EXTENTS(FNTE) \
+   {(FNTE)->max_height=0; (FNTE)->max_width=0; (FNTE)->baseline=0;}
+
+DECLSTRUCT(DEFont){
+    char *pattern;
+    int refcount;
+    XftFont *font;
+    DEFont *next, *prev;
+};
+
+extern bool de_load_font_for_style(DEStyle *style, const char *fontname);
+extern bool de_set_font_for_style(DEStyle *style, DEFont *font);
+extern DEFont *de_load_font(const char *fontname);
+extern void de_free_font(DEFont *font);
+
+extern void debrush_draw_string(DEBrush *brush, int x, int y,
+                                const char *str, int len, bool needfill,
+                                const char *attrib);
+extern void debrush_do_draw_string(DEBrush *brush, int x, int y,
+                                   const char *str, int len, bool needfill, 
+                                   DEColourGroup *colours);
+extern void debrush_do_draw_string_default(DEBrush *brush, int x, int y,
+                                           const char *str, int len, 
+                                           bool needfill, 
+                                           DEColourGroup *colours);
+
+extern void debrush_get_font_extents(DEBrush *brush, GrFontExtents *fnte);
+
+extern uint debrush_get_text_width(DEBrush *brush, const char *text, uint len);
+
+extern uint defont_get_text_width(DEFont *font, const char *text, uint len);
+extern void defont_get_font_extents(DEFont *font, GrFontExtents *fnte);
+
+#endif /* ION_DE_FONT_H */
diff -rN -u old-ion-3/xftde/fontset.c new-ion-3/xftde/fontset.c
--- old-ion-3/xftde/fontset.c	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/fontset.c	2005-10-06 09:34:53.000000000 +0200
@@ -0,0 +1,186 @@
+/*
+ * ion/de/fontset.c
+ * 
+ * This file contains routines to attempt to add fonts to a font pattern
+ * so that XCreateFontSet will not fail because the given font(s) do not
+ * contain all the characters required by the locale. The original code
+ * was apparently written by Tomohiro Kubota; see
+ * <http://www.debian.org/doc/manuals/intro-i18n/ch-examples.en.html#s13.4.5>.
+ * 
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <locale.h>
+
+#include <ioncore/common.h>
+#include <ioncore/global.h>
+
+#ifndef CF_FONT_ELEMENT_SIZE
+#define CF_FONT_ELEMENT_SIZE 50
+#endif
+
+#define FNT_D(X) /*X*/
+
+
+static const char *get_font_element(const char *pattern, char *buf,
+                                    int bufsiz, ...) 
+{
+    const char *p, *v;
+    char *p2;
+    va_list va;
+    
+    va_start(va, bufsiz);
+    buf[bufsiz-1]=0;
+    buf[bufsiz-2]='*';
+    while((v=va_arg(va, char *))!=NULL){
+        p=libtu_strcasestr(pattern, v);
+        if(p){
+            strncpy(buf, p+1, bufsiz-2);
+            p2=strchr(buf, '-');
+            if(p2) *p2=0;
+            va_end(va);
+            return p;
+        }
+    }
+    va_end(va);
+    strncpy(buf, "*", bufsiz);
+    return NULL;
+}
+
+
+static const char *get_font_size(const char *pattern, int *size) 
+{
+    const char *p;
+    const char *p2=NULL;
+    int n=0;
+    
+    for(p=pattern; 1; p++){
+        if(!*p){
+            if(p2!=NULL && n>1 && n<72){
+                *size=n; return p2+1;
+            }else{
+                *size=16; return NULL;
+            }
+        }else if(*p=='-'){
+            if(n>1 && n<72 && p2!=NULL){
+                *size=n;
+                return p2+1;
+            }
+            p2=p; n=0;
+        }else if(*p>='0' && *p<='9' && p2!=NULL){
+            n*=10;
+            n+=*p-'0';
+        }else{
+            p2=NULL; n=0;
+        }
+    }
+}
+
+
+XFontSet de_create_font_set(const char *fontname) 
+{
+    XFontSet fs;
+    char **missing=NULL, *def="-";
+    int nmissing, pixel_size=0;
+    char weight[CF_FONT_ELEMENT_SIZE], slant[CF_FONT_ELEMENT_SIZE];
+    const char *nfontname=fontname;
+    char *pattern2=NULL;
+    int i;
+    
+    FNT_D(fprintf(stderr, "FNTRQ: %s\n", fontname));
+    
+    fs=XCreateFontSet(ioncore_g.dpy, fontname, &missing, &nmissing, &def);
+
+    if(fs && nmissing==0){
+        if(missing!=NULL) 
+            XFreeStringList(missing);
+        return fs;
+    }
+    
+    /* Not a warning, nothing serious */
+    FNT_D(fprintf(stderr, "Failed to load fontset.\n"));
+    
+    if(!fs){
+        char *lcc=NULL;
+        const char *lc;
+        if(missing!=NULL)
+            XFreeStringList(missing);
+        
+        lc=setlocale(LC_CTYPE, NULL);
+        if(lc!=NULL && strcmp(lc, "POSIX")!=0 && strcmp(lc, "C")!=0)
+            lcc=scopy(lc);
+        
+        setlocale(LC_CTYPE, "C");
+        
+        fs=XCreateFontSet(ioncore_g.dpy, fontname, &missing, &nmissing, &def);
+        
+        if(lcc!=NULL){
+            setlocale(LC_CTYPE, lcc);
+            free(lcc);
+        }
+    }
+
+#ifndef CF_NO_FONTSET_KLUDGE    
+
+    if(fs){
+        XFontStruct **fontstructs;
+        char **fontnames;
+        XFontsOfFontSet(fs, &fontstructs, &fontnames);
+        nfontname=fontnames[0];
+    }
+
+    get_font_element(nfontname, weight, CF_FONT_ELEMENT_SIZE,
+                     "-medium-", "-bold-", "-demibold-", "-regular-", NULL);
+    get_font_element(nfontname, slant, CF_FONT_ELEMENT_SIZE,
+                     "-r-", "-i-", "-o-", "-ri-", "-ro-", NULL);
+    get_font_size(nfontname, &pixel_size);
+    
+    if(!strcmp(weight, "*"))
+        strncpy(weight, "medium", CF_FONT_ELEMENT_SIZE);
+    if(!strcmp(slant, "*"))
+        strncpy(slant, "r", CF_FONT_ELEMENT_SIZE);
+    if(pixel_size<3)
+        pixel_size=3;
+    else if(pixel_size>97)
+        pixel_size=97;
+    
+    if(ioncore_g.enc_utf8){
+        libtu_asprintf(&pattern2,
+                       "%s,"
+                       "-misc-fixed-%s-%s-*-*-%d-*-*-*-*-*-*-*,"
+                       "-misc-fixed-*-*-*-*-%d-*-*-*-*-*-*-*",
+                       fontname, weight, slant, pixel_size, pixel_size);
+    }else{
+        libtu_asprintf(&pattern2,
+                       "%s,"
+                       "-*-*-%s-%s-*-*-%d-*-*-*-*-*-*-*,"
+                       "-*-*-*-*-*-*-%d-*-*-*-*-*-*-*",
+                       fontname, weight, slant, pixel_size, pixel_size);
+    }
+    
+    if(pattern2==NULL)
+        return NULL;
+
+    FNT_D(fprintf(stderr, "NRQ: %s\n", pattern2));
+    
+    nfontname=pattern2;
+    
+    if(nmissing)
+        XFreeStringList(missing);
+    if(fs)
+        XFreeFontSet(ioncore_g.dpy, fs);
+
+    FNT_D(if(fs) fprintf(stderr, "Trying '%s'.\n", nfontname));
+    
+    fs=XCreateFontSet(ioncore_g.dpy, nfontname, &missing, &nmissing, &def);
+    
+    free(pattern2);
+    
+#endif
+    
+    if(missing!=NULL) 
+        XFreeStringList(missing);
+
+    return fs;
+}
diff -rN -u old-ion-3/xftde/fontset.h new-ion-3/xftde/fontset.h
--- old-ion-3/xftde/fontset.h	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/fontset.h	2005-10-06 09:34:53.000000000 +0200
@@ -0,0 +1,20 @@
+/*
+ * ion/de/fontset.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef ION_DE_FONTSET_H
+#define ION_DE_FONTSET_H
+
+#include <ioncore/common.h>
+#include <ioncore/gr.h>
+
+extern XFontSet de_create_font_set(const char *fontname);
+
+#endif /* ION_DE_FONTSET_H */
diff -rN -u old-ion-3/xftde/init.c new-ion-3/xftde/init.c
--- old-ion-3/xftde/init.c	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/init.c	2005-10-06 18:17:20.000000000 +0200
@@ -0,0 +1,369 @@
+/*
+ * ion/de/init.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <string.h>
+
+#include <libextl/readconfig.h>
+#include <libextl/extl.h>
+
+#include <ioncore/common.h>
+#include <ioncore/global.h>
+#include <ioncore/rootwin.h>
+#include <ioncore/extlconv.h>
+#include <ioncore/ioncore.h>
+
+#include "brush.h"
+#include "font.h"
+#include "colour.h"
+#include "private.h"
+#include "init.h"
+#include "exports.h"
+
+
+/*{{{ Borders */
+
+
+#define CF_BORDER_VAL_SANITY_CHECK 16
+
+void de_get_border_val(uint *val, ExtlTab tab, const char *what)
+{
+    int g;
+    
+    if(extl_table_gets_i(tab, what, &g)){
+        if(g>CF_BORDER_VAL_SANITY_CHECK || g<0)
+            warn(TR("Border attribute %s sanity check failed."), what);
+        else
+            *val=g;
+    }
+}
+
+
+void de_get_border_style(uint *ret, ExtlTab tab)
+{
+    char *style=NULL;
+    
+    if(!extl_table_gets_s(tab, "border_style", &style))
+        return;
+    
+    if(strcmp(style, "inlaid")==0)
+        *ret=DEBORDER_INLAID;
+    else if(strcmp(style, "elevated")==0)
+        *ret=DEBORDER_ELEVATED;
+    else if(strcmp(style, "groove")==0)
+        *ret=DEBORDER_GROOVE;
+    else if(strcmp(style, "ridge")==0)
+        *ret=DEBORDER_RIDGE;
+    else
+        warn(TR("Unknown border style \"%s\"."), style);
+    
+    free(style);
+}
+
+
+void de_get_border(DEBorder *border, ExtlTab tab)
+{
+    de_get_border_val(&(border->sh), tab, "shadow_pixels");
+    de_get_border_val(&(border->hl), tab, "highlight_pixels");
+    de_get_border_val(&(border->pad), tab, "padding_pixels");
+    de_get_border_style(&(border->style), tab);
+}
+
+
+/*}}}*/
+
+
+/*{{{ Colours */
+
+
+bool de_get_colour(WRootWin *rootwin, DEColour *ret, 
+                   ExtlTab tab, DEStyle *based_on,
+                   const char *what, DEColour substitute)
+{
+    char *name=NULL;
+    bool ok=FALSE;
+    
+    if(extl_table_gets_s(tab, what, &name)){
+        ok=de_alloc_colour(rootwin, ret, name);
+    
+        if(!ok)
+            warn(TR("Unable to allocate colour \"%s\"."), name);
+
+        free(name);
+    }
+    
+    if(!ok && based_on!=NULL){
+        return de_get_colour(rootwin, ret, based_on->data_table,
+                             based_on->based_on, what, substitute);
+    }else if(!ok){
+        return de_duplicate_colour(rootwin, substitute, ret);
+    }
+    
+    return ok;
+}
+
+
+void de_get_colour_group(WRootWin *rootwin, DEColourGroup *cg, 
+                         ExtlTab tab, DEStyle *based_on)
+{
+	DEColour black, white;
+	de_alloc_colour(rootwin, &black, "black");
+	de_alloc_colour(rootwin, &white, "white");
+
+	de_get_colour(rootwin, &(cg->hl), tab, based_on, "highlight_colour",white);
+	de_get_colour(rootwin, &(cg->sh), tab, based_on, "shadow_colour", white);
+	de_get_colour(rootwin, &(cg->bg), tab, based_on, "background_colour", black);
+	de_get_colour(rootwin, &(cg->fg), tab, based_on, "foreground_colour", white);
+	de_get_colour(rootwin, &(cg->pad), tab, based_on, "padding_colour", cg->bg);
+}
+
+
+void de_get_extra_cgrps(WRootWin *rootwin, DEStyle *style, ExtlTab tab)
+{
+    
+    uint i=0, nfailed=0, n=extl_table_get_n(tab);
+    char *name;
+    ExtlTab sub;
+    
+    if(n==0)
+        return;
+    
+    style->extra_cgrps=ALLOC_N(DEColourGroup, n);
+    
+    if(style->extra_cgrps==NULL)
+        return;
+
+    for(i=0; i<n-nfailed; i++){
+        if(!extl_table_geti_t(tab, i+1, &sub))
+            goto err;
+        if(!extl_table_gets_s(sub, "substyle_pattern", &name)){
+            extl_unref_table(sub);
+            goto err;
+        }
+        
+        /*de_init_colour_group(rootwin, style->extra_cgrps+i-nfailed);*/
+        style->extra_cgrps[i-nfailed].spec=name;
+        de_get_colour_group(rootwin, style->extra_cgrps+i-nfailed, sub, 
+                            style);
+        
+        extl_unref_table(sub);
+        continue;
+        
+    err:
+        warn(TR("Corrupt substyle table %d."), i);
+        nfailed++;
+    }
+    
+    if(n-nfailed==0){
+        free(style->extra_cgrps);
+        style->extra_cgrps=NULL;
+    }
+    
+    style->n_extra_cgrps=n-nfailed;
+}
+
+
+/*}}}*/
+
+
+/*{{{ Misc. */
+
+
+void de_get_text_align(int *alignret, ExtlTab tab)
+{
+    char *align=NULL;
+    
+    if(!extl_table_gets_s(tab, "text_align", &align))
+        return;
+    
+    if(strcmp(align, "left")==0)
+        *alignret=DEALIGN_LEFT;
+    else if(strcmp(align, "right")==0)
+        *alignret=DEALIGN_RIGHT;
+    else if(strcmp(align, "center")==0)
+        *alignret=DEALIGN_CENTER;
+    else
+        warn(TR("Unknown text alignment \"%s\"."), align);
+    
+    free(align);
+}
+
+
+void de_get_transparent_background(uint *mode, ExtlTab tab)
+{
+    bool b;
+    
+    if(extl_table_gets_b(tab, "transparent_background", &b))
+        *mode=b;
+}
+
+
+/*}}}*/
+
+
+/*{{{ de_defstyle */
+
+
+void de_get_nonfont(WRootWin *rootwin, DEStyle *style, ExtlTab tab)
+{
+    DEStyle *based_on=style->based_on;
+    
+    style->data_table=extl_ref_table(tab);
+
+    if(based_on!=NULL){
+        style->border=based_on->border;
+        style->transparency_mode=based_on->transparency_mode;
+        style->textalign=based_on->textalign;
+        style->spacing=based_on->spacing;
+    }
+    
+    de_get_border(&(style->border), tab);
+    de_get_border_val(&(style->spacing), tab, "spacing");
+
+    de_get_text_align(&(style->textalign), tab);
+
+    de_get_transparent_background(&(style->transparency_mode), tab);
+
+    style->cgrp_alloced=TRUE;
+    de_get_colour_group(rootwin, &(style->cgrp), tab, based_on);
+    de_get_extra_cgrps(rootwin, style, tab);
+}
+
+
+/*EXTL_DOC
+ * Define a style for the root window \var{rootwin}. 
+ */
+EXTL_EXPORT
+bool xftde_defstyle_rootwin(WRootWin *rootwin, const char *name, ExtlTab tab)
+{
+    DEStyle *style;
+    char *fnt;
+    uint n;
+    DEStyle *based_on=NULL;
+    char *based_on_name=NULL;
+
+    if(name==NULL)
+        return FALSE;
+    
+    style=de_create_style(rootwin, name);
+
+    if(style==NULL)
+        return FALSE;
+
+    if(extl_table_gets_s(tab, "based_on", &based_on_name)){
+        based_on=de_get_style(rootwin, based_on_name);
+        if(based_on==style){
+            warn(TR("'based_on' for %s points back to the style itself."),
+                 name);
+        }else if(based_on==NULL){
+            warn(TR("Unknown base style \"%s\"."), based_on);
+        }else{
+            style->based_on=based_on;
+            based_on->usecount++;
+            /* Copy simple parameters */
+        }
+        free(based_on_name);
+    }
+
+    de_get_nonfont(rootwin, style, tab);
+
+    if(extl_table_gets_s(tab, "font", &fnt)){
+        de_load_font_for_style(style, fnt);
+        free(fnt);
+    }else if(based_on!=NULL && based_on->font!=NULL){
+        de_set_font_for_style(style, based_on->font);
+    }
+    
+    if(style->font==NULL)
+        de_load_font_for_style(style, CF_FALLBACK_FONT_NAME);
+    
+    return TRUE;
+}
+
+
+/*EXTL_DOC
+ * Define a style.
+ */
+EXTL_EXPORT
+bool xftde_defstyle(const char *name, ExtlTab tab)
+{
+    bool ok=TRUE;
+    WRootWin *rw;
+    
+    FOR_ALL_ROOTWINS(rw){
+        if(!xftde_defstyle_rootwin(rw, name, tab))
+            ok=FALSE;
+    }
+    
+    return ok;
+}
+
+
+/*EXTL_DOC
+ * Define a substyle.
+ */
+EXTL_SAFE
+EXTL_EXPORT
+ExtlTab xftde_substyle(const char *pattern, ExtlTab tab)
+{
+    extl_table_sets_s(tab, "substyle_pattern", pattern);
+    return extl_ref_table(tab);
+}
+
+
+/*}}}*/
+
+
+/*{{{ Module initialisation */
+
+
+#include "version.h"
+
+char xftde_ion_api_version[]=ION_API_VERSION;
+
+
+bool xftde_init()
+{
+    WRootWin *rootwin;
+    DEStyle *style;
+    
+    if(!xftde_register_exports())
+        return FALSE;
+    
+    if(!gr_register_engine("xftde", (GrGetBrushFn*)&de_get_brush))
+        goto fail;
+    
+    /* Create fallback brushes */
+    FOR_ALL_ROOTWINS(rootwin){
+        style=de_create_style(rootwin, "*");
+        if(style!=NULL){
+            style->is_fallback=TRUE;
+            de_load_font_for_style(style, CF_FALLBACK_FONT_NAME);
+        }
+    }
+    
+    return TRUE;
+    
+fail:
+    xftde_unregister_exports();
+    return FALSE;
+}
+
+
+void de_deinit()
+{
+    gr_unregister_engine("xftde");
+    xftde_unregister_exports();
+    de_deinit_styles();
+}
+
+
+/*}}}*/
+
diff -rN -u old-ion-3/xftde/init.h new-ion-3/xftde/init.h
--- old-ion-3/xftde/init.h	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/init.h	2005-10-06 09:34:53.000000000 +0200
@@ -0,0 +1,41 @@
+/*
+ * ion/de/init.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef ION_DE_INIT_H
+#define ION_DE_INIT_H
+
+#include <ioncore/common.h>
+#include <ioncore/gr.h>
+#include "brush.h"
+
+extern void de_get_border_val(uint *val, ExtlTab tab, const char *what);
+extern void de_get_border_style(uint *ret, ExtlTab tab);
+extern void de_get_border(DEBorder *border, ExtlTab tab);
+
+extern bool de_get_colour(WRootWin *rootwin, DEColour *ret, 
+                          ExtlTab tab, DEStyle *based_on,
+                          const char *what, DEColour substitute);
+extern void de_get_colour_group(WRootWin *rootwin, DEColourGroup *cg, 
+                                ExtlTab tab, DEStyle *based_on);
+extern void de_get_extra_cgrps(WRootWin *rootwin, DEStyle *style, 
+                               ExtlTab tab);
+
+extern void de_get_text_align(int *alignret, ExtlTab tab);
+
+extern void de_get_transparent_background(uint *mode, ExtlTab tab);
+
+extern void de_get_nonfont(WRootWin *rw, DEStyle *style, ExtlTab tab);
+
+extern bool de_defstyle_rootwin(WRootWin *rootwin, const char *name, 
+                                ExtlTab tab);
+extern bool de_defstyle(const char *name, ExtlTab tab);
+
+#endif /* ION_DE_INIT_H */
diff -rN -u old-ion-3/xftde/Makefile new-ion-3/xftde/Makefile
--- old-ion-3/xftde/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/Makefile	2005-10-06 18:17:58.000000000 +0200
@@ -0,0 +1,28 @@
+##
+## Default drawing engine module Makefile
+##
+
+# System-specific configuration is in system.mk
+TOPDIR=..
+include $(TOPDIR)/system-inc.mk
+
+######################################
+
+INCLUDES += $(X11_INCLUDES) $(LIBTU_INCLUDES) $(LIBEXTL_INCLUDES) -I.. `xft-config --cflags`
+CFLAGS += $(XOPEN_SOURCE) $(C99_SOURCE)
+
+SOURCES=init.c draw.c font.c colour.c brush.c style.c
+
+MODULE=xftde
+
+MAKE_EXPORTS=xftde
+
+LIBS += `xft-config --libs`
+
+######################################
+
+include $(TOPDIR)/rules.mk
+
+######################################
+
+_install: module_install
diff -rN -u old-ion-3/xftde/private.h new-ion-3/xftde/private.h
--- old-ion-3/xftde/private.h	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/private.h	2005-10-06 09:34:53.000000000 +0200
@@ -0,0 +1,21 @@
+/*
+ * ion/de/private.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef ION_DE_PRIVATE_H
+#define ION_DE_PRIVATE_H
+
+#define DE_SUB_IND " ->"
+#define DE_SUB_IND_LEN 3
+
+#define MATCHES(S, A) (gr_stylespec_score(S, A)>0)
+#define MATCHES2(S, A1, A2) (gr_stylespec_score2(S, A1, A2)>0)
+
+#endif /* ION_DE_PRIVATE_H */
diff -rN -u old-ion-3/xftde/style.c new-ion-3/xftde/style.c
--- old-ion-3/xftde/style.c	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/style.c	2005-10-06 18:18:54.000000000 +0200
@@ -0,0 +1,329 @@
+/*
+ * ion/de/style.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <string.h>
+
+#include <libextl/extl.h>
+
+#include <ioncore/common.h>
+#include <ioncore/rootwin.h>
+#include <ioncore/extlconv.h>
+#include <ioncore/ioncore.h>
+
+#include "brush.h"
+#include "font.h"
+#include "colour.h"
+#include "private.h"
+#include "style.h"
+
+
+/*{{{ GC creation */
+
+
+static void create_normal_gc(DEStyle *style, WRootWin *rootwin)
+{
+    XGCValues gcv;
+    ulong gcvmask;
+    GC gc;
+
+    /* Create normal gc */
+    gcv.line_style=LineSolid;
+    gcv.line_width=1;
+    gcv.join_style=JoinBevel;
+    gcv.cap_style=CapButt;
+    gcv.fill_style=FillSolid;
+    gcvmask=(GCLineStyle|GCLineWidth|GCFillStyle|
+             GCJoinStyle|GCCapStyle);
+    
+    style->normal_gc=XCreateGC(ioncore_g.dpy, WROOTWIN_ROOT(rootwin), 
+                               gcvmask, &gcv);
+}
+
+
+void destyle_create_tab_gcs(DEStyle *style)
+{
+    Display *dpy=ioncore_g.dpy;
+    WRootWin *rootwin=style->rootwin;
+    Window root=WROOTWIN_ROOT(rootwin);
+    Pixmap stipple_pixmap;
+    XGCValues gcv;
+    ulong gcvmask;
+    GC tmp_gc;
+
+    /* Create a temporary 1-bit GC for drawing the tag and stipple pixmaps */
+    stipple_pixmap=XCreatePixmap(dpy, root, 2, 2, 1);
+    gcv.foreground=1;
+    tmp_gc=XCreateGC(dpy, stipple_pixmap, GCForeground, &gcv);
+
+    /* Create stipple pattern and stipple GC */
+    XDrawPoint(dpy, stipple_pixmap, tmp_gc, 0, 0);
+    XDrawPoint(dpy, stipple_pixmap, tmp_gc, 1, 1);
+    XSetForeground(dpy, tmp_gc, 0);
+    XDrawPoint(dpy, stipple_pixmap, tmp_gc, 1, 0);
+    XDrawPoint(dpy, stipple_pixmap, tmp_gc, 0, 1);
+    
+    gcv.fill_style=FillStippled;
+    /*gcv.function=GXclear;*/
+    gcv.stipple=stipple_pixmap;
+    gcvmask=GCFillStyle|GCStipple/*|GCFunction*/;
+//    if(style->font!=NULL){
+//        gcv.font=style->font;
+//        gcvmask|=GCFont;
+//    }
+
+    style->stipple_gc=XCreateGC(dpy, root, gcvmask, &gcv);
+    XCopyGC(dpy, style->normal_gc, 
+            GCLineStyle|GCLineWidth|GCJoinStyle|GCCapStyle,
+            style->stipple_gc);
+            
+    XFreePixmap(dpy, stipple_pixmap);
+    
+    /* Create tag pixmap and copying GC */
+    style->tag_pixmap_w=5;
+    style->tag_pixmap_h=5;
+    style->tag_pixmap=XCreatePixmap(dpy, root, 5, 5, 1);
+    
+    XSetForeground(dpy, tmp_gc, 0);
+    XFillRectangle(dpy, style->tag_pixmap, tmp_gc, 0, 0, 5, 5);
+    XSetForeground(dpy, tmp_gc, 1);
+    XFillRectangle(dpy, style->tag_pixmap, tmp_gc, 0, 0, 5, 2);
+    XFillRectangle(dpy, style->tag_pixmap, tmp_gc, 3, 2, 2, 3);
+    
+    gcv.foreground=DE_BLACK(rootwin);
+    gcv.background=DE_WHITE(rootwin);
+    gcv.line_width=2;
+    gcvmask=GCLineWidth|GCForeground|GCBackground;
+    
+    style->copy_gc=XCreateGC(dpy, root, gcvmask, &gcv);
+    
+    XFreeGC(dpy, tmp_gc);
+    
+    style->tabbrush_data_ok=TRUE;
+}
+
+
+/*}}}*/
+
+
+/*{{{ Style lookup */
+
+
+static DEStyle *styles=NULL;
+
+
+DEStyle *de_get_style(WRootWin *rootwin, const char *stylename)
+{
+    DEStyle *style, *maxstyle=NULL;
+    int score, maxscore=0;
+    
+    for(style=styles; style!=NULL; style=style->next){
+        if(style->rootwin!=rootwin)
+            continue;
+        score=gr_stylespec_score(style->style, stylename);
+        if(score>maxscore){
+            maxstyle=style;
+            maxscore=score;
+        }
+    }
+    
+    return maxstyle;
+}
+
+
+/*}}}*/
+
+
+/*{{{ Style initialisation and deinitialisation */
+
+
+void destyle_unref(DEStyle *style)
+{
+    style->usecount--;
+    if(style->usecount==0){
+        destyle_deinit(style);
+        free(style);
+    }
+}
+
+
+void destyle_deinit(DEStyle *style)
+{
+    int i;
+    
+    UNLINK_ITEM(styles, style, next, prev);
+    
+    if(style->style!=NULL)
+        free(style->style);
+    
+    if(style->font!=NULL){
+        de_free_font(style->font);
+        style->font=NULL;
+    }
+    
+    if(style->cgrp_alloced)
+        de_free_colour_group(style->rootwin, &(style->cgrp));
+    
+    for(i=0; i<style->n_extra_cgrps; i++)
+        de_free_colour_group(style->rootwin, style->extra_cgrps+i);
+    
+    if(style->extra_cgrps!=NULL)
+        free(style->extra_cgrps);
+    
+    extl_unref_table(style->data_table);
+    
+    XFreeGC(ioncore_g.dpy, style->normal_gc);
+    
+    if(style->tabbrush_data_ok){
+        XFreeGC(ioncore_g.dpy, style->copy_gc);
+        XFreeGC(ioncore_g.dpy, style->stipple_gc);
+        XFreePixmap(ioncore_g.dpy, style->tag_pixmap);
+    }
+    
+    XSync(ioncore_g.dpy, False);
+    
+    if(style->based_on!=NULL){
+        destyle_unref(style->based_on);
+        style->based_on=NULL;
+    }
+}
+
+
+static void dump_style(DEStyle *style)
+{
+    /* Allow the style still be used but get if off the list. */
+    UNLINK_ITEM(styles, style, next, prev);
+    destyle_unref(style);
+}
+
+
+bool destyle_init(DEStyle *style, WRootWin *rootwin, const char *name)
+{
+	DEColour black, white;
+	
+    style->style=scopy(name);
+    if(style->style==NULL)
+        return FALSE;
+    
+    style->based_on=NULL;
+    
+    style->usecount=1;
+    /* Fallback brushes are not released on de_reset() */
+    style->is_fallback=FALSE;
+    
+    style->rootwin=rootwin;
+    
+    style->border.sh=1;
+    style->border.hl=1;
+    style->border.pad=1;
+    style->border.style=DEBORDER_INLAID;
+
+    style->spacing=0;
+    
+    style->textalign=DEALIGN_CENTER;
+
+    style->cgrp_alloced=FALSE;
+    style->cgrp.spec=NULL;
+	de_alloc_colour(rootwin, &black, "black");
+	de_alloc_colour(rootwin, &white, "white");
+	style->cgrp.bg=black;
+	style->cgrp.pad=black;
+	style->cgrp.fg=white;
+	style->cgrp.hl=white;
+	style->cgrp.sh=white;
+    
+    style->font=NULL;
+    
+    style->transparency_mode=GR_TRANSPARENCY_NO;
+    
+    style->n_extra_cgrps=0;
+    style->extra_cgrps=NULL;
+    
+    style->data_table=extl_table_none();
+    
+    create_normal_gc(style, rootwin);
+    
+    style->tabbrush_data_ok=FALSE;
+    
+    return TRUE;
+}
+
+
+static DEStyle *do_create_style(WRootWin *rootwin, const char *name)
+{
+    DEStyle *style=ALLOC(DEStyle);
+    if(style!=NULL){
+        if(!destyle_init(style, rootwin, name)){
+            free(style);
+            return NULL;
+        }
+    }
+    return style;
+}
+
+
+DEStyle *de_create_style(WRootWin *rootwin, const char *name)
+{
+    DEStyle *oldstyle, *style;
+
+    style=do_create_style(rootwin, name);
+    
+    if(style==NULL)
+        return NULL;
+    
+    for(oldstyle=styles; oldstyle!=NULL; oldstyle=oldstyle->next){
+        if(oldstyle->rootwin==rootwin && oldstyle->style!=NULL && 
+           strcmp(oldstyle->style, name)==0){
+            break;
+        }
+    }
+    
+    if(oldstyle!=NULL && !oldstyle->is_fallback)
+        dump_style(oldstyle);
+    
+    LINK_ITEM_FIRST(styles, style, next, prev);
+    
+    return style;
+}
+
+
+
+/*EXTL_DOC
+ * Clear all styles from drawing engine memory.
+ */
+EXTL_EXPORT
+void xftde_reset()
+{
+    DEStyle *style, *next;
+    for(style=styles; style!=NULL; style=next){
+        next=style->next;
+        if(!style->is_fallback)
+            dump_style(style);
+    }
+}
+
+
+void de_deinit_styles()
+{
+    DEStyle *style, *next;
+    for(style=styles; style!=NULL; style=next){
+        next=style->next;
+        if(style->usecount>1){
+            warn(TR("Style %s still in use [%d] but the module "
+                    "is being unloaded!"), style->style, style->usecount);
+        }
+        dump_style(style);
+    }
+}
+
+
+/*}}}*/
+
+
diff -rN -u old-ion-3/xftde/style.h new-ion-3/xftde/style.h
--- old-ion-3/xftde/style.h	1970-01-01 01:00:00.000000000 +0100
+++ new-ion-3/xftde/style.h	2005-10-06 09:34:53.000000000 +0200
@@ -0,0 +1,97 @@
+/*
+ * ion/de/style.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2005. 
+ *
+ * Ion is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef ION_DE_STYLE_H
+#define ION_DE_STYLE_H
+
+#include <libextl/extl.h>
+
+#include <ioncore/common.h>
+#include <ioncore/gr.h>
+#include <ioncore/rectangle.h>
+
+INTRSTRUCT(DEBorder);
+INTRSTRUCT(DEStyle);
+
+#include "font.h"
+#include "colour.h"
+
+enum{
+    DEBORDER_INLAID=0,    /* -\xxxxxx/- */
+    DEBORDER_RIDGE,       /* /-\xxxx/-\ */
+    DEBORDER_ELEVATED,    /* /-xxxxxx-\ */
+    DEBORDER_GROOVE       /* \_/xxxx\_/ */
+};
+
+
+enum{
+    DEALIGN_LEFT=0,
+    DEALIGN_RIGHT=1,
+    DEALIGN_CENTER=2
+};
+
+
+DECLSTRUCT(DEBorder){
+    uint sh, hl, pad;
+    uint style;
+};
+
+
+DECLSTRUCT(DEStyle){
+    char *style;
+    int usecount;
+    bool is_fallback;
+    
+    WRootWin *rootwin;
+    
+    DEStyle *based_on;
+    
+    GC normal_gc;    
+    
+    DEBorder border;
+    bool cgrp_alloced;
+    DEColourGroup cgrp;
+    int n_extra_cgrps;
+    DEColourGroup *extra_cgrps;
+    GrTransparency transparency_mode;
+    DEFont *font;
+    int textalign;
+    uint spacing;
+    
+    ExtlTab data_table;
+
+    /* Only initialised if used as a DETabBrush */
+    bool tabbrush_data_ok;
+    GC stipple_gc;
+    GC copy_gc;
+    
+    Pixmap tag_pixmap;
+    int tag_pixmap_w;
+    int tag_pixmap_h;
+    
+    DEStyle *next, *prev;
+};
+
+
+extern bool destyle_init(DEStyle *style, WRootWin *rootwin, const char *name);
+extern void destyle_deinit(DEStyle *style);
+extern DEStyle *de_create_style(WRootWin *rootwin, const char *name);
+extern void destyle_unref(DEStyle *style);
+
+extern void destyle_create_tab_gcs(DEStyle *style);
+
+extern void de_reset();
+extern void de_deinit_styles();
+
+extern DEStyle *de_get_style(WRootWin *rootwin, const char *name);
+
+
+#endif /* ION_DE_STYLE_H */

