1 /*
2 * pwm/frame.c
3 *
4 * Copyright (c) Tuomo Valkonen 1999-2001.
5 *
6 * You may distribute and modify this program under the terms of either
7 * the Clarified Artistic License or the GNU GPL, version 2 or later.
8 */
9
10 #include <string.h>
11
12 #include "common.h"
13 #include "frame.h"
14 #include "frameid.h"
15 #include "clientwin.h"
16 #include "screen.h"
17 #include "draw.h"
18 #include "property.h"
19 #include "winobj.h"
20 #include "focus.h"
21 #include "event.h"
22 #include "binding.h"
23 #include "moveres.h"
24 #include "placement.h"
25 #include "winlist.h"
26
27
28 #define IS_CURRENT_FRAME(FRAME) ((WWinObj*)(FRAME)==wglobal.current_winobj)
29
30
31 static bool do_frame_detach_clientwin(WFrame *frame, WClientWin *cwin,
32 WFrame *transient_dest);
33 static void check_minmax_size(WFrame *frame, WClientWin *cwin);
34 static void fit_clientwin(WFrame *frame, WClientWin *cwin);
35 static void move_transients_to(WFrame *dest, WFrame *src,
36 Window transient_for);
37 static void hideshow_transients(WFrame *dest,
38 Window show_for, Window hide_for);
39
40
41 /* */
42
43
clientwin_to_frame_size(int iw,int ih,int flags,int * fw,int * fh)44 void clientwin_to_frame_size(int iw, int ih, int flags, int *fw, int *fh)
45 {
46 if(!(flags&WFRAME_NO_BORDER)){
47 iw+=2*CF_BORDER_WIDTH;
48 ih+=2*CF_BORDER_WIDTH;
49 }
50
51 if(!(flags&WFRAME_NO_BAR))
52 ih+=GRDATA->bar_height;
53
54 *fw=iw;
55 *fh=ih;
56 }
57
58
59 /*
60 * Frame creation
61 */
62
63
create_frame(int x,int y,int iw,int ih,int id,int flags)64 WFrame* create_frame(int x, int y, int iw, int ih, int id, int flags)
65 {
66 WFrame *frame;
67 int w, h;
68 Window frame_win, bar_win;
69
70 frame=ALLOC(WFrame);
71
72 if(frame==NULL){
73 warn_err();
74 return NULL;
75 }
76
77 WTHING_INIT(frame, WTHING_FRAME);
78
79 flags&=WFRAME_NO_BAR|WFRAME_NO_BORDER;
80 flags|=WFRAME_HIDDEN|WFRAME_SHADE;
81
82 frame->flags=flags;
83 frame->frame_id=(id==0 ? new_frame_id() : use_frame_id(id));
84 frame->frame_iw=iw;
85 frame->frame_ih=ih;
86 frame->frame_ix=frame->frame_iy=(flags&WFRAME_NO_BORDER ? 0 :
87 CF_BORDER_WIDTH);
88 frame->min_w=CF_WIN_MIN_WIDTH;
89 frame->min_h=CF_WIN_MIN_HEIGHT;
90 frame->max_w=-1;
91 frame->max_h=-1;
92 frame->cwin_count=0;
93
94 clientwin_to_frame_size(iw, ih, flags, &w, &h);
95
96 frame->x=x;
97 frame->y=y;
98 frame->w=w;
99 frame->h=h;
100 frame->bar_w=frame->tab_w=frame->w;
101 frame->bar_h=(flags&WFRAME_NO_BAR ? 0 : GRDATA->bar_height);
102
103 #ifdef CF_WANT_TRANSPARENT_TERMS
104 frame_win=XCreateWindow(wglobal.dpy, SCREEN->root,
105 FRAME_X(frame), FRAME_Y(frame),
106 FRAME_W(frame), FRAME_H(frame),
107 0, CopyFromParent, InputOutput, CopyFromParent,
108 0, NULL);
109 #else
110 frame_win=create_simple_window(FRAME_X(frame), FRAME_Y(frame),
111 FRAME_W(frame), FRAME_H(frame),
112 GRDATA->base_colors.pixels[WCG_PIX_BG]);
113 #endif
114 bar_win=create_simple_window(BAR_X(frame), BAR_Y(frame),
115 BAR_W(frame), GRDATA->bar_height,
116 GRDATA->tab_colors.pixels[WCG_PIX_BG]);
117
118 frame->frame_win=frame_win;
119 frame->bar_win=bar_win;
120
121 XSelectInput(wglobal.dpy, frame_win, FRAME_MASK);
122 XSaveContext(wglobal.dpy, frame_win, wglobal.win_context, (XPointer)frame);
123
124 XSelectInput(wglobal.dpy, bar_win, BAR_MASK);
125 XSaveContext(wglobal.dpy, bar_win, wglobal.win_context, (XPointer)frame);
126
127 grab_bindings(frame_win, ACTX_WINDOW|ACTX_GLOBAL);
128
129 return frame;
130 }
131
132
create_add_frame_simple(int root_x,int root_y,int iiw,int iih)133 WFrame *create_add_frame_simple(int root_x, int root_y, int iiw, int iih)
134 {
135 WFrame *frame;
136
137 frame=create_frame(root_x, root_y, iiw, iih, 0, 0);
138
139 if(frame!=NULL)
140 add_winobj((WWinObj*)frame, WORKSPACE_CURRENT, LVL_NORMAL);
141
142 return frame;
143 }
144
145
146 /*
147 * Frame destroy stuff
148 */
149
150
destroy_frame(WFrame * frame)151 void destroy_frame(WFrame *frame)
152 {
153 unlink_winobj_d((WWinObj*)frame);
154
155 XDeleteContext(wglobal.dpy, frame->frame_win, wglobal.win_context);
156 XDeleteContext(wglobal.dpy, frame->bar_win, wglobal.win_context);
157
158 XDestroyWindow(wglobal.dpy, frame->frame_win);
159 XDestroyWindow(wglobal.dpy, frame->bar_win);
160
161 free_frame_id(frame->frame_id);
162
163 free_thing((WThing*)frame);
164 }
165
166
167 /*
168 * Clientwin switching stuff
169 */
170
171
do_frame_switch_clientwin(WFrame * frame,WClientWin * cwin,bool simple)172 static void do_frame_switch_clientwin(WFrame *frame, WClientWin *cwin,
173 bool simple)
174 {
175 if(!WFRAME_IS_NORMAL(frame)){
176 frame->current_cwin=cwin;
177 if(!simple && WFRAME_IS_SHADE(frame))
178 draw_frame_bar(frame, TRUE);
179
180 update_winlist();
181 return;
182 }
183
184 #if 0
185 fit_clientwin(frame, cwin);
186 #endif
187 show_clientwin(cwin);
188
189 if(!simple)
190 hide_clientwin(frame->current_cwin);
191
192 hideshow_transients(frame, cwin->client_win,
193 simple ? None : frame->current_cwin->client_win);
194
195 frame->current_cwin=cwin;
196
197 if(IS_CURRENT_FRAME(frame))
198 set_focus_weak((WThing*)cwin);
199
200 if(!simple)
201 draw_frame_bar(frame, TRUE);
202
203 update_winlist();
204 }
205
206
frame_switch_clientwin(WFrame * frame,WClientWin * cwin)207 void frame_switch_clientwin(WFrame *frame, WClientWin *cwin)
208 {
209 if(cwin!=frame->current_cwin)
210 do_frame_switch_clientwin(frame, cwin, FALSE);
211 }
212
213
frame_switch_nth(WFrame * frame,int num)214 void frame_switch_nth(WFrame *frame, int num)
215 {
216 WThing *thing;
217
218 thing=nth_subthing((WThing*)frame, num);
219
220 if(thing!=NULL)
221 frame_switch_clientwin(frame, (WClientWin*)thing);
222 }
223
224
frame_switch_rot(WFrame * frame,int rotcnt)225 void frame_switch_rot(WFrame *frame, int rotcnt)
226 {
227 WThing *thing;
228
229 if(frame->current_cwin==NULL)
230 thing=nth_subthing((WThing*)frame, rotcnt);
231 else
232 thing=nth_thing((WThing*)(frame->current_cwin), rotcnt);
233
234 if(thing!=NULL)
235 frame_switch_clientwin(frame, (WClientWin*)thing);
236 }
237
238
239 /*
240 * Frame state
241 */
242
243
set_frame_state(WFrame * frame,int stateflags)244 void set_frame_state(WFrame *frame, int stateflags)
245 {
246 int changes;
247 Window show_for=None, hide_for=None;
248 /*
249 if(WFRAME_IS_NO_BAR(frame))
250 stateflags&=~WFRAME_HIDDEN;
251
252 if(WFRAME_IS_NO_BORDER(frame))
253 stateflags&=~WFRAME_SHADE;
254 */
255 changes=(stateflags^frame->flags)&(WFRAME_HIDDEN|WFRAME_SHADE);
256
257 if(changes==0)
258 return;
259
260 if(WFRAME_IS_NORMAL(frame)){
261 hide_clientwin(frame->current_cwin);
262 hide_for=frame->current_cwin->client_win;
263 }
264
265 frame->flags^=changes;
266
267 if(stateflags&WFRAME_HIDDEN){
268 /* hide it */
269 if(changes&WFRAME_HIDDEN)
270 unmap_winobj((WWinObj*)frame);
271 }else if(stateflags&WFRAME_SHADE){
272 /* shade it */
273 if(WWINOBJ_IS_MAPPED(frame))
274 XUnmapWindow(wglobal.dpy, frame->frame_win);
275 else
276 map_winobj((WWinObj*)frame);
277
278 if(IS_CURRENT_FRAME(frame))
279 set_focus_weak((WThing*)frame);
280 }else{
281 /* show it */
282 if(WWINOBJ_IS_MAPPED(frame))
283 XMapWindow(wglobal.dpy, frame->frame_win);
284 else
285 map_winobj((WWinObj*)frame);
286
287 show_clientwin(frame->current_cwin);
288 show_for=frame->current_cwin->client_win;
289
290 if(IS_CURRENT_FRAME(frame))
291 set_focus_weak((WThing*)frame);
292 }
293
294 hideshow_transients(frame, show_for, hide_for);
295 }
296
297
298 /*
299 * Focus
300 */
301
302
activate_frame(WFrame * frame)303 void activate_frame(WFrame *frame)
304 {
305 draw_frame_bar(frame, TRUE);
306 draw_frame_frame(frame, TRUE);
307 }
308
309
deactivate_frame(WFrame * frame)310 void deactivate_frame(WFrame *frame)
311 {
312 draw_frame_bar(frame, TRUE);
313 draw_frame_frame(frame, TRUE);
314 }
315
316
317 /* */
318
319
restack_transient(WFrame * frame,Window transient_for)320 static void restack_transient(WFrame *frame, Window transient_for)
321 {
322 WClientWin *cwin=find_clientwin(transient_for);
323
324 if(cwin==NULL || !CWIN_HAS_FRAME(cwin))
325 return;
326
327 restack_winobj_above((WWinObj*)frame, (WWinObj*)CWIN_FRAME(cwin),
328 FALSE);
329 }
330
331
frame_reconf_clientwin(WFrame * frame,WClientWin * cwin)332 static void frame_reconf_clientwin(WFrame* frame, WClientWin *cwin)
333 {
334 int x, y;
335
336 x=FRAME_X(frame)+frame->frame_ix;
337 y=FRAME_Y(frame)+frame->frame_iy;
338 #ifndef CF_CWIN_TOPLEFT
339 x+=(frame->frame_iw-cwin->client_w)/2;
340 y+=(frame->frame_ih-cwin->client_h)/2;
341 #endif
342 clientwin_reconf_at(cwin, x, y);
343 }
344
345
346 /*
347 * Attach new window to a frame.
348 */
349
do_frame_attach_clientwin(WFrame * frame,WClientWin * cwin)350 static void do_frame_attach_clientwin(WFrame *frame, WClientWin *cwin)
351 {
352 int tw=frame->frame_iw, th=frame->frame_ih;
353
354 link_thing((WThing*)frame, (WThing*)cwin);
355 frame->cwin_count++;
356
357 set_integer_property(cwin->client_win, wglobal.atom_frame_id,
358 frame->frame_id);
359 set_integer_property(cwin->client_win, wglobal.atom_workspace_num,
360 frame->workspace);
361
362 check_minmax_size(frame, cwin);
363 if(frame->frame_iw!=cwin->client_w || frame->frame_ih!=cwin->client_h)
364 frame_clientwin_resize(frame, cwin, frame->frame_iw, frame->frame_ih,
365 FALSE);
366 else
367 frame_recalc_bar(frame);
368
369 if(cwin->state!=IconicState && WFRAME_IS_SHADE(frame)){
370 frame_switch_clientwin(frame, cwin);
371 set_frame_state(frame, frame->flags&~WFRAME_SHADE);
372 }else if(frame->cwin_count==1){
373 if(cwin->state==IconicState)
374 set_frame_state(frame, frame->flags|WFRAME_SHADE);
375 frame_switch_clientwin(frame, cwin);
376 }
377
378 if(!WFRAME_IS_NORMAL(frame) || cwin!=frame->current_cwin)
379 hide_clientwin(cwin);
380 }
381
382
frame_attach_clientwin(WFrame * frame,WClientWin * cwin)383 bool frame_attach_clientwin(WFrame *frame, WClientWin *cwin)
384 {
385 WFrame *oframe=NULL;
386 WWinObj *tmp;
387
388 if(CWIN_HAS_FRAME(cwin)){
389 if(CWIN_FRAME(cwin)==frame)
390 return TRUE;
391
392 oframe=CWIN_FRAME(cwin);
393 }
394
395 if(frame->cwin_count==1 && frame->stack_above!=NULL){
396 /* Adding new window to a transient-stacked frame ->
397 * stack normally.
398 */
399 tmp=(WWinObj*)frame;
400 do{
401 tmp=tmp->stack_above;
402 }while(tmp->stack_above!=NULL);
403
404 restack_winobj((WWinObj*)frame, tmp->stack_lvl, FALSE);
405 }
406
407 #ifndef CF_NO_WILD_WINDOWS
408 if(frame->cwin_count==0 && CWIN_IS_WILD(cwin))
409 frame_set_decor(frame, WFRAME_NO_DECOR);
410 else
411 frame_set_decor(frame, 0);
412 #endif
413
414 /* Reparent and attach the window */
415 XSelectInput(wglobal.dpy, cwin->client_win,
416 cwin->event_mask&~StructureNotifyMask);
417 XReparentWindow(wglobal.dpy, cwin->client_win, frame->frame_win,
418 frame->frame_ix, frame->frame_iy);
419 XSelectInput(wglobal.dpy, cwin->client_win, cwin->event_mask);
420
421 /* Tk apps need this or else their menus will be initially fsck'd up */
422 frame_reconf_clientwin(frame, cwin);
423
424 if(oframe!=NULL){
425 if(!do_frame_detach_clientwin(oframe, cwin, frame))
426 oframe=NULL;
427 }
428
429 do_frame_attach_clientwin(frame, cwin);
430
431 if(frame->cwin_count==1 && cwin->transient_for!=None){
432 /* Adding a new transient window to an empty frame? */
433 restack_transient(frame, cwin->transient_for);
434 }
435
436 if(oframe!=NULL && oframe->cwin_count==1){
437 cwin=first_clientwin((WThing*)oframe);
438 assert(cwin!=NULL);
439
440 if(cwin->transient_for!=None)
441 restack_transient(oframe, cwin->transient_for);
442
443 #ifndef CF_NO_WILD_WINDOWS
444 if(CWIN_IS_WILD(cwin))
445 frame_set_decor(oframe, WFRAME_NO_DECOR);
446 #endif
447 }
448
449 update_winlist();
450
451 return TRUE;
452 }
453
454
455 /*
456 * Detach a window from a frame
457 */
458
do_frame_detach_clientwin(WFrame * frame,WClientWin * cwin,WFrame * transient_dest)459 static bool do_frame_detach_clientwin(WFrame *frame, WClientWin *cwin,
460 WFrame *transient_dest)
461 {
462 WClientWin *next;
463 int nw, nh;
464
465 #if 0
466 next=prev_clientwin(cwin);
467 if(next==NULL)
468 next=next_clientwin(cwin);
469 #else
470 next=next_clientwin(cwin);
471 if(next==NULL)
472 next=prev_clientwin(cwin);
473 #endif
474 move_transients_to(transient_dest, frame, cwin->client_win);
475
476 unlink_thing((WThing*)cwin);
477 frame->cwin_count--;
478
479 if(frame->cwin_count==0){
480 if(!(frame->flags&WTHING_SUBDEST))
481 destroy_frame(frame);
482 return FALSE;
483 }
484
485 assert(next!=NULL && next!=cwin);
486
487 nw=frame->frame_iw;
488 nh=frame->frame_ih;
489
490 frame_recalc_minmax(frame);
491
492 if(!FRAME_MAXW_UNSET(frame) && frame->frame_iw>frame->max_w)
493 nw=frame->max_w;
494 if(!FRAME_MAXH_UNSET(frame) && frame->frame_ih>frame->max_h)
495 nh=frame->max_h;
496
497 if(cwin==frame->current_cwin)
498 do_frame_switch_clientwin(frame, next, TRUE);
499
500 if(nw!=frame->frame_iw || nh!=frame->frame_ih)
501 set_frame_size(frame, nw, nh);
502 else
503 frame_recalc_bar(frame);
504
505 return TRUE;
506 }
507
508
frame_detach_clientwin(WFrame * frame,WClientWin * cwin,int x,int y)509 void frame_detach_clientwin(WFrame *frame, WClientWin *cwin, int x, int y)
510 {
511 XSelectInput(wglobal.dpy, cwin->client_win,
512 cwin->event_mask&~StructureNotifyMask);
513 XReparentWindow(wglobal.dpy, cwin->client_win, SCREEN->root, x, y);
514 XSelectInput(wglobal.dpy, cwin->client_win, cwin->event_mask);
515
516 if(do_frame_detach_clientwin(frame, cwin, NULL) && frame->cwin_count==1){
517 cwin=first_clientwin((WThing*)frame);
518 assert(cwin!=NULL);
519
520 if(cwin->transient_for!=None)
521 restack_transient(frame, cwin->transient_for);
522
523 #ifndef CF_NO_WILD_WINDOWS
524 if(CWIN_IS_WILD(cwin))
525 frame_set_decor(frame, WFRAME_NO_DECOR);
526 #endif
527 }
528
529 update_winlist();
530 }
531
532
533 /*
534 * Move and resize
535 */
536
537
do_set_frame_size(WFrame * frame,int iw,int ih)538 static void do_set_frame_size(WFrame *frame, int iw, int ih)
539 {
540 frame->frame_iw=iw;
541 frame->frame_ih=ih;
542
543 clientwin_to_frame_size(iw, ih, frame->flags, &(frame->w), &(frame->h));
544
545 XResizeWindow(wglobal.dpy, frame->frame_win,
546 FRAME_W(frame), FRAME_H(frame));
547
548 frame_recalc_bar(frame);
549 }
550
551
set_frame_size(WFrame * frame,int iw,int ih)552 void set_frame_size(WFrame *frame, int iw, int ih)
553 {
554 WClientWin *cwin;
555
556 do_set_frame_size(frame, iw, ih);
557
558 frame->flags&=~WFRAME_MAX_BOTH;
559
560 cwin=first_clientwin((WThing*)frame);
561
562 while(cwin!=NULL){
563 fit_clientwin(frame, cwin);
564 cwin=next_clientwin(cwin);
565 }
566 }
567
568
set_frame_pos(WFrame * frame,int x,int y)569 void set_frame_pos(WFrame *frame, int x, int y)
570 {
571 WClientWin *cwin;
572
573 frame->x=x;
574 frame->y=y;
575 XMoveWindow(wglobal.dpy, frame->bar_win, BAR_X(frame), BAR_Y(frame));
576 XMoveWindow(wglobal.dpy, frame->frame_win, FRAME_X(frame), FRAME_Y(frame));
577
578 cwin=first_clientwin((WThing*)frame);
579 while(cwin!=NULL){
580 frame_reconf_clientwin(frame, cwin);
581 cwin=next_clientwin(cwin);
582 }
583 }
584
585
check_minmax_size(WFrame * frame,WClientWin * cwin)586 static void check_minmax_size(WFrame *frame, WClientWin *cwin)
587 {
588 if(cwin->size_hints.flags&PMinSize){
589 if(cwin->size_hints.min_width>frame->min_w)
590 frame->min_w=cwin->size_hints.min_width;
591 if(cwin->size_hints.min_height>frame->min_h)
592 frame->min_h=cwin->size_hints.min_height;
593 }
594
595 if(cwin->size_hints.flags&PMaxSize){
596 if(frame->max_w!=0 && cwin->size_hints.max_width>frame->max_w)
597 frame->max_w=cwin->size_hints.max_width;
598 if(frame->max_h!=0 && cwin->size_hints.max_height>frame->max_h)
599 frame->max_h=cwin->size_hints.max_height;
600 }else{
601 frame->max_w=0;
602 frame->max_h=0;
603 }
604
605 if(!FRAME_MAXW_UNSET(frame) && frame->min_w>frame->max_w)
606 frame->max_w=frame->min_w;
607
608 if(!FRAME_MAXH_UNSET(frame) && frame->min_h>frame->max_h)
609 frame->max_h=frame->min_h;
610 }
611
612
frame_recalc_minmax(WFrame * frame)613 void frame_recalc_minmax(WFrame *frame)
614 {
615 WClientWin *cwin=first_clientwin((WThing*)frame);
616
617 frame->min_w=CF_WIN_MIN_WIDTH;
618 frame->min_h=CF_WIN_MIN_HEIGHT;
619 frame->max_w=-1;
620 frame->max_h=-1;
621
622 while(cwin!=NULL){
623 check_minmax_size(frame, cwin);
624 cwin=next_clientwin(cwin);
625 }
626 }
627
628
do_resize_clientwin(WFrame * frame,WClientWin * cwin,int w,int h)629 static void do_resize_clientwin(WFrame *frame, WClientWin *cwin, int w, int h)
630 {
631 #ifndef CF_CWIN_TOPLEFT
632 int x, y;
633 #endif
634
635 if(w!=cwin->client_w || h!=cwin->client_h){
636 cwin->client_w=w;
637 cwin->client_h=h;
638 XResizeWindow(wglobal.dpy, cwin->client_win, w, h);
639 }
640
641 #ifndef CF_CWIN_TOPLEFT
642 x=frame->frame_ix+(frame->frame_iw-cwin->client_w)/2;
643 y=frame->frame_iy+(frame->frame_ih-cwin->client_h)/2;
644 XMoveWindow(wglobal.dpy, cwin->client_win, x, y);
645 clientwin_reconf_at(cwin, FRAME_X(frame)+x, FRAME_Y(frame)+y);
646 #endif
647 }
648
649
fit_clientwin(WFrame * frame,WClientWin * cwin)650 static void fit_clientwin(WFrame *frame, WClientWin *cwin)
651 {
652 int w=frame->frame_iw;
653 int h=frame->frame_ih;
654
655 calc_size(frame, cwin, FALSE, &w, &h);
656 do_resize_clientwin(frame, cwin, w, h);
657 }
658
659
660 /* This is called when a client wants its window resized.
661 */
frame_clientwin_resize(WFrame * frame,WClientWin * cwin,int w,int h,bool dmax)662 void frame_clientwin_resize(WFrame *frame, WClientWin *cwin, int w, int h,
663 bool dmax)
664 {
665 int fw, fh;
666 WClientWin *tmp;
667 int tmpf=frame->flags;
668
669 calc_size(frame, cwin, FALSE, &w, &h);
670
671 fw=w;
672 fh=h;
673
674 if(frame->cwin_count>1){
675 /* Don't resize the frame smaller then the biggest window */
676 for(tmp=first_clientwin((WThing*)frame);
677 tmp!=NULL;
678 tmp=next_clientwin(tmp)){
679
680 if(tmp==cwin)
681 continue;
682 if(tmp->client_w>fw)
683 fw=tmp->client_w;
684 if(tmp->client_h>fh)
685 fh=tmp->client_h;
686 }
687 }
688
689
690 do_set_frame_size(frame, fw, fh);
691
692 if(!dmax)
693 frame->flags=tmpf;
694
695 /* Resize all the windows */
696 tmp=first_clientwin((WThing*)frame);
697 while(tmp!=NULL){
698 if(tmp==cwin)
699 do_resize_clientwin(frame, tmp, w, h);
700 else
701 fit_clientwin(frame, tmp);
702 tmp=next_clientwin(tmp);
703 }
704 }
705
706
707 /* Possibly take dock into account? */
708 #define MAX_WIDTH (SCREEN->width)
709 #define MAX_HEIGHT (SCREEN->height)
710
711
maximize_frame(WFrame * frame,int flags)712 static void maximize_frame(WFrame *frame, int flags)
713 {
714 int ow, oh;
715 int ox, oy;
716 int w, h;
717 int x, y;
718
719 ox=frame->x;
720 oy=frame->y;
721 ow=frame->frame_iw;
722 oh=frame->frame_ih;
723
724 if(flags&WFRAME_MAX_HORIZ){
725 w=MAX_WIDTH-frame->frame_ix*2;
726 x=0;
727
728 frame->saved_iw=ow;
729 frame->saved_x=ox;
730 }else{
731 x=ox;
732 w=ow;
733 }
734
735 if(flags&WFRAME_MAX_VERT){
736 h=MAX_HEIGHT-frame->frame_iy*2-frame->bar_h;
737 y=0;
738
739 frame->saved_ih=oh;
740 frame->saved_y=oy;
741 }else{
742 y=oy;
743 h=oh;
744 }
745
746 flags|=frame->flags;
747
748 calc_size(frame, frame->current_cwin, frame->cwin_count!=1, &w, &h);
749
750 set_frame_pos(frame, x, y);
751 set_frame_size(frame, w, h);
752
753 frame->flags=flags;
754 }
755
756
unmaximize_frame(WFrame * frame,int flags)757 static void unmaximize_frame(WFrame *frame, int flags)
758 {
759 int x, y;
760 int w, h;
761
762 if(flags&WFRAME_MAX_HORIZ){
763 x=frame->saved_x;
764 w=frame->saved_iw;
765 }else{
766 x=frame->x;
767 w=frame->frame_iw;
768 }
769
770 if(flags&WFRAME_MAX_VERT){
771 y=frame->saved_y;
772 h=frame->saved_ih;
773 }else{
774 y=frame->y;
775 h=frame->frame_ih;
776 }
777
778 flags=frame->flags&~flags;
779
780 calc_size(frame, frame->current_cwin, frame->cwin_count!=1, &w, &h);
781
782 set_frame_size(frame, w, h);
783 set_frame_pos(frame, x, y);
784
785 frame->flags=flags;
786 }
787
788
frame_do_toggle_maximize(WFrame * frame,int mask)789 static void frame_do_toggle_maximize(WFrame *frame, int mask)
790 {
791 int f=mask&~frame->flags;
792
793 if(f==0)
794 unmaximize_frame(frame, mask&frame->flags);
795 else
796 maximize_frame(frame, f);
797 }
798
799
frame_toggle_maximize(WFrame * frame,int mask)800 void frame_toggle_maximize(WFrame *frame, int mask)
801 {
802 mask&=WFRAME_MAX_BOTH;
803
804 if(mask==0)
805 mask=WFRAME_MAX_BOTH;
806
807 frame_do_toggle_maximize(frame, mask);
808 }
809
810
811 /*
812 * Transient stuff
813 */
814
815
hideshow_transients(WFrame * frame,Window show_for,Window hide_for)816 static void hideshow_transients(WFrame *frame,
817 Window show_for, Window hide_for)
818 {
819 WWinObj *obj;
820 WClientWin *cwin;
821
822 if(hide_for==show_for)
823 return;
824
825 obj=frame->stack_above_list;
826
827 while(obj!=NULL){
828 if(obj->type!=WTHING_FRAME)
829 goto cont;
830
831 /* There should only be exactly one client window if it is
832 * a transient. */
833 cwin=first_clientwin((WThing*)obj);
834
835 if(cwin==NULL)
836 continue;
837
838 if(cwin->transient_for==hide_for && hide_for!=None)
839 set_frame_state((WFrame*)obj, obj->flags|WFRAME_HIDDEN);
840 else if(cwin->transient_for==show_for && show_for!=None)
841 set_frame_state((WFrame*)obj, obj->flags&~WFRAME_HIDDEN);
842 cont:
843 obj=traverse_winobjs(obj, (WWinObj*)frame);
844 }
845 }
846
847
move_transients_to(WFrame * dest,WFrame * src,Window transient_for)848 static void move_transients_to(WFrame *dest, WFrame *src, Window transient_for)
849 {
850 WWinObj *obj, *next;
851 WClientWin *cwin=NULL;
852
853 for(obj=src->stack_above_list; obj!=NULL; obj=next){
854 next=obj->stack_next;
855
856 if(obj->type!=WTHING_FRAME)
857 continue;
858
859 /* A window is being attached to a frame containing its
860 * transient windows - this should be taken care of elsewhere
861 */
862 assert((WFrame*)obj!=dest);
863
864 /* There should only be exactly one client window if it is
865 * a transient.
866 */
867 cwin=first_clientwin((WThing*)obj);
868 if(cwin==NULL)
869 continue;
870
871 if(cwin->transient_for!=transient_for)
872 continue;
873
874 if(dest==NULL){
875 restack_winobj(obj, src->stack_lvl, FALSE /*TRUE*/);
876 set_frame_state((WFrame*)obj, obj->flags&~WFRAME_HIDDEN);
877 }else{
878 restack_winobj_above(obj, (WWinObj*)dest, TRUE);
879 /* Hide now, no need to run through the list again later */
880 if(dest->cwin_count>0)
881 set_frame_state((WFrame*)obj, obj->flags|WFRAME_HIDDEN);
882 }
883
884 }
885 }
886
887
888 /*
889 * Tagged-clientwin stuff
890 */
891
892
do_attach_tagged(WFrame * frame)893 static void do_attach_tagged(WFrame *frame)
894 {
895 WClientWin *cwin;
896 bool newframe=FALSE;
897 int x, y;
898
899 cwin=SCREEN->clientwin_list;
900
901 for(; cwin!=NULL; cwin=cwin->s_cwin_next){
902 if(!(cwin->flags&CWIN_TAGGED))
903 continue;
904
905 cwin->flags&=~CWIN_TAGGED;
906
907 if(frame==NULL){
908 frame=create_add_frame_simple(0, 0,
909 cwin->client_w, cwin->client_h);
910 if(frame==NULL)
911 return;
912 newframe=TRUE;
913 }
914 frame_attach_clientwin(frame, cwin);
915 }
916
917 if(newframe){
918 calc_placement(frame->w, frame->h, frame->workspace, &x, &y);
919 set_frame_pos(frame, x, y);
920 set_frame_state(frame, 0);
921 }
922 }
923
924
frame_attach_tagged(WFrame * frame)925 void frame_attach_tagged(WFrame *frame)
926 {
927 do_attach_tagged(frame);
928 }
929
930
join_tagged()931 void join_tagged()
932 {
933 do_attach_tagged(NULL);
934 }
935
936
937 /*
938 * Misc.
939 */
940
941
frame_recalc_bar(WFrame * frame)942 void frame_recalc_bar(WFrame *frame)
943 {
944 WClientWin *cwin;
945 const char *str;
946 int maxw=0;
947 int tmaxw=0;
948 int w, tmp;
949 int n=0;
950
951 if(frame->flags&WFRAME_NO_BAR)
952 return;
953
954 for(cwin=first_clientwin((WThing*)frame);
955 cwin!=NULL;
956 cwin=next_clientwin(cwin)){
957
958 if(cwin->state!=NormalState && cwin->state!=IconicState)
959 continue;
960
961 str=clientwin_full_label(cwin);
962
963 w=XTextWidth(GRDATA->font, str, strlen(str));
964
965 if(w>tmaxw)
966 tmaxw=w;
967
968 n++;
969 }
970
971 assert(n!=0);
972
973 maxw=CF_BAR_MAX_WIDTH_Q*frame->w;
974 if(maxw<CF_BAR_MIN_WIDTH && frame->w>=CF_BAR_MIN_WIDTH)
975 maxw=CF_BAR_MIN_WIDTH;
976
977 w=(tmaxw+CF_TAB_MIN_TEXT_X_OFF*2);
978 tmp=maxw-w*n; /* tmp=bar max width - min space for full-label tabs */
979
980 if(tmp>0){
981 /* No label truncation needed. Good. See how much can be padded. */
982 tmp/=n*2;
983
984 if(tmp>CF_TAB_MAX_TEXT_X_OFF)
985 tmp=CF_TAB_MAX_TEXT_X_OFF;
986
987 w=tmaxw+tmp*2;
988
989 if(w<CF_TAB_MIN_WIDTH){
990 w=CF_TAB_MIN_WIDTH;
991 if(w*n>maxw)
992 w=maxw/n;
993 }
994 }else{
995 /* Some labels must be truncated. */
996 w=maxw/n;
997 }
998
999 tmaxw=w-2*CF_TAB_MIN_TEXT_X_OFF;
1000
1001 /* Make the labels */
1002 for(cwin=first_clientwin((WThing*)frame);
1003 cwin!=NULL;
1004 cwin=next_clientwin(cwin)){
1005
1006 if(cwin->state!=NormalState && cwin->state!=IconicState)
1007 continue;
1008
1009 clientwin_make_label(cwin, tmaxw);
1010 }
1011
1012 frame->tab_w=w;
1013
1014 if(frame->bar_w==n*w){
1015 draw_frame_bar(frame, TRUE);
1016 }else{
1017 frame->bar_w=n*w;
1018 XResizeWindow(wglobal.dpy, frame->bar_win, frame->bar_w, frame->bar_h);
1019 }
1020 }
1021
1022
1023 /*
1024 * Shade
1025 */
1026
1027
frame_toggle_shade(WFrame * frame)1028 void frame_toggle_shade(WFrame *frame)
1029 {
1030 set_frame_state(frame, frame->flags^WFRAME_SHADE);
1031 }
1032
1033
frame_toggle_sticky(WFrame * frame)1034 void frame_toggle_sticky(WFrame *frame)
1035 {
1036 int ws=WORKSPACE_STICKY;
1037
1038 if(WWINOBJ_IS_STICKY(frame))
1039 ws=WORKSPACE_CURRENT;
1040
1041 move_to_workspace((WWinObj*)frame, ws);
1042
1043 /*draw_frame_bar(frame, TRUE);*/
1044 }
1045
1046
1047 /*
1048 * Decor toggle
1049 */
1050
frame_set_decor(WFrame * frame,int decorflags)1051 void frame_set_decor(WFrame *frame, int decorflags)
1052 {
1053 int flagchg;
1054 int w, h, x, y;
1055 WClientWin *cwin;
1056
1057 flagchg=(frame->flags&WFRAME_NO_DECOR)^decorflags;
1058
1059 if(flagchg==0)
1060 return;
1061
1062 if(flagchg&WFRAME_NO_BAR){
1063 if(frame->flags&WFRAME_NO_BAR){
1064 XMapWindow(wglobal.dpy, frame->bar_win);
1065 frame->bar_h=GRDATA->bar_height;
1066 }else{
1067 if(WFRAME_IS_SHADE(frame))
1068 set_frame_state(frame, frame->flags&~WFRAME_SHADE);
1069 XUnmapWindow(wglobal.dpy, frame->bar_win);
1070 frame->bar_h=0;
1071 }
1072 }
1073
1074 if(flagchg&WFRAME_NO_BORDER){
1075 if(frame->flags&WFRAME_NO_BORDER){
1076 frame->frame_ix=frame->frame_iy=CF_BORDER_WIDTH;
1077 }else{
1078 frame->frame_ix=frame->frame_iy=0;
1079 }
1080 }
1081
1082 frame->flags^=flagchg;
1083
1084 w=frame->frame_iw+2*frame->frame_ix;
1085 h=frame->frame_ih+2*frame->frame_iy;
1086 frame->w=w;
1087 frame->h=h+frame->bar_h;
1088
1089 XMoveResizeWindow(wglobal.dpy, frame->frame_win,
1090 frame->x, frame->y+frame->bar_h, w, h);
1091
1092 if(flagchg&WFRAME_NO_BAR && !(decorflags&WFRAME_NO_BAR))
1093 frame_recalc_bar(frame);
1094
1095 cwin=first_clientwin((WThing*)frame);
1096 while(cwin!=NULL){
1097 x=frame->frame_ix;
1098 y=frame->frame_iy;
1099 #ifndef CF_CWIN_TOPLEFT
1100 x+=(frame->frame_iw-cwin->client_w)/2;
1101 y+=(frame->frame_ih-cwin->client_h)/2;
1102 #endif
1103 XMoveWindow(wglobal.dpy, cwin->client_win, x, y);
1104 cwin=next_clientwin(cwin);
1105 }
1106 }
1107
1108
frame_toggle_decor(WFrame * frame)1109 void frame_toggle_decor(WFrame *frame)
1110 {
1111 int decorflags=0;
1112
1113 if((frame->flags&WFRAME_NO_DECOR)==0)
1114 decorflags=WFRAME_NO_DECOR;
1115
1116 frame_set_decor(frame, decorflags);
1117 }
1118
1119