]> git.decadent.org.uk Git - ion3.git/blobdiff - ioncore/focus.c
Update cfg_kludge_flash for Flash 10
[ion3.git] / ioncore / focus.c
index fb2159bf7f992f6ee0dc74f51d2681b3f95b3470..ee3fd86ab796625077e6101b5b8460bdf2d9cc1b 100644 (file)
@@ -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 <libmainloop/hooks.h>
@@ -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;
+}
+
+
+/*}}}*/
+