2 * ion/ioncore/frame-draw.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
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.
14 #include <libtu/objp.h>
15 #include <libtu/minmax.h>
16 #include <libtu/map.h>
21 #include "frame-draw.h"
29 #define BAR_INSIDE_BORDER(FRAME) \
30 ((FRAME)->barmode==FRAME_BAR_INSIDE || (FRAME)->barmode==FRAME_BAR_NONE)
31 #define BAR_EXISTS(FRAME) ((FRAME)->barmode!=FRAME_BAR_NONE)
32 #define BAR_H(FRAME) (FRAME)->bar_h
41 GR_DEFATTR(unselected);
43 GR_DEFATTR(not_tagged);
45 GR_DEFATTR(not_dragged);
47 GR_DEFATTR(no_activity);
48 GR_DEFATTR(quasiactive);
49 GR_DEFATTR(not_quasiactive);
52 static void ensure_create_attrs()
56 GR_ALLOCATTR(inactive);
57 GR_ALLOCATTR(selected);
58 GR_ALLOCATTR(unselected);
60 GR_ALLOCATTR(not_tagged);
61 GR_ALLOCATTR(dragged);
62 GR_ALLOCATTR(not_dragged);
63 GR_ALLOCATTR(no_activity);
64 GR_ALLOCATTR(activity);
65 GR_ALLOCATTR(quasiactive);
66 GR_ALLOCATTR(not_quasiactive);
71 void frame_update_attr(WFrame *frame, int i, WRegion *reg)
74 bool selected, tagged, dragged, activity;
76 if(i>=frame->titles_n){
77 /* Might happen when deinitialising */
81 ensure_create_attrs();
83 spec=&frame->titles[i].attr;
85 selected=(reg==FRAME_CURRENT(frame));
86 tagged=(reg!=NULL && reg->flags®ION_TAGGED);
87 dragged=(i==frame->tab_dragged_idx);
88 activity=(reg!=NULL && region_is_activity_r(reg));
90 gr_stylespec_unalloc(spec);
91 gr_stylespec_set(spec, selected ? GR_ATTR(selected) : GR_ATTR(unselected));
92 gr_stylespec_set(spec, tagged ? GR_ATTR(tagged) : GR_ATTR(not_tagged));
93 gr_stylespec_set(spec, dragged ? GR_ATTR(dragged) : GR_ATTR(not_dragged));
94 gr_stylespec_set(spec, activity ? GR_ATTR(activity) : GR_ATTR(no_activity));
101 /*{{{ (WFrame) dynfun default implementations */
104 static uint get_spacing(const WFrame *frame)
108 if(frame->brush==NULL)
111 grbrush_get_border_widths(frame->brush, &bdw);
117 void frame_border_geom(const WFrame *frame, WRectangle *geom)
121 geom->w=REGION_GEOM(frame).w;
122 geom->h=REGION_GEOM(frame).h;
124 if(!BAR_INSIDE_BORDER(frame) && frame->brush!=NULL){
125 geom->y+=frame->bar_h;
126 geom->h=maxof(0, geom->h-frame->bar_h);
131 void frame_border_inner_geom(const WFrame *frame, WRectangle *geom)
135 frame_border_geom(frame, geom);
137 if(frame->brush!=NULL){
138 grbrush_get_border_widths(frame->brush, &bdw);
142 geom->w=maxof(0, geom->w-(bdw.left+bdw.right));
143 geom->h=maxof(0, geom->h-(bdw.top+bdw.bottom));
148 void frame_bar_geom(const WFrame *frame, WRectangle *geom)
152 if(BAR_INSIDE_BORDER(frame)){
153 off=0; /*get_spacing(frame);*/
154 frame_border_inner_geom(frame, geom);
159 geom->w=(frame->barmode==FRAME_BAR_SHAPED
161 : REGION_GEOM(frame).w);
165 geom->w=maxof(0, geom->w-2*off);
166 geom->h=BAR_H(frame);
170 void frame_managed_geom(const WFrame *frame, WRectangle *geom)
172 uint spacing=get_spacing(frame);
174 frame_border_inner_geom(frame, geom);
183 if(BAR_INSIDE_BORDER(frame) && BAR_EXISTS(frame)){
184 geom->y+=frame->bar_h+spacing;
185 geom->h-=frame->bar_h+spacing;
188 geom->w=maxof(geom->w, 0);
189 geom->h=maxof(geom->h, 0);
193 void frame_set_shape(WFrame *frame)
198 if(frame->brush!=NULL){
199 if(BAR_EXISTS(frame)){
200 frame_bar_geom(frame, gs+n);
203 frame_border_geom(frame, gs+n);
206 grbrush_set_window_shape(frame->brush, TRUE, n, gs);
211 void frame_clear_shape(WFrame *frame)
213 grbrush_set_window_shape(frame->brush, TRUE, 0, NULL);
217 #define CF_TAB_MAX_TEXT_X_OFF 10
220 static void frame_shaped_recalc_bar_size(WFrame *frame)
222 int bar_w=0, textw=0, tmaxw=frame->tab_min_w, tmp=0;
231 if(frame->bar_brush==NULL)
234 m=FRAME_MCOUNT(frame);
237 grbrush_get_border_widths(frame->bar_brush, &bdw);
238 bdtotal=((m-1)*(bdw.tb_ileft+bdw.tb_iright+bdw.spacing)
239 +bdw.right+bdw.left);
241 FRAME_MX_FOR_ALL(sub, frame, itmp){
242 p=region_displayname(sub);
246 textw=grbrush_get_text_width(frame->bar_brush,
252 bar_w=frame->bar_max_width_q*REGION_GEOM(frame).w;
253 if(bar_w<frame->tab_min_w &&
254 REGION_GEOM(frame).w>frame->tab_min_w)
255 bar_w=frame->tab_min_w;
257 tmp=bar_w-bdtotal-m*tmaxw;
260 /* No label truncation needed, good. See how much can be padded. */
262 if(tmp>CF_TAB_MAX_TEXT_X_OFF)
263 tmp=CF_TAB_MAX_TEXT_X_OFF;
264 bar_w=(tmaxw+tmp*2)*m+bdtotal;
266 /* Some labels must be truncated */
269 bar_w=frame->tab_min_w;
270 if(bar_w>frame->bar_max_width_q*REGION_GEOM(frame).w)
271 bar_w=frame->bar_max_width_q*REGION_GEOM(frame).w;
274 if(frame->bar_w!=bar_w){
276 frame_set_shape(frame);
281 static int init_title(WFrame *frame, int i)
285 if(frame->titles[i].text!=NULL){
286 free(frame->titles[i].text);
287 frame->titles[i].text=NULL;
290 textw=frame_nth_tab_iw((WFrame*)frame, i);
291 frame->titles[i].iw=textw;
296 void frame_recalc_bar(WFrame *frame)
303 if(frame->bar_brush==NULL || frame->titles==NULL)
306 if(frame->barmode==FRAME_BAR_SHAPED)
307 frame_shaped_recalc_bar_size(frame);
311 if(FRAME_MCOUNT(frame)==0){
312 textw=init_title(frame, i);
314 title=grbrush_make_label(frame->bar_brush, TR("<empty frame>"),
316 frame->titles[i].text=title;
321 FRAME_MX_FOR_ALL(sub, frame, tmp){
322 textw=init_title(frame, i);
324 if(frame->flags&FRAME_SHOW_NUMBERS){
326 libtu_asprintf(&s, "[%d]", i+1);
328 title=grbrush_make_label(frame->bar_brush, s, textw);
334 title=region_make_label(sub, textw, frame->bar_brush);
336 frame->titles[i].text=title;
343 static void set_common_attrs(const WFrame *frame, GrBrush *brush)
345 ensure_create_attrs();
347 grbrush_set_attr(brush, REGION_IS_ACTIVE(frame)
349 : GR_ATTR(inactive));
350 grbrush_set_attr(brush, frame->quasiactive_count>0
351 ? GR_ATTR(quasiactive)
352 : GR_ATTR(not_quasiactive));
356 void frame_draw_bar(const WFrame *frame, bool complete)
360 if(frame->bar_brush==NULL
361 || !BAR_EXISTS(frame)
362 || frame->titles==NULL){
366 frame_bar_geom(frame, &geom);
368 grbrush_begin(frame->bar_brush, &geom, GRBRUSH_AMEND);
370 set_common_attrs(frame, frame->bar_brush);
372 grbrush_draw_textboxes(frame->bar_brush, &geom, frame->titles_n,
373 frame->titles, complete);
375 grbrush_end(frame->bar_brush);
378 void frame_draw(const WFrame *frame, bool complete)
382 if(frame->brush==NULL)
385 frame_border_geom(frame, &geom);
387 grbrush_begin(frame->brush, &geom, (complete ? 0 : GRBRUSH_NO_CLEAR_OK));
389 set_common_attrs(frame, frame->brush);
391 grbrush_draw_border(frame->brush, &geom);
393 frame_draw_bar(frame, TRUE);
395 grbrush_end(frame->brush);
399 void frame_brushes_updated(WFrame *frame)
401 WFrameBarMode barmode=FRAME_BAR_INSIDE;
405 if(frame->brush==NULL)
408 if(frame->mode==FRAME_MODE_FLOATING)
409 barmode=FRAME_BAR_SHAPED;
410 else if(frame->mode==FRAME_MODE_TRANSIENT)
411 barmode=FRAME_BAR_NONE;
412 else if(frame->mode==FRAME_MODE_TILED_ALT)
413 barmode=FRAME_BAR_NONE;
415 if(grbrush_get_extra(frame->brush, "bar", 's', &s)){
416 if(strcmp(s, "inside")==0)
417 barmode=FRAME_BAR_INSIDE;
418 else if(strcmp(s, "outside")==0)
419 barmode=FRAME_BAR_OUTSIDE;
420 else if(strcmp(s, "shaped")==0)
421 barmode=FRAME_BAR_SHAPED;
422 else if(strcmp(s, "none")==0)
423 barmode=FRAME_BAR_NONE;
427 frame->barmode=barmode;
429 if(barmode==FRAME_BAR_NONE || frame->bar_brush==NULL){
435 grbrush_get_border_widths(frame->bar_brush, &bdw);
436 grbrush_get_font_extents(frame->bar_brush, &fnte);
438 frame->bar_h=bdw.top+bdw.bottom+fnte.max_height;
441 /* shaped mode stuff */
442 frame->tab_min_w=100;
443 frame->bar_max_width_q=0.95;
445 if(grbrush_get_extra(frame->brush, "floatframe_tab_min_w",
446 'i', &(frame->tab_min_w))){
447 if(frame->tab_min_w<=0)
451 if(grbrush_get_extra(frame->brush, "floatframe_bar_max_w_q",
452 'd', &(frame->bar_max_width_q))){
453 if(frame->bar_max_width_q<=0.0 || frame->bar_max_width_q>1.0)
454 frame->bar_max_width_q=1.0;
465 void frame_updategr(WFrame *frame)
467 frame_release_brushes(frame);
469 frame_initialise_gr(frame);
471 /* Update children */
472 region_updategr_default((WRegion*)frame);
474 mplex_fit_managed(&frame->mplex);
475 frame_recalc_bar(frame);
476 frame_set_background(frame, TRUE);
480 StringIntMap frame_tab_styles[]={
481 {"tab-frame-tiled", FRAME_MODE_TILED},
482 {"tab-frame-tiled-alt", FRAME_MODE_TILED_ALT},
483 {"tab-frame-floating", FRAME_MODE_FLOATING},
484 {"tab-frame-transient", FRAME_MODE_TRANSIENT},
489 const char *framemode_get_tab_style(WFrameMode mode)
491 return stringintmap_key(frame_tab_styles, mode, "tab-frame");
495 const char *framemode_get_style(WFrameMode mode)
497 const char *p=framemode_get_tab_style(mode);
503 void frame_initialise_gr(WFrame *frame)
505 Window win=frame->mplex.win.win;
506 WRootWin *rw=region_rootwin_of((WRegion*)frame);
507 const char *style=framemode_get_style(frame->mode);
508 const char *tab_style=framemode_get_tab_style(frame->mode);
510 frame->brush=gr_get_brush(win, rw, style);
512 if(frame->brush==NULL)
515 frame->bar_brush=grbrush_get_slave(frame->brush, rw, tab_style);
517 if(frame->bar_brush==NULL)
520 frame_brushes_updated(frame);
524 void frame_release_brushes(WFrame *frame)
526 if(frame->bar_brush!=NULL){
527 grbrush_release(frame->bar_brush);
528 frame->bar_brush=NULL;
531 if(frame->brush!=NULL){
532 grbrush_release(frame->brush);
538 bool frame_set_background(WFrame *frame, bool set_always)
540 GrTransparency mode=GR_TRANSPARENCY_DEFAULT;
542 if(FRAME_CURRENT(frame)!=NULL){
543 if(OBJ_IS(FRAME_CURRENT(frame), WClientWin)){
544 WClientWin *cwin=(WClientWin*)FRAME_CURRENT(frame);
545 mode=(cwin->flags&CLIENTWIN_PROP_TRANSPARENT
546 ? GR_TRANSPARENCY_YES : GR_TRANSPARENCY_NO);
547 }else if(!OBJ_IS(FRAME_CURRENT(frame), WGroup)){
548 mode=GR_TRANSPARENCY_NO;
552 if(mode!=frame->tr_mode || set_always){
554 if(frame->brush!=NULL){
555 grbrush_enable_transparency(frame->brush, mode);
556 window_draw((WWindow*)frame, TRUE);
565 void frame_setup_dragwin_style(WFrame *frame, GrStyleSpec *spec, int tab)
567 gr_stylespec_append(spec, &frame->titles[tab].attr);
569 gr_stylespec_set(spec, REGION_IS_ACTIVE(frame)
571 : GR_ATTR(inactive));
572 gr_stylespec_set(spec, frame->quasiactive_count>0
573 ? GR_ATTR(quasiactive)
574 : GR_ATTR(not_quasiactive));