]> git.decadent.org.uk Git - ion3.git/blob - ioncore/region.c
[svn-upgrade] Integrating new upstream version, ion3 (20070720)
[ion3.git] / ioncore / region.c
1 /*
2  * ion/ioncore/region.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
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(!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 \codestr{deinit} notification. If \var{relocate} is not set, 
386  * and \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     /* Reset status, as it is set by manager */
600     reg->flags&=~REGION_SKIP_FOCUS;
601
602     if(region_is_activity_r(reg))
603         region_clear_mgd_activity(mgr);
604     
605     region_unset_return(reg);
606 }
607
608
609 /* This should be called within region attach routines,
610  * _after_ any managed lists and other essential structures
611  * of mgr have been set up.
612  */
613 void region_set_manager(WRegion *reg, WRegion *mgr)
614 {
615     assert(reg->manager==NULL);
616     
617     reg->manager=mgr;
618     
619     region_set_manager_pseudoactivity(reg);
620     
621     if(region_is_activity_r(reg))
622         region_mark_mgd_activity(mgr);
623     
624     region_notify_change_(reg, ioncore_g.notifies.set_manager);
625 }
626
627
628 void region_set_parent(WRegion *reg, WWindow *parent)
629 {
630     assert(reg->parent==NULL && parent!=NULL);
631     LINK_ITEM(((WRegion*)parent)->children, reg, p_next, p_prev);
632     reg->parent=parent;
633 }
634
635
636 void region_unset_parent(WRegion *reg)
637 {
638     WRegion *p=REGION_PARENT_REG(reg);
639
640     if(p==NULL || p==reg)
641         return;
642
643     UNLINK_ITEM(p->children, reg, p_next, p_prev);
644     reg->parent=NULL;
645
646     if(p->active_sub==reg){
647         p->active_sub=NULL;
648         region_update_owned_grabs(p);
649     }
650     
651     region_child_removed(p, reg);
652 }
653
654
655 /*EXTL_DOC
656  * Returns the region that manages \var{reg}.
657  */
658 EXTL_SAFE
659 EXTL_EXPORT_MEMBER
660 WRegion *region_manager(WRegion *reg)
661 {
662     return reg->manager;
663 }
664
665
666 /*EXTL_DOC
667  * Returns the parent region of \var{reg}.
668  */
669 EXTL_SAFE
670 EXTL_EXPORT_MEMBER
671 WWindow *region_parent(WRegion *reg)
672 {
673     return reg->parent;
674 }
675
676
677 WRegion *region_manager_or_parent(WRegion *reg)
678 {
679     if(reg->manager!=NULL)
680         return reg->manager;
681     else
682         return (WRegion*)(reg->parent);
683 }
684
685
686 WRegion *region_get_manager_chk(WRegion *p, const ClassDescr *descr)
687 {
688     WRegion *mgr=NULL;
689     
690     if(p!=NULL){
691         mgr=REGION_MANAGER(p);
692         if(obj_is((Obj*)mgr, descr))
693             return mgr;
694     }
695     
696     return NULL;
697 }
698
699 /*}}}*/
700
701
702 /*{{{ Stacking and ordering */
703
704
705 static void region_stacking_default(WRegion *reg, 
706                                     Window *bottomret, Window *topret)
707 {
708     Window win=region_xwindow(reg);
709     *bottomret=win;
710     *topret=win;
711 }
712
713
714 void region_stacking(WRegion *reg, Window *bottomret, Window *topret)
715 {
716     CALL_DYN(region_stacking, reg, (reg, bottomret, topret));
717 }
718
719
720 void region_restack(WRegion *reg, Window other, int mode)
721 {
722     CALL_DYN(region_restack, reg, (reg, other, mode));
723 }
724
725
726
727 bool region_managed_rqorder(WRegion *reg, WRegion *sub, WRegionOrder order)
728 {
729     bool ret=FALSE;
730     CALL_DYN_RET(ret, bool, region_managed_rqorder, reg, (reg, sub, order));
731     return ret;
732 }
733
734
735 bool region_rqorder(WRegion *reg, WRegionOrder order)
736 {
737     WRegion *mgr=REGION_MANAGER(reg);
738     
739     if(mgr==NULL)
740         return FALSE;
741     else
742         return region_managed_rqorder(mgr, reg, order);
743 }
744
745
746 /*EXTL_DOC
747  * Request ordering. Currently supported values for \var{ord}
748  * are \codestr{front} and \codestr{back}.
749  */
750 EXTL_EXPORT_AS(WRegion, rqorder)
751 bool region_rqorder_extl(WRegion *reg, const char *ord)
752 {
753     WRegionOrder order;
754     
755     if(strcmp(ord, "front")==0){
756         order=REGION_ORDER_FRONT;
757     }else if(strcmp(ord, "back")==0){
758         order=REGION_ORDER_BACK;
759     }else{
760         return FALSE;
761     }
762     
763     return region_rqorder(reg, order);
764 }
765
766
767 /*}}}*/
768
769
770 /*{{{ Misc. */
771
772
773 /*EXTL_DOC
774  * Returns the root window \var{reg} is on.
775  */
776 EXTL_SAFE
777 EXTL_EXPORT_MEMBER
778 WRootWin *region_rootwin_of(const WRegion *reg)
779 {
780     WRootWin *rw;
781     assert(reg!=NULL); /* Lua interface should not pass NULL reg. */
782     rw=(WRootWin*)(reg->rootwin);
783     assert(rw!=NULL);
784     return rw;
785 }
786
787
788 /*EXTL_DOC
789  * Returns the screen \var{reg} is on.
790  */
791 EXTL_SAFE
792 EXTL_EXPORT_MEMBER
793 WScreen *region_screen_of(WRegion *reg)
794 {
795     while(reg!=NULL){
796         if(OBJ_IS(reg, WScreen))
797             return (WScreen*)reg;
798         reg=REGION_PARENT_REG(reg);
799     }
800     return NULL;
801 }
802
803
804 Window region_root_of(const WRegion *reg)
805 {
806     return WROOTWIN_ROOT(region_rootwin_of(reg));
807 }
808
809
810 bool region_same_rootwin(const WRegion *reg1, const WRegion *reg2)
811 {
812     return (reg1->rootwin==reg2->rootwin);
813 }
814
815
816 /*EXTL_DOC
817  * Is \var{reg} visible/is it and all it's ancestors mapped?
818  */
819 EXTL_SAFE
820 EXTL_EXPORT_AS(WRegion, is_mapped)
821 bool region_is_fully_mapped(WRegion *reg)
822 {
823     for(; reg!=NULL; reg=REGION_PARENT_REG(reg)){
824         if(!REGION_IS_MAPPED(reg))
825             return FALSE;
826     }
827     
828     return TRUE;
829 }
830
831
832 void region_rootpos(WRegion *reg, int *xret, int *yret)
833 {
834     WRegion *par;
835
836     par=REGION_PARENT_REG(reg);
837     
838     if(par==NULL || par==reg){
839         *xret=0;
840         *yret=0;
841         return;
842     }
843     
844     region_rootpos(par, xret, yret);
845     
846     *xret+=REGION_GEOM(reg).x;
847     *yret+=REGION_GEOM(reg).y;
848 }
849
850
851 typedef struct{
852     WRegion *reg;
853     WRegionNotify how;
854 } MRSHP;
855
856
857 static bool mrsh_notify_change(WHookDummy *fn, void *p_)
858 {
859     MRSHP *p=(MRSHP*)p_;
860     
861     fn(p->reg, p->how);
862     
863     return TRUE;
864 }
865
866
867 static bool mrshe_notify_change(ExtlFn fn, void *p_)
868 {
869     MRSHP *p=(MRSHP*)p_;
870     
871     extl_call(fn, "os", NULL, p->reg, stringstore_get(p->how));
872     
873     return TRUE;
874 }
875
876
877 static void region_notify_change_(WRegion *reg, WRegionNotify how)
878 {
879     MRSHP p;
880     
881     p.reg=reg;
882     p.how=how;
883     
884     extl_protect(NULL);
885     hook_call(region_notify_hook, &p, mrsh_notify_change, mrshe_notify_change),
886     extl_unprotect(NULL);
887 }
888
889
890 void region_notify_change(WRegion *reg, WRegionNotify how)
891 {
892     WRegion *mgr=REGION_MANAGER(reg);
893
894     if(mgr!=NULL)
895         region_managed_notify(mgr, reg, how);
896     
897     region_notify_change_(reg, how);
898 }
899
900
901 /*EXTL_DOC
902  * Returns the geometry of \var{reg} within its parent; a table with fields
903  * \var{x}, \var{y}, \var{w} and \var{h}.
904  */
905 EXTL_SAFE
906 EXTL_EXPORT_MEMBER
907 ExtlTab region_geom(WRegion *reg)
908 {
909     return extl_table_from_rectangle(&REGION_GEOM(reg));
910 }
911
912
913 bool region_handle_drop(WRegion *reg, int x, int y, WRegion *dropped)
914 {
915     bool ret=FALSE;
916     CALL_DYN_RET(ret, bool, region_handle_drop, reg, (reg, x, y, dropped));
917     return ret;
918 }
919
920
921 WRegion *region_managed_within(WRegion *reg, WRegion *mgd)
922 {
923     while(mgd!=NULL && 
924           (REGION_PARENT_REG(mgd)==reg ||
925            REGION_PARENT_REG(mgd)==REGION_PARENT_REG(reg))){
926         
927         if(REGION_MANAGER(mgd)==reg)
928             return mgd;
929         mgd=REGION_MANAGER(mgd);
930     }
931     
932     return NULL;
933 }
934
935
936 /*}}}*/
937
938
939 /*{{{ Dynamic function table and class implementation */
940
941
942 static DynFunTab region_dynfuntab[]={
943     {region_managed_rqgeom,
944      region_managed_rqgeom_allow},
945      
946     {region_managed_rqgeom_absolute,
947      region_managed_rqgeom_absolute_default},
948     
949     {region_updategr, 
950      region_updategr_default},
951     
952     {(DynFun*)region_rescue_clientwins,
953      (DynFun*)region_rescue_child_clientwins},
954      
955     {(DynFun*)region_may_dispose,
956      (DynFun*)region_may_dispose_default},
957
958     {(DynFun*)region_prepare_manage,
959      (DynFun*)region_prepare_manage_default},
960
961     {(DynFun*)region_prepare_manage_transient,
962      (DynFun*)region_prepare_manage_transient_default},
963
964     {(DynFun*)region_managed_prepare_focus,
965      (DynFun*)region_managed_prepare_focus_default},
966      
967     {(DynFun*)region_managed_disposeroot,
968      (DynFun*)region_managed_disposeroot_default},
969
970     {(DynFun*)region_rqclose_propagate,
971      (DynFun*)region_rqclose_propagate_default},
972
973     {(DynFun*)region_rqclose,
974      (DynFun*)region_rqclose_default},
975     
976     {(DynFun*)region_displayname,
977      (DynFun*)region_name},
978     
979     {region_stacking, 
980      region_stacking_default},
981     
982     END_DYNFUNTAB
983 };
984
985
986 EXTL_EXPORT
987 IMPLCLASS(WRegion, Obj, region_deinit, region_dynfuntab);
988
989     
990 /*}}}*/
991