3e13889b6d31ef350bf32e992e1a9f8b0cd749a5
[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
21 /* you can edit these */
22 #define MAX_TASK_WIDTH 500
23 #define PADDING 2
24 #define ICON_SIZE ((tb->h)-(2*PADDING))
25
26 static void set_icon_geometry(screen *sc, taskbar *tb, task *tk);
27
28 #define SURF(x) with->surface.x
29 #define TEXT(x) with->texture[0].data.text.x
30 #define USE(x) (with = x)
31 #define SETTEXT(x, y, z) with->texture[0].type = RR_TEXTURE_TEXT; \
32                          with->texture[0].data.text.font = x; \
33                          with->texture[0].data.text.justify = y; \
34                          with->texture[0].data.text.ellipsize = z;
35 #define SETSHADOW(y, z, u, v) with->texture[0].data.text.shadow_offset_x = y; \
36                               with->texture[0].data.text.shadow_offset_y = z; \
37                               with->texture[0].data.text.shadow_alpha = u; \
38                               with->texture[0].data.text.shadow_color = v;
39
40 void gui_init(screen *sc)
41 {
42     XGCValues gcv;
43     
44     gcv.graphics_exposures = False;
45     sc->fore_gc = XCreateGC(sc->dd, sc->root, GCGraphicsExposures, &gcv);
46
47     gui_load_theme(sc);
48 }
49
50 void gui_load_theme(screen *sc)
51 {
52     RrFont *font;
53     RrAppearance *with;
54     char *name;
55     static int loaded = 0;
56
57     printf("loading theme\n");
58
59     if (loaded) return; /* only run this once for now */
60     loaded = 1;
61
62     name = xprop_get_utf8(sc, sc->root, _OB_THEME);
63     RrThemeFree(sc->theme);
64     sc->theme = RrThemeNew(sc->rr, name, TRUE, NULL, NULL, NULL, NULL, NULL);
65
66     /* We don't allow different fonts for various window states... */
67     font = RrFontOpen(sc->rr, "Candara, sans", 10,
68                       RR_FONTWEIGHT_NORMAL, RR_FONTSLANT_NORMAL);
69
70     /* this appearance will be used to draw icons */
71     a_icon = RrAppearanceNew(sc->rr, 1);
72     USE(a_icon);
73     SURF(grad) = RR_SURFACE_PARENTREL;
74     SURF(parentx) = PADDING;
75     SURF(parenty) = PADDING;
76     a_icon->texture[0].type = RR_TEXTURE_RGBA;
77
78     /* this is the appearance for the background of the panel */
79     background = RrAppearanceNew(sc->rr, 0);
80     USE(background);
81     SURF(grad) = RR_SURFACE_DIAGONAL;
82     SURF(primary) = RrColorNew(sc->rr, 170, 170, 190);
83     SURF(secondary) = RrColorNew(sc->rr, 100, 100, 160);
84
85     /* this is the appearance for unfocused tasks,
86      * text needs to be separate appearances so we can align it correctly */
87     unfocused_task = RrAppearanceNew(sc->rr, 0);
88     USE(unfocused_task);
89     SURF(parent) = background;
90     SURF(grad) = RR_SURFACE_PARENTREL;
91     SURF(relief) = RR_RELIEF_RAISED;
92     SURF(bevel) = RR_BEVEL_2;
93
94     /* ... for iconified tasks, also used for shaded ones currently */
95     iconified_task = RrAppearanceCopy(unfocused_task);
96     USE(iconified_task);
97     SURF(relief) = RR_RELIEF_FLAT;
98     SURF(parent) = background; /* RrAppearanceCopy doesn't copy .parent */
99
100     /* ... for focused tasks */
101     focused_task = RrAppearanceNew(sc->rr, 0);
102     USE(focused_task);
103     SURF(grad) = RR_SURFACE_CROSS_DIAGONAL;
104     SURF(secondary) = RrColorNew(sc->rr, 70, 80, 110);
105     SURF(primary) = RrColorNew(sc->rr, 130, 160, 250);
106     SURF(relief) = RR_RELIEF_SUNKEN;
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 = RrAppearanceNew(sc->rr, 1);
113     USE(normal_text);
114     SURF(grad) = RR_SURFACE_PARENTREL;
115     SETTEXT(font, RR_JUSTIFY_LEFT, RR_ELLIPSIZE_END);
116
117     /* ... for iconified tasks */
118     iconified_text = RrAppearanceCopy(normal_text);
119     /* ... and for focused tasks, we copy this here (ie not 5 lines down)
120      * so the color isn't copied i actually don't know if that would
121      * hurt so XXX on that */
122     focused_text = RrAppearanceCopy(normal_text);
123     USE(focused_text);
124     TEXT(color) = RrColorNew(sc->rr, 230, 230, 255);
125
126     USE(normal_text);
127     TEXT(color) = RrColorNew(sc->rr, 20, 20, 40);
128
129     USE(iconified_text);
130     SETSHADOW(2, 2, 100, RrColorNew(sc->rr, 0, 0, 0));
131     TEXT(color) = RrColorNew(sc->rr, 200, 200, 200);
132
133     shaded_text = RrAppearanceCopy(normal_text);
134     USE(shaded_text);
135     TEXT(color) = RrColorNew(sc->rr, 50, 60, 90);
136
137     XFree(name);
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 the height conigurable */
149     tb->x = 0;
150     tb->y = sc->height - 24;
151     tb->w = sc->width;
152     tb->h = 24;
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->bg = None;
167
168     /* reside on ALL desktops */
169     xprop_set_num(sc, tb->win, _NET_WM_DESKTOP, 0xFFFFFFFF);
170     xprop_set_atom(sc, tb->win, _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DOCK);
171     xprop_set_atom(sc, tb->win, _NET_WM_STATE, _NET_WM_STATE_BELOW);
172     xprop_set_string(sc, tb->win, WM_NAME, "rspanel");
173
174     /* make sure the WM obays our window position */
175     size_hints.flags = PPosition;
176     size_hints.x = tb->x;
177     size_hints.y = tb->y;
178     /*XSetWMNormalHints (sc->dd, tb->win, &size_hints); */
179     XChangeProperty(sc->dd, tb->win, XA_WM_NORMAL_HINTS, XA_WM_SIZE_HINTS, 32,
180                     PropModeReplace, (unsigned char *)&size_hints,
181                     sizeof(XSizeHints) / 4);
182
183     xclhints.res_name = "rspanel";
184     xclhints.res_class = "RSPanel";
185     XSetClassHint(sc->dd, tb->win, &xclhints);
186
187     XMapWindow(sc->dd, tb->win);
188 }
189
190 void gui_draw_task(screen *sc, taskbar *tb, task *tk, int redraw)
191 {
192     RrAppearance *a;
193     RrAppearance *b;
194     const icon *i;
195     int icon_size = 0;
196
197     if (tk->iconified)
198         b = iconified_task;
199     else if (tk->focused)
200         b = focused_task;
201     else if (tk->shaded)
202         b = iconified_task;
203     else
204         b = unfocused_task;
205
206     if (tk->iconified)
207         a = iconified_text;
208     else if (tk->shaded)
209         a = shaded_text;
210     else if (tk->focused)
211         a = focused_text;
212     else
213         a = normal_text;
214
215     i = icon_get_best(tk->icons, tk->nicons, ICON_SIZE, ICON_SIZE);
216
217     if (i) {
218         RrTextureRGBA *d = &a_icon->texture[0].data.rgba;
219         a_icon->surface.parent = b;
220         d->width = i->width;
221         d->height = i->height;
222         d->alpha = tk->iconified ? 0x80 : tk->shaded ? 0xB0 : 0xff;
223         d->data = i->data;
224         icon_size = ICON_SIZE + PADDING;
225     }
226
227     a->surface.parent = b;
228     a->surface.parentx = icon_size + PADDING;
229     a->texture[0].data.text.string = tk->name;
230     b->surface.parentx = tk->pos_x;
231
232     RrPaintPixmap(b, tk->width, tb->h);
233     RrPaintPixmap(a, tk->width-(2*PADDING+icon_size), tb->h);
234
235     if (i) {
236         RrPaintPixmap(a_icon, ICON_SIZE, ICON_SIZE);
237         XCopyArea(sc->dd, a_icon->pixmap, b->pixmap, sc->fore_gc, 0, 0,
238                   ICON_SIZE, ICON_SIZE, PADDING, PADDING);
239     }
240
241     XCopyArea(sc->dd, a->pixmap, b->pixmap, sc->fore_gc, 0, 0,
242               tk->width-(2*PADDING+icon_size), tb->h, icon_size + PADDING, 0);
243     XCopyArea(sc->dd, b->pixmap, tb->bg, sc->fore_gc, 0, 0,
244               tk->width, tb->h, tk->pos_x, 0);
245
246     XFreePixmap(sc->dd, a->pixmap);
247     XFreePixmap(sc->dd, b->pixmap);
248     XFreePixmap(sc->dd, a_icon->pixmap);
249     if (redraw) {
250         XSetWindowBackgroundPixmap(sc->dd, tb->win, tb->bg);
251         XClearWindow(sc->dd, tb->win);
252     }
253 }
254
255 void gui_draw_taskbar(screen *sc, taskbar *tb)
256 {
257     task *tk;
258     int x, width, taskw;
259     int num_tasks = 0;
260
261 #ifdef PAGER
262     pager_draw();
263 #else
264     pager_size = TEXTPAD;
265 #endif
266
267     x = pager_size + 2;
268     width = tb->w - (pager_size + GRILL_WIDTH);
269 #warning only rerender if width changed!
270     if (tb->bg) XFreePixmap(sc->dd, tb->bg);
271     tb->bg = XCreatePixmap(sc->dd, sc->root, tb->w, tb->h, RrDepth(sc->rr));
272
273     XFreePixmap(sc->dd, RrPaintPixmap(background, tb->w, tb->h));
274     XCopyArea(sc->dd, background->pixmap, tb->bg, sc->fore_gc, 0, 0,
275               tb->w, tb->h, 0, 0);
276
277     /* find the number of visible tasks */
278     for (tk = tb->task_list; tk; tk = tk->next) {
279         if (!task_shown(tk))
280             continue;
281         num_tasks++;
282     }
283
284     if (num_tasks == 0)
285         goto clear;
286
287     taskw = width / num_tasks;
288     if (taskw > MAX_TASK_WIDTH)
289         taskw = MAX_TASK_WIDTH;
290
291     for (tk = tb->task_list; tk; tk = tk->next) {
292         if (!task_shown(tk))
293             continue;
294         tk->pos_x = x;
295         tk->width = taskw - 1;
296         gui_draw_task(sc, tb, tk, FALSE);
297         set_icon_geometry(sc, tb, tk);
298         x += taskw;
299     }
300
301 clear:
302     XSetWindowBackgroundPixmap(sc->dd, tb->win, tb->bg);
303     XClearWindow(sc->dd, tb->win);
304 }
305
306 void gui_move_taskbar(screen *sc, taskbar *tb)
307 {
308     tb->x = tb->y = 0;
309
310     if (tb->hidden)
311         tb->x = TEXTPAD - tb->w;
312
313     if (!tb->at_top)
314         tb->y = sc->height - tb->h;
315
316     XMoveWindow(sc->dd, tb->win, tb->x, tb->y);
317 }
318
319 static void set_icon_geometry(screen *sc, taskbar *tb, task *tk)
320 {
321     long coords[4];
322
323     coords[0] = tb->x + tk->pos_x;
324     coords[1] = tb->y;
325     coords[2] = MAX(tk->width, 1);
326     coords[3] = tb->h;
327
328     xprop_set_array(sc, tk->win, _NET_WM_ICON_GEOMETRY, coords, 4);
329 }