/*
* ion/ioncore/region.c
*
- * Copyright (c) Tuomo Valkonen 1999-2006.
+ * Copyright (c) Tuomo Valkonen 1999-2008.
*
- * 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 <string.h>
#include "extlconv.h"
#include "activity.h"
#include "region-iter.h"
+#include "return.h"
+#include "key.h"
#define D2(X)
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 */
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));
}
}
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);
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);
}
/*{{{ 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)
}
-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));
}
/*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
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){
/* 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;
}
/*{{{ 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);
}
* 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));
}
{
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;
+ }
}
* 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)
}
-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);
}
/* 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);
}
+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.
{
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);
}
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);
}
/*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)
}
-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);
}
{(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},
{(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},