--- Makefile | 9 ++- drw.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ drw.h | 61 ++++++++++++++++++ tabbed.c | 214 ++++++++++++++------------------------------------------------- util.c | 17 +++++ util.h | 6 ++ 6 files changed, 342 insertions(+), 172 deletions(-) create mode 100644 drw.c create mode 100644 drw.h create mode 100644 util.c create mode 100644 util.h diff --git a/Makefile b/Makefile index 32cc25b..998e58d 100644 --- a/Makefile +++ b/Makefile _AT_@ -3,7 +3,9 @@ include config.mk -SRC = tabbed.c +SRC = tabbed.c \ + drw.c \ + util.c OBJ = ${SRC:.c=.o} all: options tabbed _AT_@ -24,9 +26,10 @@ config.h: _AT_echo creating $@ from config.def.h _AT_cp config.def.h $@ -tabbed: tabbed.o +# TODO explicit deps suck +tabbed: tabbed.o drw.o drw.h util.c util.h util.o _AT_echo CC -o $@ - _AT_${CC} -o $@ tabbed.o ${LDFLAGS} + _AT_${CC} -o $@ tabbed.o drw.o util.o ${LDFLAGS} clean: _AT_echo cleaning diff --git a/drw.c b/drw.c new file mode 100644 index 0000000..749795d --- /dev/null +++ b/drw.c _AT_@ -0,0 +1,207 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <X11/Xlib.h> + +#include "drw.h" +#include "util.h" + +Drw * +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) { + Drw *drw = (Drw *)calloc(1, sizeof(Drw)); + if(!drw) + return NULL; + drw->dpy = dpy; + drw->screen = screen; + drw->root = root; + drw->w = w; + drw->h = h; + drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); + drw->gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); + return drw; +} + +void +drw_resize(Drw *drw, unsigned int w, unsigned int h) { + if(!drw) + return; + drw->w = w; + drw->h = h; + if(drw->drawable != 0) + XFreePixmap(drw->dpy, drw->drawable); + drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); +} + +void +drw_free(Drw *drw) { + XFreePixmap(drw->dpy, drw->drawable); + XFreeGC(drw->dpy, drw->gc); + free(drw); +} + +Fnt * +drw_font_create(Display *dpy, const char *fontname) { + Fnt *font; + char *def, **missing; + int n; + + font = (Fnt *)calloc(1, sizeof(Fnt)); + if(!font) + return NULL; + font->set = XCreateFontSet(dpy, fontname, &missing, &n, &def); + if(missing) { + while(n--) + fprintf(stderr, "drw: missing fontset: %s\n", missing[n]); + XFreeStringList(missing); + } + if(font->set) { + XFontStruct **xfonts; + char **font_names; + XExtentsOfFontSet(font->set); + n = XFontsOfFontSet(font->set, &xfonts, &font_names); + while(n--) { + font->ascent = MAX(font->ascent, (*xfonts)->ascent); + font->descent = MAX(font->descent,(*xfonts)->descent); + xfonts++; + } + } + else { + if(!(font->xfont = XLoadQueryFont(dpy, fontname)) + && !(font->xfont = XLoadQueryFont(dpy, "fixed"))) + die("error, cannot load font: '%s'\n", fontname); + font->ascent = font->xfont->ascent; + font->descent = font->xfont->descent; + } + font->h = font->ascent + font->descent; + return font; +} + +void +drw_font_free(Display *dpy, Fnt *font) { + if(!font) + return; + if(font->set) + XFreeFontSet(dpy, font->set); + else + XFreeFont(dpy, font->xfont); + free(font); +} + +Clr * +drw_clr_create(Drw *drw, const char *clrname) { + Clr *clr; + Colormap cmap; + XColor color; + + if(!drw) + return NULL; + clr = (Clr *)calloc(1, sizeof(Clr)); + if(!clr) + return NULL; + cmap = DefaultColormap(drw->dpy, drw->screen); + if(!XAllocNamedColor(drw->dpy, cmap, clrname, &color, &color)) + die("error, cannot allocate color '%s'\n", clrname); + clr->rgb = color.pixel; + return clr; +} + +void +drw_clr_free(Clr *clr) { + free(clr); +} + +void +drw_setfont(Drw *drw, Fnt *font) { + if(drw) + drw->font = font; +} + +void +drw_setscheme(Drw *drw, ClrScheme *scheme) { + if(drw && scheme) + drw->scheme = scheme; +} + +void +drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) { + int dx; + + if(!drw || !drw->font || !drw->scheme) + return; + XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->rgb : drw->scheme->fg->rgb); + dx = (drw->font->ascent + drw->font->descent + 2) / 4; + if(filled) + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x+1, y+1, dx+1, dx+1); + else if(empty) + XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x+1, y+1, dx, dx); +} + +void +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert) { + char buf[256]; + int i, tx, ty, th, len, olen; + Extnts tex; + + if(!drw || !drw->scheme) + return; + XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->fg->rgb : drw->scheme->bg->rgb); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + if(!text || !drw->font) + return; + olen = strlen(text); + drw_font_getexts(drw->font, text, olen, &tex); + th = drw->font->ascent + drw->font->descent; + ty = y + (h / 2) - (th / 2) + drw->font->ascent; + tx = x + (h / 2); + /* shorten text if necessary */ + for(len = MIN(olen, sizeof buf); len && (tex.w > w - tex.h || w < tex.h); len--) + drw_font_getexts(drw->font, text, len, &tex); + if(!len) + return; + memcpy(buf, text, len); + if(len < olen) + for(i = len; i && i > len - 3; buf[--i] = '.'); + XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->rgb : drw->scheme->fg->rgb); + if(drw->font->set) + XmbDrawString(drw->dpy, drw->drawable, drw->font->set, drw->gc, tx, ty, buf, len); + else + XDrawString(drw->dpy, drw->drawable, drw->gc, tx, ty, buf, len); +} + +void +drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) { + if(!drw) + return; + XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); + XSync(drw->dpy, False); +} + + +void +drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *tex) { + XRectangle r; + + if(!font || !text) + return; + if(font->set) { + XmbTextExtents(font->set, text, len, NULL, &r); + tex->w = r.width; + tex->h = r.height; + } + else { + tex->h = font->ascent + font->descent; + tex->w = XTextWidth(font->xfont, text, len); + } +} + +unsigned int +drw_font_getexts_width(Fnt *font, const char *text, unsigned int len) { + Extnts tex; + + if(!font) + return -1; + drw_font_getexts(font, text, len, &tex); + return tex.w; +} diff --git a/drw.h b/drw.h new file mode 100644 index 0000000..e77a49c --- /dev/null +++ b/drw.h _AT_@ -0,0 +1,61 @@ +/* See LICENSE file for copyright and license details. */ + +typedef struct { + unsigned long rgb; +} Clr; + +typedef struct { + int ascent; + int descent; + unsigned int h; + XFontSet set; + XFontStruct *xfont; +} Fnt; + +typedef struct { + Clr *fg; + Clr *bg; + Clr *border; +} ClrScheme; + +typedef struct { + unsigned int w, h; + Display *dpy; + int screen; + Window root; + Drawable drawable; + GC gc; + ClrScheme *scheme; + Fnt *font; +} Drw; + +typedef struct { + unsigned int w; + unsigned int h; +} Extnts; + +/* Drawable abstraction */ +Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); +void drw_resize(Drw *drw, unsigned int w, unsigned int h); +void drw_free(Drw *drw); + +/* Fnt abstraction */ +Fnt *drw_font_create(Display *dpy, const char *fontname); +void drw_font_free(Display *dpy, Fnt *font); +void drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *extnts); +unsigned int drw_font_getexts_width(Fnt *font, const char *text, unsigned int len); + +/* Colour abstraction */ +Clr *drw_clr_create(Drw *drw, const char *clrname); +void drw_clr_free(Clr *clr); + +/* Drawing context manipulation */ +void drw_setfont(Drw *drw, Fnt *font); +void drw_setscheme(Drw *drw, ClrScheme *scheme); + +/* Drawing functions */ +void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert); +void drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert); + +/* Map functions */ +void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); diff --git a/tabbed.c b/tabbed.c index 93a213a..3ef5968 100644 --- a/tabbed.c +++ b/tabbed.c _AT_@ -17,6 +17,7 @@ #include <X11/XKBlib.h> #include "arg.h" +#include "drw.h" /* XEMBED messages */ #define XEMBED_EMBEDDED_NOTIFY 0 _AT_@ -44,9 +45,9 @@ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define LENGTH(x) (sizeof((x)) / sizeof(*(x))) #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask)) -#define TEXTW(x) (textnw(x, strlen(x)) + dc.font.height) +#define TEXTW(X) (drw_font_getexts_width(drw->font, X, strlen(X)) + drw->font->h) -enum { ColFG, ColBG, ColLast }; /* color */ +enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ enum { WMProtocols, WMDelete, WMName, WMState, WMFullscreen, XEmbed, WMSelectTab, WMLast }; /* default atoms */ _AT_@ -62,21 +63,6 @@ typedef struct { const Arg arg; } Key; -typedef struct { - int x, y, w, h; - unsigned long norm[ColLast]; - unsigned long sel[ColLast]; - Drawable drawable; - GC gc; - struct { - int ascent; - int descent; - int height; - XFontSet set; - XFontStruct *xfont; - } font; -} DC; /* draw context */ - typedef struct Client { char name[256]; Window win; _AT_@ -95,7 +81,6 @@ static void createnotify(const XEvent *e); static void destroynotify(const XEvent *e); static void die(const char *errstr, ...); static void drawbar(void); -static void drawtext(const char *text, unsigned long col[ColLast]); static void *emallocz(size_t size); static void *erealloc(void *o, size_t size); static void expose(const XEvent *e); _AT_@ -105,10 +90,8 @@ static void focusonce(const Arg *arg); static void fullscreen(const Arg *arg); static char* getatom(int a); static int getclient(Window w); -static unsigned long getcolor(const char *colstr); static int getfirsttab(void); static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); -static void initfont(const char *fontstr); static Bool isprotodel(int c); static void keypress(const XEvent *e); static void killclient(const Arg *arg); _AT_@ -125,7 +108,6 @@ static void setup(void); static void setcmd(int argc, char *argv[], int); static void sigchld(int unused); static void spawn(const Arg *arg); -static int textnw(const char *text, unsigned int len); static void unmanage(int c); static void updatenumlockmask(void); static void updatetitle(int c); _AT_@ -152,7 +134,9 @@ static unsigned int numlockmask = 0; static Bool running = True, nextfocus, doinitspawn = True, fillagain = False, closelastclient = False; static Display *dpy; -static DC dc; +static Drw* drw; +static Fnt* fnt; +static ClrScheme scheme[SchemeLast]; static Atom wmatom[WMLast]; static Window root, win; static Client **clients = NULL; _AT_@ -219,14 +203,13 @@ cleanup(void) { free(clients); clients = NULL; - if(dc.font.set) { - XFreeFontSet(dpy, dc.font.set); - } else { - XFreeFont(dpy, dc.font.xfont); - } + drw_font_free(dpy, fnt); + drw_clr_free(scheme[SchemeNorm].bg); + drw_clr_free(scheme[SchemeNorm].fg); + drw_clr_free(scheme[SchemeSel].bg); + drw_clr_free(scheme[SchemeSel].fg); + drw_free(drw); - XFreePixmap(dpy, dc.drawable); - XFreeGC(dpy, dc.gc); XDestroyWindow(dpy, win); XSync(dpy, False); free(cmd); _AT_@ -249,9 +232,7 @@ configurenotify(const XEvent *e) { if(ev->window == win && (ev->width != ww || ev->height != wh)) { ww = ev->width; wh = ev->height; - XFreePixmap(dpy, dc.drawable); - dc.drawable = XCreatePixmap(dpy, root, ww, wh, - DefaultDepth(dpy, screen)); + drw_resize(drw, ww, bh); if(sel > -1) resize(sel, ww, wh - bh); XSync(dpy, False); _AT_@ -305,16 +286,13 @@ die(const char *errstr, ...) { void drawbar(void) { - unsigned long *col; - int c, fc, width, n = 0; + int c, fc, width, n = 0, xoff = 0, draww = 0; char *name = NULL; if(nclients == 0) { - dc.x = 0; - dc.w = ww; XFetchName(dpy, win, &name); - drawtext(name ? name : "", dc.norm); - XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, ww, bh, 0, 0); + drw_text(drw, 0, /* y */ 0, ww, bh, name ? name : "", False); + XCopyArea(dpy, drw->drawable, win, drw->gc, 0, 0, ww, bh, 0, 0); XSync(dpy, False); return; _AT_@ -327,76 +305,40 @@ drawbar(void) { n = nclients - fc; if((n * tabwidth) > width) { - dc.w = TEXTW(after); - dc.x = width - dc.w; - drawtext(after, dc.sel); - width -= dc.w; + draww = TEXTW(after); + drw_setscheme(drw, &scheme[SchemeSel]); + drw_text(drw, width - draww, /* y */ 0, draww, bh, after, False); + width -= draww; } - dc.x = 0; if(fc > 0) { - dc.w = TEXTW(before); - drawtext(before, dc.sel); - dc.x += dc.w; - width -= dc.w; + draww = TEXTW(before); + drw_setscheme(drw, &scheme[SchemeSel]); + drw_text(drw, 0, /* y */ 0, draww, bh, before, False); + xoff = draww; + width -= draww; } - for(c = (fc > 0)? fc : 0; c < nclients && dc.x < width; c++) { - dc.w = tabwidth; + for(c = (fc > 0)? fc : 0; c < nclients && xoff < width; c++) { + draww = tabwidth; if(c == sel) { - col = dc.sel; + drw_setscheme(drw, &scheme[SchemeSel]); if((n * tabwidth) > width) { - dc.w += width % tabwidth; + draww += width % tabwidth; } else { - dc.w = width - (n - 1) * tabwidth; + draww = width - (n - 1) * tabwidth; } } else { - col = dc.norm; + drw_setscheme(drw, &scheme[SchemeNorm]); } - drawtext(clients[c]->name, col); - dc.x += dc.w; - clients[c]->tabx = dc.x; + drw_text(drw, xoff, /* y */ 0, draww, bh, clients[c]->name, False); + xoff += draww; + clients[c]->tabx = xoff; } - XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, ww, bh, 0, 0); + XCopyArea(dpy, drw->drawable, win, drw->gc, 0, 0, ww, bh, 0, 0); XSync(dpy, False); } -void -drawtext(const char *text, unsigned long col[ColLast]) { - int i, x, y, h, len, olen; - char buf[256]; - XRectangle r = { dc.x, dc.y, dc.w, dc.h }; - - XSetForeground(dpy, dc.gc, col[ColBG]); - XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); - if(!text) - return; - - olen = strlen(text); - h = dc.font.ascent + dc.font.descent; - y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; - x = dc.x + (h / 2); - - /* shorten text if necessary */ - for(len = MIN(olen, sizeof(buf)); - len && textnw(text, len) > dc.w - h; len--); - if(!len) - return; - - memcpy(buf, text, len); - if(len < olen) { - for(i = len; i && i > len - 3; buf[--i] = '.'); - } - - XSetForeground(dpy, dc.gc, col[ColFG]); - if(dc.font.set) { - XmbDrawString(dpy, dc.drawable, dc.font.set, - dc.gc, x, y, buf, len); - } else { - XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); - } -} - void * emallocz(size_t size) { void *p; _AT_@ -524,17 +466,6 @@ getclient(Window w) { return -1; } -unsigned long -getcolor(const char *colstr) { - Colormap cmap = DefaultColormap(dpy, screen); - XColor color; - - if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) - die("tabbed: cannot allocate color '%s'\n", colstr); - - return color.pixel; -} - int getfirsttab(void) { int c, n, fc; _AT_@ -583,46 +514,6 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size) { return True; } -void -initfont(const char *fontstr) { - char *def, **missing, **font_names; - int i, n; - XFontStruct **xfonts; - - missing = NULL; - if(dc.font.set) - XFreeFontSet(dpy, dc.font.set); - - dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); - if(missing) { - while(n--) - fprintf(stderr, "tabbed: missing fontset: %s\n", missing[n]); - XFreeStringList(missing); - } - - if(dc.font.set) { - dc.font.ascent = dc.font.descent = 0; - n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); - for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { - dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent); - dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent); - xfonts++; - } - } else { - if(dc.font.xfont) - XFreeFont(dpy, dc.font.xfont); - dc.font.xfont = NULL; - if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) - && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) { - die("tabbed: cannot load font: '%s'\n", fontstr); - } - - dc.font.ascent = dc.font.xfont->ascent; - dc.font.descent = dc.font.xfont->descent; - } - dc.font.height = dc.font.ascent + dc.font.descent; -} - Bool isprotodel(int c) { int i, n; _AT_@ -919,8 +810,8 @@ setup(void) { /* init screen */ screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); - initfont(font); - bh = dc.h = dc.font.height + 2; + fnt = drw_font_create(dpy, font); + bh = fnt->h + 2; /* init atoms */ wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); _AT_@ -965,18 +856,16 @@ setup(void) { wy = dh + wy - wh - 1; } - dc.norm[ColBG] = getcolor(normbgcolor); - dc.norm[ColFG] = getcolor(normfgcolor); - dc.sel[ColBG] = getcolor(selbgcolor); - dc.sel[ColFG] = getcolor(selfgcolor); - dc.drawable = XCreatePixmap(dpy, root, ww, wh, - DefaultDepth(dpy, screen)); - dc.gc = XCreateGC(dpy, root, 0, 0); - if(!dc.font.set) - XSetFont(dpy, dc.gc, dc.font.xfont->fid); + drw = drw_create(dpy, screen, root, ww, bh); + drw_setfont(drw, fnt); + + scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor); + scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor); + scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); + scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); win = XCreateSimpleWindow(dpy, root, wx, wy, ww, wh, 0, - dc.norm[ColFG], dc.norm[ColBG]); + scheme[SchemeNorm].fg->rgb, scheme[SchemeNorm].bg->rgb); XMapRaised(dpy, win); XSelectInput(dpy, win, SubstructureNotifyMask|FocusChangeMask| ButtonPressMask|ExposureMask|KeyPressMask|PropertyChangeMask| _AT_@ -1038,19 +927,6 @@ spawn(const Arg *arg) { } } -int -textnw(const char *text, unsigned int len) { - XRectangle r; - - if(dc.font.set) { - XmbTextExtents(dc.font.set, text, len, NULL, &r); - - return r.width; - } - - return XTextWidth(dc.font.xfont, text, len); -} - void unmanage(int c) { if(c < 0 || c >= nclients) { diff --git a/util.c b/util.c new file mode 100644 index 0000000..51acd1a --- /dev/null +++ b/util.c _AT_@ -0,0 +1,17 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#include "util.h" + +void +die(const char *errstr, ...) { + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + diff --git a/util.h b/util.h new file mode 100644 index 0000000..033700c --- /dev/null +++ b/util.h _AT_@ -0,0 +1,6 @@ +/* See LICENSE file for copyright and license details. */ + +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) + +void die(const char *errstr, ...); -- 1.8.5.3 --Bn2rw/3z4jIqBvZU--Received on Mon Sep 17 2001 - 00:00:00 CEST
This archive was generated by hypermail 2.3.0 : Wed Jan 22 2014 - 16:12:06 CET