Renamed package to ion1, and made it conflict with package 'ion'.
[ion1.git] / src / frame.c
blob6b0b43943722c88e7f1cfadefb469b2f0c8b98d6
1 /*
2 * ion/frame.c
4 * Copyright (c) Tuomo Valkonen 1999-2001.
5 * See the included file LICENSE for details.
6 */
8 #include <string.h>
10 #include "common.h"
11 #include "frame.h"
12 #include "frameid.h"
13 #include "clientwin.h"
14 #include "screen.h"
15 #include "property.h"
16 #include "focus.h"
17 #include "event.h"
18 #include "binding.h"
19 #include "global.h"
20 #include "client.h"
21 #include "workspace.h"
22 #include "draw.h"
23 #include "thingp.h"
24 #include "split.h"
25 #include "input.h"
26 #include "query.h"
27 #include "splitmisc.h"
28 #include "shortcut.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)
68 Window win;
69 XSetWindowAttributes attr;
70 WGRData *grdata=&(scr->grdata);
71 int sp=grdata->spacing;
73 frame->flags=flags;
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;
79 #if 1
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);
86 #else
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);
92 #endif
94 if(!init_window((WWindow*)frame, win, geom)){
95 XDestroyWindow(wglobal.dpy, win);
96 return FALSE;
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);
108 return TRUE;
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)
129 WWorkspace *ws;
130 WScreen *scr;
131 WFrame *other;
133 other=find_sister_frame(frame);
135 if(frame->client_count!=0){
136 if(other==NULL){
137 fwarn(frame,
138 errmsg("Last frame on workspace and not empty"
139 " - refusing to destroy."));
140 return;
142 move_clients(other, frame);
144 assert(frame->client_count==0);
147 ws=FIND_PARENT(frame, WWorkspace);
149 if(ws!=NULL){
150 scr=FIND_PARENT(ws, WScreen);
151 assert(scr!=NULL);
153 if(scr->workspace_count<=1 && ws->splitree==(WObj*)frame){
154 fwarn(frame,
155 errmsg("Cannot destroy only frame on only workspace."));
156 return;
160 destroy_thing((WThing*)frame);
162 if(other!=NULL)
163 set_focus((WThing*)other);
167 void closedestroy(WFrame *frame)
169 if(frame->current_client!=NULL)
170 close_client(frame->current_client);
171 else
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))
183 focus_frame(frame);
188 /*}}}*/
191 /*{{{ Client switching */
194 static void do_frame_switch_client(WFrame *frame, WClient *client)
196 show_client(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);
206 }else{
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);
227 if(client!=NULL)
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);
238 if(client==NULL)
239 client=FIRST_THING(frame, WClient);
241 if(client==NULL)
242 return;
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);
254 if(client==NULL)
255 client=LAST_THING(frame, WClient);
257 if(client==NULL)
258 return;
260 frame_switch_client(frame, client);
264 /*}}}*/
267 /*{{{ Focus */
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);
288 else
289 focus_window((WWindow*)frame);
293 /*}}}*/
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)
305 WFrame *oframe=NULL;
306 WClientWin *cwin;
308 if(CLIENT_HAS_FRAME(client)){
309 if(CLIENT_FRAME(client)==frame)
310 return TRUE;
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);
319 #if 0
320 link_thing((WThing*)frame, (WThing*)client);
321 #else
322 if(frame->current_client!=NULL && wglobal.opmode!=OPMODE_INIT)
323 link_thing_after((WThing*)(frame->current_client), (WThing*)client);
324 else
325 link_thing((WThing*)frame, (WThing*)client);
326 #endif
328 if(frame->client_count==0)
329 switchto=TRUE;
331 frame->client_count++;
333 if(switchto)
334 do_frame_switch_client(frame, client);
335 else
336 hide_client(client); /* Perhaps notify_hide_client -
337 unmap is unnecessary */
338 frame_recalc_bar(frame);
340 return TRUE;
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);
355 /* */
358 static bool do_frame_detach_client(WFrame *frame, WClient *client,
359 bool reparent, bool destroy)
361 WClient *next=NULL;
363 if(frame->current_client==client){
364 #if 0
365 next=NEXT_THING(client, WClient);
366 if(next==NULL)
367 next=PREV_THING(client, WClient);
368 frame->current_client=NULL;
369 #else
370 next=PREV_THING(client, WClient);
371 if(next==NULL)
372 next=NEXT_THING(client, WClient);
373 frame->current_client=NULL;
374 #endif
377 unlink_thing((WThing*)client);
378 frame->client_count--;
380 if(reparent)
381 reparent_client(client, SCREEN_OF(frame)->root.win, 0, 0);
383 if(wglobal.opmode!=OPMODE_DEINIT){
384 if(next!=NULL)
385 do_frame_switch_client(frame, next);
387 frame_recalc_bar(frame);
390 return TRUE;
394 void frame_detach_client(WFrame *frame, WClient* client)
396 do_frame_detach_client(frame, client, FALSE, FALSE);
400 /* */
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,
409 frame->frame_id);
412 if(client==frame->current_client){
413 show_clientwin(cwin);
414 if(IS_ACTIVE_FRAME(frame))
415 focus_clientwin(cwin);
416 }else{
417 hide_clientwin(cwin);
422 /*}}}*/
425 /*{{{ Fit/reconf */
428 void frame_fit_input(WFrame *frame)
430 WRectangle geom;
432 if(frame->current_input==NULL)
433 return;
435 frame_client_geom(frame, &geom);
437 input_resize(frame->current_input, geom);
441 static void frame_fit_clients(WFrame *frame)
443 WClient *client;
445 FOR_ALL_TYPED(frame, client, WClient){
446 fit_client_frame(client, frame);
451 static void frame_reconf_clients(WFrame *frame)
453 WClient *client;
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));
465 int tab_w;
466 int textw;
467 WClient *client;
469 if(shortcut_is_valid(frame->shortcut))
470 bar_w-=FRAME_SHORTCUT_W+scr->grdata.spacing;
472 if(frame->client_count==0){
473 frame->tab_w=bar_w;
474 draw_frame_bar(frame, TRUE);
475 return;
478 tab_w=(bar_w-(frame->client_count-1)*scr->grdata.spacing)/frame->client_count;
479 frame->tab_w=tab_w;
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);
491 /*}}}*/
494 /*{{{ Move/resize */
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;
505 #if 1
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);
509 #else
510 XMoveResizeWindow(wglobal.dpy, FRAME_WIN(frame),
511 FRAME_X(frame), FRAME_Y(frame),
512 FRAME_W(frame), FRAME_H(frame));
513 #endif
514 frame_fit_clients(frame);
515 frame_fit_input(frame);
517 if(wchg)
518 frame_recalc_bar(frame);
522 void set_frame_pos(WFrame *frame, int x, int y)
524 frame->win.geom.x=x;
525 frame->win.geom.y=y;
527 XMoveWindow(wglobal.dpy, FRAME_WIN(frame), FRAME_X(frame), FRAME_Y(frame));
529 frame_reconf_clients(frame);
533 /*}}}*/
536 /*{{{ Attach tagged clients */
539 static void do_attach_tagged(WFrame *frame)
541 WClient *client;
542 int tot=0, sc=0;
544 for(client=wglobal.client_list;
545 client!=NULL;
546 client=client->g_client_next){
548 if(!(client->flags&CLIENT_TAGGED))
549 continue;
550 tot++;
552 client_toggle_tagged(client);
554 if(!same_screen((WThing*)frame, (WThing*)client))
555 continue;
557 frame_attach_client(frame, client, FALSE);
558 sc++;
561 if(tot!=sc){
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);
574 /*}}}*/
577 /*{{{ Split */
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)
588 WWindow *wwin;
589 wwin=split_window((WWindow*)frame, VERTICAL, frame->win.min_h,
590 split_create_frame);
591 if(wwin!=NULL)
592 warp(wwin);
596 void split_horiz(WFrame *frame)
598 WWindow *wwin;
599 wwin=split_window((WWindow*)frame, HORIZONTAL, frame->win.min_w,
600 split_create_frame);
601 if(wwin!=NULL)
602 warp(wwin);
606 void split_top(WWorkspace *ws, char *str)
608 WWindow *wwin;
609 int dir, primn;
611 if(str==NULL)
612 return;
614 if(!strcmp(str, "left")){
615 primn=TOP_OR_LEFT;
616 dir=HORIZONTAL;
617 }else if(!strcmp(str, "right")){
618 primn=BOTTOM_OR_RIGHT;
619 dir=HORIZONTAL;
620 }else if(!strcmp(str, "top")){
621 primn=TOP_OR_LEFT;
622 dir=VERTICAL;
623 }else if(!strcmp(str, "bottom")){
624 primn=BOTTOM_OR_RIGHT;
625 dir=VERTICAL;
626 }else{
627 return;
630 wwin=split_toplevel(ws, dir, primn,
631 FRAME_MIN_H(SCREEN_OF(ws)),
632 split_create_frame);
633 if(wwin!=NULL)
634 warp(wwin);
638 /*}}}*/
640 /*{{{ Misc */
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);
664 /*}}}*/