Add kludge for IntelliJ IDEA transients
[notion.git] / ioncore / frame.c
blob7e77c63011061ef1cfd750af4206f524ad6e9dc1
1 /*
2 * ion/ioncore/frame.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
11 #include <libtu/obj.h>
12 #include <libtu/objp.h>
13 #include <libtu/minmax.h>
14 #include <libtu/map.h>
15 #include <libmainloop/defer.h>
17 #include "common.h"
18 #include "window.h"
19 #include "global.h"
20 #include "rootwin.h"
21 #include "focus.h"
22 #include "event.h"
23 #include "attach.h"
24 #include "resize.h"
25 #include "tags.h"
26 #include "names.h"
27 #include "saveload.h"
28 #include "framep.h"
29 #include "frame-pointer.h"
30 #include "frame-draw.h"
31 #include "sizehint.h"
32 #include "extlconv.h"
33 #include "mplex.h"
34 #include "bindmaps.h"
35 #include "regbind.h"
36 #include "gr.h"
37 #include "llist.h"
38 #include "framedpholder.h"
39 #include "return.h"
42 extern bool frame_set_background(WFrame *frame, bool set_always);
43 extern void frame_initialise_gr(WFrame *frame);
45 static bool frame_initialise_titles(WFrame *frame);
46 static void frame_free_titles(WFrame *frame);
48 static void frame_add_mode_bindmaps(WFrame *frame);
51 WHook *frame_managed_changed_hook=NULL;
53 #define FORWARD_CWIN_RQGEOM(FRAME) framemode_is_floating(frame_mode(FRAME))
54 #define USE_MINMAX(FRAME) framemode_is_floating(frame_mode(FRAME))
55 #define DEST_EMPTY(FRAME) framemode_is_floating(frame_mode(FRAME))
58 WFrameMode framemode_unalt(WFrameMode mode)
60 if(mode==FRAME_MODE_UNKNOWN_ALT)
61 return FRAME_MODE_UNKNOWN;
62 else if(mode==FRAME_MODE_TILED_ALT)
63 return FRAME_MODE_TILED;
64 else if(mode==FRAME_MODE_FLOATING_ALT)
65 return FRAME_MODE_FLOATING;
66 else if(mode==FRAME_MODE_TRANSIENT_ALT)
67 return FRAME_MODE_TRANSIENT;
68 else
69 return mode;
73 static WFrameMode framemode_is_floating(WFrameMode mode)
75 WFrameMode modea=framemode_unalt(mode);
77 return (modea==FRAME_MODE_FLOATING || modea==FRAME_MODE_TRANSIENT);
81 /*{{{ Destroy/create frame */
84 bool frame_init(WFrame *frame, WWindow *parent, const WFitParams *fp,
85 WFrameMode mode, char *name)
87 WRectangle mg;
89 frame->flags=0;
90 frame->saved_geom.w=0;
91 frame->saved_geom.h=0;
92 frame->saved_geom.x=0;
93 frame->saved_geom.y=0;
94 frame->tab_dragged_idx=-1;
95 frame->titles=NULL;
96 frame->titles_n=0;
97 frame->bar_h=0;
98 frame->bar_w=fp->g.w;
99 frame->tr_mode=GR_TRANSPARENCY_DEFAULT;
100 frame->brush=NULL;
101 frame->bar_brush=NULL;
102 frame->mode=mode;
103 frame_tabs_width_recalc_init(frame);
105 gr_stylespec_init(&frame->baseattr);
107 if(!mplex_init((WMPlex*)frame, parent, fp, name))
108 return FALSE;
110 frame_initialise_gr(frame);
111 frame_initialise_titles(frame);
113 region_add_bindmap((WRegion*)frame, ioncore_frame_bindmap);
114 region_add_bindmap((WRegion*)frame, ioncore_mplex_bindmap);
116 frame_add_mode_bindmaps(frame);
118 mplex_managed_geom((WMPlex*)frame, &mg);
120 if(mg.h<=1)
121 frame->flags|=FRAME_SHADED;
123 ((WRegion*)frame)->flags|=REGION_PLEASE_WARP;
125 return TRUE;
129 WFrame *create_frame(WWindow *parent, const WFitParams *fp, WFrameMode mode, char *name)
131 CREATEOBJ_IMPL(WFrame, frame, (p, parent, fp, mode, name));
135 void frame_deinit(WFrame *frame)
137 frame_free_titles(frame);
138 frame_release_brushes(frame);
139 gr_stylespec_unalloc(&frame->baseattr);
140 mplex_deinit((WMPlex*)frame);
144 /*}}}*/
147 /*{{{ Mode switching */
150 static void frame_add_mode_bindmaps(WFrame *frame)
152 WFrameMode modea=framemode_unalt(frame->mode);
154 if(modea==FRAME_MODE_FLOATING){
155 region_add_bindmap((WRegion*)frame, ioncore_mplex_toplevel_bindmap);
156 region_add_bindmap((WRegion*)frame, ioncore_frame_toplevel_bindmap);
157 region_add_bindmap((WRegion*)frame, ioncore_frame_floating_bindmap);
158 }else if(modea==FRAME_MODE_TRANSIENT){
159 region_add_bindmap((WRegion*)frame, ioncore_frame_transient_bindmap);
160 region_add_bindmap((WRegion*)frame, ioncore_frame_floating_bindmap);
161 }else{
162 /* mode==FRAME_MODE_TILED || mode==FRAME_MODE_TILED_ALT || mode==FRAME_MODE_UNKNOWN */
163 region_add_bindmap((WRegion*)frame, ioncore_mplex_toplevel_bindmap);
164 region_add_bindmap((WRegion*)frame, ioncore_frame_toplevel_bindmap);
165 region_add_bindmap((WRegion*)frame, ioncore_frame_tiled_bindmap);
170 void frame_set_mode(WFrame *frame, WFrameMode mode)
172 if(frame->mode==mode)
173 return;
175 frame_clear_shape(frame);
177 frame_release_brushes(frame);
179 region_remove_bindmap((WRegion*)frame, ioncore_mplex_toplevel_bindmap);
180 region_remove_bindmap((WRegion*)frame, ioncore_frame_toplevel_bindmap);
181 region_remove_bindmap((WRegion*)frame, ioncore_frame_tiled_bindmap);
182 region_remove_bindmap((WRegion*)frame, ioncore_frame_floating_bindmap);
183 region_remove_bindmap((WRegion*)frame, ioncore_frame_transient_bindmap);
185 frame->mode=mode;
187 frame_add_mode_bindmaps(frame);
189 frame_updategr(frame);
193 WFrameMode frame_mode(WFrame *frame)
195 return frame->mode;
199 static StringIntMap frame_modes[]={
200 {"unknown", FRAME_MODE_UNKNOWN},
201 {"unknown-alt", FRAME_MODE_UNKNOWN_ALT},
202 {"tiled", FRAME_MODE_TILED},
203 {"tiled-alt", FRAME_MODE_TILED_ALT},
204 {"floating", FRAME_MODE_FLOATING},
205 {"floating-alt", FRAME_MODE_FLOATING_ALT},
206 {"transient", FRAME_MODE_TRANSIENT},
207 {"transient-alt", FRAME_MODE_TRANSIENT_ALT},
208 END_STRINGINTMAP
212 /*EXTL_DOC
213 * Get frame mode.
215 EXTL_SAFE
216 EXTL_EXPORT_AS(WFrame, mode)
217 const char *frame_mode_extl(WFrame *frame)
219 return stringintmap_key(frame_modes, frame->mode, NULL);
223 /*EXTL_DOC
224 * Set frame mode (one of
225 * \codestr{unknown}, \codestr{tiled}, \codestr{floating}, \codestr{transient},
226 * or any of these suffixed with \codestr{-alt}).
228 EXTL_EXPORT_AS(WFrame, set_mode)
229 bool frame_set_mode_extl(WFrame *frame, const char *modestr)
231 WFrameMode mode;
232 int idx;
234 idx=stringintmap_ndx(frame_modes, modestr);
235 if(idx<0)
236 return FALSE;
238 frame_set_mode(frame, frame_modes[idx].value);
240 return TRUE;
244 /*}}}*/
247 /*{{{ Tabs */
250 int frame_tab_at_x(WFrame *frame, int x)
252 WRectangle bg;
253 int tab, tx;
255 frame_bar_geom(frame, &bg);
257 if(x>=bg.x+bg.w || x<bg.x)
258 return -1;
260 tx=bg.x;
262 for(tab=0; tab<FRAME_MCOUNT(frame); tab++){
263 tx+=frame_nth_tab_w(frame, tab);
264 if(x<tx)
265 break;
268 return tab;
272 int frame_nth_tab_x(WFrame *frame, int n)
274 uint x=0;
275 int i;
277 for(i=0; i<n; i++)
278 x+=frame_nth_tab_w(frame, i);
280 return x;
284 int frame_nth_tab_w(WFrame *frame, int n)
286 GrBorderWidths bdw=GR_BORDER_WIDTHS_INIT;
288 if (n>frame->titles_n){
289 fprintf(stderr,"WARNING: we should not be here, please contact notion developers\n");
290 return 0;
292 if(frame->titles[n].iw==0) return 0; /* Too small tab. */
294 if(frame->bar_brush!=NULL)
295 grbrush_get_border_widths(frame->bar_brush, &bdw);
297 return frame->titles[n].iw +
298 (n==0 ? bdw.left : bdw.tb_ileft) +
299 (n==frame->titles_n-1 ? bdw.right : bdw.tb_iright+bdw.spacing);
304 void frame_update_attr_nth(WFrame *frame, int i)
306 WRegion *reg;
308 if(i<0 || i>=frame->titles_n)
309 return;
311 frame_update_attr(frame, i, mplex_mx_nth((WMPlex*)frame, i));
315 static void frame_update_attrs(WFrame *frame)
317 int i=0;
318 WRegion *sub;
319 WLListIterTmp tmp;
321 FRAME_MX_FOR_ALL(sub, frame, tmp){
322 frame_update_attr(frame, i, sub);
323 i++;
328 static void frame_free_titles(WFrame *frame)
330 int i;
332 if(frame->titles!=NULL){
333 for(i=0; i<frame->titles_n; i++){
334 if(frame->titles[i].text)
335 free(frame->titles[i].text);
336 gr_stylespec_unalloc(&frame->titles[i].attr);
338 free(frame->titles);
339 frame->titles=NULL;
341 frame->titles_n=0;
345 static void do_init_title(WFrame *frame, int i, WRegion *sub)
347 frame->titles[i].text=NULL;
349 gr_stylespec_init(&frame->titles[i].attr);
351 frame_update_attr(frame, i, sub);
355 static bool frame_initialise_titles(WFrame *frame)
357 int i, n=FRAME_MCOUNT(frame);
359 frame_free_titles(frame);
361 if(n==0)
362 n=1;
364 frame->titles=ALLOC_N(GrTextElem, n);
365 if(frame->titles==NULL)
366 return FALSE;
367 frame->titles_n=n;
369 if(FRAME_MCOUNT(frame)==0){
370 do_init_title(frame, 0, NULL);
371 }else{
372 WLListIterTmp tmp;
373 WRegion *sub;
374 i=0;
375 FRAME_MX_FOR_ALL(sub, frame, tmp){
376 do_init_title(frame, i, sub);
377 i++;
381 frame_recalc_bar(frame, FALSE);
383 return TRUE;
387 /*}}}*/
390 /*{{{ Resize and reparent */
393 bool frame_fitrep(WFrame *frame, WWindow *par, const WFitParams *fp)
395 WRectangle old_geom, mg;
396 bool wchg=(REGION_GEOM(frame).w!=fp->g.w);
397 bool hchg=(REGION_GEOM(frame).h!=fp->g.h);
399 old_geom=REGION_GEOM(frame);
401 if(!window_fitrep(&(frame->mplex.win), par, fp))
402 return FALSE;
404 mplex_managed_geom((WMPlex*)frame, &mg);
406 if(!(frame->flags&FRAME_KEEP_FLAGS)){
407 if(hchg){
408 if(mg.h<=1){
409 frame->flags|=(FRAME_SHADED|FRAME_SAVED_VERT);
410 frame->saved_geom.y=old_geom.y;
411 frame->saved_geom.h=old_geom.h;
412 }else{
413 frame->flags&=~FRAME_SHADED;
415 frame->flags&=~FRAME_MAXED_VERT;
418 if(wchg){
419 if(mg.w<=1){
420 frame->flags|=(FRAME_MIN_HORIZ|FRAME_SAVED_HORIZ);
421 frame->saved_geom.x=old_geom.x;
422 frame->saved_geom.w=old_geom.w;
423 }else{
424 frame->flags&=~FRAME_MIN_HORIZ;
426 frame->flags&=~FRAME_MAXED_HORIZ;
430 if(wchg || hchg){
431 mplex_fit_managed((WMPlex*)frame);
432 mplex_size_changed((WMPlex*)frame, wchg, hchg);
435 return TRUE;
439 void frame_size_hints(WFrame *frame, WSizeHints *hints_ret)
441 WRectangle subgeom;
442 WLListIterTmp tmp;
443 WRegion *sub;
444 int woff, hoff;
446 mplex_managed_geom((WMPlex*)frame, &subgeom);
448 woff=maxof(REGION_GEOM(frame).w-subgeom.w, 0);
449 hoff=maxof(REGION_GEOM(frame).h-subgeom.h, 0);
451 if(FRAME_CURRENT(frame)!=NULL)
452 region_size_hints(FRAME_CURRENT(frame), hints_ret);
453 else
454 sizehints_clear(hints_ret);
456 FRAME_MX_FOR_ALL(sub, frame, tmp){
457 sizehints_adjust_for(hints_ret, sub);
460 if(!USE_MINMAX(frame)){
461 hints_ret->max_set=0;
462 hints_ret->min_set=0;
463 /*hints_ret->base_set=0;*/
464 hints_ret->aspect_set=0;
465 hints_ret->no_constrain=FALSE;
466 /*hints_ret->no_constrain=TRUE;*/
469 if(!hints_ret->min_set){
470 hints_ret->min_width=0;
471 hints_ret->min_height=0;
472 hints_ret->min_set=TRUE;
475 if(!hints_ret->base_set){
476 hints_ret->base_width=0;
477 hints_ret->base_height=0;
478 hints_ret->base_set=TRUE;
481 hints_ret->base_width+=woff;
482 hints_ret->base_height+=hoff;
484 if(hints_ret->max_set) {
485 if(hints_ret->max_width!=INT_MAX)
486 hints_ret->max_width+=woff;
487 if(hints_ret->max_height!=INT_MAX)
488 hints_ret->max_height+=hoff;
491 hints_ret->min_width+=woff;
492 hints_ret->min_height+=hoff;
494 /* shaded */ {
495 int f=frame->flags&(FRAME_SHADED|FRAME_SHADED_TOGGLE);
497 if(f==FRAME_SHADED || f==FRAME_SHADED_TOGGLE){
498 int h=frame_shaded_height(frame);
499 hints_ret->min_height=h;
500 hints_ret->max_height=h;
501 hints_ret->base_height=h;
502 if(!hints_ret->max_set){
503 hints_ret->max_width=INT_MAX;
504 hints_ret->max_set=TRUE;
511 /*}}}*/
514 /*{{{ Client window rqgeom */
517 static void frame_managed_rqgeom_absolute(WFrame *frame, WRegion *sub,
518 const WRQGeomParams *rq,
519 WRectangle *geomret)
521 if(!FORWARD_CWIN_RQGEOM(frame)){
522 region_managed_rqgeom_absolute_default((WRegion*)frame, sub,
523 rq, geomret);
524 }else{
525 WRQGeomParams rq2=RQGEOMPARAMS_INIT;
526 int gravity=ForgetGravity;
527 WRectangle off;
528 WRegion *par;
530 rq2.geom=rq->geom;
531 rq2.flags=rq->flags&(REGION_RQGEOM_WEAK_ALL
532 |REGION_RQGEOM_TRYONLY
533 |REGION_RQGEOM_ABSOLUTE);
535 if(rq->flags&REGION_RQGEOM_GRAVITY)
536 gravity=rq->gravity;
538 mplex_managed_geom(&frame->mplex, &off);
539 off.x=-off.x;
540 off.y=-off.y;
541 off.w=REGION_GEOM(frame).w-off.w;
542 off.h=REGION_GEOM(frame).h-off.h;
544 rq2.geom.w=maxof(rq2.geom.w+off.w, 0);
545 rq2.geom.h=maxof(rq2.geom.h+off.h, 0);
547 /*region_size_hints_correct((WRegion*)frame, &(geom.w), &(geom.h), TRUE);*/
549 /* If WEAK_? is set, then geom.(x|y) is root-relative as it was not
550 * requested by the client and clientwin_handle_configure_request has
551 * no better guess. Otherwise the coordinates are those requested by
552 * the client (modulo borders/gravity) and we interpret them to be
553 * root-relative coordinates for this frame modulo gravity.
555 if(rq->flags&REGION_RQGEOM_WEAK_X)
556 rq2.geom.x+=off.x;
557 else
558 rq2.geom.x+=xgravity_deltax(gravity, -off.x, off.x+off.w);
560 if(rq->flags&REGION_RQGEOM_WEAK_Y)
561 rq2.geom.y+=off.y;
562 else
563 rq2.geom.y+=xgravity_deltay(gravity, -off.y, off.y+off.h);
565 region_rqgeom((WRegion*)frame, &rq2, geomret);
567 if(geomret!=NULL){
568 geomret->x-=off.x;
569 geomret->y-=off.y;
570 geomret->w-=off.w;
571 geomret->h-=off.h;
577 /*}}}*/
580 /*{{{ Frame recreate pholder stuff */
583 static WFramedPHolder *frame_make_recreate_pholder(WFrame *frame, WPHolder *rph)
585 WFramedParam fparam=FRAMEDPARAM_INIT;
586 WFramedPHolder *fph=NULL;
588 if(rph!=NULL){
589 fparam.mode=frame->mode;
591 fph=create_framedpholder(rph, &fparam);
593 if(fph==NULL)
594 destroy_obj((Obj*)rph);
597 return fph;
601 static void mplex_migrate_phs_to_fph(WMPlex *mplex, WFramedPHolder *fph)
603 WMPlexPHolder *phs, *ph;
605 phs=mplex->misc_phs;
606 mplex->misc_phs=NULL;
608 phs->recreate_pholder=fph;
610 for(ph=phs; ph!=NULL; ph=ph->next)
611 ph->mplex=NULL;
616 bool frame_rescue_clientwins(WFrame *frame, WRescueInfo *info)
618 bool ret;
620 ret=mplex_rescue_clientwins(&frame->mplex, info);
622 /* Now, do placeholders.
623 * We can't currently be arsed to keep them ordered with regions...
624 * First we check if we can simply recreate this frame, which takes
625 * care of e.g. floating frames being destroyed when entering full
626 * screen mode. If not, we check if the target would be a WMPlex, and
627 * migrate there. This takes care of frames destroyed in tilings.
629 mplex_flatten_phs(&frame->mplex);
631 if(frame->mplex.misc_phs!=NULL){
632 WPHolder *ret_ph=region_make_return_pholder((WRegion*)frame);
633 WFramedPHolder *fph=frame_make_recreate_pholder(frame, ret_ph);
635 if(fph!=NULL){
636 mplex_migrate_phs_to_fph(&frame->mplex, fph);
637 }else{
638 WPHolder *rescueph=rescueinfo_pholder(info);
639 if(rescueph!=NULL){
640 WRegion *target=pholder_target(rescueph);
641 WMPlex *other_mplex=OBJ_CAST(target, WMPlex);
643 if(other_mplex!=NULL){
644 assert(other_mplex!=&frame->mplex);
645 mplex_migrate_phs(&frame->mplex, other_mplex);
651 return ret;
655 /*}}}*/
658 /*{{{ Misc. */
661 bool frame_set_shaded(WFrame *frame, int sp)
663 bool set=(frame->flags&FRAME_SHADED);
664 bool nset=libtu_do_setparam(sp, set);
665 WRQGeomParams rq=RQGEOMPARAMS_INIT;
666 GrBorderWidths bdw;
667 int h;
669 if(!XOR(nset, set))
670 return nset;
672 rq.flags=REGION_RQGEOM_H_ONLY;
673 rq.geom=REGION_GEOM(frame);
675 if(!nset){
676 if(!(frame->flags&FRAME_SAVED_VERT))
677 return FALSE;
678 rq.geom.h=frame->saved_geom.h;
679 }else{
680 if(frame->barmode==FRAME_BAR_NONE)
681 return FALSE;
682 rq.geom.h=frame_shaded_height(frame);
685 frame->flags|=FRAME_SHADED_TOGGLE;
687 region_rqgeom((WRegion*)frame, &rq, NULL);
689 frame->flags&=~FRAME_SHADED_TOGGLE;
691 return (frame->flags&FRAME_SHADED);
695 /*EXTL_DOC
696 * Set shading state according to the parameter \var{how}
697 * (\codestr{set}, \codestr{unset}, or \codestr{toggle}).
698 * Resulting state is returned, which may not be
699 * what was requested.
701 EXTL_EXPORT_AS(WFrame, set_shaded)
702 bool frame_set_shaded_extl(WFrame *frame, const char *how)
704 return frame_set_shaded(frame, libtu_string_to_setparam(how));
708 /*EXTL_DOC
709 * Is \var{frame} shaded?
711 EXTL_SAFE
712 EXTL_EXPORT_MEMBER
713 bool frame_is_shaded(WFrame *frame)
715 return ((frame->flags&FRAME_SHADED)!=0);
719 /*EXTL_DOC
720 * Is the attribute \var{attr} set on \var{frame}?
722 EXTL_SAFE
723 EXTL_EXPORT_MEMBER
724 bool frame_is_grattr(WFrame *frame, const char *attr)
726 GrAttr a=stringstore_alloc(attr);
727 bool set=gr_stylespec_isset(&frame->baseattr, a);
728 stringstore_free(a);
729 return set;
733 bool frame_set_grattr(WFrame *frame, GrAttr a, int sp)
735 bool set=gr_stylespec_isset(&frame->baseattr, a);
736 bool nset=libtu_do_setparam(sp, set);
738 if(XOR(set, nset)){
739 if(nset)
740 gr_stylespec_set(&frame->baseattr, a);
741 else
742 gr_stylespec_unset(&frame->baseattr, a);
743 window_draw((WWindow*)frame, TRUE);
746 return nset;
750 /*EXTL_DOC
751 * Set extra drawing engine attributes for the frame.
752 * The parameter \var{attr} is the attribute, and \var{how} is
753 * one of \codestr{set}, \codestr{unset}, or \codestr{toggle}.
755 EXTL_EXPORT_AS(WFrame, set_grattr)
756 bool frame_set_grattr_extl(WFrame *frame, const char *attr, const char *how)
758 if(attr!=NULL){
759 GrAttr a=stringstore_alloc(attr);
760 bool ret=frame_set_grattr(frame, a, libtu_string_to_setparam(how));
761 stringstore_free(a);
762 return ret;
763 }else{
764 return FALSE;
769 void frame_managed_notify(WFrame *frame, WRegion *sub, WRegionNotify how)
771 bool complete;
773 if(how==ioncore_g.notifies.activated ||
774 how==ioncore_g.notifies.inactivated ||
775 how==ioncore_g.notifies.name ||
776 how==ioncore_g.notifies.activity ||
777 how==ioncore_g.notifies.sub_activity ||
778 how==ioncore_g.notifies.tag){
780 complete=how==ioncore_g.notifies.name;
782 frame_update_attrs(frame);
783 frame_recalc_bar(frame, complete);
784 frame_draw_bar(frame, complete);
789 static void frame_size_changed_default(WFrame *frame,
790 bool wchg, bool hchg)
792 int bar_w=frame->bar_w;
794 if(wchg)
795 frame_recalc_bar(frame, TRUE);
797 if(frame->barmode==FRAME_BAR_SHAPED &&
798 ((!wchg && hchg) || (wchg && bar_w==frame->bar_w))){
799 frame_set_shape(frame);
804 static void frame_managed_changed(WFrame *frame, int mode, bool sw,
805 WRegion *reg)
807 bool need_draw=TRUE;
809 if(mode!=MPLEX_CHANGE_SWITCHONLY)
810 frame_initialise_titles(frame);
811 else
812 frame_update_attrs(frame);
814 if(sw)
815 need_draw=!frame_set_background(frame, FALSE);
817 if(need_draw)
818 frame_draw_bar(frame, mode!=MPLEX_CHANGE_SWITCHONLY);
820 mplex_call_changed_hook((WMPlex*)frame,
821 frame_managed_changed_hook,
822 mode, sw, reg);
826 WRegion *frame_managed_disposeroot(WFrame *frame, WRegion *reg)
828 if(DEST_EMPTY(frame) &&
829 frame->mplex.mgd!=NULL &&
830 frame->mplex.mgd->reg==reg &&
831 frame->mplex.mgd->mgr_next==NULL){
832 WRegion *tmp=region_disposeroot((WRegion*)frame);
833 return (tmp!=NULL ? tmp : reg);
836 return reg;
840 int frame_default_index(WFrame *frame)
842 return ioncore_g.frame_default_index;
846 /*}}}*/
849 /*{{{ prepare_manage_transient */
852 WPHolder *frame_prepare_manage_transient(WFrame *frame,
853 const WClientWin *transient,
854 const WManageParams *param,
855 int unused)
857 /* Transient manager searches should not cross tiled frames
858 * unless explicitly floated.
860 if(framemode_is_floating(frame_mode(frame)) ||
861 extl_table_is_bool_set(transient->proptab, "float")){
862 return region_prepare_manage_transient_default((WRegion*)frame,
863 transient,
864 param,
865 unused);
866 }else{
867 return NULL;
872 /*}}}*/
875 /*{{{ Save/load */
878 ExtlTab frame_get_configuration(WFrame *frame)
880 ExtlTab tab=mplex_get_configuration(&frame->mplex);
882 extl_table_sets_i(tab, "mode", frame->mode);
884 if(frame->flags&FRAME_SAVED_VERT){
885 extl_table_sets_i(tab, "saved_y", frame->saved_geom.y);
886 extl_table_sets_i(tab, "saved_h", frame->saved_geom.h);
889 if(frame->flags&FRAME_SAVED_HORIZ){
890 extl_table_sets_i(tab, "saved_x", frame->saved_geom.x);
891 extl_table_sets_i(tab, "saved_w", frame->saved_geom.w);
894 return tab;
899 void frame_do_load(WFrame *frame, ExtlTab tab)
901 int flags=0;
902 int p=0, s=0;
904 if(extl_table_gets_i(tab, "saved_x", &p) &&
905 extl_table_gets_i(tab, "saved_w", &s)){
906 frame->saved_geom.x=p;
907 frame->saved_geom.w=s;
908 frame->flags|=FRAME_SAVED_HORIZ;
911 if(extl_table_gets_i(tab, "saved_y", &p) &&
912 extl_table_gets_i(tab, "saved_h", &s)){
913 frame->saved_geom.y=p;
914 frame->saved_geom.h=s;
915 frame->flags|=FRAME_SAVED_VERT;
918 mplex_load_contents(&frame->mplex, tab);
922 WRegion *frame_load(WWindow *par, const WFitParams *fp, ExtlTab tab)
924 int mode=FRAME_MODE_UNKNOWN;
925 WFrame *frame;
927 if(!extl_table_gets_i(tab, "mode", &mode)){
928 char *tmp;
929 if(extl_table_gets_s(tab, "mode", &tmp)){
930 mode=stringintmap_value(frame_modes, tmp, mode);
931 free(tmp);
935 frame=create_frame(par, fp, mode, "WFrame");
937 if(frame!=NULL)
938 frame_do_load(frame, tab);
940 if(DEST_EMPTY(frame) && frame->mplex.mgd==NULL){
941 if(frame->mplex.misc_phs!=NULL){
942 /* Session management hack */
943 WFramedPHolder *fph;
944 fph=frame_make_recreate_pholder(frame, ioncore_get_load_pholder());
945 if(fph!=NULL)
946 mplex_migrate_phs_to_fph(&frame->mplex, fph);
949 destroy_obj((Obj*)frame);
950 return NULL;
953 return (WRegion*)frame;
957 /*}}}*/
960 /*{{{ Dynfuntab and class info */
963 static DynFunTab frame_dynfuntab[]={
964 {region_size_hints, frame_size_hints},
966 {mplex_managed_changed, frame_managed_changed},
967 {mplex_size_changed, frame_size_changed_default},
968 {region_managed_notify, frame_managed_notify},
970 {region_activated, frame_activated},
971 {region_inactivated, frame_inactivated},
973 {(DynFun*)window_press, (DynFun*)frame_press},
975 {(DynFun*)region_get_configuration,
976 (DynFun*)frame_get_configuration},
978 {window_draw,
979 frame_draw},
981 {mplex_managed_geom,
982 frame_managed_geom},
984 {region_updategr,
985 frame_updategr},
987 {(DynFun*)region_fitrep,
988 (DynFun*)frame_fitrep},
990 {(DynFun*)region_managed_disposeroot,
991 (DynFun*)frame_managed_disposeroot},
993 {region_managed_rqgeom_absolute,
994 frame_managed_rqgeom_absolute},
996 {(DynFun*)mplex_default_index,
997 (DynFun*)frame_default_index},
999 {(DynFun*)region_prepare_manage_transient,
1000 (DynFun*)frame_prepare_manage_transient},
1002 {(DynFun*)region_rescue_clientwins,
1003 (DynFun*)frame_rescue_clientwins},
1005 END_DYNFUNTAB
1009 EXTL_EXPORT
1010 IMPLCLASS(WFrame, WMPlex, frame_deinit, frame_dynfuntab);
1013 /*}}}*/