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 }