]> git.decadent.org.uk Git - ion3.git/blob - ioncore/frame-draw.c
Update cfg_kludge_flash for Flash 10
[ion3.git] / ioncore / frame-draw.c
1 /*
2  * ion/ioncore/frame-draw.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2009. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <string.h>
10
11 #include <libtu/objp.h>
12 #include <libtu/minmax.h>
13 #include <libtu/map.h>
14
15 #include "common.h"
16 #include "frame.h"
17 #include "framep.h"
18 #include "frame-draw.h"
19 #include "strings.h"
20 #include "activity.h"
21 #include "names.h"
22 #include "gr.h"
23 #include "gr-util.h"
24
25
26 #define BAR_INSIDE_BORDER(FRAME) \
27     ((FRAME)->barmode==FRAME_BAR_INSIDE || (FRAME)->barmode==FRAME_BAR_NONE)
28 #define BAR_EXISTS(FRAME) ((FRAME)->barmode!=FRAME_BAR_NONE)
29 #define BAR_H(FRAME) (FRAME)->bar_h
30
31
32 /*{{{ Attributes */
33
34
35 GR_DEFATTR(active);
36 GR_DEFATTR(inactive);
37 GR_DEFATTR(selected);
38 GR_DEFATTR(unselected);
39 GR_DEFATTR(tagged);
40 GR_DEFATTR(not_tagged);
41 GR_DEFATTR(dragged);
42 GR_DEFATTR(not_dragged);
43 GR_DEFATTR(activity);
44 GR_DEFATTR(no_activity);
45
46
47 static void ensure_create_attrs()
48 {
49     GR_ALLOCATTR_BEGIN;
50     GR_ALLOCATTR(active);
51     GR_ALLOCATTR(inactive);
52     GR_ALLOCATTR(selected);
53     GR_ALLOCATTR(unselected);
54     GR_ALLOCATTR(tagged);
55     GR_ALLOCATTR(not_tagged);
56     GR_ALLOCATTR(dragged);
57     GR_ALLOCATTR(not_dragged);
58     GR_ALLOCATTR(no_activity);
59     GR_ALLOCATTR(activity);
60     GR_ALLOCATTR_END;
61 }
62     
63
64 void frame_update_attr(WFrame *frame, int i, WRegion *reg)
65 {
66     GrStyleSpec *spec;
67     bool selected, tagged, dragged, activity;
68     
69     if(i>=frame->titles_n){
70         /* Might happen when deinitialising */
71         return;
72     }
73     
74     ensure_create_attrs();
75     
76     spec=&frame->titles[i].attr;
77     
78     selected=(reg==FRAME_CURRENT(frame));
79     tagged=(reg!=NULL && reg->flags&REGION_TAGGED);
80     dragged=(i==frame->tab_dragged_idx);
81     activity=(reg!=NULL && region_is_activity_r(reg));
82     
83     gr_stylespec_unalloc(spec);
84     gr_stylespec_set(spec, selected ? GR_ATTR(selected) : GR_ATTR(unselected));
85     gr_stylespec_set(spec, tagged ? GR_ATTR(tagged) : GR_ATTR(not_tagged));
86     gr_stylespec_set(spec, dragged ? GR_ATTR(dragged) : GR_ATTR(not_dragged));
87     gr_stylespec_set(spec, activity ? GR_ATTR(activity) : GR_ATTR(no_activity));
88 }
89
90
91 /*}}}*/
92
93
94 /*{{{ (WFrame) dynfun default implementations */
95
96
97 static uint get_spacing(const WFrame *frame)
98 {
99     GrBorderWidths bdw;
100     
101     if(frame->brush==NULL)
102         return 0;
103     
104     grbrush_get_border_widths(frame->brush, &bdw);
105     
106     return bdw.spacing;
107 }
108
109
110 void frame_border_geom(const WFrame *frame, WRectangle *geom)
111 {
112     geom->x=0;
113     geom->y=0;
114     geom->w=REGION_GEOM(frame).w;
115     geom->h=REGION_GEOM(frame).h;
116     
117     if(!BAR_INSIDE_BORDER(frame) && frame->brush!=NULL){
118         geom->y+=frame->bar_h;
119         geom->h=maxof(0, geom->h-frame->bar_h);
120     }
121 }
122
123
124 void frame_border_inner_geom(const WFrame *frame, WRectangle *geom)
125 {
126     GrBorderWidths bdw;
127     
128     frame_border_geom(frame, geom);
129
130     if(frame->brush!=NULL){
131         grbrush_get_border_widths(frame->brush, &bdw);
132
133         geom->x+=bdw.left;
134         geom->y+=bdw.top;
135         geom->w=maxof(0, geom->w-(bdw.left+bdw.right));
136         geom->h=maxof(0, geom->h-(bdw.top+bdw.bottom));
137     }
138 }
139
140
141 void frame_bar_geom(const WFrame *frame, WRectangle *geom)
142 {
143     uint off;
144     
145     if(BAR_INSIDE_BORDER(frame)){
146         off=0; /*get_spacing(frame);*/
147         frame_border_inner_geom(frame, geom);
148     }else{
149         off=0;
150         geom->x=0;
151         geom->y=0;
152         geom->w=(frame->barmode==FRAME_BAR_SHAPED
153                  ? frame->bar_w
154                  : REGION_GEOM(frame).w);
155     }
156     geom->x+=off;
157     geom->y+=off;
158     geom->w=maxof(0, geom->w-2*off);
159     geom->h=BAR_H(frame);
160 }
161
162
163 void frame_managed_geom(const WFrame *frame, WRectangle *geom)
164 {
165     uint spacing=get_spacing(frame);
166     
167     frame_border_inner_geom(frame, geom);
168     
169     /*
170     geom->x+=spacing;
171     geom->y+=spacing;
172     geom->w-=2*spacing;
173     geom->h-=2*spacing;
174     */
175     
176     if(BAR_INSIDE_BORDER(frame) && BAR_EXISTS(frame)){
177         geom->y+=frame->bar_h+spacing;
178         geom->h-=frame->bar_h+spacing;
179     }
180     
181     geom->w=maxof(geom->w, 0);
182     geom->h=maxof(geom->h, 0);
183 }
184
185
186 int frame_shaded_height(const WFrame *frame)
187 {
188     if(frame->barmode==FRAME_BAR_NONE){
189         return 0;
190     }else if(!BAR_INSIDE_BORDER(frame)){
191         return frame->bar_h;
192     }else {
193         GrBorderWidths bdw;
194         
195         grbrush_get_border_widths(frame->brush, &bdw);
196         
197         return frame->bar_h+bdw.top+bdw.bottom;
198     }
199 }
200
201
202 void frame_set_shape(WFrame *frame)
203 {
204     WRectangle gs[2];
205     int n=0;
206     
207     if(frame->brush!=NULL){
208         if(BAR_EXISTS(frame)){
209             frame_bar_geom(frame, gs+n);
210             n++;
211         }
212         frame_border_geom(frame, gs+n);
213         n++;
214     
215         grbrush_set_window_shape(frame->brush, TRUE, n, gs);
216     }
217 }
218
219
220 void frame_clear_shape(WFrame *frame)
221 {
222     grbrush_set_window_shape(frame->brush, TRUE, 0, NULL);
223 }
224
225
226 #define CF_TAB_MAX_TEXT_X_OFF 10
227
228
229 static void frame_shaped_recalc_bar_size(WFrame *frame, bool complete)
230 {
231     int bar_w=0, textw=0, tmaxw=frame->tab_min_w, tmp=0;
232     WLListIterTmp itmp;
233     WRegion *sub;
234     const char *p;
235     GrBorderWidths bdw;
236     char *title;
237     uint bdtotal;
238     int i, m;
239     
240     if(frame->bar_brush==NULL)
241         return;
242     
243     m=FRAME_MCOUNT(frame);
244     
245     if(m>0){
246         grbrush_get_border_widths(frame->bar_brush, &bdw);
247         bdtotal=((m-1)*(bdw.tb_ileft+bdw.tb_iright+bdw.spacing)
248                  +bdw.right+bdw.left);
249
250         FRAME_MX_FOR_ALL(sub, frame, itmp){
251             p=region_displayname(sub);
252             if(p==NULL)
253                 continue;
254             
255             textw=grbrush_get_text_width(frame->bar_brush,
256                                          p, strlen(p));
257             if(textw>tmaxw)
258                 tmaxw=textw;
259         }
260
261         bar_w=frame->bar_max_width_q*REGION_GEOM(frame).w;
262         if(bar_w<frame->tab_min_w && 
263            REGION_GEOM(frame).w>frame->tab_min_w)
264             bar_w=frame->tab_min_w;
265         
266         tmp=bar_w-bdtotal-m*tmaxw;
267         
268         if(tmp>0){
269             /* No label truncation needed, good. See how much can be padded. */
270             tmp/=m*2;
271             if(tmp>CF_TAB_MAX_TEXT_X_OFF)
272                 tmp=CF_TAB_MAX_TEXT_X_OFF;
273             bar_w=(tmaxw+tmp*2)*m+bdtotal;
274         }else{
275             /* Some labels must be truncated */
276         }
277     }else{
278         bar_w=frame->tab_min_w;
279         if(bar_w>frame->bar_max_width_q*REGION_GEOM(frame).w)
280             bar_w=frame->bar_max_width_q*REGION_GEOM(frame).w;
281     }
282
283     if(complete || frame->bar_w!=bar_w){
284         frame->bar_w=bar_w;
285         frame_set_shape(frame);
286     }
287 }
288
289
290 static int init_title(WFrame *frame, int i)
291 {
292     int textw;
293     
294     if(frame->titles[i].text!=NULL){
295         free(frame->titles[i].text);
296         frame->titles[i].text=NULL;
297     }
298     
299     textw=frame_nth_tab_iw((WFrame*)frame, i);
300     frame->titles[i].iw=textw;
301     return textw;
302 }
303
304
305 void frame_recalc_bar(WFrame *frame, bool complete)
306 {
307     int textw, i;
308     WLListIterTmp tmp;
309     WRegion *sub;
310     char *title;
311
312     if(frame->bar_brush==NULL || frame->titles==NULL)
313         return;
314     
315     if(frame->barmode==FRAME_BAR_SHAPED)
316         frame_shaped_recalc_bar_size(frame, complete);
317     else if(complete)
318         frame_clear_shape(frame);
319     
320     i=0;
321     
322     if(FRAME_MCOUNT(frame)==0){
323         textw=init_title(frame, i);
324         if(textw>0){
325             title=grbrush_make_label(frame->bar_brush, TR("<empty frame>"), 
326                                      textw);
327             frame->titles[i].text=title;
328         }
329         return;
330     }
331     
332     FRAME_MX_FOR_ALL(sub, frame, tmp){
333         textw=init_title(frame, i);
334         if(textw>0){
335             title=region_make_label(sub, textw, frame->bar_brush);
336             frame->titles[i].text=title;
337         }
338         i++;
339     }
340 }
341
342
343 void frame_draw_bar(const WFrame *frame, bool complete)
344 {
345     WRectangle geom;
346     
347     if(frame->bar_brush==NULL
348        || !BAR_EXISTS(frame)
349        || frame->titles==NULL){
350         return;
351     }
352     
353     frame_bar_geom(frame, &geom);
354
355     grbrush_begin(frame->bar_brush, &geom, GRBRUSH_AMEND);
356     
357     grbrush_init_attr(frame->bar_brush, &frame->baseattr);
358     
359     grbrush_draw_textboxes(frame->bar_brush, &geom, frame->titles_n, 
360                            frame->titles, complete);
361     
362     grbrush_end(frame->bar_brush);
363 }
364
365 void frame_draw(const WFrame *frame, bool complete)
366 {
367     WRectangle geom;
368     
369     if(frame->brush==NULL)
370         return;
371         
372     frame_border_geom(frame, &geom);
373     
374     grbrush_begin(frame->brush, &geom, (complete ? 0 : GRBRUSH_NO_CLEAR_OK));
375     
376     grbrush_init_attr(frame->brush, &frame->baseattr);
377     
378     grbrush_draw_border(frame->brush, &geom);
379     
380     frame_draw_bar(frame, TRUE);
381     
382     grbrush_end(frame->brush);
383 }
384
385
386 void frame_brushes_updated(WFrame *frame)
387 {
388     WFrameBarMode barmode;
389     ExtlTab tab;
390     char *s;
391
392     if(frame->brush==NULL)
393         return;
394     
395     if(frame->mode==FRAME_MODE_FLOATING){
396         barmode=FRAME_BAR_SHAPED;
397     }else if(frame->mode==FRAME_MODE_TILED || frame->mode==FRAME_MODE_UNKNOWN ||
398             frame->mode==FRAME_MODE_TRANSIENT_ALT){
399         barmode=FRAME_BAR_INSIDE;
400     }else{
401         barmode=FRAME_BAR_NONE;
402     }
403     
404     if(grbrush_get_extra(frame->brush, "bar", 's', &s)){
405         if(strcmp(s, "inside")==0)
406             barmode=FRAME_BAR_INSIDE;
407         else if(strcmp(s, "outside")==0)
408             barmode=FRAME_BAR_OUTSIDE;
409         else if(strcmp(s, "shaped")==0)
410             barmode=FRAME_BAR_SHAPED;
411         else if(strcmp(s, "none")==0)
412             barmode=FRAME_BAR_NONE;
413         free(s);
414     }
415         
416     frame->barmode=barmode;
417     
418     if(barmode==FRAME_BAR_NONE || frame->bar_brush==NULL){
419         frame->bar_h=0;
420     }else{
421         GrBorderWidths bdw;
422         GrFontExtents fnte;
423
424         grbrush_get_border_widths(frame->bar_brush, &bdw);
425         grbrush_get_font_extents(frame->bar_brush, &fnte);
426
427         frame->bar_h=bdw.top+bdw.bottom+fnte.max_height;
428     }
429     
430     /* shaped mode stuff */
431     frame->tab_min_w=100;
432     frame->bar_max_width_q=0.95;
433     
434     if(grbrush_get_extra(frame->brush, "floatframe_tab_min_w",
435                          'i', &(frame->tab_min_w))){
436         if(frame->tab_min_w<=0)
437             frame->tab_min_w=1;
438     }
439     
440     if(grbrush_get_extra(frame->brush, "floatframe_bar_max_w_q", 
441                          'd', &(frame->bar_max_width_q))){
442         if(frame->bar_max_width_q<=0.0 || frame->bar_max_width_q>1.0)
443             frame->bar_max_width_q=1.0;
444     }
445 }
446
447
448 /*}}}*/
449
450
451 /*{{{ Misc. */
452
453
454 void frame_updategr(WFrame *frame)
455 {
456     frame_release_brushes(frame);
457     
458     frame_initialise_gr(frame);
459     
460     /* Update children */
461     region_updategr_default((WRegion*)frame);
462     
463     mplex_fit_managed(&frame->mplex);
464     frame_recalc_bar(frame, TRUE);
465     frame_set_background(frame, TRUE);
466 }
467
468
469 static StringIntMap frame_tab_styles[]={
470     {"tab-frame-unknown", FRAME_MODE_UNKNOWN},
471     {"tab-frame-unknown-alt", FRAME_MODE_UNKNOWN_ALT},
472     {"tab-frame-tiled", FRAME_MODE_TILED},
473     {"tab-frame-tiled-alt", FRAME_MODE_TILED_ALT},
474     {"tab-frame-floating", FRAME_MODE_FLOATING},
475     {"tab-frame-floating-alt", FRAME_MODE_FLOATING_ALT},
476     {"tab-frame-transient", FRAME_MODE_TRANSIENT},
477     {"tab-frame-transient-alt", FRAME_MODE_TRANSIENT_ALT},
478     END_STRINGINTMAP
479 };
480
481
482 const char *framemode_get_tab_style(WFrameMode mode)
483 {
484     return stringintmap_key(frame_tab_styles, mode, "tab-frame");
485 }
486
487
488 const char *framemode_get_style(WFrameMode mode)
489 {
490     const char *p=framemode_get_tab_style(mode);
491     assert(p!=NULL);
492     return (p+4);
493 }
494
495
496 void frame_initialise_gr(WFrame *frame)
497 {
498     Window win=frame->mplex.win.win;
499     WRootWin *rw=region_rootwin_of((WRegion*)frame);
500     const char *style=framemode_get_style(frame->mode);
501     const char *tab_style=framemode_get_tab_style(frame->mode);
502     
503     frame->brush=gr_get_brush(win, rw, style);
504     
505     if(frame->brush==NULL)
506         return;
507     
508     frame->bar_brush=grbrush_get_slave(frame->brush, rw, tab_style);
509     
510     if(frame->bar_brush==NULL)
511         return;
512     
513     frame_brushes_updated(frame);
514 }
515
516
517 void frame_release_brushes(WFrame *frame)
518 {
519     if(frame->bar_brush!=NULL){
520         grbrush_release(frame->bar_brush);
521         frame->bar_brush=NULL;
522     }
523     
524     if(frame->brush!=NULL){
525         grbrush_release(frame->brush);
526         frame->brush=NULL;
527     }
528 }
529
530
531 bool frame_set_background(WFrame *frame, bool set_always)
532 {
533     GrTransparency mode=GR_TRANSPARENCY_DEFAULT;
534     
535     if(FRAME_CURRENT(frame)!=NULL){
536         if(OBJ_IS(FRAME_CURRENT(frame), WClientWin)){
537             WClientWin *cwin=(WClientWin*)FRAME_CURRENT(frame);
538             mode=(cwin->flags&CLIENTWIN_PROP_TRANSPARENT
539                   ? GR_TRANSPARENCY_YES : GR_TRANSPARENCY_NO);
540         }else if(!OBJ_IS(FRAME_CURRENT(frame), WGroup)){
541             mode=GR_TRANSPARENCY_NO;
542         }
543     }
544     
545     if(mode!=frame->tr_mode || set_always){
546         frame->tr_mode=mode;
547         if(frame->brush!=NULL){
548             grbrush_enable_transparency(frame->brush, mode);
549             window_draw((WWindow*)frame, TRUE);
550         }
551         return TRUE;
552     }
553     
554     return FALSE;
555 }
556
557
558 void frame_setup_dragwin_style(WFrame *frame, GrStyleSpec *spec, int tab)
559 {
560     gr_stylespec_append(spec, &frame->baseattr);
561     gr_stylespec_append(spec, &frame->titles[tab].attr);
562 }
563
564
565 /*}}}*/
566
567
568 /*{{{ Activated/inactivated */
569
570
571 void frame_inactivated(WFrame *frame)
572 {
573     ensure_create_attrs();
574     
575     gr_stylespec_set(&frame->baseattr, GR_ATTR(inactive));
576     gr_stylespec_unset(&frame->baseattr, GR_ATTR(active));
577
578     window_draw((WWindow*)frame, FALSE);
579 }
580
581
582 void frame_activated(WFrame *frame)
583 {
584     ensure_create_attrs();
585     
586     gr_stylespec_set(&frame->baseattr, GR_ATTR(active));
587     gr_stylespec_unset(&frame->baseattr, GR_ATTR(inactive));
588     
589     window_draw((WWindow*)frame, FALSE);
590 }
591
592
593 /*}}}*/
594