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