Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[albireo-dev] New fix for a focus problem

I've been forced to re-implement the solution to test case 3 from this page:

http://wiki.eclipse.org/Albireo_Focus_Management_Test_Cases

The original solution was causing problems with maintaining focus in a swing component after dragging its parent view to another location in the workbench.

The original solution attempted to immediately re-activate the Swing component under certain conditions when it appears to have been temporarily deactivated.

The new solution simply defers deactivation in all cases (under Windows). It later performs the deactivation, but only before the SwingControl is about to re-activated.

I don't particularly like the new solution (nor did I like the old one), but it is the best I've found so far. Deferring the deactivation is harmless, as best I can tell, as long as it is done before another activation is performed.
### Eclipse Workspace Patch 1.0
#P org.eclipse.albireo.core
Index: META-INF/MANIFEST.MF
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.core/META-INF/MANIFEST.MF,v
retrieving revision 1.2
diff -u -r1.2 MANIFEST.MF
--- META-INF/MANIFEST.MF	2 Apr 2008 15:05:42 -0000	1.2
+++ META-INF/MANIFEST.MF	8 May 2008 21:13:16 -0000
@@ -4,7 +4,7 @@
 Bundle-SymbolicName: org.eclipse.albireo.core
 Bundle-Version: 3.3.94
 Bundle-RequiredExecutionEnvironment: J2SE-1.4
-Require-Bundle: org.eclipse.swt
 Export-Package: org.eclipse.albireo.core,
  org.eclipse.albireo.internal;x-internal:=true
 Bundle-Vendor: Albireo Project (Eclipse Foundation)
+Require-Bundle: org.eclipse.swt
Index: src/org/eclipse/albireo/internal/FocusHandler.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.core/src/org/eclipse/albireo/internal/FocusHandler.java,v
retrieving revision 1.20
diff -u -r1.20 FocusHandler.java
--- src/org/eclipse/albireo/internal/FocusHandler.java	6 May 2008 20:09:35 -0000	1.20
+++ src/org/eclipse/albireo/internal/FocusHandler.java	8 May 2008 21:13:16 -0000
@@ -71,6 +71,7 @@
     private int extraTabCount = 0;
     private boolean isActiveSwt;
     private boolean isFocusedSwt;
+    private boolean pendingDeactivate = false;
     
     // Listeners
     private KeyEventDispatcher keyEventDispatcher = new AwtKeyDispatcher();
@@ -304,26 +305,6 @@
         return result;
     }
 
-    // ==============
-    // On Windows, when the embedded frame loses focus to an ancestor which then assigns focus to 
-    // the embedded composite, the composite receives only a Deactivate event and not an Activate
-    // event. This method schedules an async exec, meant to run after the SWT focus change is complete. 
-    // It sends the missing activation when necessary, so that the frame can get back focus.
-    //
-    // This solves the problem where clicking on an RCP view tab causes an embedded Swing control
-    // to lose focus. 
-    protected void postMissingActivation() {
-        assert Platform.isWin32();               // currently only implemented/needed for win32
-        
-        if (!display.isDisposed()) {
-            ThreadingHandler.getInstance().asyncExec(display, new Runnable() {
-                public void run() {
-                    activateEmbeddedFrame();
-                }
-            });
-        }
-    }
-
     // ==== Fix Eclipse bug 216431 on pre-3.4
     // XEmbeddedFrame does not implement the synthesize method, and the Eclipse bug was fixed only for
     // win32, so we do the same in the methods below
@@ -519,11 +500,26 @@
                 case SWT.Activate:
                     isActiveSwt = true;
                     activeBorderless = borderless;
+                    
+                    // Process deferred de-activation first (Windows only). 
+                    // If a deactivation has been deferred (see SWT.Deactivate case below), handle it here. 
+                    // Ideally we would have already deactivated as soon as some other control gets focus, but
+                    // the deactivation code does nothing in that case. On the other hand, if we just ignore 
+                    // the deactivation altogether, the subsequent Activate triggered by this event, does
+                    // nothing and the embedded frame never gets focus. So we do the deactivate right here, 
+                    // just before the activation. 
+                    if (Platform.isWin32() && pendingDeactivate) {
+                        synthesizeWindowActivation(false);
+                        pendingDeactivate = false;
+                    }
+                    
                     if (Platform.isWin32() && (Platform.SWT_VERSION < Platform.SWT_FIX216431) && (synthesizeMethod != null)) {
+                        // Override SWT_AWT-installed listener with the correct way to activate
                         synthesizeWindowActivation(true);
                         if (verboseFocusEvents) {
                             trace("Consuming SWT.Activate event: " + event);
                         }
+                        // Prevent the SWT_AWT-installed listener from running
                         event.type = SWT.None;
                     }
 
@@ -534,17 +530,21 @@
                 case SWT.Deactivate:
                     isActiveSwt = false;
                     activeBorderless = null;
-                    if (Platform.isWin32() && (Platform.SWT_VERSION < Platform.SWT_FIX216431) && (synthesizeMethod != null)) {
-                        synthesizeWindowActivation(false);
-                        if (verboseFocusEvents) {
-                            trace("Consuming SWT.Deactivate event: " + event);
-                        }
-                        event.type = SWT.None;
-                    }
+                    
+                    // On Windows, when the SwingControl temporarily loses focus to an ancestor, and 
+                    // that ancestor then assigns focus right back to it, the SwingControl receives only a 
+                    // Deactivate event and not a subsequent Activate event. This causes the embedded 
+                    // Swing component to lose focus when, for example, clicking on its parent RCP view tab.
+                    //
+                    // To work around this problem, we defer the deactivation
+                    // of the embedded frame here. See the SWT.Activate case above for processing of the 
+                    // deferred event. 
                     if (Platform.isWin32()) {
-                        postMissingActivation();
+                        pendingDeactivate = true;
+                        // Prevent the SWT_AWT-installed listener from running (and deactivating the frame).
+                        event.type = SWT.None;
+                        break;
                     }
-                    break;
                     
                 }
             }

Back to the top