1 module theme.manager; 2 3 import theme.layout; 4 import gui.font; 5 import config; 6 import cboxapp; 7 import window; 8 import types; 9 import gui.bar; 10 import kernel; 11 12 import std.algorithm; 13 import std.c..string; 14 import deimos.X11.X; 15 import deimos.X11.Xlib; 16 import deimos.X11.keysymdef; 17 import deimos.X11.Xutil; 18 import deimos.X11.Xatom; 19 20 /* color schemes */ 21 enum 22 { 23 SchemeNorm, 24 SchemeSel, 25 SchemeLast 26 }; 27 28 /// The colour scheme to use 29 struct ClrScheme 30 { 31 Clr *fg; 32 Clr *bg; 33 Clr *border; 34 } 35 36 class ThemeManager 37 { 38 39 ClrScheme[SchemeLast] scheme; 40 41 static ThemeManager instance() 42 { 43 if (!instantiated_) { 44 synchronized { 45 if (instance_ is null) { 46 instance_ = new ThemeManager; 47 } 48 instantiated_ = true; 49 } 50 } 51 return instance_; 52 } 53 54 void setlayout(const Arg *arg) 55 { 56 if(!arg || !arg.v || arg.v != selmon.lt[selmon.sellt]) 57 selmon.sellt ^= 1; 58 59 if(arg && arg.v) { 60 selmon.lt[selmon.sellt] = cast(Layout *)arg.v; 61 } 62 63 selmon.ltsymbol = selmon.lt[selmon.sellt].symbol; 64 65 if(selmon.sel) 66 arrange(selmon); 67 else 68 drawbar(selmon); 69 } 70 71 ClrScheme getScheme(int type) 72 { 73 return this.scheme[type]; 74 } 75 76 77 private: 78 this() 79 { 80 /* init appearance */ 81 scheme[SchemeNorm].border = new Clr(drw, normbordercolor); 82 scheme[SchemeNorm].bg = new Clr(drw, normbgcolor); 83 scheme[SchemeNorm].fg = new Clr(drw, normfgcolor); 84 scheme[SchemeSel].border = new Clr(drw, selbordercolor); 85 scheme[SchemeSel].bg = new Clr(drw, selbgcolor); 86 scheme[SchemeSel].fg = new Clr(drw, selfgcolor); 87 } 88 89 static bool instantiated_; // Thread local 90 __gshared ThemeManager instance_; 91 92 } 93 94 /** 95 * Drw provides an interface for working with drawable surfaces. 96 */ 97 struct Drw 98 { 99 uint w, h; /// The width and height of the drawable area 100 Display *dpy; /// The X display 101 int screen; /// The X screen ID 102 Window root; /// The root window for this drawable 103 Drawable drawable; /// The X drawable encapsulated by this. 104 XGC gc; /// The X graphic context 105 ClrScheme *scheme; /// The colour scheme to use 106 Fnt *font; /// The X font to use for rendering text. 107 108 /** 109 * Ctor to initialise the draw object 110 * Params: 111 * dpy= X display to render with. 112 * screen= X screen id 113 * root= Root X window for this drawable 114 * w= Width of the drawable 115 * h= Height of the drawable 116 * Example: 117 * --- 118 * drw = new Drw(AppDisplay.instance().dpy, screen, root, sw, sh); 119 * --- 120 */ 121 this(Display* dpy, int screen, Window root, uint w, uint h) 122 { 123 this.dpy = dpy; 124 this.screen = screen; 125 this.root = root; 126 this.w = w; 127 this.h = h; 128 this.drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); 129 this.gc = XCreateGC(dpy, root, 0, null); 130 XSetLineAttributes(dpy, this.gc, 1, LineSolid, CapButt, JoinMiter); 131 132 } 133 134 /** 135 * Resize the drawable to a new width and height 136 * Params: 137 * w= Width 138 * h= Height 139 * Example: 140 * --- 141 * drw.resize(100, 100); 142 * --- 143 */ 144 void resize(uint w, uint h) 145 { 146 this.w = w; 147 this.h = h; 148 if(this.drawable != 0) { 149 XFreePixmap(this.dpy, this.drawable); 150 } 151 this.drawable = XCreatePixmap(this.dpy, this.root, w, h, DefaultDepth(this.dpy, this.screen)); 152 } 153 154 /** 155 * Set the font to use for rendering. 156 * Params: 157 * font= Pointer to the font to use. 158 */ 159 void setfont(Fnt *font) 160 { 161 this.font = font; 162 } 163 164 /** 165 * Set the scheme for this drawable 166 * Params: 167 * scheme = Pointer to the scheme to use 168 */ 169 void setscheme(ClrScheme *scheme) 170 { 171 if(scheme) 172 this.scheme = scheme; 173 } 174 175 /** 176 * Draw a rectangle to the X display using the current settings. Note that 177 * filled and empty are not mutually exclusive. 178 * Params: 179 * x= Left edge of the rect 180 * y= Top edge of the rect 181 * w= Width of the rect 182 * h= Height of the rect 183 * filled= If true the rect will be filled 184 * empty= If true the rect will be empty 185 * invert= If true the colours will be inverted. 186 * Example: 187 * --- 188 * drw.rect(10, 10, 90, 90, true, false, false); 189 * --- 190 */ 191 void rect(int x, int y, uint w, uint h, int filled, int empty, int invert) 192 { 193 int dx; 194 195 if(!this.font || !this.scheme) 196 return; 197 XSetForeground(this.dpy, this.gc, invert ? this.scheme.bg.rgb : this.scheme.fg.rgb); 198 dx = (this.font.ascent + this.font.descent + 2) / 4; 199 if(filled) 200 XFillRectangle(this.dpy, this.drawable, this.gc, x+1, y+1, dx+1, dx+1); 201 else if(empty) 202 XDrawRectangle(this.dpy, this.drawable, this.gc, x+1, y+1, dx, dx); 203 } 204 205 /** 206 * Render some text to the display using the current font. 207 * Params: 208 * x= Left edge of the text area 209 * y= Top of the text area 210 * w= Width of the text area 211 * h= Height of the text area 212 * text= Text to write 213 * invert= true the text bg/fg coluors will be inverted 214 * Example: 215 * --- 216 * drw.text(10, 10, 100, 100, "this is a test", false); 217 * --- 218 */ 219 void text(int x, int y, uint w, uint h, in string text, int invert) 220 { 221 char[256] buf; 222 Extnts tex; 223 224 if(!this.scheme) { 225 return; 226 } 227 XSetForeground(this.dpy, this.gc, invert ? this.scheme.fg.rgb : this.scheme.bg.rgb); 228 XFillRectangle(this.dpy, this.drawable, this.gc, x, y, w, h); 229 if(!text || !this.font) { 230 return; 231 } 232 this.font.getexts(text, &tex); 233 auto th = this.font.ascent + this.font.descent; 234 auto ty = y + (h / 2) - (th / 2) + this.font.ascent; 235 auto tx = x + (h / 2); 236 /* shorten text if necessary */ 237 auto len = min(text.length, buf.sizeof); 238 for(; len && (tex.w > w - tex.h || w < tex.h); len--) { 239 this.font.getexts(text[0..len], &tex); 240 } 241 if(!len) { 242 return; 243 } 244 memcpy(buf.ptr, text.ptr, len); 245 246 XSetForeground(this.dpy, this.gc, invert ? this.scheme.bg.rgb : this.scheme.fg.rgb); 247 if(this.font.set) 248 XmbDrawString(this.dpy, this.drawable, this.font.set, this.gc, tx, ty, buf.ptr, cast(uint)(len)); 249 else 250 XDrawString(this.dpy, this.drawable, this.gc, tx, ty, buf.ptr, cast(int)len); 251 } 252 253 /** 254 * Copy the drawable area to a window. 255 * Params: 256 * win= Destination to copy to. 257 * x= Left edge of area to copy 258 * y= Top of area to copy 259 * w= Width of area to copy 260 * h= Height of area to copy 261 * Example: 262 * --- 263 * drw.map(win, 10, 10, 100, 100); 264 * --- 265 */ 266 void map(Window win, int x, int y, uint w, uint h) 267 { 268 XCopyArea(this.dpy, this.drawable, win, this.gc, x, y, w, h, x, y); 269 XSync(this.dpy, false); 270 } 271 272 /** 273 * Release the GC memory used for the Drw object 274 * Params: 275 * drw = Drw object to release 276 */ 277 static void free(Drw* drw) 278 { 279 drw.destroy; 280 DGC.free(drw); 281 } 282 283 /** 284 * Destroy the X resources used by this drawable. 285 */ 286 void destroy() 287 { 288 XFreePixmap(this.dpy, this.drawable); 289 XFreeGC(this.dpy, this.gc); 290 } 291 292 }