[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
[albireo-dev] Forcing AWT permanent focus loss
|
I've committed code to handle the problem described in:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=60967
As described in comment #6, it is due to temporary focus loss when an
embedded AWT frame is deactivated. Since it is embedded with other
controls in a single SWT shell, a permanent focus loss would be more
appropriate, allowing Swing validation code to be activated.
The new code forces a permanent focus loss when another control in the
same shell is activated. This is a little tricky in general due to lack
of API on the AWT side. Where possible, I use
KeyboardFocusManager.clearGlobalFocusOwner() to make it happen. But if
the previously active embedded AWT frame is no longer the AWT global
focus owner (a rare but possible case), I fall back to a hack of
disabling and re-enabling the current focus owner in the frame. This
fallback is visually noticeable; that's why we shouldn't use it all of
the time.
When the frame for which we forced a permanent focus loss is
re-activated, Component.requestFocus() is called to manually reset focus
to the correct owner.
This feature is optional and can be controlled through
SwingControl.setAWTPermanentFocusLossForced().
### Eclipse Workspace Patch 1.0
#P org.eclipse.albireo.core
Index: src/org/eclipse/albireo/core/AwtEnvironment.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.core/src/org/eclipse/albireo/core/AwtEnvironment.java,v
retrieving revision 1.26
diff -u -r1.26 AwtEnvironment.java
--- src/org/eclipse/albireo/core/AwtEnvironment.java 1 Aug 2008 20:31:36 -0000 1.26
+++ src/org/eclipse/albireo/core/AwtEnvironment.java 4 Aug 2008 20:21:42 -0000
@@ -33,6 +33,7 @@
import org.eclipse.albireo.internal.AwtDialogListener;
import org.eclipse.albireo.internal.FocusDebugging;
import org.eclipse.albireo.internal.FocusHandler;
+import org.eclipse.albireo.internal.GlobalFocusHandler;
import org.eclipse.albireo.internal.Platform;
import org.eclipse.albireo.internal.SwtInputBlocker;
import org.eclipse.swt.SWT;
@@ -46,7 +47,6 @@
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Widget;
/**
@@ -144,6 +144,7 @@
private final Display display;
private final AwtDialogListener dialogListener;
+ private final GlobalFocusHandler globalFocusHandler;
// Private constructor - clients use getInstance() to obtain instances
@@ -201,7 +202,7 @@
// Dismiss AWT popups when SWT menus are shown
initSwingPopupsDismissal();
- initializeEventFilter();
+ globalFocusHandler = new GlobalFocusHandler(display);
}
void dispose() {
@@ -210,7 +211,7 @@
popupParent.setVisible(false);
popupParent.dispose();
}
- disposeEventFilter();
+ globalFocusHandler.dispose();
}
// ======================= Look&Feel initialization =======================
@@ -543,148 +544,10 @@
}
}
- // ----------------------- Event Listening ------------------------------------------
+ // ----------------------- Focus Handling ------------------------------------------
- private SwtEventFilter swtEventFilter;
- private final List listeners = new ArrayList();
-
- public int getCurrentSwtTraversal() {
- assert Display.getCurrent() != null; // On SWT event thread
- return swtEventFilter.currentSwtTraversal;
- }
-
- public Widget getActiveWidget() {
- assert Display.getCurrent() != null; // On SWT event thread
- return swtEventFilter.activeWidget;
- }
-
- public Shell getActiveShell() {
- assert Display.getCurrent() != null; // On SWT event thread
- return swtEventFilter.activeShell;
- }
-
- public SwingControl getActiveEmbedded() {
- assert Display.getCurrent() != null; // On SWT event thread
- return swtEventFilter.activeEmbedded;
- }
-
- public int getLastSwtTraversal() {
- assert Display.getCurrent() != null; // On SWT event thread
- return swtEventFilter.lastSwtTraversal;
- }
-
- public Widget getLastActiveWidget() {
- assert Display.getCurrent() != null; // On SWT event thread
- return swtEventFilter.lastActiveWidget;
- }
-
- public SwingControl getLastActiveEmbedded() {
- assert Display.getCurrent() != null; // On SWT event thread
- return swtEventFilter.lastActiveEmbedded;
- }
-
- public void addEventFilter(Listener filter) {
- listeners.add(filter);
- }
-
- public void removeEventFilter(Listener filter) {
- listeners.remove(filter);
- }
-
- protected void fireEvent(Event event) {
- for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
- Listener listener = (Listener)iterator.next();
- listener.handleEvent(event);
- }
- }
-
- protected void initializeEventFilter() {
- swtEventFilter = new SwtEventFilter();
- display.addFilter(SWT.Activate, swtEventFilter);
- display.addFilter(SWT.Deactivate, swtEventFilter);
- display.addFilter(SWT.Traverse, swtEventFilter);
- }
-
- protected void disposeEventFilter() {
- display.removeFilter(SWT.Activate, swtEventFilter);
- display.removeFilter(SWT.Deactivate, swtEventFilter);
- display.removeFilter(SWT.Traverse, swtEventFilter);
- }
-
- protected class SwtEventFilter implements Listener {
-
- int currentSwtTraversal = SWT.TRAVERSE_NONE;
- Widget activeWidget;
- Shell activeShell;
- SwingControl activeEmbedded;
-
- int lastSwtTraversal = SWT.TRAVERSE_NONE;
- Widget lastActiveWidget = null;
- SwingControl lastActiveEmbedded = null;
-
- public SwtEventFilter() {
- activeWidget = display.getFocusControl();
- activeShell = display.getActiveShell();
- if ((activeWidget instanceof SwingControl) && ((activeWidget.getStyle() & SWT.EMBEDDED) != 0)) {
- activeEmbedded = (SwingControl)activeWidget;
- }
- }
-
- public void handleEvent(Event event) {
- Widget widget = event.widget;
- switch (event.type) {
- case SWT.Activate:
- activeWidget = widget;
-
- // Track the currently active shell. This is more reliable than
- // depending on Display.getActiveShell() which sometimes returns an
- // inactive shell.
- if (widget instanceof Shell) {
- activeShell = (Shell)widget;
- }
-
- if ((widget instanceof SwingControl) && ((widget.getStyle() & SWT.EMBEDDED) != 0)) {
- activeEmbedded = (SwingControl)widget;
- }
-
- if (currentSwtTraversal != SWT.TRAVERSE_NONE) {
- lastSwtTraversal = currentSwtTraversal;
- }
- currentSwtTraversal = SWT.TRAVERSE_NONE;
- break;
-
- case SWT.Deactivate:
- if (activeWidget != null) {
- lastActiveWidget = activeWidget;
- activeWidget = null;
- }
-
- if (event.widget instanceof Shell) {
- activeShell = null;
- }
-
- if ((widget instanceof SwingControl) && ((widget.getStyle() & SWT.EMBEDDED) != 0)) {
- if (activeEmbedded != null) {
- lastActiveEmbedded = activeEmbedded;
- activeEmbedded = null;
- }
- }
-
- break;
-
- case SWT.Traverse:
- currentSwtTraversal = event.detail;
-
- break;
- }
-
- // Propagate to any listeners
- fireEvent(event);
-
-
- }
-
+ protected GlobalFocusHandler getGlobalFocusHandler() {
+ return globalFocusHandler;
}
- // ========================================================================
}
Index: src/org/eclipse/albireo/core/SwingControl.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.core/src/org/eclipse/albireo/core/SwingControl.java,v
retrieving revision 1.88
diff -u -r1.88 SwingControl.java
--- src/org/eclipse/albireo/core/SwingControl.java 24 Jun 2008 19:22:15 -0000 1.88
+++ src/org/eclipse/albireo/core/SwingControl.java 4 Aug 2008 20:21:42 -0000
@@ -40,6 +40,7 @@
import org.eclipse.albireo.internal.CleanResizeListener;
import org.eclipse.albireo.internal.ComponentDebugging;
import org.eclipse.albireo.internal.FocusHandler;
+import org.eclipse.albireo.internal.GlobalFocusHandler;
import org.eclipse.albireo.internal.Platform;
import org.eclipse.albireo.internal.RunnableWithResult;
import org.eclipse.albireo.internal.SwtPopupHandler;
@@ -1077,7 +1078,7 @@
* should be enabled or not.
* <p>
* For this setting to be useful, a background colour should have been
-Â Â * set that approximately matches the window's contents.
+ * set that approximately matches the window's contents.
* <p>
* By default, this setting is enabled on Windows with JDK 1.5 or older, and
* disabled otherwise.
@@ -1254,12 +1255,14 @@
// ============================= Focus Management =============================
private FocusHandler focusHandler;
private boolean isSwtTabOrderExtended = true;
-
+ private boolean isAWTPermanentFocusLossForced = true;
+
protected void initializeFocusManagement() {
assert frame != null;
assert Display.getCurrent() != null; // On SWT event thread
- focusHandler = new FocusHandler(this, borderlessChild, frame);
+ GlobalFocusHandler handler = AwtEnvironment.getInstance(display).getGlobalFocusHandler();
+ focusHandler = new FocusHandler(this, handler, borderlessChild, frame);
}
@@ -1296,7 +1299,38 @@
return isSwtTabOrderExtended;
}
- /**
+ /**
+ * Returns whether a permanent focus lost event is forced on a SwingControl when focus moves to
+ * another SWT component within the same shell. See {@link #setAWTPermanentFocusLossForced(boolean)}
+ * for more information.
+ *
+ * @return boolean
+ */
+ public boolean isAWTPermanentFocusLossForced() {
+ return isAWTPermanentFocusLossForced;
+ }
+
+ /**
+ * Controls whether a permanent focus lost event is forced on a SwingControl when focus moves to
+ * another SWT component within the same shell. Normally, when an AWT frame loses focus to another
+ * window, it only receives a temporary focus lost event. This can cause unexpected results when
+ * the AWT window is embedded in a SWT shell and should really act more like a composite widget
+ * within that shell. If this property is set to <code>true</code> (the default), then
+ * permanent focus loss is synthesized.
+ * <p>
+ * For more information on permanent/temporary focus loss,
+ * see the <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/FocusSpec.html">AWT
+ * Focus Subsystem</a> spec. For an example of the type of problem solved by keeping this property
+ * <code>true</code>, see <a href="http://bugs.eclipse.org/60967">bug 60967</a>.
+ *
+ * @param isAWTPermanentFocusLossForced - <code>true</code> to enable the forcing of permanent
+ * focus loss. <code>false</code> to disable it.
+ */
+ public void setAWTPermanentFocusLossForced(boolean isAWTPermanentFocusLossForced) {
+ this.isAWTPermanentFocusLossForced = isAWTPermanentFocusLossForced;
+ }
+
+ /**
* {@inheritDoc}
* <p>
* Overridden to return false and prevent any focus change if the embedded Swing component is
@@ -1530,7 +1564,7 @@
// ============================= Keystroke Management =============================
Set consumedKeystrokes = new HashSet();
-
+
/**
* Initializes keystroke management for this control.
*/
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.23
diff -u -r1.23 FocusHandler.java
--- src/org/eclipse/albireo/internal/FocusHandler.java 1 Aug 2008 20:31:36 -0000 1.23
+++ src/org/eclipse/albireo/internal/FocusHandler.java 4 Aug 2008 20:21:42 -0000
@@ -27,7 +27,6 @@
import javax.swing.text.Caret;
import javax.swing.text.JTextComponent;
-import org.eclipse.albireo.core.AwtEnvironment;
import org.eclipse.albireo.core.SwingControl;
import org.eclipse.albireo.core.ThreadingHandler;
import org.eclipse.swt.SWT;
@@ -62,13 +61,14 @@
private final Composite borderless; // the Control corresponding to the frame
private final SwingControl swingControl; // either borderless or its parent
private final Display display;
+ private final GlobalFocusHandler globalHandler;
private boolean pendingTraverseOut = false;
private int pendingTraverseOutSeqNum = 0;
private int currentTraverseOutSeqNum = 0;
private int extraTabCount = 0;
private boolean isFocusedSwt;
private boolean pendingDeactivate = false;
- private AwtEnvironment env;
+
// Listeners
private KeyEventDispatcher keyEventDispatcher = new AwtKeyDispatcher();
@@ -76,7 +76,8 @@
private FocusListener swtFocusListener = new SwtFocusListener();
private Listener swtEventFilter = new SwtEventFilter();
- public FocusHandler(final SwingControl swingControl, final Composite borderless, final Frame frame) {
+ public FocusHandler(final SwingControl swingControl, GlobalFocusHandler globalHandler, final Composite borderless, final Frame frame) {
+ this.globalHandler = globalHandler;
assert Display.getCurrent() != null; // On SWT event thread
if (verboseFocusEvents)
@@ -86,11 +87,10 @@
this.borderless = borderless;
this.frame = frame;
display = swingControl.getDisplay();
- env = AwtEnvironment.getInstance(display);
getSynthesizeMethod(frame.getClass());
- env.addEventFilter(swtEventFilter);
+ globalHandler.addEventFilter(swtEventFilter);
frame.addWindowFocusListener(awtWindowFocusListener);
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(keyEventDispatcher);
@@ -100,7 +100,7 @@
}
public void dispose() {
- env.removeEventFilter(swtEventFilter);
+ globalHandler.removeEventFilter(swtEventFilter);
frame.removeWindowFocusListener(awtWindowFocusListener);
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(keyEventDispatcher);
borderless.removeFocusListener(swtFocusListener);
@@ -230,7 +230,7 @@
if (verboseTraverseOut) {
trace("SWT: traversing, control=" + focusControl);
}
- SwingControl activeBorderless = env.getActiveEmbedded();
+ SwingControl activeBorderless = globalHandler.getActiveEmbedded();
if ((focusControl == null) && (activeBorderless != null)) {
focusControl = activeBorderless;
if (verboseTraverseOut) {
@@ -278,7 +278,7 @@
// the SwingControl to be skipped while tabbing. Try to fix it here by resetting
// the forceFocus result back to true when SWT events indicate we really do have
// focus.
- if (!result && (env.getActiveWidget() == borderless) && isFocusedSwt) {
+ if (!result && (globalHandler.getActiveWidget() == borderless) && isFocusedSwt) {
// Force focus should have returned true
result = true;
if (verboseTraverseOut) {
@@ -416,8 +416,8 @@
public void activateEmbeddedFrame() {
assert Display.getCurrent() != null;
- Shell activeShell = env.getActiveShell();
- SwingControl activeBorderless = env.getActiveEmbedded();
+ Shell activeShell = globalHandler.getActiveShell();
+ SwingControl activeBorderless = globalHandler.getActiveEmbedded();
if (!borderless.isDisposed() &&
@@ -457,6 +457,9 @@
}
protected void doActivation(int swtTraversal) {
+ if (swingControl.isDisposed()) {
+ return;
+ }
if (!swingControl.isFocusControl()) {
// We've lost focus, don't activate the underlying AWT window
if (verboseFocusEvents) {
@@ -491,12 +494,12 @@
protected class SwtEventFilter implements Listener {
public void handleEvent(Event event) {
- // Handle activation of the SWT.EMBEDDED composite. Track the currently active one.
+ // Handle activation of the SWT.EMBEDDED composite. Track the currently active one.
if (event.widget == borderless) {
switch (event.type) {
case SWT.Activate:
// The lastSwtTraversal may change before it is used. Save its value for the asyncExecs
- final int swtTraversal = env.getLastSwtTraversal();
+ final int swtTraversal = globalHandler.getLastSwtTraversal();
// We use asyncExec to defer the activation and focus setting in the underlying AWT frame.
// This allows proper handling of the case where focus is briefly
Index: src/org/eclipse/albireo/internal/GlobalFocusHandler.java
===================================================================
RCS file: src/org/eclipse/albireo/internal/GlobalFocusHandler.java
diff -N src/org/eclipse/albireo/internal/GlobalFocusHandler.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/albireo/internal/GlobalFocusHandler.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,261 @@
+package org.eclipse.albireo.internal;
+
+import java.awt.Component;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.KeyboardFocusManager;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.albireo.core.SwingControl;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Widget;
+
+// Handler for global focus events. Maintains global state information like current and
+// previous active widgets. When actions based on global state need to be done, they are
+// implemented in this class. See also the FocusHandler class for additional handling based
+// on a single SwingControl.
+public class GlobalFocusHandler {
+ private static final String SAVED_FOCUS_OWNER_KEY = "org.eclipse.albireo.savedFocusOwner";
+ private final Display display;
+ private final SwtEventFilter swtEventFilter;
+ private final List listeners = new ArrayList();
+ private static final boolean verboseFocusEvents = FocusHandler.verboseFocusEvents;
+
+ public GlobalFocusHandler(Display display) {
+ this.display = display;
+ swtEventFilter = new SwtEventFilter();
+ display.addFilter(SWT.Activate, swtEventFilter);
+ display.addFilter(SWT.Deactivate, swtEventFilter);
+ display.addFilter(SWT.Traverse, swtEventFilter);
+ }
+
+ public int getCurrentSwtTraversal() {
+ assert Display.getCurrent() != null; // On SWT event thread
+ return swtEventFilter.currentSwtTraversal;
+ }
+
+ public Widget getActiveWidget() {
+ assert Display.getCurrent() != null; // On SWT event thread
+ return swtEventFilter.activeWidget;
+ }
+
+ public Shell getActiveShell() {
+ assert Display.getCurrent() != null; // On SWT event thread
+ return swtEventFilter.activeShell;
+ }
+
+ public SwingControl getActiveEmbedded() {
+ assert Display.getCurrent() != null; // On SWT event thread
+ return swtEventFilter.activeEmbedded;
+ }
+
+ public int getLastSwtTraversal() {
+ assert Display.getCurrent() != null; // On SWT event thread
+ return swtEventFilter.lastSwtTraversal;
+ }
+
+ public Widget getLastActiveWidget() {
+ assert Display.getCurrent() != null; // On SWT event thread
+ return swtEventFilter.lastActiveWidget;
+ }
+
+ public SwingControl getLastActiveEmbedded() {
+ assert Display.getCurrent() != null; // On SWT event thread
+ return swtEventFilter.lastActiveEmbedded;
+ }
+
+ public boolean getLastActiveFocusCleared() {
+ assert Display.getCurrent() != null; // On SWT event thread
+ return swtEventFilter.lastActiveFocusCleared;
+ }
+
+ public void setLastActiveFocusCleared(boolean lastActiveFocusCleared) {
+ assert Display.getCurrent() != null; // On SWT event thread
+ swtEventFilter.lastActiveFocusCleared = lastActiveFocusCleared;
+ }
+
+ public void addEventFilter(Listener filter) {
+ listeners.add(filter);
+ }
+
+ public void removeEventFilter(Listener filter) {
+ listeners.remove(filter);
+ }
+
+ protected void fireEvent(Event event) {
+ for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
+ Listener listener = (Listener)iterator.next();
+ listener.handleEvent(event);
+ }
+ }
+
+ public void dispose() {
+ display.removeFilter(SWT.Activate, swtEventFilter);
+ display.removeFilter(SWT.Deactivate, swtEventFilter);
+ display.removeFilter(SWT.Traverse, swtEventFilter);
+ }
+
+ protected boolean isBorderlessSwingControl(Widget widget) {
+ return (widget instanceof SwingControl) && ((widget.getStyle() & SWT.EMBEDDED) != 0);
+ }
+
+ protected void clearFocusOwner(SwingControl swingControl) {
+ assert Display.getCurrent() != null; // On SWT event thread
+
+ if (!swingControl.isAWTPermanentFocusLossForced()) {
+ return;
+ }
+
+ // It appears safe to call getFocusOwner on SWT thread
+ final Component owner = ((Frame)swingControl.getAWTHierarchyRoot()).getFocusOwner();
+ if (owner != null) {
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ // Clear the AWT focus owner so that a permanent focus lost event is
+ // generated. Where possible, we use the KeyboardFocusManager, but
+ // it has no method to clear the focus owner within a particular frame,
+ // if that frame is no longer active. In that case, we use a hack of
+ // disabling and re-enabling the window's focus owner. The hack has
+ // the drawback of a brief visual movement of the cursor (or other
+ // focus indicator), so it is good to avoid it whenever possible, as
+ // we do here.
+ KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ if (owner == kfm.getFocusOwner()) {
+ if (verboseFocusEvents) {
+ trace("clearing focus thru kfm: " + owner);
+ }
+ kfm.clearGlobalFocusOwner();
+ } else {
+ if (verboseFocusEvents) {
+ trace("clearing focus thru hack: " + owner);
+ }
+ owner.setEnabled(false);
+ owner.setEnabled(true);
+ }
+ }
+ });
+ swingControl.setData(SAVED_FOCUS_OWNER_KEY, owner);
+ }
+ }
+
+ protected void restoreFocusOwner(SwingControl swingControl) {
+ assert Display.getCurrent() != null; // On SWT event thread
+
+ final Component savedOwner = (Component)swingControl.getData(SAVED_FOCUS_OWNER_KEY);
+ if (savedOwner != null) {
+ swingControl.setData(SAVED_FOCUS_OWNER_KEY, null);
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ // Restore focus to any AWT component that lost focus due to
+ // clearFocusOwner().
+ if (verboseFocusEvents) {
+ trace("restoring focus: " + savedOwner);
+ }
+ savedOwner.requestFocus();
+ }
+ });
+ }
+ }
+
+ private void trace(String msg) {
+ System.err.println(header() + ' ' + msg);
+ }
+ private String header() {
+ return "@" + System.currentTimeMillis() + " " + System.identityHashCode(this);
+ }
+
+ protected class SwtEventFilter implements Listener {
+
+ int currentSwtTraversal = SWT.TRAVERSE_NONE;
+ Widget activeWidget;
+ Shell activeShell;
+ SwingControl activeEmbedded;
+
+ int lastSwtTraversal = SWT.TRAVERSE_NONE;
+ Widget lastActiveWidget = null;
+ SwingControl lastActiveEmbedded = null;
+ boolean lastActiveFocusCleared = false;
+
+ public SwtEventFilter() {
+ activeWidget = display.getFocusControl();
+ activeShell = display.getActiveShell();
+ if (isBorderlessSwingControl(activeWidget)) {
+ activeEmbedded = (SwingControl)activeWidget;
+ }
+ }
+
+ public void handleEvent(Event event) {
+ Widget widget = event.widget;
+ switch (event.type) {
+ case SWT.Activate:
+ activeWidget = widget;
+
+ // Track the currently active shell. This is more reliable than
+ // depending on Display.getActiveShell() which sometimes returns an
+ // inactive shell.
+ if (widget instanceof Shell) {
+ activeShell = (Shell)widget;
+ }
+
+ if (currentSwtTraversal != SWT.TRAVERSE_NONE) {
+ lastSwtTraversal = currentSwtTraversal;
+ }
+ currentSwtTraversal = SWT.TRAVERSE_NONE;
+
+ // If we have moved from a SwingControl to another control in the same
+ // shell, clear its current focus owner so that a permanent focus
+ // lost event is generated.
+ if ((lastActiveEmbedded != null) && (lastActiveEmbedded != event.widget) &&
+ !lastActiveFocusCleared &&
+ (event.widget instanceof Control) && // (need a getShell() method)
+ (lastActiveEmbedded.getShell() == ((Control)event.widget).getShell())) {
+ clearFocusOwner(lastActiveEmbedded);
+ lastActiveFocusCleared = true;
+ }
+
+ // If we have moved to a SwingControl, restore the current focus owner
+ // that was cleared above during a previous Activate event.
+ if (isBorderlessSwingControl(widget)) {
+ activeEmbedded = (SwingControl)widget;
+ restoreFocusOwner(activeEmbedded);
+ }
+ break;
+
+ case SWT.Deactivate:
+ if (activeWidget != null) {
+ lastActiveWidget = activeWidget;
+ activeWidget = null;
+ }
+
+ if (event.widget instanceof Shell) {
+ activeShell = null;
+ }
+
+ if (isBorderlessSwingControl(widget)) {
+ if (activeEmbedded != null) {
+ lastActiveEmbedded = activeEmbedded;
+ lastActiveFocusCleared = false;
+ activeEmbedded = null;
+ }
+ }
+
+ break;
+
+ case SWT.Traverse:
+ currentSwtTraversal = event.detail;
+
+ break;
+ }
+
+ // Propagate to any listeners
+ fireEvent(event);
+ }
+ }
+}
#P org.eclipse.albireo.examples.plugin
Index: plugin.xml
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.examples.plugin/plugin.xml,v
retrieving revision 1.20
diff -u -r1.20 plugin.xml
--- plugin.xml 14 May 2008 23:18:34 -0000 1.20
+++ plugin.xml 4 Aug 2008 20:21:43 -0000
@@ -99,6 +99,12 @@
name="SWT Bug #58308">
</view>
<view
+ class="org.eclipse.albireo.examples.plugin.views.SWTBug60967"
+ id="org.eclipse.albireo.examples.plugin.60967"
+ category="org.eclipse.albireo"
+ name="SWT Bug #60967">
+ </view>
+ <view
category="org.eclipse.albireo"
class="org.eclipse.albireo.examples.plugin.views.RelayoutExampleView"
id=" org.eclipse.albireo.examples.plugin.relayoutExample "
Index: src/org/eclipse/albireo/examples/plugin/views/SWTBug60967.java
===================================================================
RCS file: src/org/eclipse/albireo/examples/plugin/views/SWTBug60967.java
diff -N src/org/eclipse/albireo/examples/plugin/views/SWTBug60967.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/albireo/examples/plugin/views/SWTBug60967.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,87 @@
+package org.eclipse.albireo.examples.plugin.views;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+import org.eclipse.albireo.core.SwingControl;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.ui.part.ViewPart;
+
+/**
+ * This view allows to check against the SWT bug #58308.
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=58308
+ */
+public class SWTBug60967 extends ViewPart {
+
+ public static String ID = "org.eclipse.albireo.examples.plugin.60967"; //$NON-NLS-1$
+
+ SwingControl swingControl;
+ JComboBox jComboBox1;
+
+ public void createPartControl(final Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new FillLayout());
+
+ swingControl = new SwingControl(composite, SWT.NONE) {
+
+ protected JComponent createSwingComponent() {
+ JComponent container = new JPanel();
+ container.setLayout(new BorderLayout());
+ jComboBox1 = new JComboBox();
+ jComboBox1.setEditable(true);
+ jComboBox1.addFocusListener(new FocusListener() {
+ public void focusGained(FocusEvent e) {
+ System.out.println("gained");
+ }
+ public void focusLost(FocusEvent e) {
+ System.out.println("lost");
+ }
+ });
+ container.add(jComboBox1, BorderLayout.NORTH);
+ JButton button = new JButton("Press");
+ container.add(button, BorderLayout.SOUTH);
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ System.out.println("selection=" + jComboBox1.getSelectedItem());
+ }
+ });
+ return container;
+ }
+
+ public Composite getLayoutAncestor() {
+ return getParent();
+ }
+ };
+ // Uncomment this line, to disable the Albireo workaround and thus demonstrate the bug
+ // swingControl.setAWTPermanentFocusLossForced(false);
+
+ Button swtButton = new Button(composite, SWT.PUSH);
+ swtButton.setText("SWT Button");
+
+ swtButton.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event event) {
+ // If the workaround is successful, any changes to the combobox contents
+ // will be seen here when the SWT button is pushed.
+ System.out.println("selected=" + jComboBox1.getSelectedItem());
+ }
+ });
+ }
+
+ public void setFocus() {
+ swingControl.setFocus();
+ }
+
+}