]> git.decadent.org.uk Git - ion3.git/blob - ioncore/region.c
10f7c28f851bfdff14bc8e888341a6c7d06d62ef
[ion3.git] / ioncore / region.c
1 /*
2  * ion/ioncore/region.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
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.
10  */
11
12 #include <string.h>
13
14 #include <libtu/objp.h>
15 #include <libextl/extl.h>
16 #include <libmainloop/defer.h>
17
18 #include "common.h"
19 #include "global.h"
20 #include "region.h"
21 #include "focus.h"
22 #include "regbind.h"
23 #include "names.h"
24 #include "resize.h"
25 #include "manage.h"
26 #include "extlconv.h"
27 #include "activity.h"
28 #include "region-iter.h"
29 #include "return.h"
30
31
32 #define D2(X)
33
34
35 WHook *region_notify_hook=NULL;
36
37
38 static void region_notify_change_(WRegion *reg, WRegionNotify how);
39
40
41 /*{{{ Init & deinit */
42
43
44 void region_init(WRegion *reg, WWindow *par, const WFitParams *fp)
45 {
46     if(fp->g.w<0 || fp->g.h<0)
47         warn(TR("Creating region with negative width or height!"));
48     
49     reg->geom=fp->g;
50     reg->flags=0;
51     reg->bindings=NULL;
52     reg->rootwin=NULL;
53     
54     reg->children=NULL;
55     reg->parent=NULL;
56     reg->p_next=NULL;
57     reg->p_prev=NULL;
58     
59     reg->active_sub=NULL;
60     reg->active_prev=NULL;
61     reg->active_next=NULL;
62     
63     reg->ni.name=NULL;
64     reg->ni.inst_off=0;
65     reg->ni.node=NULL;
66     
67     reg->manager=NULL;
68     
69     reg->submapstat=NULL;
70     
71     reg->mgd_activity=FALSE;
72
73     if(par!=NULL){
74         reg->rootwin=((WRegion*)par)->rootwin;
75         region_set_parent(reg, par);
76     }else{
77         assert(OBJ_IS(reg, WRootWin));
78     }
79 }
80
81
82 static void destroy_children(WRegion *reg)
83 {
84     WRegion *sub, *prev=NULL;
85     bool complained=FALSE;
86     
87     /* destroy children */
88     while(1){
89         sub=reg->children;
90         if(sub==NULL)
91             break;
92         assert(!OBJ_IS_BEING_DESTROYED(sub));
93         assert(sub!=prev);
94         if(ioncore_g.opmode!=IONCORE_OPMODE_DEINIT && !complained && OBJ_IS(reg, WClientWin)){
95             warn(TR("Destroying object \"%s\" with client windows as "
96                     "children."), region_name(reg));
97             complained=TRUE;
98         }
99         prev=sub;
100         destroy_obj((Obj*)sub);
101     }
102 }
103
104
105 void region_deinit(WRegion *reg)
106 {
107     region_notify_change(reg, ioncore_g.notifies.deinit);
108     
109     destroy_children(reg);
110
111     if(ioncore_g.focus_next==reg){
112         D(warn("Region to be focused next destroyed[1]."));
113         ioncore_g.focus_next=NULL;
114     }
115
116     region_detach_manager(reg);
117     region_unset_return(reg);
118     region_unset_parent(reg);
119     region_remove_bindings(reg);
120     
121     region_unregister(reg);
122
123     region_focuslist_deinit(reg);
124
125     if(ioncore_g.focus_next==reg){
126         D(warn("Region to be focused next destroyed[2]."));
127         ioncore_g.focus_next=NULL;
128     }
129 }
130
131
132 /*}}}*/
133
134
135 /*{{{ Dynfuns */
136
137
138 bool region_fitrep(WRegion *reg, WWindow *par, const WFitParams *fp)
139 {
140     bool ret=FALSE;
141     CALL_DYN_RET(ret, bool, region_fitrep, reg, (reg, par, fp));
142     return ret;
143 }
144
145
146 void region_updategr(WRegion *reg)
147 {
148     CALL_DYN(region_updategr, reg, (reg));
149 }
150
151
152 void region_map(WRegion *reg)
153 {
154     CALL_DYN(region_map, reg, (reg));
155     region_notify_change_(reg, ioncore_g.notifies.map);
156 }
157
158
159 void region_unmap(WRegion *reg)
160 {
161     CALL_DYN(region_unmap, reg, (reg));
162     region_notify_change_(reg, ioncore_g.notifies.unmap);
163 }
164
165
166 void region_notify_rootpos(WRegion *reg, int x, int y)
167 {
168     CALL_DYN(region_notify_rootpos, reg, (reg, x, y));
169 }
170
171
172 Window region_xwindow(const WRegion *reg)
173 {
174     Window ret=None;
175     CALL_DYN_RET(ret, Window, region_xwindow, reg, (reg));
176     return ret;
177 }
178
179
180 void region_activated(WRegion *reg)
181 {
182     CALL_DYN(region_activated, reg, (reg));
183 }
184
185
186 void region_inactivated(WRegion *reg)
187 {
188     CALL_DYN(region_inactivated, reg, (reg));
189 }
190
191
192 void region_do_set_focus(WRegion *reg, bool warp)
193 {
194     CALL_DYN(region_do_set_focus, reg, (reg, warp));
195 }
196
197
198 /*{{{ Manager region dynfuns */
199
200
201 static bool region_managed_prepare_focus_default(WRegion *mgr, WRegion *reg, 
202                                                  int flags, 
203                                                  WPrepareFocusResult *res)
204 {
205     if(!region_prepare_focus(mgr, flags, res))
206         return FALSE;
207     
208     res->reg=reg;
209     res->flags=flags;
210     return TRUE;
211 }
212
213     
214 bool region_managed_prepare_focus(WRegion *mgr, WRegion *reg, 
215                                   int flags, 
216                                   WPrepareFocusResult *res)
217 {
218     bool ret=TRUE;
219     CALL_DYN_RET(ret, bool, region_managed_prepare_focus, mgr, 
220                  (mgr, reg, flags, res));
221     return ret;
222 }
223
224
225 void region_managed_notify(WRegion *mgr, WRegion *reg, WRegionNotify how)
226 {
227     CALL_DYN(region_managed_notify, mgr, (mgr, reg, how));
228 }
229
230
231 void region_managed_remove(WRegion *mgr, WRegion *reg)
232 {
233     CALL_DYN(region_managed_remove, mgr, (mgr, reg));
234 }
235
236
237 /*EXTL_DOC
238  * Return the object, if any, that is considered ''currently active''
239  * within the objects managed by \var{mplex}.
240  */
241 EXTL_SAFE
242 EXTL_EXPORT_MEMBER
243 WRegion *region_current(WRegion *mgr)
244 {
245     WRegion *ret=NULL;
246     CALL_DYN_RET(ret, WRegion*, region_current, mgr, (mgr));
247     return ret;
248 }
249
250
251 void region_child_removed(WRegion *reg, WRegion *sub)
252 {
253     CALL_DYN(region_child_removed, reg, (reg, sub));
254 }
255
256
257 /*}}}*/
258
259
260 /*{{{ Dynfun defaults */
261
262
263 void region_updategr_default(WRegion *reg)
264 {
265     WRegion *sub=NULL;
266     
267     FOR_ALL_CHILDREN(reg, sub){
268         region_updategr(sub);
269     }
270 }
271
272
273 /*}}}*/
274
275
276 /*}}}*/
277
278
279 /*{{{ Goto */
280
281
282 bool region_prepare_focus(WRegion *reg, int flags, 
283                           WPrepareFocusResult *res)
284 {
285
286     if(!REGION_IS_ACTIVE(reg) || !REGION_IS_MAPPED(reg)){
287         WRegion *mgr=REGION_MANAGER(reg);
288         WRegion *par=REGION_PARENT_REG(reg);
289         
290         if(mgr!=NULL){
291             return region_managed_prepare_focus(mgr, reg, flags, res);
292         }else if(par!=NULL){
293             if(!region_prepare_focus(par, flags, res))
294                 return FALSE;
295             /* Just focus reg, if it has no manager, and parent can be 
296              * focused. 
297              */
298         }else if(!REGION_IS_MAPPED(reg)){
299             region_map(reg);
300         }
301     }
302     
303     res->reg=reg;
304     res->flags=flags;
305     return TRUE;
306 }
307
308
309 bool region_goto_flags(WRegion *reg, int flags)
310 {
311     WPrepareFocusResult res;
312     bool ret;
313     
314     ret=region_prepare_focus(reg, flags, &res);
315     
316     if(res.reg!=NULL){
317         if(res.flags&REGION_GOTO_FOCUS)
318             region_maybewarp(res.reg, !(res.flags&REGION_GOTO_NOWARP));
319     }
320     
321     return ret;
322 }
323
324
325 /*EXTL_DOC
326  * Attempt to display \var{reg}, save region activity status and then
327  * warp to (or simply set focus to if warping is disabled) \var{reg}.
328  * 
329  * Note that this function is asynchronous; the region will not
330  * actually have received the focus when this function returns.
331  */
332 EXTL_EXPORT_MEMBER
333 bool region_goto(WRegion *reg)
334 {
335     return region_goto_flags(reg, REGION_GOTO_FOCUS);
336 }
337
338
339 /*}}}*/
340
341
342 /*{{{ Fit/reparent */
343
344
345 void region_fit(WRegion *reg, const WRectangle *geom, WRegionFitMode mode)
346 {
347     WFitParams fp;
348     fp.g=*geom;
349     fp.mode=mode&~REGION_FIT_GRAVITY;
350     fp.gravity=ForgetGravity;
351     region_fitrep(reg, NULL, &fp);
352 }
353
354
355 bool region_reparent(WRegion *reg, WWindow *par,
356                      const WRectangle *geom, WRegionFitMode mode)
357 {
358     WFitParams fp;
359     fp.g=*geom;
360     fp.mode=mode;
361     return region_fitrep(reg, par, &fp);
362 }
363
364
365 /*}}}*/
366
367
368 /*{{{ Close */
369
370
371 static void region_rqclose_default(WRegion *reg, bool relocate)
372 {
373     if(relocate || region_may_dispose(reg))
374         region_defer_rqdispose(reg);
375 }
376
377
378 /*EXTL_DOC
379  * Attempt to close/destroy \var{reg}. Whether this operation works
380  * depends on whether the particular type of region in question has
381  * implemented the feature and, in case of client windows, whether
382  * the client supports the \code{WM_DELETE} protocol (see also
383  * \fnref{WClientWin.kill}). The region will not be destroyed when
384  * this function returns. To find out if and when it is destroyed,
385  * use the "deinit" notification. If \var{relocate} is not set, and
386  * \var{reg} manages other regions, it will not be closed. Otherwise
387  * the managed regions will be attempted to be relocated.
388  */
389 EXTL_EXPORT_MEMBER
390 void region_rqclose(WRegion *reg, bool relocate)
391 {
392     CALL_DYN(region_rqclose, reg, (reg, relocate));
393 }
394
395
396 static WRegion *region_rqclose_propagate_default(WRegion *reg, 
397                                                  WRegion *maybe_sub)
398 {
399     if(maybe_sub==NULL)
400         maybe_sub=region_current(reg);
401     
402     if(maybe_sub!=NULL){
403         return region_rqclose_propagate(maybe_sub, NULL);
404     }else{
405         region_rqclose(reg, FALSE);
406         return reg;
407     }
408 }
409
410
411 /*EXTL_DOC
412  * Recursively attempt to close a region or one of the regions managed by 
413  * it. If \var{sub} is set, it will be used as the managed region, otherwise
414  * \fnref{WRegion.current}\code{(reg)}. The object to be closed is
415  * returned, or NULL if nothing can be closed. For further details, see
416  * notes for \fnref{WRegion.rqclose}.
417  */
418 EXTL_EXPORT_MEMBER
419 WRegion *region_rqclose_propagate(WRegion *reg, WRegion *maybe_sub)
420 {
421     WRegion *ret=NULL;
422     CALL_DYN_RET(ret, WRegion*, region_rqclose_propagate, reg,
423                  (reg, maybe_sub));
424     return ret;
425 }
426
427
428 bool region_may_dispose_default(WRegion *reg)
429 {
430     bool res=region_rescue_needed(reg);
431     
432     if(res){
433         const char *name=region_name(reg);
434         warn(TR("Can not destroy %s: contains client windows."),
435              (name!=NULL ? name : TR("(unknown)")));
436     }
437     
438     return !res;
439 }
440
441
442 bool region_may_dispose(WRegion *reg)
443 {
444     bool ret=TRUE;
445     CALL_DYN_RET(ret, bool, region_may_dispose, reg, (reg));
446     return ret;
447 }
448
449
450 static WRegion *region_managed_disposeroot_default(WRegion *mgr, WRegion *reg)
451 {
452     return reg;
453 }
454
455
456 WRegion *region_managed_disposeroot(WRegion *mgr, WRegion *reg)
457 {
458     WRegion *ret=NULL;
459     CALL_DYN_RET(ret, WRegion*, region_managed_disposeroot, mgr, (mgr, reg));
460     return ret;
461 }
462
463
464 WRegion *region_disposeroot(WRegion *reg)
465 {
466     WRegion *mgr=REGION_MANAGER(reg);
467     
468     return (mgr!=NULL
469             ? region_managed_disposeroot(mgr, reg)
470             : reg);
471 }
472
473
474 bool region_rqdispose(WRegion *reg)
475 {
476     WRegion *root;
477     
478     if(!region_may_dispose(reg))
479         return FALSE;
480     
481     root=region_disposeroot(reg);
482     
483     if(root==NULL)
484         return FALSE;
485
486     return region_dispose(root);
487 }
488
489
490 bool region_dispose_(WRegion *reg, bool not_simple)
491 {
492     bool rescue=not_simple;
493     bool was_mcf=(not_simple && region_may_control_focus(reg));
494     WPHolder *ph=NULL;
495     
496     if(rescue){
497         if(!region_rescue(reg, NULL)){
498             warn(TR("Failed to rescue some client windows - not closing."));
499             return FALSE;
500         }
501     }
502
503     if(was_mcf)
504         ph=region_unset_get_return(reg);
505     
506     destroy_obj((Obj*)reg);
507     
508     if(ph!=NULL){
509         pholder_goto(ph);
510         destroy_obj((Obj*)ph);
511     }
512     
513     return TRUE;
514 }
515
516
517 bool region_dispose(WRegion *reg)
518 {
519     return region_dispose_(reg, TRUE);
520 }
521
522
523 void region_defer_rqdispose(WRegion *reg)
524 {
525     mainloop_defer_action((Obj*)reg, (WDeferredAction*)region_rqdispose);
526 }
527
528
529 /*}}}*/
530
531
532 /*{{{ Manager/parent stuff */
533
534
535 /* Routine to call to unmanage a region */
536 void region_detach_manager(WRegion *reg)
537 {
538     WRegion *mgr=REGION_MANAGER(reg);
539     
540     if(mgr==NULL)
541         return;
542     
543     region_set_activity(reg, SETPARAM_UNSET);
544
545     region_managed_remove(mgr, reg);
546
547     assert(REGION_MANAGER(reg)==NULL);
548 }
549
550
551 void region_unset_manager_pseudoactivity(WRegion *reg)
552 {
553     WRegion *mgr=reg->manager, *par=REGION_PARENT_REG(reg);
554     
555     if(mgr==NULL || mgr==par || !REGION_IS_PSEUDOACTIVE(mgr))
556         return;
557         
558     mgr->flags&=~REGION_PSEUDOACTIVE;
559     
560     region_notify_change(mgr, ioncore_g.notifies.pseudoinactivated);
561     
562     region_unset_manager_pseudoactivity(mgr);
563 }
564
565
566 void region_set_manager_pseudoactivity(WRegion *reg)
567 {
568     WRegion *mgr=reg->manager, *par=REGION_PARENT_REG(reg);
569     
570     if(!REGION_IS_ACTIVE(reg) && !REGION_IS_PSEUDOACTIVE(reg))
571         return;
572         
573     if(mgr==NULL || mgr==par || REGION_IS_PSEUDOACTIVE(mgr))
574         return;
575     
576     mgr->flags|=REGION_PSEUDOACTIVE;
577     
578     region_notify_change(mgr, ioncore_g.notifies.pseudoactivated);
579     
580     region_set_manager_pseudoactivity(mgr);
581 }
582
583
584 /* This should only be called within region_managed_remove,
585  * _after_ any managed lists and other essential structures
586  * of mgr have been broken.
587  */
588 void region_unset_manager(WRegion *reg, WRegion *mgr)
589 {
590     if(reg->manager!=mgr)
591         return;
592         
593     region_notify_change_(reg, ioncore_g.notifies.unset_manager);
594     
595     region_unset_manager_pseudoactivity(reg);
596     
597     reg->manager=NULL;
598     
599     if(region_is_activity_r(reg))
600         region_clear_mgd_activity(mgr);
601     
602     region_unset_return(reg);
603 }
604
605
606 /* This should be called within region attach routines,
607  * _after_ any managed lists and other essential structures
608  * of mgr have been set up.
609  */
610 void region_set_manager(WRegion *reg, WRegion *mgr)
611 {
612     assert(reg->manager==NULL);
613     
614     reg->manager=mgr;
615     
616     region_set_manager_pseudoactivity(reg);
617     
618     if(region_is_activity_r(reg))
619         region_mark_mgd_activity(mgr);
620     
621     region_notify_change_(reg, ioncore_g.notifies.set_manager);
622 }
623
624
625 void region_set_parent(WRegion *reg, WWindow *parent)
626 {
627     assert(reg->parent==NULL && parent!=NULL);
628     LINK_ITEM(((WRegion*)parent)->children, reg, p_next, p_prev);
629     reg->parent=parent;
630 }
631
632
633 void region_unset_parent(WRegion *reg)
634 {
635     WRegion *p=REGION_PARENT_REG(reg);
636
637     if(p==NULL || p==reg)
638         return;
639
640     UNLINK_ITEM(p->children, reg, p_next, p_prev);
641     reg->parent=NULL;
642
643     if(p->active_sub==reg){
644         p->active_sub=NULL;
645         region_update_owned_grabs(p);
646     }
647     
648     region_child_removed(p, reg);
649 }
650
651
652 /*EXTL_DOC
653  * Returns the region that manages \var{reg}.
654  */
655 EXTL_SAFE
656 EXTL_EXPORT_MEMBER
657 WRegion *region_manager(WRegion *reg)
658 {
659     return reg->manager;
660 }
661
662
663 /*EXTL_DOC
664  * Returns the parent region of \var{reg}.
665  */
666 EXTL_SAFE
667 EXTL_EXPORT_MEMBER
668 WWindow *region_parent(WRegion *reg)
669 {
670     return reg->parent;
671 }
672
673
674 WRegion *region_manager_or_parent(WRegion *reg)
675 {
676     if(reg->manager!=NULL)
677         return reg->manager;
678     else
679         return (WRegion*)(reg->parent);
680 }
681
682
683 WRegion *region_get_manager_chk(WRegion *p, const ClassDescr *descr)
684 {
685     WRegion *mgr=NULL;
686     
687     if(p!=NULL){
688         mgr=REGION_MANAGER(p);
689         if(obj_is((Obj*)mgr, descr))
690             return mgr;
691     }
692     
693     return NULL;
694 }
695
696 /*}}}*/
697
698
699 /*{{{ Stacking and ordering */
700
701
702 static void region_stacking_default(WRegion *reg, 
703                                     Window *bottomret, Window *topret)
704 {
705     Window win=region_xwindow(reg);
706     *bottomret=win;
707     *topret=win;
708 }
709
710
711 void region_stacking(WRegion *reg, Window *bottomret, Window *topret)
712 {
713     CALL_DYN(region_stacking, reg, (reg, bottomret, topret));
714 }
715
716
717 void region_restack(WRegion *reg, Window other, int mode)
718 {
719     CALL_DYN(region_restack, reg, (reg, other, mode));
720 }
721
722
723
724 bool region_managed_rqorder(WRegion *reg, WRegion *sub, WRegionOrder order)
725 {
726     bool ret=FALSE;
727     CALL_DYN_RET(ret, bool, region_managed_rqorder, reg, (reg, sub, order));
728     return ret;
729 }
730
731
732 bool region_rqorder(WRegion *reg, WRegionOrder order)
733 {
734     WRegion *mgr=REGION_MANAGER(reg);
735     
736     if(mgr==NULL)
737         return FALSE;
738     else
739         return region_managed_rqorder(mgr, reg, order);
740 }
741
742
743 /*EXTL_DOC
744  * Request ordering. Currently supported values for \var{ord}
745  * are 'front' and 'back'.
746  */
747 EXTL_EXPORT_AS(WRegion, rqorder)
748 bool region_rqorder_extl(WRegion *reg, const char *ord)
749 {
750     WRegionOrder order;
751     
752     if(strcmp(ord, "front")==0){
753         order=REGION_ORDER_FRONT;
754     }else if(strcmp(ord, "back")==0){
755         order=REGION_ORDER_BACK;
756     }else{
757         return FALSE;
758     }
759     
760     return region_rqorder(reg, order);
761 }
762
763
764 /*}}}*/
765
766
767 /*{{{ Misc. */
768
769
770 /*EXTL_DOC
771  * Returns the root window \var{reg} is on.
772  */
773 EXTL_SAFE
774 EXTL_EXPORT_MEMBER
775 WRootWin *region_rootwin_of(const WRegion *reg)
776 {
777     WRootWin *rw;
778     assert(reg!=NULL); /* Lua interface should not pass NULL reg. */
779     rw=(WRootWin*)(reg->rootwin);
780     assert(rw!=NULL);
781     return rw;
782 }
783
784
785 /*EXTL_DOC
786  * Returns the screen \var{reg} is on.
787  */
788 EXTL_SAFE
789 EXTL_EXPORT_MEMBER
790 WScreen *region_screen_of(WRegion *reg)
791 {
792     while(reg!=NULL){
793         if(OBJ_IS(reg, WScreen))
794             return (WScreen*)reg;
795         reg=REGION_PARENT_REG(reg);
796     }
797     return NULL;
798 }
799
800
801 Window region_root_of(const WRegion *reg)
802 {
803     return WROOTWIN_ROOT(region_rootwin_of(reg));
804 }
805
806
807 bool region_same_rootwin(const WRegion *reg1, const WRegion *reg2)
808 {
809     return (reg1->rootwin==reg2->rootwin);
810 }
811
812
813 /*EXTL_DOC
814  * Is \var{reg} visible/is it and all it's ancestors mapped?
815  */
816 EXTL_SAFE
817 EXTL_EXPORT_AS(WRegion, is_mapped)
818 bool region_is_fully_mapped(WRegion *reg)
819 {
820     for(; reg!=NULL; reg=REGION_PARENT_REG(reg)){
821         if(!REGION_IS_MAPPED(reg))
822             return FALSE;
823     }
824     
825     return TRUE;
826 }
827
828
829 void region_rootpos(WRegion *reg, int *xret, int *yret)
830 {
831     WRegion *par;
832
833     par=REGION_PARENT_REG(reg);
834     
835     if(par==NULL || par==reg){
836         *xret=0;
837         *yret=0;
838         return;
839     }
840     
841     region_rootpos(par, xret, yret);
842     
843     *xret+=REGION_GEOM(reg).x;
844     *yret+=REGION_GEOM(reg).y;
845 }
846
847
848 typedef struct{
849     WRegion *reg;
850     WRegionNotify how;
851 } MRSHP;
852
853
854 static bool mrsh_notify_change(WHookDummy *fn, void *p_)
855 {
856     MRSHP *p=(MRSHP*)p_;
857     
858     fn(p->reg, p->how);
859     
860     return TRUE;
861 }
862
863
864 static bool mrshe_notify_change(ExtlFn fn, void *p_)
865 {
866     MRSHP *p=(MRSHP*)p_;
867     
868     extl_call(fn, "os", NULL, p->reg, stringstore_get(p->how));
869     
870     return TRUE;
871 }
872
873
874 static void region_notify_change_(WRegion *reg, WRegionNotify how)
875 {
876     MRSHP p;
877     
878     p.reg=reg;
879     p.how=how;
880     
881     extl_protect(NULL);
882     hook_call(region_notify_hook, &p, mrsh_notify_change, mrshe_notify_change),
883     extl_unprotect(NULL);
884 }
885
886
887 void region_notify_change(WRegion *reg, WRegionNotify how)
888 {
889     WRegion *mgr=REGION_MANAGER(reg);
890
891     if(mgr!=NULL)
892         region_managed_notify(mgr, reg, how);
893     
894     region_notify_change_(reg, how);
895 }
896
897
898 /*EXTL_DOC
899  * Returns the geometry of \var{reg} within its parent; a table with fields
900  * \var{x}, \var{y}, \var{w} and \var{h}.
901  */
902 EXTL_SAFE
903 EXTL_EXPORT_MEMBER
904 ExtlTab region_geom(WRegion *reg)
905 {
906     return extl_table_from_rectangle(&REGION_GEOM(reg));
907 }
908
909
910 bool region_handle_drop(WRegion *reg, int x, int y, WRegion *dropped)
911 {
912     bool ret=FALSE;
913     CALL_DYN_RET(ret, bool, region_handle_drop, reg, (reg, x, y, dropped));
914     return ret;
915 }
916
917
918 WRegion *region_managed_within(WRegion *reg, WRegion *mgd)
919 {
920     while(mgd!=NULL && 
921           (REGION_PARENT_REG(mgd)==reg ||
922            REGION_PARENT_REG(mgd)==REGION_PARENT_REG(reg))){
923         
924         if(REGION_MANAGER(mgd)==reg)
925             return mgd;
926         mgd=REGION_MANAGER(mgd);
927     }
928     
929     return NULL;
930 }
931
932
933 /*}}}*/
934
935
936 /*{{{ Dynamic function table and class implementation */
937
938
939 static DynFunTab region_dynfuntab[]={
940     {region_managed_rqgeom,
941      region_managed_rqgeom_allow},
942      
943     {region_managed_rqgeom_absolute,
944      region_managed_rqgeom_absolute_default},
945     
946     {region_updategr, 
947      region_updategr_default},
948     
949     {(DynFun*)region_rescue_clientwins,
950      (DynFun*)region_rescue_child_clientwins},
951      
952     {(DynFun*)region_may_dispose,
953      (DynFun*)region_may_dispose_default},
954
955     {(DynFun*)region_prepare_manage,
956      (DynFun*)region_prepare_manage_default},
957
958     {(DynFun*)region_prepare_manage_transient,
959      (DynFun*)region_prepare_manage_transient_default},
960
961     {(DynFun*)region_managed_prepare_focus,
962      (DynFun*)region_managed_prepare_focus_default},
963      
964     {(DynFun*)region_managed_disposeroot,
965      (DynFun*)region_managed_disposeroot_default},
966
967     {(DynFun*)region_rqclose_propagate,
968      (DynFun*)region_rqclose_propagate_default},
969
970     {(DynFun*)region_rqclose,
971      (DynFun*)region_rqclose_default},
972     
973     {(DynFun*)region_displayname,
974      (DynFun*)region_name},
975     
976     {region_stacking, 
977      region_stacking_default},
978     
979     END_DYNFUNTAB
980 };
981
982
983 EXTL_EXPORT
984 IMPLCLASS(WRegion, Obj, region_deinit, region_dynfuntab);
985
986     
987 /*}}}*/
988