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 + +#include +#include + +#include +#include +#include +#include + +#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 + +#include +#include +#include +#include + +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 +#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 +#include +#include +#include + + +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 + +#include +#include +#include +#include "brush.h" +#include "font.h" +#include "private.h" + +#include + + +/*{{{ 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; in_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; ix, 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; i0 && 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; iwin, + 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 +#include + +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 + +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 + +#include +#include +#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 +#include +#include + +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 + * . + * + */ + +#include +#include +#include + +#include +#include + +#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 +#include + +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 + +#include +#include + +#include +#include +#include +#include +#include + +#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; iextra_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 +#include +#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 + +#include + +#include +#include +#include +#include + +#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; in_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 + +#include +#include +#include + +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 */