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