]> git.decadent.org.uk Git - ion3.git/blob - ioncore/frame-draw.c
[svn-inject] Installing original source of ion3
[ion3.git] / ioncore / frame-draw.c
1 /*
2  * ion/ioncore/frame-draw.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2006. 
5  *
6  * Ion is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <string.h>
13
14 #include <libtu/objp.h>
15 #include <libtu/minmax.h>
16 #include <libtu/map.h>
17
18 #include "common.h"
19 #include "frame.h"
20 #include "framep.h"
21 #include "frame-draw.h"
22 #include "strings.h"
23 #include "names.h"
24 #include "gr.h"
25
26
27 #define BAR_INSIDE_BORDER(FRAME) \
28     ((FRAME)->barmode==FRAME_BAR_INSIDE || (FRAME)->barmode==FRAME_BAR_NONE)
29 #define BAR_EXISTS(FRAME) ((FRAME)->barmode!=FRAME_BAR_NONE)
30 #define BAR_H(FRAME) (FRAME)->bar_h
31
32
33 /*{{{ (WFrame) dynfun default implementations */
34
35
36 static uint get_spacing(const WFrame *frame)
37 {
38     GrBorderWidths bdw;
39     
40     if(frame->brush==NULL)
41         return 0;
42     
43     grbrush_get_border_widths(frame->brush, &bdw);
44     
45     return bdw.spacing;
46 }
47
48
49 void frame_border_geom(const WFrame *frame, WRectangle *geom)
50 {
51     geom->x=0;
52     geom->y=0;
53     geom->w=REGION_GEOM(frame).w;
54     geom->h=REGION_GEOM(frame).h;
55     
56     if(!BAR_INSIDE_BORDER(frame) && frame->brush!=NULL){
57         geom->y+=frame->bar_h;
58         geom->h=maxof(0, geom->h-frame->bar_h);
59     }
60 }
61
62
63 void frame_border_inner_geom(const WFrame *frame, WRectangle *geom)
64 {
65     GrBorderWidths bdw;
66     
67     frame_border_geom(frame, geom);
68
69     if(frame->brush!=NULL){
70         grbrush_get_border_widths(frame->brush, &bdw);
71
72         geom->x+=bdw.left;
73         geom->y+=bdw.top;
74         geom->w=maxof(0, geom->w-(bdw.left+bdw.right));
75         geom->h=maxof(0, geom->h-(bdw.top+bdw.bottom));
76     }
77 }
78
79
80 void frame_bar_geom(const WFrame *frame, WRectangle *geom)
81 {
82     uint off;
83     
84     if(BAR_INSIDE_BORDER(frame)){
85         off=get_spacing(frame);
86         frame_border_inner_geom(frame, geom);
87     }else{
88         off=0;
89         geom->x=0;
90         geom->y=0;
91         geom->w=(frame->barmode==FRAME_BAR_SHAPED
92                  ? frame->bar_w
93                  : REGION_GEOM(frame).w);
94     }
95     geom->x+=off;
96     geom->y+=off;
97     geom->w=maxof(0, geom->w-2*off);
98     geom->h=BAR_H(frame);
99 }
100
101
102 void frame_managed_geom(const WFrame *frame, WRectangle *geom)
103 {
104     uint spacing=get_spacing(frame);
105     
106     frame_border_inner_geom(frame, geom);
107     
108     geom->x+=spacing;
109     geom->y+=spacing;
110     geom->w-=2*spacing;
111     geom->h-=2*spacing;
112     
113     if(BAR_INSIDE_BORDER(frame) && BAR_EXISTS(frame)){
114         geom->y+=frame->bar_h+spacing;
115         geom->h-=frame->bar_h+spacing;
116     }
117     
118     geom->w=maxof(geom->w, 0);
119     geom->h=maxof(geom->h, 0);
120 }
121
122
123 void frame_set_shape(WFrame *frame)
124 {
125     WRectangle gs[2];
126     int n=0;
127     
128     if(frame->brush!=NULL){
129         if(BAR_EXISTS(frame)){
130             frame_bar_geom(frame, gs+n);
131             n++;
132         }
133         frame_border_geom(frame, gs+n);
134         n++;
135     
136         grbrush_set_window_shape(frame->brush, TRUE, n, gs);
137     }
138 }
139
140
141 void frame_clear_shape(WFrame *frame)
142 {
143     grbrush_set_window_shape(frame->brush, TRUE, 0, NULL);
144 }
145
146
147 #define CF_TAB_MAX_TEXT_X_OFF 10
148
149
150 static void frame_shaped_recalc_bar_size(WFrame *frame)
151 {
152     int bar_w=0, textw=0, tmaxw=frame->tab_min_w, tmp=0;
153     WLListIterTmp itmp;
154     WRegion *sub;
155     const char *p;
156     GrBorderWidths bdw;
157     char *title;
158     uint bdtotal;
159     int i, m;
160     
161     if(frame->bar_brush==NULL)
162         return;
163     
164     m=FRAME_MCOUNT(frame);
165     
166     if(m>0){
167         grbrush_get_border_widths(frame->bar_brush, &bdw);
168         bdtotal=((m-1)*(bdw.tb_ileft+bdw.tb_iright)
169                  +bdw.right+bdw.left);
170
171         FRAME_MX_FOR_ALL(sub, frame, itmp){
172             p=region_displayname(sub);
173             if(p==NULL)
174                 continue;
175             
176             textw=grbrush_get_text_width(frame->bar_brush,
177                                          p, strlen(p));
178             if(textw>tmaxw)
179                 tmaxw=textw;
180         }
181
182         bar_w=frame->bar_max_width_q*REGION_GEOM(frame).w;
183         if(bar_w<frame->tab_min_w && 
184            REGION_GEOM(frame).w>frame->tab_min_w)
185             bar_w=frame->tab_min_w;
186         
187         tmp=bar_w-bdtotal-m*tmaxw;
188         
189         if(tmp>0){
190             /* No label truncation needed, good. See how much can be padded. */
191             tmp/=m*2;
192             if(tmp>CF_TAB_MAX_TEXT_X_OFF)
193                 tmp=CF_TAB_MAX_TEXT_X_OFF;
194             bar_w=(tmaxw+tmp*2)*m+bdtotal;
195         }else{
196             /* Some labels must be truncated */
197         }
198     }else{
199         bar_w=frame->tab_min_w;
200         if(bar_w>frame->bar_max_width_q*REGION_GEOM(frame).w)
201             bar_w=frame->bar_max_width_q*REGION_GEOM(frame).w;
202     }
203
204     if(frame->bar_w!=bar_w){
205         frame->bar_w=bar_w;
206         frame_set_shape(frame);
207     }
208 }
209
210
211 static int init_title(WFrame *frame, int i)
212 {
213     int textw;
214     
215     if(frame->titles[i].text!=NULL){
216         free(frame->titles[i].text);
217         frame->titles[i].text=NULL;
218     }
219     
220     textw=frame_nth_tab_iw((WFrame*)frame, i);
221     frame->titles[i].iw=textw;
222     return textw;
223 }
224
225
226 void frame_recalc_bar(WFrame *frame)
227 {
228     int textw, i;
229     WLListIterTmp tmp;
230     WRegion *sub;
231     char *title;
232
233     if(frame->bar_brush==NULL || frame->titles==NULL)
234         return;
235     
236     if(frame->barmode==FRAME_BAR_SHAPED)
237         frame_shaped_recalc_bar_size(frame);
238     
239     i=0;
240     
241     if(FRAME_MCOUNT(frame)==0){
242         textw=init_title(frame, i);
243         if(textw>0){
244             title=grbrush_make_label(frame->bar_brush, CF_STR_EMPTY, textw);
245             frame->titles[i].text=title;
246         }
247         return;
248     }
249     
250     FRAME_MX_FOR_ALL(sub, frame, tmp){
251         textw=init_title(frame, i);
252         if(textw>0){
253             if(frame->flags&FRAME_SHOW_NUMBERS){
254                 char *s=NULL;
255                 libtu_asprintf(&s, "[%d]", i+1);
256                 if(s!=NULL){
257                     title=grbrush_make_label(frame->bar_brush, s, textw);
258                     free(s);
259                 }else{
260                     title=NULL;
261                 }
262             }else{
263                 title=region_make_label(sub, textw, frame->bar_brush);
264             }
265             frame->titles[i].text=title;
266         }
267         i++;
268     }
269 }
270
271
272 void frame_draw_bar(const WFrame *frame, bool complete)
273 {
274     WRectangle geom;
275     const char *cattr=(REGION_IS_ACTIVE(frame) 
276                        ? "active" : "inactive");
277     
278     if(frame->bar_brush==NULL
279        || !BAR_EXISTS(frame)
280        || frame->titles==NULL){
281         return;
282     }
283     
284     frame_bar_geom(frame, &geom);
285
286     grbrush_begin(frame->bar_brush, &geom, GRBRUSH_AMEND);
287     
288     grbrush_draw_textboxes(frame->bar_brush, &geom, frame->titles_n, 
289                            frame->titles, complete, cattr);
290     
291     grbrush_end(frame->bar_brush);
292 }
293
294
295 void frame_draw(const WFrame *frame, bool complete)
296 {
297     WRectangle geom;
298     const char *attr=(REGION_IS_ACTIVE(frame) 
299                       ? "active" : "inactive");
300     
301     if(frame->brush==NULL)
302         return;
303     
304     frame_border_geom(frame, &geom);
305     
306     grbrush_begin(frame->brush, &geom, (complete ? 0 : GRBRUSH_NO_CLEAR_OK));
307     
308     grbrush_draw_border(frame->brush, &geom, attr);
309     frame_draw_bar(frame, TRUE);
310     
311     grbrush_end(frame->brush);
312 }
313
314
315 void frame_brushes_updated(WFrame *frame)
316 {
317     WFrameBarMode barmode=FRAME_BAR_INSIDE;
318     ExtlTab tab;
319     char *s;
320
321     if(frame->brush==NULL)
322         return;
323     
324     if(frame->mode==FRAME_MODE_FLOATING)
325         barmode=FRAME_BAR_SHAPED;
326     else if(frame->mode==FRAME_MODE_TRANSIENT)
327         barmode=FRAME_BAR_NONE;
328     else if(frame->mode==FRAME_MODE_TILED_ALT)
329         barmode=FRAME_BAR_NONE;
330     
331     if(grbrush_get_extra(frame->brush, "bar", 's', &s)){
332         if(strcmp(s, "inside")==0)
333             barmode=FRAME_BAR_INSIDE;
334         else if(strcmp(s, "outside")==0)
335             barmode=FRAME_BAR_OUTSIDE;
336         else if(strcmp(s, "shaped")==0)
337             barmode=FRAME_BAR_SHAPED;
338         else if(strcmp(s, "none")==0)
339             barmode=FRAME_BAR_NONE;
340         free(s);
341     }
342         
343     frame->barmode=barmode;
344     
345     if(barmode==FRAME_BAR_NONE || frame->bar_brush==NULL){
346         frame->bar_h=0;
347     }else{
348         GrBorderWidths bdw;
349         GrFontExtents fnte;
350
351         grbrush_get_border_widths(frame->bar_brush, &bdw);
352         grbrush_get_font_extents(frame->bar_brush, &fnte);
353
354         frame->bar_h=bdw.top+bdw.bottom+fnte.max_height;
355     }
356     
357     /* shaped mode stuff */
358     frame->tab_min_w=100;
359     frame->bar_max_width_q=0.95;
360     
361     if(grbrush_get_extra(frame->brush, "floatframe_tab_min_w",
362                          'i', &(frame->tab_min_w))){
363         if(frame->tab_min_w<=0)
364             frame->tab_min_w=1;
365     }
366     
367     if(grbrush_get_extra(frame->brush, "floatframe_bar_max_w_q", 
368                          'd', &(frame->bar_max_width_q))){
369         if(frame->bar_max_width_q<=0.0 || frame->bar_max_width_q>1.0)
370             frame->bar_max_width_q=1.0;
371     }
372 }
373
374
375 /*}}}*/
376
377
378 /*{{{ Misc. */
379
380
381 void frame_updategr(WFrame *frame)
382 {
383     frame_release_brushes(frame);
384     
385     frame_initialise_gr(frame);
386     
387     /* Update children */
388     region_updategr_default((WRegion*)frame);
389     
390     mplex_fit_managed(&frame->mplex);
391     frame_recalc_bar(frame);
392     frame_set_background(frame, TRUE);
393 }
394
395
396 StringIntMap frame_tab_styles[]={
397     {"tab-frame-tiled", FRAME_MODE_TILED},
398     {"tab-frame-tiled-alt", FRAME_MODE_TILED_ALT},
399     {"tab-frame-floating", FRAME_MODE_FLOATING},
400     {"tab-frame-transient", FRAME_MODE_TRANSIENT},
401     END_STRINGINTMAP
402 };
403
404
405 const char *framemode_get_tab_style(WFrameMode mode)
406 {
407     return stringintmap_key(frame_tab_styles, mode, "tab-frame");
408 }
409
410
411 const char *framemode_get_style(WFrameMode mode)
412 {
413     const char *p=framemode_get_tab_style(mode);
414     assert(p!=NULL);
415     return (p+4);
416 }
417
418
419 void frame_initialise_gr(WFrame *frame)
420 {
421     Window win=frame->mplex.win.win;
422     WRootWin *rw=region_rootwin_of((WRegion*)frame);
423     const char *style=framemode_get_style(frame->mode);
424     const char *tab_style=framemode_get_tab_style(frame->mode);
425     
426     frame->brush=gr_get_brush(win, rw, style);
427     
428     if(frame->brush==NULL)
429         return;
430     
431     frame->bar_brush=grbrush_get_slave(frame->brush, rw, tab_style);
432     
433     if(frame->bar_brush==NULL)
434         return;
435     
436     frame_brushes_updated(frame);
437 }
438
439
440 void frame_release_brushes(WFrame *frame)
441 {
442     if(frame->bar_brush!=NULL){
443         grbrush_release(frame->bar_brush);
444         frame->bar_brush=NULL;
445     }
446     
447     if(frame->brush!=NULL){
448         grbrush_release(frame->brush);
449         frame->brush=NULL;
450     }
451 }
452
453
454 bool frame_set_background(WFrame *frame, bool set_always)
455 {
456     GrTransparency mode=GR_TRANSPARENCY_DEFAULT;
457     
458     if(FRAME_CURRENT(frame)!=NULL){
459         if(OBJ_IS(FRAME_CURRENT(frame), WClientWin)){
460             WClientWin *cwin=(WClientWin*)FRAME_CURRENT(frame);
461             mode=(cwin->flags&CLIENTWIN_PROP_TRANSPARENT
462                   ? GR_TRANSPARENCY_YES : GR_TRANSPARENCY_NO);
463         }else if(!OBJ_IS(FRAME_CURRENT(frame), WGroup)){
464             mode=GR_TRANSPARENCY_NO;
465         }
466     }
467     
468     if(mode!=frame->tr_mode || set_always){
469         frame->tr_mode=mode;
470         if(frame->brush!=NULL){
471             grbrush_enable_transparency(frame->brush, mode);
472             window_draw((WWindow*)frame, TRUE);
473         }
474         return TRUE;
475     }
476     
477     return FALSE;
478 }
479
480
481 /*}}}*/