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