X-Git-Url: https://git.decadent.org.uk/gitweb/?p=ion3.git;a=blobdiff_plain;f=ioncore%2Fregion.c;h=47f8f5c3d93fd09feef16123a485929a8a7fd285;hp=dede094fae0db007d9732d37cbbef10987260479;hb=e3aec18706513a87eaa7839dfdaf7e0fcd0d8d2a;hpb=8366314611bf30a0f31d25bf5f5023186fa87692 diff --git a/ioncore/region.c b/ioncore/region.c index dede094..47f8f5c 100644 --- a/ioncore/region.c +++ b/ioncore/region.c @@ -1,12 +1,9 @@ /* * ion/ioncore/region.c * - * Copyright (c) Tuomo Valkonen 1999-2006. + * Copyright (c) Tuomo Valkonen 1999-2009. * - * Ion is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. + * See the included file LICENSE for details. */ #include @@ -26,6 +23,8 @@ #include "extlconv.h" #include "activity.h" #include "region-iter.h" +#include "return.h" +#include "key.h" #define D2(X) @@ -33,8 +32,8 @@ WHook *region_notify_hook=NULL; -static void region_notify_change_(WRegion *reg, const char *how, - Obj *detail); + +static void region_notify_change_(WRegion *reg, WRegionNotify how); /*{{{ Init & deinit */ @@ -73,7 +72,7 @@ void region_init(WRegion *reg, WWindow *par, const WFitParams *fp) reg->rootwin=((WRegion*)par)->rootwin; region_set_parent(reg, par); }else{ - assert(OBJ_IS(reg, WRootWin));/* || OBJ_IS(reg, WScreen));*/ + assert(OBJ_IS(reg, WRootWin)); } } @@ -103,14 +102,19 @@ static void destroy_children(WRegion *reg) void region_deinit(WRegion *reg) { + region_notify_change(reg, ioncore_g.notifies.deinit); + destroy_children(reg); if(ioncore_g.focus_next==reg){ D(warn("Region to be focused next destroyed[1].")); ioncore_g.focus_next=NULL; } - + + assert(reg->submapstat==NULL); + /*region_free_submapstat(reg);*/ region_detach_manager(reg); + region_unset_return(reg); region_unset_parent(reg); region_remove_bindings(reg); @@ -148,12 +152,14 @@ void region_updategr(WRegion *reg) void region_map(WRegion *reg) { CALL_DYN(region_map, reg, (reg)); + region_notify_change_(reg, ioncore_g.notifies.map); } void region_unmap(WRegion *reg) { CALL_DYN(region_unmap, reg, (reg)); + region_notify_change_(reg, ioncore_g.notifies.unmap); } @@ -192,18 +198,6 @@ void region_do_set_focus(WRegion *reg, bool warp) /*{{{ Manager region dynfuns */ -void region_managed_activated(WRegion *mgr, WRegion *reg) -{ - CALL_DYN(region_managed_activated, mgr, (mgr, reg)); -} - - -void region_managed_inactivated(WRegion *mgr, WRegion *reg) -{ - CALL_DYN(region_managed_inactivated, mgr, (mgr, reg)); -} - - static bool region_managed_prepare_focus_default(WRegion *mgr, WRegion *reg, int flags, WPrepareFocusResult *res) @@ -228,7 +222,7 @@ bool region_managed_prepare_focus(WRegion *mgr, WRegion *reg, } -void region_managed_notify(WRegion *mgr, WRegion *reg, const char *how) +void region_managed_notify(WRegion *mgr, WRegion *reg, WRegionNotify how) { CALL_DYN(region_managed_notify, mgr, (mgr, reg, how)); } @@ -241,7 +235,7 @@ void region_managed_remove(WRegion *mgr, WRegion *reg) /*EXTL_DOC - * Return the object, if any, that is considered ''currently active'' + * Return the object, if any, that is considered ``currently active'' * within the objects managed by \var{mplex}. */ EXTL_SAFE @@ -288,14 +282,13 @@ void region_updategr_default(WRegion *reg) bool region_prepare_focus(WRegion *reg, int flags, WPrepareFocusResult *res) { - WRegion *mgr=REGION_MANAGER(reg); - WRegion *par=REGION_PARENT_REG(reg); - if(REGION_IS_MAPPED(reg) && region_may_control_focus(reg)){ - res->reg=reg; - res->flags=0; - return TRUE; - }else{ + if(TRUE /* !REGION_IS_ACTIVE(reg) || + !REGION_IS_MAPPED(reg) || + ioncore_g.focus_next!=NULL*/){ + WRegion *mgr=REGION_MANAGER(reg); + WRegion *par=REGION_PARENT_REG(reg); + if(mgr!=NULL){ return region_managed_prepare_focus(mgr, reg, flags, res); }else if(par!=NULL){ @@ -304,11 +297,14 @@ bool region_prepare_focus(WRegion *reg, int flags, /* Just focus reg, if it has no manager, and parent can be * focused. */ + }else if(!REGION_IS_MAPPED(reg)){ + region_map(reg); } - res->reg=reg; - res->flags=flags; - return TRUE; } + + res->reg=reg; + res->flags=flags; + return TRUE; } @@ -374,31 +370,10 @@ bool region_reparent(WRegion *reg, WWindow *par, /*{{{ Close */ -static bool region_rqclose_default(WRegion *reg, bool relocate) +static void region_rqclose_default(WRegion *reg, bool relocate) { - WPHolder *ph; - bool refuse=TRUE; - - if((!relocate && !region_may_destroy(reg)) || - !region_manager_allows_destroying(reg)){ - return FALSE; - } - - ph=region_get_rescue_pholder(reg); - - if(ph!=NULL){ - refuse=!region_rescue_clientwins(reg, ph); - destroy_obj((Obj*)ph); - } - - if(refuse){ - warn(TR("Failed to rescue some client windows - not closing.")); - return FALSE; - } - - mainloop_defer_destroy((Obj*)reg); - - return TRUE; + if(relocate || region_may_dispose(reg)) + region_defer_rqdispose(reg); } @@ -407,19 +382,16 @@ static bool region_rqclose_default(WRegion *reg, bool relocate) * depends on whether the particular type of region in question has * implemented the feature and, in case of client windows, whether * the client supports the \code{WM_DELETE} protocol (see also - * \fnref{WClientWin.kill}). If the operation is likely to succeed, - * \code{true} is returned, otherwise \code{false}. In most cases the - * region will not have been actually destroyed when this function returns. - * If \var{relocate} is not set, and \var{reg} manages other regions, it - * will not be closed. Otherwise the managed regions will be attempted - * to be relocated. + * \fnref{WClientWin.kill}). The region will not be destroyed when + * this function returns. To find out if and when it is destroyed, + * use the \codestr{deinit} notification. If \var{relocate} is not set, + * and \var{reg} manages other regions, it will not be closed. Otherwise + * the managed regions will be attempted to be relocated. */ EXTL_EXPORT_MEMBER -bool region_rqclose(WRegion *reg, bool relocate) +void region_rqclose(WRegion *reg, bool relocate) { - bool ret=FALSE; - CALL_DYN_RET(ret, bool, region_rqclose, reg, (reg, relocate)); - return ret; + CALL_DYN(region_rqclose, reg, (reg, relocate)); } @@ -428,9 +400,13 @@ static WRegion *region_rqclose_propagate_default(WRegion *reg, { if(maybe_sub==NULL) maybe_sub=region_current(reg); - if(maybe_sub!=NULL) + + if(maybe_sub!=NULL){ return region_rqclose_propagate(maybe_sub, NULL); - return (region_rqclose(reg, FALSE) ? reg : NULL); + }else{ + region_rqclose(reg, FALSE); + return reg; + } } @@ -438,8 +414,8 @@ static WRegion *region_rqclose_propagate_default(WRegion *reg, * Recursively attempt to close a region or one of the regions managed by * it. If \var{sub} is set, it will be used as the managed region, otherwise * \fnref{WRegion.current}\code{(reg)}. The object to be closed is - * returned or NULL if nothing can be closed. Also see notes for - * \fnref{WRegion.rqclose}. + * returned, or NULL if nothing can be closed. For further details, see + * notes for \fnref{WRegion.rqclose}. */ EXTL_EXPORT_MEMBER WRegion *region_rqclose_propagate(WRegion *reg, WRegion *maybe_sub) @@ -451,30 +427,104 @@ WRegion *region_rqclose_propagate(WRegion *reg, WRegion *maybe_sub) } -bool region_may_destroy(WRegion *reg) +bool region_may_dispose_default(WRegion *reg) +{ + bool res=region_rescue_needed(reg); + + if(res){ + const char *name=region_name(reg); + warn(TR("Can not destroy %s: contains client windows."), + (name!=NULL ? name : TR("(unknown)"))); + } + + return !res; +} + + +bool region_may_dispose(WRegion *reg) { bool ret=TRUE; - CALL_DYN_RET(ret, bool, region_may_destroy, reg, (reg)); + CALL_DYN_RET(ret, bool, region_may_dispose, reg, (reg)); return ret; } -bool region_managed_may_destroy(WRegion *mgr, WRegion *reg) +static WRegion *region_managed_disposeroot_default(WRegion *mgr, WRegion *reg) { - bool ret=TRUE; - CALL_DYN_RET(ret, bool, region_managed_may_destroy, mgr, (mgr, reg)); + return reg; +} + + +WRegion *region_managed_disposeroot(WRegion *mgr, WRegion *reg) +{ + WRegion *ret=NULL; + CALL_DYN_RET(ret, WRegion*, region_managed_disposeroot, mgr, (mgr, reg)); return ret; } -bool region_manager_allows_destroying(WRegion *reg) +WRegion *region_disposeroot(WRegion *reg) { WRegion *mgr=REGION_MANAGER(reg); - if(mgr==NULL) - return TRUE; + return (mgr!=NULL + ? region_managed_disposeroot(mgr, reg) + : reg); +} + + +bool region_rqdispose(WRegion *reg) +{ + WRegion *root; + + if(!region_may_dispose(reg)) + return FALSE; + + root=region_disposeroot(reg); + + if(root==NULL) + return FALSE; + + return region_dispose(root); +} + + +bool region_dispose_(WRegion *reg, bool not_simple) +{ + bool rescue=not_simple; + bool was_mcf=(not_simple && region_may_control_focus(reg)); + WPHolder *ph=NULL; + + if(rescue){ + if(!region_rescue(reg, NULL, 0)){ + warn(TR("Failed to rescue some client windows - not closing.")); + return FALSE; + } + } + + if(was_mcf) + ph=region_unset_get_return(reg); + + destroy_obj((Obj*)reg); + + if(ph!=NULL){ + pholder_goto(ph); + destroy_obj((Obj*)ph); + } - return region_managed_may_destroy(mgr, reg); + return TRUE; +} + + +bool region_dispose(WRegion *reg) +{ + return region_dispose_(reg, TRUE); +} + + +void region_defer_rqdispose(WRegion *reg) +{ + mainloop_defer_action((Obj*)reg, (WDeferredAction*)region_rqdispose); } @@ -487,29 +537,11 @@ bool region_manager_allows_destroying(WRegion *reg) /* Routine to call to unmanage a region */ void region_detach_manager(WRegion *reg) { - WRegion *mgr; - - mgr=REGION_MANAGER(reg); + WRegion *mgr=REGION_MANAGER(reg); if(mgr==NULL) return; - /* Restore activity state to non-parent manager */ - if(region_may_control_focus(reg)){ - WRegion *par=REGION_PARENT_REG(reg); - if(par!=NULL && mgr!=par && REGION_PARENT_REG(mgr)==par){ - /* REGION_ACTIVE shouldn't be set for windowless regions - * but make the parent's active_sub point to it - * nevertheless so that region_may_control_focus can - * be made to work. - */ - par->active_sub=mgr; - /*if(region_xwindow(mgr)!=None){*/ - region_do_set_focus(mgr, FALSE); - /*}*/ - } - } - region_set_activity(reg, SETPARAM_UNSET); region_managed_remove(mgr, reg); @@ -518,6 +550,39 @@ void region_detach_manager(WRegion *reg) } +void region_unset_manager_pseudoactivity(WRegion *reg) +{ + WRegion *mgr=reg->manager, *par=REGION_PARENT_REG(reg); + + if(mgr==NULL || mgr==par || !REGION_IS_PSEUDOACTIVE(mgr)) + return; + + mgr->flags&=~REGION_PSEUDOACTIVE; + + region_notify_change(mgr, ioncore_g.notifies.pseudoinactivated); + + region_unset_manager_pseudoactivity(mgr); +} + + +void region_set_manager_pseudoactivity(WRegion *reg) +{ + WRegion *mgr=reg->manager, *par=REGION_PARENT_REG(reg); + + if(!REGION_IS_ACTIVE(reg) && !REGION_IS_PSEUDOACTIVE(reg)) + return; + + if(mgr==NULL || mgr==par || REGION_IS_PSEUDOACTIVE(mgr)) + return; + + mgr->flags|=REGION_PSEUDOACTIVE; + + region_notify_change(mgr, ioncore_g.notifies.pseudoactivated); + + region_set_manager_pseudoactivity(mgr); +} + + /* This should only be called within region_managed_remove, * _after_ any managed lists and other essential structures * of mgr have been broken. @@ -526,13 +591,20 @@ void region_unset_manager(WRegion *reg, WRegion *mgr) { if(reg->manager!=mgr) return; + + region_notify_change_(reg, ioncore_g.notifies.unset_manager); + + region_unset_manager_pseudoactivity(reg); reg->manager=NULL; + /* Reset status, as it is set by manager */ + reg->flags&=~REGION_SKIP_FOCUS; + if(region_is_activity_r(reg)) region_clear_mgd_activity(mgr); - - region_notify_change_(reg, "unset_manager", (Obj*)mgr); + + region_unset_return(reg); } @@ -546,10 +618,12 @@ void region_set_manager(WRegion *reg, WRegion *mgr) reg->manager=mgr; + region_set_manager_pseudoactivity(reg); + if(region_is_activity_r(reg)) region_mark_mgd_activity(mgr); - region_notify_change_(reg, "set_manager", (Obj*)mgr); + region_notify_change_(reg, ioncore_g.notifies.set_manager); } @@ -673,7 +747,7 @@ bool region_rqorder(WRegion *reg, WRegionOrder order) /*EXTL_DOC * Request ordering. Currently supported values for \var{ord} - * are 'front' and 'back'. + * are \codestr{front} and \codestr{back}. */ EXTL_EXPORT_AS(WRegion, rqorder) bool region_rqorder_extl(WRegion *reg, const char *ord) @@ -776,54 +850,53 @@ void region_rootpos(WRegion *reg, int *xret, int *yret) } -static bool mrsh_not(WHookDummy *fn, void *p) +typedef struct{ + WRegion *reg; + WRegionNotify how; +} MRSHP; + + +static bool mrsh_notify_change(WHookDummy *fn, void *p_) { - WRegion *reg=(WRegion*)((void**)p)[0]; - const char *how=(const char*)((void**)p)[1]; - Obj *detail=(Obj*)((void**)p)[2]; + MRSHP *p=(MRSHP*)p_; - fn(reg, how, detail); + fn(p->reg, p->how); return TRUE; } -static bool mrshe_not(ExtlFn fn, void *p) +static bool mrshe_notify_change(ExtlFn fn, void *p_) { - WRegion *reg=(WRegion*)((void**)p)[0]; - const char *how=(const char*)((void**)p)[1]; - Obj *detail=(Obj*)((void**)p)[2]; + MRSHP *p=(MRSHP*)p_; - extl_call(fn, "oso", NULL, reg, how, detail); + extl_call(fn, "os", NULL, p->reg, stringstore_get(p->how)); return TRUE; } -static void region_notify_change_(WRegion *reg, const char *how, - Obj *detail) +static void region_notify_change_(WRegion *reg, WRegionNotify how) { - const void *p[3]; + MRSHP p; + + p.reg=reg; + p.how=how; - p[0]=reg; - p[1]=how; - p[2]=detail; - extl_protect(NULL); - hook_call(region_notify_hook, p, mrsh_not, mrshe_not), + hook_call(region_notify_hook, &p, mrsh_notify_change, mrshe_notify_change), extl_unprotect(NULL); - } -void region_notify_change(WRegion *reg, const char *how) +void region_notify_change(WRegion *reg, WRegionNotify how) { WRegion *mgr=REGION_MANAGER(reg); if(mgr!=NULL) region_managed_notify(mgr, reg, how); - region_notify_change_(reg, how, NULL); + region_notify_change_(reg, how); } @@ -880,6 +953,9 @@ static DynFunTab region_dynfuntab[]={ {(DynFun*)region_rescue_clientwins, (DynFun*)region_rescue_child_clientwins}, + + {(DynFun*)region_may_dispose, + (DynFun*)region_may_dispose_default}, {(DynFun*)region_prepare_manage, (DynFun*)region_prepare_manage_default}, @@ -889,6 +965,9 @@ static DynFunTab region_dynfuntab[]={ {(DynFun*)region_managed_prepare_focus, (DynFun*)region_managed_prepare_focus_default}, + + {(DynFun*)region_managed_disposeroot, + (DynFun*)region_managed_disposeroot_default}, {(DynFun*)region_rqclose_propagate, (DynFun*)region_rqclose_propagate_default},