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