X-Git-Url: https://git.decadent.org.uk/gitweb/?p=ion3.git;a=blobdiff_plain;f=ioncore%2Ffocus.c;h=ee3fd86ab796625077e6101b5b8460bdf2d9cc1b;hp=fb2159bf7f992f6ee0dc74f51d2681b3f95b3470;hb=HEAD;hpb=8366314611bf30a0f31d25bf5f5023186fa87692 diff --git a/ioncore/focus.c b/ioncore/focus.c index fb2159b..ee3fd86 100644 --- a/ioncore/focus.c +++ b/ioncore/focus.c @@ -1,12 +1,9 @@ /* * ion/ioncore/focus.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 @@ -25,8 +22,6 @@ WHook *region_do_warp_alt=NULL; -WHook *region_activated_hook=NULL; -WHook *region_inactivated_hook=NULL; /*}}}*/ @@ -35,22 +30,27 @@ WHook *region_inactivated_hook=NULL; /*{{{ Focus list */ -void region_focuslist_remove(WRegion *reg) +void region_focuslist_remove_with_mgrs(WRegion *reg) { + WRegion *mgrp=region_manager_or_parent(reg); + UNLINK_ITEM(ioncore_g.focus_current, reg, active_next, active_prev); + + if(mgrp!=NULL) + region_focuslist_remove_with_mgrs(mgrp); } void region_focuslist_push(WRegion *reg) { - region_focuslist_remove(reg); + region_focuslist_remove_with_mgrs(reg); LINK_ITEM_FIRST(ioncore_g.focus_current, reg, active_next, active_prev); } void region_focuslist_move_after(WRegion *reg, WRegion *after) { - region_focuslist_remove(reg); + region_focuslist_remove_with_mgrs(reg); LINK_ITEM_AFTER(ioncore_g.focus_current, after, reg, active_next, active_prev); } @@ -62,8 +62,8 @@ void region_focuslist_deinit(WRegion *reg) if(replace!=NULL) region_focuslist_move_after(replace, reg); - - region_focuslist_remove(reg); + + UNLINK_ITEM(ioncore_g.focus_current, reg, active_next, active_prev); } @@ -99,6 +99,35 @@ WRegion *ioncore_goto_previous() } +/*EXTL_DOC + * Iterate over focus history until \var{iterfn} returns \code{false}. + * The function is called in protected mode. + * This routine returns \code{true} if it reaches the end of list + * without this happening. + */ +EXTL_EXPORT +bool ioncore_focushistory_i(ExtlFn iterfn) +{ + WRegion *next; + + if(ioncore_g.focus_current==NULL) + return FALSE; + + /* Find the first region on focus history list that isn't currently + * active. + */ + for(next=ioncore_g.focus_current->active_next; + next!=NULL; + next=next->active_next){ + + if(!extl_iter_obj(iterfn, (Obj*)next)) + return FALSE; + } + + return TRUE; +} + + /*}}}*/ @@ -135,10 +164,8 @@ void region_set_await_focus(WRegion *reg) } -static bool region_is_await(WRegion *reg) +static bool region_is_parent(WRegion *reg, WRegion *aw) { - WRegion *aw=(WRegion*)await_watch.obj; - while(aw!=NULL){ if(aw==reg) return TRUE; @@ -149,6 +176,18 @@ static bool region_is_await(WRegion *reg) } +static bool region_is_await(WRegion *reg) +{ + return region_is_parent(reg, (WRegion*)await_watch.obj); +} + + +static bool region_is_focusnext(WRegion *reg) +{ + return region_is_parent(reg, ioncore_g.focus_next); +} + + /* Only keep await status if focus event is to an ancestor of the await * region. */ @@ -161,9 +200,9 @@ static void check_clear_await(WRegion *reg) } -bool ioncore_await_focus() +WRegion *ioncore_await_focus() { - return (await_watch.obj!=NULL); + return (WRegion*)(await_watch.obj); } @@ -175,7 +214,7 @@ bool ioncore_await_focus() void region_got_focus(WRegion *reg) { - WRegion *par, *mgr, *tmp; + WRegion *par; check_clear_await(reg); @@ -188,30 +227,18 @@ void region_got_focus(WRegion *reg) if(!REGION_IS_ACTIVE(reg)){ D(fprintf(stderr, "got focus (inact) %s [%p]\n", OBJ_TYPESTR(reg), reg);) + reg->flags|=REGION_ACTIVE; + region_set_manager_pseudoactivity(reg); par=REGION_PARENT_REG(reg); if(par!=NULL){ par->active_sub=reg; region_update_owned_grabs(par); } - - region_activated(reg); - mgr=REGION_MANAGER(reg); - tmp=reg; - while(mgr!=NULL){ - /* We need to loop over managing non-windows (workspaces) here to - * signal their managers. - */ - region_managed_activated(mgr, tmp); - - if(REGION_PARENT_REG(reg)==mgr) - break; - - tmp=mgr; - mgr=REGION_MANAGER(mgr); - } + region_activated(reg); + region_notify_change(reg, ioncore_g.notifies.activated); }else{ D(fprintf(stderr, "got focus (act) %s [%p]\n", OBJ_TYPESTR(reg), reg);) } @@ -223,16 +250,12 @@ void region_got_focus(WRegion *reg) */ if(reg->active_sub==NULL && !OBJ_IS(reg, WClientWin)) rootwin_install_colormap(region_rootwin_of(reg), None); - - extl_protect(NULL); - hook_call_o(region_activated_hook, (Obj*)reg); - extl_unprotect(NULL); } void region_lost_focus(WRegion *reg) { - WRegion *r, *par; + WRegion *par; if(!REGION_IS_ACTIVE(reg)){ D(fprintf(stderr, "lost focus (inact) %s [%p:]\n", OBJ_TYPESTR(reg), reg);) @@ -260,14 +283,10 @@ void region_lost_focus(WRegion *reg) D(fprintf(stderr, "lost focus (act) %s [%p:]\n", OBJ_TYPESTR(reg), reg);) reg->flags&=~REGION_ACTIVE; - region_inactivated(reg); - r=REGION_MANAGER(reg); - if(r!=NULL) - region_managed_inactivated(r, reg); + region_unset_manager_pseudoactivity(reg); - extl_protect(NULL); - hook_call_o(region_inactivated_hook, (Obj*)reg); - extl_unprotect(NULL); + region_inactivated(reg); + region_notify_change(reg, ioncore_g.notifies.inactivated); } @@ -282,36 +301,38 @@ void region_lost_focus(WRegion *reg) */ EXTL_SAFE EXTL_EXPORT_MEMBER -bool region_is_active(WRegion *reg) +bool region_is_active(WRegion *reg, bool pseudoact_ok) { - return REGION_IS_ACTIVE(reg); + return (REGION_IS_ACTIVE(reg) || + (pseudoact_ok && REGION_IS_PSEUDOACTIVE(reg))); +} + + +bool region_manager_is_focusnext(WRegion *reg) +{ + if(reg==NULL || ioncore_g.focus_next==NULL) + return FALSE; + + if(reg==ioncore_g.focus_next) + return TRUE; + + return region_manager_is_focusnext(REGION_MANAGER(reg)); } bool region_may_control_focus(WRegion *reg) { - WRegion *par, *r2; - if(OBJ_IS_BEING_DESTROYED(reg)) return FALSE; - if(REGION_IS_ACTIVE(reg)) + if(REGION_IS_ACTIVE(reg) || REGION_IS_PSEUDOACTIVE(reg)) return TRUE; - - if(region_is_await(reg)) + + if(region_is_await(reg) || region_is_focusnext(reg)) + return TRUE; + + if(region_manager_is_focusnext(reg)) return TRUE; - - par=REGION_PARENT_REG(reg); - - if(par==NULL || !REGION_IS_ACTIVE(par)) - return FALSE; - - r2=par->active_sub; - while(r2!=NULL && r2!=par){ - if(r2==reg) - return TRUE; - r2=REGION_MANAGER(r2); - } return FALSE; } @@ -331,6 +352,9 @@ void region_finalise_focusing(WRegion* reg, Window win, bool warp) if(warp) region_do_warp(reg); + if(REGION_IS_ACTIVE(reg) && ioncore_await_focus()==NULL) + return; + region_set_await_focus(reg); /*xwindow_do_set_focus(win);*/ XSetInputFocus(ioncore_g.dpy, win, RevertToParent, @@ -391,10 +415,19 @@ void region_do_warp(WRegion *reg) void region_maybewarp(WRegion *reg, bool warp) { ioncore_g.focus_next=reg; + ioncore_g.focus_next_source=IONCORE_FOCUSNEXT_OTHER; ioncore_g.warp_next=(warp && ioncore_g.warp_enabled); } +void region_maybewarp_now(WRegion *reg, bool warp) +{ + ioncore_g.focus_next=NULL; + /* TODO: what if focus isn't set? Should focus_next be reset then? */ + region_do_set_focus(reg, warp && ioncore_g.warp_enabled); +} + + void region_set_focus(WRegion *reg) { region_maybewarp(reg, FALSE); @@ -432,4 +465,48 @@ WRegion *ioncore_current() return ioncore_g.focus_current; } + /*}}}*/ + + +/*{{{ Pointer focus hack */ + + +/* This ugly hack tries to prevent focus change, when the pointer is + * in a window to be unmapped (or destroyed), and that does not have + * the focus, or should not soon have it. + */ +void region_pointer_focus_hack(WRegion *reg) +{ + WRegion *act; + + if(ioncore_g.opmode!=IONCORE_OPMODE_NORMAL) + return; + + if(ioncore_g.focus_next!=NULL && + ioncore_g.focus_next_source<=IONCORE_FOCUSNEXT_POINTERHACK){ + return; + } + + act=ioncore_await_focus(); + + if((REGION_IS_ACTIVE(reg) && act==NULL) || !region_is_fully_mapped(reg)) + return; + + if(act==NULL) + act=ioncore_g.focus_current; + + if(act==NULL || + OBJ_IS_BEING_DESTROYED(act) || + !region_is_fully_mapped(act) || + region_skip_focus(act)){ + return; + } + + region_set_focus(act); + ioncore_g.focus_next_source=IONCORE_FOCUSNEXT_POINTERHACK; +} + + +/*}}}*/ +