2 * ion/ioncore/frame-draw.c
4 * Copyright (c) Tuomo Valkonen 1999-2006.
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"
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
33 /*{{{ (WFrame) dynfun default implementations */
36 static uint get_spacing(const WFrame *frame)
40 if(frame->brush==NULL)
43 grbrush_get_border_widths(frame->brush, &bdw);
49 void frame_border_geom(const WFrame *frame, WRectangle *geom)
53 geom->w=REGION_GEOM(frame).w;
54 geom->h=REGION_GEOM(frame).h;
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);
63 void frame_border_inner_geom(const WFrame *frame, WRectangle *geom)
67 frame_border_geom(frame, geom);
69 if(frame->brush!=NULL){
70 grbrush_get_border_widths(frame->brush, &bdw);
74 geom->w=maxof(0, geom->w-(bdw.left+bdw.right));
75 geom->h=maxof(0, geom->h-(bdw.top+bdw.bottom));
80 void frame_bar_geom(const WFrame *frame, WRectangle *geom)
84 if(BAR_INSIDE_BORDER(frame)){
85 off=get_spacing(frame);
86 frame_border_inner_geom(frame, geom);
91 geom->w=(frame->barmode==FRAME_BAR_SHAPED
93 : REGION_GEOM(frame).w);
97 geom->w=maxof(0, geom->w-2*off);
102 void frame_managed_geom(const WFrame *frame, WRectangle *geom)
104 uint spacing=get_spacing(frame);
106 frame_border_inner_geom(frame, geom);
113 if(BAR_INSIDE_BORDER(frame) && BAR_EXISTS(frame)){
114 geom->y+=frame->bar_h+spacing;
115 geom->h-=frame->bar_h+spacing;
118 geom->w=maxof(geom->w, 0);
119 geom->h=maxof(geom->h, 0);
123 void frame_set_shape(WFrame *frame)
128 if(frame->brush!=NULL){
129 if(BAR_EXISTS(frame)){
130 frame_bar_geom(frame, gs+n);
133 frame_border_geom(frame, gs+n);
136 grbrush_set_window_shape(frame->brush, TRUE, n, gs);
141 void frame_clear_shape(WFrame *frame)
143 grbrush_set_window_shape(frame->brush, TRUE, 0, NULL);
147 #define CF_TAB_MAX_TEXT_X_OFF 10
150 static void frame_shaped_recalc_bar_size(WFrame *frame)
152 int bar_w=0, textw=0, tmaxw=frame->tab_min_w, tmp=0;
161 if(frame->bar_brush==NULL)
164 m=FRAME_MCOUNT(frame);
167 grbrush_get_border_widths(frame->bar_brush, &bdw);
168 bdtotal=((m-1)*(bdw.tb_ileft+bdw.tb_iright)
169 +bdw.right+bdw.left);
171 FRAME_MX_FOR_ALL(sub, frame, itmp){
172 p=region_displayname(sub);
176 textw=grbrush_get_text_width(frame->bar_brush,
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;
187 tmp=bar_w-bdtotal-m*tmaxw;
190 /* No label truncation needed, good. See how much can be padded. */
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;
196 /* Some labels must be truncated */
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;
204 if(frame->bar_w!=bar_w){
206 frame_set_shape(frame);
211 static int init_title(WFrame *frame, int i)
215 if(frame->titles[i].text!=NULL){
216 free(frame->titles[i].text);
217 frame->titles[i].text=NULL;
220 textw=frame_nth_tab_iw((WFrame*)frame, i);
221 frame->titles[i].iw=textw;
226 void frame_recalc_bar(WFrame *frame)
233 if(frame->bar_brush==NULL || frame->titles==NULL)
236 if(frame->barmode==FRAME_BAR_SHAPED)
237 frame_shaped_recalc_bar_size(frame);
241 if(FRAME_MCOUNT(frame)==0){
242 textw=init_title(frame, i);
244 title=grbrush_make_label(frame->bar_brush, CF_STR_EMPTY, textw);
245 frame->titles[i].text=title;
250 FRAME_MX_FOR_ALL(sub, frame, tmp){
251 textw=init_title(frame, i);
253 if(frame->flags&FRAME_SHOW_NUMBERS){
255 libtu_asprintf(&s, "[%d]", i+1);
257 title=grbrush_make_label(frame->bar_brush, s, textw);
263 title=region_make_label(sub, textw, frame->bar_brush);
265 frame->titles[i].text=title;
272 void frame_draw_bar(const WFrame *frame, bool complete)
275 const char *cattr=(REGION_IS_ACTIVE(frame)
276 ? "active" : "inactive");
278 if(frame->bar_brush==NULL
279 || !BAR_EXISTS(frame)
280 || frame->titles==NULL){
284 frame_bar_geom(frame, &geom);
286 grbrush_begin(frame->bar_brush, &geom, GRBRUSH_AMEND);
288 grbrush_draw_textboxes(frame->bar_brush, &geom, frame->titles_n,
289 frame->titles, complete, cattr);
291 grbrush_end(frame->bar_brush);
295 void frame_draw(const WFrame *frame, bool complete)
298 const char *attr=(REGION_IS_ACTIVE(frame)
299 ? "active" : "inactive");
301 if(frame->brush==NULL)
304 frame_border_geom(frame, &geom);
306 grbrush_begin(frame->brush, &geom, (complete ? 0 : GRBRUSH_NO_CLEAR_OK));
308 grbrush_draw_border(frame->brush, &geom, attr);
309 frame_draw_bar(frame, TRUE);
311 grbrush_end(frame->brush);
315 void frame_brushes_updated(WFrame *frame)
317 WFrameBarMode barmode=FRAME_BAR_INSIDE;
321 if(frame->brush==NULL)
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;
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;
343 frame->barmode=barmode;
345 if(barmode==FRAME_BAR_NONE || frame->bar_brush==NULL){
351 grbrush_get_border_widths(frame->bar_brush, &bdw);
352 grbrush_get_font_extents(frame->bar_brush, &fnte);
354 frame->bar_h=bdw.top+bdw.bottom+fnte.max_height;
357 /* shaped mode stuff */
358 frame->tab_min_w=100;
359 frame->bar_max_width_q=0.95;
361 if(grbrush_get_extra(frame->brush, "floatframe_tab_min_w",
362 'i', &(frame->tab_min_w))){
363 if(frame->tab_min_w<=0)
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;
381 void frame_updategr(WFrame *frame)
383 frame_release_brushes(frame);
385 frame_initialise_gr(frame);
387 /* Update children */
388 region_updategr_default((WRegion*)frame);
390 mplex_fit_managed(&frame->mplex);
391 frame_recalc_bar(frame);
392 frame_set_background(frame, TRUE);
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},
405 const char *framemode_get_tab_style(WFrameMode mode)
407 return stringintmap_key(frame_tab_styles, mode, "tab-frame");
411 const char *framemode_get_style(WFrameMode mode)
413 const char *p=framemode_get_tab_style(mode);
419 void frame_initialise_gr(WFrame *frame)
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);
426 frame->brush=gr_get_brush(win, rw, style);
428 if(frame->brush==NULL)
431 frame->bar_brush=grbrush_get_slave(frame->brush, rw, tab_style);
433 if(frame->bar_brush==NULL)
436 frame_brushes_updated(frame);
440 void frame_release_brushes(WFrame *frame)
442 if(frame->bar_brush!=NULL){
443 grbrush_release(frame->bar_brush);
444 frame->bar_brush=NULL;
447 if(frame->brush!=NULL){
448 grbrush_release(frame->brush);
454 bool frame_set_background(WFrame *frame, bool set_always)
456 GrTransparency mode=GR_TRANSPARENCY_DEFAULT;
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;
468 if(mode!=frame->tr_mode || set_always){
470 if(frame->brush!=NULL){
471 grbrush_enable_transparency(frame->brush, mode);
472 window_draw((WWindow*)frame, TRUE);