use the theme. this might need work. heh! but ya.
[mikachu/rspanel.git] / gui.c
1 #include "gui.h"
2 #include "dims.h"
3 #include "xprop.h"
4 #include "icon.h"
5 #include "rspanel.h"
6
7 #include <openbox/theme.h>
8
9 static int pager_size;
10
11 static RrAppearance *background;
12 static RrAppearance *focused_task;
13 static RrAppearance *iconified_task;
14 static RrAppearance *unfocused_task;
15 static RrAppearance *normal_text;
16 static RrAppearance *iconified_text;
17 static RrAppearance *shaded_text;
18 static RrAppearance *focused_text;
19 static RrAppearance *a_icon;
20 static RrColor      *normal_text_color;
21 static RrColor      *focused_text_color;
22
23 /* you can edit these */
24 #define MAX_TASK_WIDTH 500
25 #define PADDING 2
26 #define ICON_SIZE ((tb->drawh)-(4*PADDING))
27 #define ICON_SPACE (ICON_SIZE + PADDING*2)
28
29 static void set_icon_geometry(screen *sc, taskbar *tb, task *tk);
30
31 #define SURF(x) with->surface.x
32 #define TEXT(x) with->texture[0].data.text.x
33 #define USE(x) (with = x)
34 #define SETTEXT(x, y, z) with->texture[0].type = RR_TEXTURE_TEXT; \
35                          with->texture[0].data.text.font = x; \
36                          with->texture[0].data.text.justify = y; \
37                          with->texture[0].data.text.ellipsize = z;
38 #define SETSHADOW(y, z, u, v) with->texture[0].data.text.shadow_offset_x = y; \
39                               with->texture[0].data.text.shadow_offset_y = z; \
40                               with->texture[0].data.text.shadow_alpha = u; \
41                               with->texture[0].data.text.shadow_color = v;
42
43 void gui_init(screen *sc)
44 {
45     XGCValues gcv;
46     
47     gcv.graphics_exposures = False;
48     sc->fore_gc = XCreateGC(sc->dd, sc->root, GCGraphicsExposures, &gcv);
49
50     gui_load_theme(sc);
51 }
52
53 void gui_load_theme(screen *sc)
54 {
55     RrFont *font;
56     RrAppearance *with;
57     char *name;
58
59     printf("loading theme\n");
60
61     RrAppearanceFree(background);
62     RrAppearanceFree(focused_task);
63     RrAppearanceFree(iconified_task);
64     RrAppearanceFree(unfocused_task);
65     RrAppearanceFree(normal_text);
66     RrAppearanceFree(iconified_text);
67     RrAppearanceFree(shaded_text);
68     RrAppearanceFree(focused_text);
69     RrAppearanceFree(a_icon);
70     RrColorFree(normal_text_color);
71     RrColorFree(focused_text_color);
72
73     name = xprop_get_utf8(sc, sc->root, _OB_THEME);
74     RrThemeFree(sc->theme);
75     sc->theme = RrThemeNew(sc->rr, name, TRUE, NULL, NULL, NULL, NULL, NULL);
76
77     /* We don't allow different fonts for various window states... */
78     font = RrFontOpen(sc->rr, "Candara, sans", 10,
79                       RR_FONTWEIGHT_NORMAL, RR_FONTSLANT_NORMAL);
80
81     /* this appearance will be used to draw icons */
82     a_icon = RrAppearanceNew(sc->rr, 1);
83     USE(a_icon);
84     SURF(grad) = RR_SURFACE_PARENTREL;
85     SURF(parentx) = PADDING;
86     SURF(parenty) = PADDING;
87     a_icon->texture[0].type = RR_TEXTURE_RGBA;
88
89     /* this is the appearance for the background of the panel */
90     background = RrAppearanceCopy(sc->theme->osd_hilite_bg);
91
92     /* this is the appearance for unfocused tasks,
93      * text needs to be separate appearances so we can align it correctly */
94     unfocused_task = RrAppearanceNew(sc->rr, 0);
95     USE(unfocused_task);
96     SURF(parent) = background;
97     SURF(grad) = RR_SURFACE_PARENTREL;
98
99     /* ... for iconified tasks, also used for shaded ones currently */
100     iconified_task = RrAppearanceCopy(unfocused_task);
101     USE(iconified_task);
102     SURF(parent) = background; /* RrAppearanceCopy doesn't copy .parent */
103
104     /* ... for focused tasks */
105     focused_task = RrAppearanceCopy(sc->theme->a_hover_focused_max);
106     USE(focused_task);
107     SURF(parent) = background;
108
109     /* this is the text used for all normal unfocused tasks */
110     /* we don't set .parent here, but in draw_task, since we
111      * want to combine _task and _text semirandomly.
112      * XXX plz not when themes are here */
113     normal_text = RrAppearanceCopy(sc->theme->osd_hilite_label);
114     normal_text_color = RrColorNew(sc->rr,
115                                    RrColorRed(sc->theme->osd_color),
116                                    RrColorGreen(sc->theme->osd_color),
117                                    RrColorBlue(sc->theme->osd_color));
118     USE(normal_text);
119     TEXT(color) = normal_text_color;
120     TEXT(ellipsize) = RR_ELLIPSIZE_END;
121
122     /* ... for iconified tasks */
123     iconified_text = RrAppearanceCopy(normal_text);
124     shaded_text = RrAppearanceCopy(normal_text);
125
126     focused_text = RrAppearanceCopy(normal_text);
127     focused_text_color =
128         RrColorNew(sc->rr,
129                    RrColorRed(sc->theme->titlebut_hover_focused_color),
130                    RrColorGreen(sc->theme->titlebut_hover_focused_color),
131                    RrColorBlue(sc->theme->titlebut_hover_focused_color));
132     USE(focused_text);
133     TEXT(color) = focused_text_color;
134     TEXT(ellipsize) = RR_ELLIPSIZE_END;
135
136     XFree(name);
137 }
138
139 void gui_create_taskbar(screen *sc, taskbar *tb)
140 {
141     XSizeHints size_hints;
142     XSetWindowAttributes att;
143     XClassHint xclhints;
144
145     att.event_mask = ButtonPressMask;
146
147     /* XXX make this stuff conigurable */
148     tb->w = sc->width * 0.7;
149     tb->h = 28;
150
151     tb->x = (sc->width - tb->w) / 2;
152     tb->y = sc->height - tb->h;
153
154     tb->win = XCreateWindow(/* display  */ sc->dd,
155                             /* parent   */ sc->root,
156                             /* x        */ tb->x,
157                             /* y        */ tb->y,
158                             /* width    */ tb->w,
159                             /* height   */ tb->h,
160                             /* border   */ 0,
161                             /* depth    */ CopyFromParent,
162                             /* class    */ InputOutput,
163                             /* visual   */ CopyFromParent,
164                             /*value mask*/ CWEventMask,
165                             /* attribs  */ &att);
166     tb->bgwin = XCreateWindow(/* display  */ sc->dd,
167                               /* parent   */ tb->win,
168                               /* x        */ 0,
169                               /* y        */ 0,
170                               /* width    */ tb->w,
171                               /* height   */ tb->h,
172                               /* border   */ 0,
173                               /* depth    */ CopyFromParent,
174                               /* class    */ InputOutput,
175                               /* visual   */ CopyFromParent,
176                               /*value mask*/ 0,
177                               /* attribs  */ 0);
178     tb->bg = None;
179
180     /* reside on ALL desktops */
181     xprop_set_num(sc, tb->win, _NET_WM_DESKTOP, 0xFFFFFFFF);
182     xprop_set_atom(sc, tb->win, _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DOCK);
183     xprop_set_atom(sc, tb->win, _NET_WM_STATE, _NET_WM_STATE_BELOW);
184     xprop_set_string(sc, tb->win, WM_NAME, "rspanel");
185
186     /* make sure the WM obays our window position */
187     size_hints.flags = PPosition;
188     size_hints.x = tb->x;
189     size_hints.y = tb->y;
190     /*XSetWMNormalHints (sc->dd, tb->win, &size_hints); */
191     XChangeProperty(sc->dd, tb->win, XA_WM_NORMAL_HINTS, XA_WM_SIZE_HINTS, 32,
192                     PropModeReplace, (unsigned char *)&size_hints,
193                     sizeof(XSizeHints) / 4);
194
195     xclhints.res_name = "rspanel";
196     xclhints.res_class = "RSPanel";
197     XSetClassHint(sc->dd, tb->win, &xclhints);
198
199     XMapWindow(sc->dd, tb->win);
200     XMapWindow(sc->dd, tb->bgwin);
201 }
202
203 void gui_draw_task(screen *sc, taskbar *tb, task *tk, int redraw)
204 {
205     RrAppearance *a;
206     RrAppearance *b;
207     const icon *i;
208     int icon_space = 0;
209     char *name;
210
211     if (tk->iconified)
212         b = iconified_task;
213     else if (tk->focused)
214         b = focused_task;
215     else if (tk->shaded)
216         b = iconified_task;
217     else
218         b = unfocused_task;
219
220     if (tk->iconified)
221         a = iconified_text;
222     else if (tk->shaded)
223         a = shaded_text;
224     else if (tk->focused)
225         a = focused_text;
226     else
227         a = normal_text;
228
229     if (tk->iconified)
230         name = g_strconcat("(", tk->name, ")", NULL);
231     else
232         name = g_strdup(tk->name);
233
234     i = icon_get_best(tk->icons, tk->nicons, ICON_SIZE, ICON_SIZE);
235
236     if (i) {
237         RrTextureRGBA *d = &a_icon->texture[0].data.rgba;
238         a_icon->surface.parent = b;
239         a_icon->surface.parentx = PADDING;
240         a_icon->surface.parenty = PADDING;
241         d->width = i->width;
242         d->height = i->height;
243         d->alpha = tk->iconified ? 0x70 : tk->shaded ? 0xB0 : 0xff;
244         d->data = i->data;
245         icon_space = ICON_SPACE;
246     }
247
248     a->surface.parent = b;
249     a->surface.parentx = icon_space;
250     a->texture[0].data.text.string = name;
251     b->surface.parentx = tk->pos_x;
252
253     RrPaintPixmap(b, tk->width, tb->drawh);
254     RrPaintPixmap(a, tk->width-icon_space, tb->drawh);
255
256     if (i) {
257         RrPaintPixmap(a_icon, ICON_SIZE, ICON_SIZE);
258         XCopyArea(sc->dd, a_icon->pixmap, b->pixmap, sc->fore_gc, 0, 0,
259                   ICON_SIZE, ICON_SIZE,
260                   (icon_space - ICON_SIZE) / 2,
261                   (tb->drawh - ICON_SIZE) / 2);
262     }
263
264     XCopyArea(sc->dd, a->pixmap, b->pixmap, sc->fore_gc, 0, 0,
265               tk->width-icon_space, tb->drawh,
266               icon_space, 0);
267     XCopyArea(sc->dd, b->pixmap, tb->bg, sc->fore_gc, 0, 0,
268               tk->width, tb->drawh, tk->pos_x, 0);
269
270     XFreePixmap(sc->dd, a->pixmap);
271     XFreePixmap(sc->dd, b->pixmap);
272     XFreePixmap(sc->dd, a_icon->pixmap);
273     if (redraw) {
274         XSetWindowBackgroundPixmap(sc->dd, tb->bgwin, tb->bg);
275         XClearWindow(sc->dd, tb->bgwin);
276     }
277
278     g_free(name);
279 }
280
281 void gui_draw_taskbar(screen *sc, taskbar *tb)
282 {
283     task *tk;
284     int x, width, taskw;
285     int num_tasks = 0;
286
287 #ifdef PAGER
288     pager_draw();
289 #else
290     pager_size = TEXTPAD;
291 #endif
292
293     tb->draww = tb->w - sc->theme->obwidth * 2;
294     tb->drawh = tb->h - sc->theme->obwidth;
295     XMoveResizeWindow(sc->dd, tb->bgwin, 0,
296                       (tb->at_top ? -sc->theme->obwidth : 0),
297                       tb->draww, tb->drawh);
298
299     x = pager_size + 2;
300     width = tb->draww - (pager_size + GRILL_WIDTH);
301 #warning only rerender if width changed!
302     if (tb->bg) XFreePixmap(sc->dd, tb->bg);
303     tb->bg = XCreatePixmap(sc->dd, sc->root, tb->draww, tb->drawh,
304                            RrDepth(sc->rr));
305
306     XFreePixmap(sc->dd, RrPaintPixmap(background, tb->draww, tb->drawh));
307     XCopyArea(sc->dd, background->pixmap, tb->bg, sc->fore_gc, 0, 0,
308               tb->draww, tb->drawh, 0, 0);
309
310     /* find the number of visible tasks */
311     for (tk = tb->task_list; tk; tk = tk->next) {
312         if (!task_shown(tk))
313             continue;
314         num_tasks++;
315     }
316
317     if (num_tasks == 0)
318         goto clear;
319
320     taskw = width / num_tasks;
321     if (taskw > MAX_TASK_WIDTH)
322         taskw = MAX_TASK_WIDTH;
323
324     for (tk = tb->task_list; tk; tk = tk->next) {
325         if (!task_shown(tk))
326             continue;
327         tk->pos_x = x;
328         tk->width = taskw - 1;
329         gui_draw_task(sc, tb, tk, FALSE);
330         set_icon_geometry(sc, tb, tk);
331         x += taskw;
332     }
333
334 clear:
335     XSetWindowBackgroundPixmap(sc->dd, tb->bgwin, tb->bg);
336     XClearWindow(sc->dd, tb->bgwin);
337     XSetWindowBorderWidth(sc->dd, tb->bgwin, sc->theme->obwidth);
338     XSetWindowBorder(sc->dd, tb->bgwin,
339                      RrColorPixel(sc->theme->osd_border_color));
340 }
341
342 void gui_move_taskbar(screen *sc, taskbar *tb)
343 {
344     tb->x = tb->y = 0;
345
346     if (tb->hidden)
347         tb->x = TEXTPAD - tb->w;
348
349     if (!tb->at_top)
350         tb->y = sc->height - tb->h;
351
352     XMoveWindow(sc->dd, tb->win, tb->x, tb->y);
353
354     gui_draw_taskbar(sc, tb);
355 }
356
357 static void set_icon_geometry(screen *sc, taskbar *tb, task *tk)
358 {
359     long coords[4];
360
361     coords[0] = tb->x + tk->pos_x;
362     coords[1] = tb->y;
363     coords[2] = MAX(tk->width, 1);
364     coords[3] = tb->h;
365
366     xprop_set_array(sc, tk->win, _NET_WM_ICON_GEOMETRY, coords, 4);
367 }