4 * Copyright (c) Tuomo Valkonen 1999-2001.
5 * See the included file LICENSE for details.
13 #include "clientwin.h"
21 #include "workspace.h"
27 #include "splitmisc.h"
31 #define FRAME_MIN_H(SCR) \
32 ((SCR)->grdata.client_off.y-(SCR)->grdata.client_off.h\
33 +CF_MIN_HEIGHT*(SCR)->h_unit)
34 #define FRAME_MIN_W(SCR) \
35 ((SCR)->grdata.client_off.x-(SCR)->grdata.client_off.w\
36 +CF_MIN_WIDTH*(SCR)->w_unit)
38 #define BAR_X(FRAME, GRDATA) ((GRDATA)->bar_off.x)
39 #define BAR_Y(FRAME, GRDATA) ((GRDATA)->bar_off.y)
40 /*#define BAR_Y(FRAME, GRDATA) ((FRAME)->win.geom.h+(GRDATA)->bar_off.y) */
41 #define BAR_W(FRAME, GRDATA) ((FRAME)->win.geom.w+(GRDATA)->bar_off.w)
42 #define BAR_H(FRAME, GRDATA) ((GRDATA)->bar_h)
44 #define FRAME_TO_CLIENT_W(W, GRDATA) ((W)+(GRDATA)->client_off.w)
45 #define FRAME_TO_CLIENT_H(H, GRDATA) ((H)+(GRDATA)->client_off.h)
46 #define CLIENT_TO_FRAME_W(W, GRDATA) ((W)-(GRDATA)->client_off.w)
47 #define CLIENT_TO_FRAME_H(H, GRDATA) ((H)-(GRDATA)->client_off.h)
49 #define CLIENT_X(FRAME, GRDATA) ((GRDATA)->client_off.x)
50 #define CLIENT_Y(FRAME, GRDATA) ((GRDATA)->client_off.y)
51 #define CLIENT_W(FRAME, GRDATA) FRAME_TO_CLIENT_W(FRAME_W(FRAME), GRDATA)
52 #define CLIENT_H(FRAME, GRDATA) FRAME_TO_CLIENT_H(FRAME_H(FRAME), GRDATA)
55 WThingFuntab frame_funtab
={deinit_frame
, frame_remove_child
};
56 IMPLOBJ(WFrame
, WWindow
, &frame_funtab
)
59 static void move_clients(WFrame
*dest
, WFrame
*src
);
62 /*{{{ Destroy/create frame */
65 static bool init_frame(WFrame
*frame
, WScreen
*scr
,
66 WRectangle geom
, int id
, int flags
)
69 XSetWindowAttributes attr
;
70 WGRData
*grdata
=&(scr
->grdata
);
71 int sp
=grdata
->spacing
;
74 frame
->frame_id
=(id
==0 ? new_frame_id() : use_frame_id(id
));
75 frame
->client_count
=0;
76 frame
->current_client
=NULL
;
77 frame
->current_input
=NULL
;
80 attr
.background_pixel
=grdata
->act_frame_colors
.bg
;
81 attr
.border_pixel
=grdata
->bgcolor
;
82 win
=XCreateWindow(wglobal
.dpy
, scr
->root
.win
,
83 geom
.x
, geom
.y
, geom
.w
-sp
*2, geom
.h
-sp
*2,
84 sp
, CopyFromParent
, InputOutput
,
85 CopyFromParent
, CWBackPixel
|CWBorderPixel
, &attr
);
87 attr
.background_pixmap
=ParentRelative
;
88 win
=XCreateWindow(wglobal
.dpy
, scrroot
.win
,
89 geom
.x
, geom
.y
, geom
.w
, geom
.h
,
90 0, CopyFromParent
, InputOutput
,
91 CopyFromParent
, CWBackPixmap
, &attr
);
94 if(!init_window((WWindow
*)frame
, win
, geom
)){
95 XDestroyWindow(wglobal
.dpy
, win
);
99 frame
->win
.min_w
=FRAME_MIN_W(scr
);
100 frame
->win
.min_h
=FRAME_MIN_H(scr
);
101 frame
->tab_w
=BAR_W(frame
, grdata
);
103 XSelectInput(wglobal
.dpy
, win
, FRAME_MASK
);
105 frame
->win
.bindmap
=&(wglobal
.main_bindmap
);
106 grab_bindings(&(wglobal
.main_bindmap
), win
);
112 WFrame
*create_frame(WScreen
*scr
, WRectangle geom
, int id
, int flags
)
114 CREATETHING_IMPL(WFrame
, frame
, scr
, (p
, scr
, geom
, id
, flags
));
118 void deinit_frame(WFrame
*frame
)
120 deinit_window((WWindow
*)frame
);
121 if (shortcut_is_valid(frame
->shortcut
))
122 shortcut_remove(frame
->shortcut
);
123 free_frame_id(frame
->frame_id
);
127 void destroy_frame(WFrame
*frame
)
133 other
=find_sister_frame(frame
);
135 if(frame
->client_count
!=0){
138 errmsg("Last frame on workspace and not empty"
139 " - refusing to destroy."));
142 move_clients(other
, frame
);
144 assert(frame
->client_count
==0);
147 ws
=FIND_PARENT(frame
, WWorkspace
);
150 scr
=FIND_PARENT(ws
, WScreen
);
153 if(scr
->workspace_count
<=1 && ws
->splitree
==(WObj
*)frame
){
155 errmsg("Cannot destroy only frame on only workspace."));
160 destroy_thing((WThing
*)frame
);
163 set_focus((WThing
*)other
);
167 void closedestroy(WFrame
*frame
)
169 if(frame
->current_client
!=NULL
)
170 close_client(frame
->current_client
);
172 destroy_frame(frame
);
176 void frame_remove_child(WFrame
*frame
, WThing
*thing
)
178 if(WTHING_IS(thing
, WClient
)){
179 frame_detach_client(frame
, (WClient
*)thing
);
180 }else if((WThing
*)(frame
->current_input
)==thing
){
181 frame
->current_input
=NULL
;
182 if(IS_ACTIVE_FRAME(frame
))
191 /*{{{ Client switching */
194 static void do_frame_switch_client(WFrame
*frame
, WClient
*client
)
198 if(frame
->current_client
!=NULL
)
199 hide_client(frame
->current_client
);
201 if(frame
->current_input
==NULL
){
202 if(IS_ACTIVE_FRAME(frame
)){
203 set_previous((WThing
*)client
);
204 set_focus((WThing
*)client
);
207 XRaiseWindow(wglobal
.dpy
, frame
->current_input
->win
.win
);
210 frame
->current_client
=client
;
214 void frame_switch_client(WFrame
*frame
, WClient
*client
)
216 if(client
!=frame
->current_client
){
217 do_frame_switch_client(frame
, client
);
218 draw_frame_bar(frame
, FALSE
);
223 void frame_switch_nth(WFrame
*frame
, int num
)
225 WClient
*client
=NTH_THING(frame
, num
, WClient
);
228 frame_switch_client(frame
, client
);
232 void frame_switch_next(WFrame
*frame
)
234 WClient
*client
=NULL
;
236 if(frame
->current_client
!=NULL
)
237 client
=NEXT_THING(frame
->current_client
, WClient
);
239 client
=FIRST_THING(frame
, WClient
);
244 frame_switch_client(frame
, client
);
248 void frame_switch_prev(WFrame
*frame
)
250 WClient
*client
=NULL
;
252 if(frame
->current_client
!=NULL
)
253 client
=PREV_THING(frame
->current_client
, WClient
);
255 client
=LAST_THING(frame
, WClient
);
260 frame_switch_client(frame
, client
);
270 void activate_frame(WFrame
*frame
)
272 draw_frame(frame
, FALSE
);
276 void deactivate_frame(WFrame
*frame
)
278 draw_frame(frame
, FALSE
);
282 void focus_frame(WFrame
*frame
)
284 if(frame
->current_input
!=NULL
)
285 focus_window((WWindow
*)frame
->current_input
);
286 else if(frame
->current_client
!=NULL
)
287 focus_client(frame
->current_client
);
289 focus_window((WWindow
*)frame
);
296 /*{{{ Attach/detach */
299 static bool do_frame_detach_client(WFrame
*frame
, WClient
*client
,
300 bool reparent
, bool destroy
);
303 bool frame_attach_client(WFrame
*frame
, WClient
*client
, bool switchto
)
308 if(CLIENT_HAS_FRAME(client
)){
309 if(CLIENT_FRAME(client
)==frame
)
311 do_frame_detach_client(CLIENT_FRAME(client
), client
, FALSE
, FALSE
);
314 reparent_fit_client_frame(client
, frame
);
316 /* Only set the ID for the main window */
317 set_client_frame_id(client
, frame
->frame_id
);
320 link_thing((WThing
*)frame
, (WThing
*)client
);
322 if(frame
->current_client
!=NULL
&& wglobal
.opmode
!=OPMODE_INIT
)
323 link_thing_after((WThing
*)(frame
->current_client
), (WThing
*)client
);
325 link_thing((WThing
*)frame
, (WThing
*)client
);
328 if(frame
->client_count
==0)
331 frame
->client_count
++;
334 do_frame_switch_client(frame
, client
);
336 hide_client(client
); /* Perhaps notify_hide_client -
337 unmap is unnecessary */
338 frame_recalc_bar(frame
);
344 static void move_clients(WFrame
*dest
, WFrame
*src
)
346 WClient
*client
, *next
;
348 for(client
=FIRST_THING(src
, WClient
); client
!=NULL
; client
=next
){
349 next
=NEXT_THING(client
, WClient
);
350 frame_attach_client(dest
, client
, FALSE
);
358 static bool do_frame_detach_client(WFrame
*frame
, WClient
*client
,
359 bool reparent
, bool destroy
)
363 if(frame
->current_client
==client
){
365 next
=NEXT_THING(client
, WClient
);
367 next
=PREV_THING(client
, WClient
);
368 frame
->current_client
=NULL
;
370 next
=PREV_THING(client
, WClient
);
372 next
=NEXT_THING(client
, WClient
);
373 frame
->current_client
=NULL
;
377 unlink_thing((WThing
*)client
);
378 frame
->client_count
--;
381 reparent_client(client
, SCREEN_OF(frame
)->root
.win
, 0, 0);
383 if(wglobal
.opmode
!=OPMODE_DEINIT
){
385 do_frame_switch_client(frame
, next
);
387 frame_recalc_bar(frame
);
394 void frame_detach_client(WFrame
*frame
, WClient
* client
)
396 do_frame_detach_client(frame
, client
, FALSE
, FALSE
);
403 void frame_add_clientwin(WFrame
*frame
, WClient
*client
, WClientWin
*cwin
)
405 reparent_fit_clientwin_frame(cwin
, frame
);
407 if(cwin
==FIRST_THING(client
, WClientWin
)){
408 set_integer_property(cwin
->win
, wglobal
.atom_frame_id
,
412 if(client
==frame
->current_client
){
413 show_clientwin(cwin
);
414 if(IS_ACTIVE_FRAME(frame
))
415 focus_clientwin(cwin
);
417 hide_clientwin(cwin
);
428 void frame_fit_input(WFrame
*frame
)
432 if(frame
->current_input
==NULL
)
435 frame_client_geom(frame
, &geom
);
437 input_resize(frame
->current_input
, geom
);
441 static void frame_fit_clients(WFrame
*frame
)
445 FOR_ALL_TYPED(frame
, client
, WClient
){
446 fit_client_frame(client
, frame
);
451 static void frame_reconf_clients(WFrame
*frame
)
455 FOR_ALL_TYPED(frame
, client
, WClient
){
456 reconf_client_frame(client
, frame
);
461 void frame_recalc_bar(WFrame
*frame
)
463 WScreen
*scr
=SCREEN_OF(frame
);
464 int bar_w
=BAR_W(frame
, &(scr
->grdata
));
469 if(shortcut_is_valid(frame
->shortcut
))
470 bar_w
-=FRAME_SHORTCUT_W
+scr
->grdata
.spacing
;
472 if(frame
->client_count
==0){
474 draw_frame_bar(frame
, TRUE
);
478 tab_w
=(bar_w
-(frame
->client_count
-1)*scr
->grdata
.spacing
)/frame
->client_count
;
481 textw
=BORDER_IW(&(scr
->grdata
.tab_border
), tab_w
);
483 FOR_ALL_TYPED(frame
, client
, WClient
){
484 client_make_label(client
, textw
);
487 draw_frame_bar(frame
, TRUE
);
497 void set_frame_geom(WFrame
*frame
, WRectangle geom
)
499 WScreen
*scr
=SCREEN_OF(frame
);
500 int sp
=scr
->grdata
.spacing
;
501 bool wchg
=(FRAME_W(frame
)!=geom
.w
);
503 frame
->win
.geom
=geom
;
506 XMoveResizeWindow(wglobal
.dpy
, FRAME_WIN(frame
),
507 FRAME_X(frame
), FRAME_Y(frame
),
508 FRAME_W(frame
)-sp
*2, FRAME_H(frame
)-sp
*2);
510 XMoveResizeWindow(wglobal
.dpy
, FRAME_WIN(frame
),
511 FRAME_X(frame
), FRAME_Y(frame
),
512 FRAME_W(frame
), FRAME_H(frame
));
514 frame_fit_clients(frame
);
515 frame_fit_input(frame
);
518 frame_recalc_bar(frame
);
522 void set_frame_pos(WFrame
*frame
, int x
, int y
)
527 XMoveWindow(wglobal
.dpy
, FRAME_WIN(frame
), FRAME_X(frame
), FRAME_Y(frame
));
529 frame_reconf_clients(frame
);
536 /*{{{ Attach tagged clients */
539 static void do_attach_tagged(WFrame
*frame
)
544 for(client
=wglobal
.client_list
;
546 client
=client
->g_client_next
){
548 if(!(client
->flags
&CLIENT_TAGGED
))
552 client_toggle_tagged(client
);
554 if(!same_screen((WThing
*)frame
, (WThing
*)client
))
557 frame_attach_client(frame
, client
, FALSE
);
562 fwarn(frame
, errmsg("Could only attach %d/%d clients"
563 "(others not on same screen).", sc
, tot
));
568 void frame_attach_tagged(WFrame
*frame
)
570 do_attach_tagged(frame
);
580 static WWindow
* split_create_frame(WScreen
*scr
, WRectangle geom
)
582 return (WWindow
*)create_frame(scr
, geom
, 0, 0);
586 void split_vert(WFrame
*frame
)
589 wwin
=split_window((WWindow
*)frame
, VERTICAL
, frame
->win
.min_h
,
596 void split_horiz(WFrame
*frame
)
599 wwin
=split_window((WWindow
*)frame
, HORIZONTAL
, frame
->win
.min_w
,
606 void split_top(WWorkspace
*ws
, char *str
)
614 if(!strcmp(str
, "left")){
617 }else if(!strcmp(str
, "right")){
618 primn
=BOTTOM_OR_RIGHT
;
620 }else if(!strcmp(str
, "top")){
623 }else if(!strcmp(str
, "bottom")){
624 primn
=BOTTOM_OR_RIGHT
;
630 wwin
=split_toplevel(ws
, dir
, primn
,
631 FRAME_MIN_H(SCREEN_OF(ws
)),
643 void frame_bar_geom(const WFrame
*frame
, WRectangle
*geom
)
645 WGRData
*grdata
=GRDATA_OF(frame
);
647 geom
->x
=BAR_X(frame
, grdata
);
648 geom
->y
=BAR_Y(frame
, grdata
);
649 geom
->w
=BAR_W(frame
, grdata
);
650 geom
->h
=BAR_H(frame
, grdata
);
653 void frame_client_geom(const WFrame
*frame
, WRectangle
*geom
)
655 WGRData
*grdata
=GRDATA_OF(frame
);
657 geom
->x
=CLIENT_X(frame
, grdata
);
658 geom
->y
=CLIENT_Y(frame
, grdata
);
659 geom
->w
=CLIENT_W(frame
, grdata
);
660 geom
->h
=CLIENT_H(frame
, grdata
);