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