Home » Archived » Albireo » More tips for the sample code
More tips for the sample code [message #1401] |
Wed, 26 September 2007 19:44 |
Eclipse User |
|
|
|
Originally posted by: canadianguy.gmail.com
I have found several more issues relating to focus and the SWT/Swing
integration. I have breifly outlined each issue below and posted my code
modifications at the bottom. I suspect I may not be clear enough in
describing both the issues, the solutions, and how they work, so please ask
any questions you might have. I would imagine others have periodically
noticed at least some of these issues as well.
Any thoughts on these Gordon?
My workarounds affect EmbeddedSwingComposite, SwtFocusHandler, and
AwtFocusHandler classes.
The issues:
#1
When using keyboard navigation, the default code misses sending the focus to
the AWT control on its first pass through (the returned focus component is
null). This can be solved by setting awtHasFocus to true at the top of the
gainFocus method instead of at the bottom. This will ensure that an attempt
is made to find a focusable swing control on the first focus attempt.
#2
I use an EmbeddedSwingComponent as the full contents of an editor
(consequently, the IWorkbenchPart's setFocus method sets the focus to the
EmbeddedSwingComponent). When issue #1 is fixed (ie, the AWT control
automatically gets the focus when the SWT control gets the focus), there is
occasionally a deadlock in Java 1.6 when several editors are opened at once
(even though only asycExec and invokeLater calls are used). The deadlock is
happening way down in AWT Code in the WPanelPeer class and is triggered by
the component.requestFocus inside of the awtHandler's gainFocus method.
This seems to be solved when issue #3 is solved.
#3
When the EmbeddedSwingComponent is the only focusable component inside of a
Tab Folder, the awtHandler.gainFocus call causes a malfunction in keyboard
navigation. When the tab labels get the focus (a tab's label is
underlined), typically one can switch between tabs by using the arrow keys
and then dive into the current tab using the 'tab' key. To do this, the SWT
Tab Folder seems to momentarily set the focus to the tab's contents and then
return focus to the tab label.
The problem is that we are telling AWT to take the focus when the tab's
contents gets the focus, so the focus doesn't go back to tab's label. I
have added set/get AbortFocus methods to the SwtFocusHandler. The abort
focus value is set whenever the SWT Control's focus is gained or lost. This
way if the SWT control loses focus before AWT has a chance to set its focus
we can decide not to set the AWT focus.
I suspect the deadlock also has something to do with this quick transfer of
focus.
#4
There is a memory leak when you dispose of the SWT Control even if you set
the frame to null. This leak is present in Java 1.5 update 11 and Java 1.6.
To remove the memory leak, the frame needs to have its FocusableWindowState
set to false and it should be disposed of when the EmbeddedSwingComponent is
disposed of. The frame should be disposed of in the Swing EDT.
In EmbeddedSwingComposite:
public EmbeddedSwingComposite(Composite parent, int style) {
super(parent, style | SWT.EMBEDDED | SWT.NO_BACKGROUND);
getDisplay().addListener(SWT.Settings, settingsListener);
setLayout(new FillLayout());
this.addDisposeListener(new DisposeListener()
{
public void widgetDisposed(DisposeEvent e)
{
final Frame frame = getFrame();
Runnable disposeEDTRunnable = new Runnable()
{
public void run()
{
disposeInEDT(frame);
}
};
if (SwingUtilities.isEventDispatchThread())
disposeEDTRunnable.run();
else
SwingUtilities.invokeLater(disposeEDTRunnable);
}
});
currentSystemFont = getFont();
}
private boolean awtDisposed = false;
public void disposeInEDT(Frame frame)
{
if (!awtDisposed)
{
awtDisposed = true;
if (frame != null)
{
frame.setFocusableWindowState(false);
frame.setFocusable(false);
frame.setEnabled(false);
getRootPaneContainer().getRootPane().getContentPane().remove All();
frame.removeAll();
frame.dispose();
}
}
}
A summary of my code changes below:
In AwtFocusHandler
public void gainFocus() {
assert frame != null;
// assert !awtHasFocus;
assert EventQueue.isDispatchThread(); // On AWT event thread
if (getSwtHandler().getAbortFocus())
{
awtHasFocus = false;
return;
}
awtHasFocus = true;
...
In SwtFocusHandler:
public void focusGained(FocusEvent e)
{
assert awtHandler != null;
assert Display.getCurrent() != null; // On SWT event thread
setAbortFocus(false);
System.out.println("Gained: " + e.toString() + " (" +
e.widget.getClass().getName() + ")");
EventQueue.invokeLater(new Runnable() {
public void run() {
System.out.println("Gain Focus - SWT Focus Handler EDT");
awtHandler.gainFocus();
}
});
}
private volatile boolean abortFocus = false;
public boolean getAbortFocus()
{
return abortFocus;
}
public void setAbortFocus(boolean abort)
{
this.abortFocus = abort;
}
public void focusLost(FocusEvent e)
{
setAbortFocus(true);/*
System.out.print("Focus Control: ");
System.out.println(e.display.getFocusControl());
System.out.println("Lost: " + e.toString() + " (" +
e.widget.getClass().getName() + ")");*/
}
|
|
|
One more issue [message #1407 is a reply to message #1401] |
Wed, 26 September 2007 20:24 |
Eclipse User |
|
|
|
Originally posted by: canadianguy.gmail.com
This also has to do with putting the EmbeddedSwingComposite under a tab
folder.
When AWT has focus and the tab is clicked, AWT loses focus but the composite
does not get a focusGained event (as far as SWT is concerned, it never lost
focus).
I have added a check when the AWT window loses focus to inform the SWT
handler that the backing composite may have re-gained the focus.
At the end of AwtFocusHandler.windowLostFocus:
if (!swtHandler.getDisplay().isDisposed())
{
Runnable runnable = new Runnable()
{
public void run()
{
swtHandler.reApplyFocus();
}
};
swtHandler.getDisplay().asyncExec(runnable);
}
In SwtFocusHandler:
public void reApplyFocus()
{
assert awtHandler != null;
assert Display.getCurrent() != null; // On SWT event thread
if (Display.getCurrent() != null &&
!Display.getCurrent().isDisposed() && composite ==
Display.getCurrent().getFocusControl())
{
setAbortFocus(false);
// System.out.println("Gained: " + e.toString() + " (" +
e.widget.getClass().getName() + ")");
EventQueue.invokeLater(new Runnable() {
public void run() {
// System.out.println("Gain Focus - SWT Focus Handler
EDT");
awtHandler.gainFocus();
}
});
}
}
|
|
|
Re: More tips for the sample code [message #1412 is a reply to message #1401] |
Thu, 27 September 2007 20:50 |
Gordon Hirsch Messages: 100 Registered: July 2009 |
Senior Member |
|
|
James wrote:
> I have found several more issues relating to focus and the SWT/Swing
> integration. I have breifly outlined each issue below and posted my code
> modifications at the bottom. I suspect I may not be clear enough in
> describing both the issues, the solutions, and how they work, so please ask
> any questions you might have. I would imagine others have periodically
> noticed at least some of these issues as well.
>
> Any thoughts on these Gordon?
James, first of all, thank you for sharing your fixes and improvements.
I have some comments and questions below.
>
> My workarounds affect EmbeddedSwingComposite, SwtFocusHandler, and
> AwtFocusHandler classes.
>
> The issues:
> #1
> When using keyboard navigation, the default code misses sending the focus to
> the AWT control on its first pass through (the returned focus component is
> null). This can be solved by setting awtHasFocus to true at the top of the
> gainFocus method instead of at the bottom. This will ensure that an attempt
> is made to find a focusable swing control on the first focus attempt.
Yes, this is definitely a bug in the article. Another solution is to
change the EmbeddedChildFocusTraversalPolicy.getCurrentComponent()
method to call super.getDefaultComponent, rather than
this.getDefaultComponent.
>
> #2
> I use an EmbeddedSwingComponent as the full contents of an editor
> (consequently, the IWorkbenchPart's setFocus method sets the focus to the
> EmbeddedSwingComponent). When issue #1 is fixed (ie, the AWT control
> automatically gets the focus when the SWT control gets the focus), there is
> occasionally a deadlock in Java 1.6 when several editors are opened at once
> (even though only asycExec and invokeLater calls are used). The deadlock is
> happening way down in AWT Code in the WPanelPeer class and is triggered by
> the component.requestFocus inside of the awtHandler's gainFocus method.
> This seems to be solved when issue #3 is solved.
It's now pretty clear that Component.requestFocus has to be used
carefully to avoid deadlock (and in our case other problems). The main
thing is to make sure that it is always called from the AWT event
thread. Unfortunately, the article code calls it from the SWT thread in
two places. For example, I've now re-implemented
EmbeddedSwingComposite.setFocus() as follows:
public boolean setFocus() {
checkWidget();
//if (!isFocusable()) {
// return false;
//}
if (swtHandler != null) {
// Setting focus on the embedded component must posted to the
// AWT thread because:
// 1) The AWT Component.requestFocus method can deadlock if
// called simultaneously from different threads.
// 2) The embedded component is created asynhronously (on the
// AWT thread), so it may not exist yet.
// The call below does the appropriate posting. Since it is
done
// asynchronously, it is impossible to know the result, so
// always return true.
swtHandler.transferFocusToAwt();
return true;
} else {
return super.setFocus();
}
}
transferFocusToAwt is what you would expect:
void transferFocusToAwt() {
EventQueue.invokeLater(new Runnable() {
public void run() {
awtHandler.gainFocus();
}
});
}
A similar change is needed to the EmbeddedSwingComposite.forceFocus method.
I suspect these fixes will eliminate the deadlock problem you saw and
that your solution to #3, though useful in its own right, simply made
the deadlock less likely.
>
> #3
> When the EmbeddedSwingComponent is the only focusable component inside of a
> Tab Folder, the awtHandler.gainFocus call causes a malfunction in keyboard
> navigation. When the tab labels get the focus (a tab's label is
> underlined), typically one can switch between tabs by using the arrow keys
> and then dive into the current tab using the 'tab' key. To do this, the SWT
> Tab Folder seems to momentarily set the focus to the tab's contents and then
> return focus to the tab label.
>
> The problem is that we are telling AWT to take the focus when the tab's
> contents gets the focus, so the focus doesn't go back to tab's label. I
> have added set/get AbortFocus methods to the SwtFocusHandler. The abort
> focus value is set whenever the SWT Control's focus is gained or lost. This
> way if the SWT control loses focus before AWT has a chance to set its focus
> we can decide not to set the AWT focus.
>
> I suspect the deadlock also has something to do with this quick transfer of
> focus.
I didn't know you could navigate this way, so it clearly wasn't tested
:-). Your solution looks like a good one.
>
> #4
> There is a memory leak when you dispose of the SWT Control even if you set
> the frame to null. This leak is present in Java 1.5 update 11 and Java 1.6.
> To remove the memory leak, the frame needs to have its FocusableWindowState
> set to false and it should be disposed of when the EmbeddedSwingComponent is
> disposed of. The frame should be disposed of in the Swing EDT.
Interesting. SWT_AWT.new_Frame() installs a listener that is supposed to
dispose the frame (on the AWT event thread) when the composite is
disposed. Any ideas on why this is not happening?
Is the need to set FocusableWindowState to false maybe due to this bug?
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6469530.
Or something else? I'm wondering if there's something that needs to be
reported to Sun...
I ran into a similar leak that was triggered by adding components to the
frame from outside the AWT EDT. See
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6411042.
|
|
|
Re: One more issue [message #1416 is a reply to message #1407] |
Thu, 27 September 2007 21:20 |
Gordon Hirsch Messages: 100 Registered: July 2009 |
Senior Member |
|
|
James,
Excellent, thanks! I had noticed this problem, but my attempted solution
had bad side effects. You can still find it (partially) in the
commented-out code. I think you are doing a better job of using the
right thread in all cases, so that may be what avoids the side effects.
As I recall, the problem with my attempt was that the AWT frame would
grab focus in cases where it shouldn't. For example, if I tried to
activate a different application's window, suddenly the RCP app with the
embedded AWT frame would pop up on top of it. I assume you haven't seen
anything like this with your fix?
James wrote:
> This also has to do with putting the EmbeddedSwingComposite under a tab
> folder.
>
> When AWT has focus and the tab is clicked, AWT loses focus but the composite
> does not get a focusGained event (as far as SWT is concerned, it never lost
> focus).
>
> I have added a check when the AWT window loses focus to inform the SWT
> handler that the backing composite may have re-gained the focus.
>
> At the end of AwtFocusHandler.windowLostFocus:
> if (!swtHandler.getDisplay().isDisposed())
> {
> Runnable runnable = new Runnable()
> {
> public void run()
> {
> swtHandler.reApplyFocus();
> }
> };
> swtHandler.getDisplay().asyncExec(runnable);
> }
>
> In SwtFocusHandler:
> public void reApplyFocus()
> {
> assert awtHandler != null;
> assert Display.getCurrent() != null; // On SWT event thread
>
>
> if (Display.getCurrent() != null &&
> !Display.getCurrent().isDisposed() && composite ==
> Display.getCurrent().getFocusControl())
> {
> setAbortFocus(false);
>
> // System.out.println("Gained: " + e.toString() + " (" +
> e.widget.getClass().getName() + ")");
> EventQueue.invokeLater(new Runnable() {
> public void run() {
> // System.out.println("Gain Focus - SWT Focus Handler
> EDT");
> awtHandler.gainFocus();
> }
> });
> }
> }
>
>
|
|
|
Re: More tips for the sample code [message #1420 is a reply to message #1401] |
Thu, 27 September 2007 21:25 |
Gordon Hirsch Messages: 100 Registered: July 2009 |
Senior Member |
|
|
James wrote:
> #4
> There is a memory leak when you dispose of the SWT Control even if you set
> the frame to null. This leak is present in Java 1.5 update 11 and Java 1.6.
> To remove the memory leak, the frame needs to have its FocusableWindowState
> set to false and it should be disposed of when the EmbeddedSwingComponent is
> disposed of. The frame should be disposed of in the Swing EDT.
>
> In EmbeddedSwingComposite:
>
> public EmbeddedSwingComposite(Composite parent, int style) {
> super(parent, style | SWT.EMBEDDED | SWT.NO_BACKGROUND);
> getDisplay().addListener(SWT.Settings, settingsListener);
> setLayout(new FillLayout());
> this.addDisposeListener(new DisposeListener()
> {
> public void widgetDisposed(DisposeEvent e)
> {
One other thing I forgot to mention... in the article, I had an
implementation of EmbeddedSwingComposite.dispose like this:
public void dispose() {
if (!isDisposed()) {
getDisplay().removeListener(SWT.Settings, settingsListener);
getDisplay().removeFilter(SWT.Show, menuListener);
super.dispose();
}
}
This is the wrong way to write code that runs at dispose time. The two
listeners should be removed in a dispose listener, just like the one
you've created here, so you should add them to your widgetDisposed() and
remove the dispose() method.
> final Frame frame = getFrame();
> Runnable disposeEDTRunnable = new Runnable()
> {
> public void run()
> {
> disposeInEDT(frame);
> }
> };
> if (SwingUtilities.isEventDispatchThread())
> disposeEDTRunnable.run();
> else
> SwingUtilities.invokeLater(disposeEDTRunnable);
> }
> });
> currentSystemFont = getFont();
> }
>
>
|
|
|
Re: One more issue [message #1424 is a reply to message #1416] |
Fri, 28 September 2007 11:33 |
Eclipse User |
|
|
|
Originally posted by: canadianguy.gmail.com
Gordon,
I haven't seen anything like that but that doesn't guarantee that it won't
happen in a kind of 'perfect storm' of the two UI Threads. When the RCP
application loses focus to another application, this causes the SWT's focus
component to become null, so the AWT component shouldn't re-grab the focus.
-James
"Gordon Hirsch" <gordon.hirsch@sas.com> wrote in message
news:fdh6qi$v82$1@build.eclipse.org...
> James,
>
> Excellent, thanks! I had noticed this problem, but my attempted solution
> had bad side effects. You can still find it (partially) in the
> commented-out code. I think you are doing a better job of using the
> right thread in all cases, so that may be what avoids the side effects.
>
> As I recall, the problem with my attempt was that the AWT frame would
> grab focus in cases where it shouldn't. For example, if I tried to
> activate a different application's window, suddenly the RCP app with the
> embedded AWT frame would pop up on top of it. I assume you haven't seen
> anything like this with your fix?
>
> James wrote:
> > This also has to do with putting the EmbeddedSwingComposite under a tab
> > folder.
> >
> > When AWT has focus and the tab is clicked, AWT loses focus but the
composite
> > does not get a focusGained event (as far as SWT is concerned, it never
lost
> > focus).
> >
> > I have added a check when the AWT window loses focus to inform the SWT
> > handler that the backing composite may have re-gained the focus.
> >
> > At the end of AwtFocusHandler.windowLostFocus:
> > if (!swtHandler.getDisplay().isDisposed())
> > {
> > Runnable runnable = new Runnable()
> > {
> > public void run()
> > {
> > swtHandler.reApplyFocus();
> > }
> > };
> > swtHandler.getDisplay().asyncExec(runnable);
> > }
> >
> > In SwtFocusHandler:
> > public void reApplyFocus()
> > {
> > assert awtHandler != null;
> > assert Display.getCurrent() != null; // On SWT event thread
> >
> >
> > if (Display.getCurrent() != null &&
> > !Display.getCurrent().isDisposed() && composite ==
> > Display.getCurrent().getFocusControl())
> > {
> > setAbortFocus(false);
> >
> > // System.out.println("Gained: " + e.toString() + " (" +
> > e.widget.getClass().getName() + ")");
> > EventQueue.invokeLater(new Runnable() {
> > public void run() {
> > // System.out.println("Gain Focus - SWT Focus
Handler
> > EDT");
> > awtHandler.gainFocus();
> > }
> > });
> > }
> > }
> >
> >
|
|
|
Re: More tips for the sample code [message #1428 is a reply to message #1420] |
Fri, 28 September 2007 11:40 |
Eclipse User |
|
|
|
Originally posted by: canadianguy.gmail.com
I thought that was the case (I noticed that the dispose code wasn't getting
called). I have already moved the dispose code elsewhere and call it from
the dispose listener.
"Gordon Hirsch" <gordon.hirsch@sas.com> wrote in message
news:fdh750$un$1@build.eclipse.org...
> James wrote:
> > #4
> > There is a memory leak when you dispose of the SWT Control even if you
set
> > the frame to null. This leak is present in Java 1.5 update 11 and Java
1.6.
> > To remove the memory leak, the frame needs to have its
FocusableWindowState
> > set to false and it should be disposed of when the
EmbeddedSwingComponent is
> > disposed of. The frame should be disposed of in the Swing EDT.
> >
> > In EmbeddedSwingComposite:
> >
> > public EmbeddedSwingComposite(Composite parent, int style) {
> > super(parent, style | SWT.EMBEDDED | SWT.NO_BACKGROUND);
> > getDisplay().addListener(SWT.Settings, settingsListener);
> > setLayout(new FillLayout());
> > this.addDisposeListener(new DisposeListener()
> > {
> > public void widgetDisposed(DisposeEvent e)
> > {
>
> One other thing I forgot to mention... in the article, I had an
> implementation of EmbeddedSwingComposite.dispose like this:
>
> public void dispose() {
> if (!isDisposed()) {
> getDisplay().removeListener(SWT.Settings, settingsListener);
> getDisplay().removeFilter(SWT.Show, menuListener);
> super.dispose();
> }
> }
>
> This is the wrong way to write code that runs at dispose time. The two
> listeners should be removed in a dispose listener, just like the one
> you've created here, so you should add them to your widgetDisposed() and
> remove the dispose() method.
>
> > final Frame frame = getFrame();
> > Runnable disposeEDTRunnable = new Runnable()
> > {
> > public void run()
> > {
> > disposeInEDT(frame);
> > }
> > };
> > if (SwingUtilities.isEventDispatchThread())
> > disposeEDTRunnable.run();
> > else
> > SwingUtilities.invokeLater(disposeEDTRunnable);
> > }
> > });
> > currentSystemFont = getFont();
> > }
> >
> >
|
|
|
Re: More tips for the sample code [message #1432 is a reply to message #1412] |
Fri, 28 September 2007 11:54 |
Eclipse User |
|
|
|
Originally posted by: canadianguy.gmail.com
"Gordon Hirsch" <gordon.hirsch@sas.com> wrote in message
news:fdh53e$j7i$1@build.eclipse.org...
> James wrote:
> > I have found several more issues relating to focus and the SWT/Swing
> > integration. I have breifly outlined each issue below and posted my
code
> > modifications at the bottom. I suspect I may not be clear enough in
> > describing both the issues, the solutions, and how they work, so please
ask
> > any questions you might have. I would imagine others have periodically
> > noticed at least some of these issues as well.
> >
> > Any thoughts on these Gordon?
>
> James, first of all, thank you for sharing your fixes and improvements.
> I have some comments and questions below.
Not a problem. Your article code allowed us to have a product that was at
least usable (I was going crazy dealing with modal dialogs). We all benefit
from making these two UIs play well together.
>
> >
> > My workarounds affect EmbeddedSwingComposite, SwtFocusHandler, and
> > AwtFocusHandler classes.
> >
> > The issues:
> > #1
> > When using keyboard navigation, the default code misses sending the
focus to
> > the AWT control on its first pass through (the returned focus component
is
> > null). This can be solved by setting awtHasFocus to true at the top of
the
> > gainFocus method instead of at the bottom. This will ensure that an
attempt
> > is made to find a focusable swing control on the first focus attempt.
>
> Yes, this is definitely a bug in the article. Another solution is to
> change the EmbeddedChildFocusTraversalPolicy.getCurrentComponent()
> method to call super.getDefaultComponent, rather than
> this.getDefaultComponent.
>
> >
> > #2
> > I use an EmbeddedSwingComponent as the full contents of an editor
> > (consequently, the IWorkbenchPart's setFocus method sets the focus to
the
> > EmbeddedSwingComponent). When issue #1 is fixed (ie, the AWT control
> > automatically gets the focus when the SWT control gets the focus), there
is
> > occasionally a deadlock in Java 1.6 when several editors are opened at
once
> > (even though only asycExec and invokeLater calls are used). The
deadlock is
> > happening way down in AWT Code in the WPanelPeer class and is triggered
by
> > the component.requestFocus inside of the awtHandler's gainFocus method.
> > This seems to be solved when issue #3 is solved.
>
In my version of the article code (I'm not sure it changed after I
downloaded it), the setFocus doesn't make any AWT Calls. It simple checks
to see if it is focusable and calls super.setFocus()... strange.
> It's now pretty clear that Component.requestFocus has to be used
> carefully to avoid deadlock (and in our case other problems). The main
> thing is to make sure that it is always called from the AWT event
> thread. Unfortunately, the article code calls it from the SWT thread in
> two places. For example, I've now re-implemented
> EmbeddedSwingComposite.setFocus() as follows:
>
> public boolean setFocus() {
> checkWidget();
>
> //if (!isFocusable()) {
> // return false;
> //}
> if (swtHandler != null) {
> // Setting focus on the embedded component must posted to the
> // AWT thread because:
> // 1) The AWT Component.requestFocus method can deadlock if
> // called simultaneously from different threads.
> // 2) The embedded component is created asynhronously (on the
> // AWT thread), so it may not exist yet.
> // The call below does the appropriate posting. Since it is
> done
> // asynchronously, it is impossible to know the result, so
> // always return true.
> swtHandler.transferFocusToAwt();
> return true;
> } else {
> return super.setFocus();
> }
> }
>
> transferFocusToAwt is what you would expect:
>
> void transferFocusToAwt() {
> EventQueue.invokeLater(new Runnable() {
> public void run() {
> awtHandler.gainFocus();
> }
> });
> }
>
> A similar change is needed to the EmbeddedSwingComposite.forceFocus
method.
>
> I suspect these fixes will eliminate the deadlock problem you saw and
> that your solution to #3, though useful in its own right, simply made
> the deadlock less likely.
>
> >
> > #3
> > When the EmbeddedSwingComponent is the only focusable component inside
of a
> > Tab Folder, the awtHandler.gainFocus call causes a malfunction in
keyboard
> > navigation. When the tab labels get the focus (a tab's label is
> > underlined), typically one can switch between tabs by using the arrow
keys
> > and then dive into the current tab using the 'tab' key. To do this, the
SWT
> > Tab Folder seems to momentarily set the focus to the tab's contents and
then
> > return focus to the tab label.
> >
> > The problem is that we are telling AWT to take the focus when the tab's
> > contents gets the focus, so the focus doesn't go back to tab's label. I
> > have added set/get AbortFocus methods to the SwtFocusHandler. The abort
> > focus value is set whenever the SWT Control's focus is gained or lost.
This
> > way if the SWT control loses focus before AWT has a chance to set its
focus
> > we can decide not to set the AWT focus.
> >
> > I suspect the deadlock also has something to do with this quick transfer
of
> > focus.
>
> I didn't know you could navigate this way, so it clearly wasn't tested
> :-). Your solution looks like a good one.
>
> >
> > #4
> > There is a memory leak when you dispose of the SWT Control even if you
set
> > the frame to null. This leak is present in Java 1.5 update 11 and Java
1.6.
> > To remove the memory leak, the frame needs to have its
FocusableWindowState
> > set to false and it should be disposed of when the
EmbeddedSwingComponent is
> > disposed of. The frame should be disposed of in the Swing EDT.
>
> Interesting. SWT_AWT.new_Frame() installs a listener that is supposed to
> dispose the frame (on the AWT event thread) when the composite is
> disposed. Any ideas on why this is not happening?
>
> Is the need to set FocusableWindowState to false maybe due to this bug?
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6469530.
Yes, I'm pretty sure that this is the same bug (as I recall from the last
time I ran this through a profiler). The GlobalRef stays in place until
another component gets focus. In our case (probably some of the special
world of the SWT/AWT mix), it is reproducable 100% of the time. I have
found that setting the setFocusableWindowState to false before the frame is
disposed is also a work-around to the problem. To be honest, I don't know
if the other explicit call to dispose is necessary.
> Or something else? I'm wondering if there's something that needs to be
> reported to Sun...
>
> I ran into a similar leak that was triggered by adding components to the
> frame from outside the AWT EDT. See
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6411042.
>
|
|
|
Re: More tips for the sample code [message #1435 is a reply to message #1432] |
Fri, 28 September 2007 12:05 |
Eclipse User |
|
|
|
Originally posted by: canadianguy.gmail.com
Aside from not seeming to make an AWT call out side of the AWT Thread, this
alternate implementation you have proposed breaks the fix for keyboard
navigation I describe (the SWT Component never really gains focus so it can
never lose it).
> In my version of the article code (I'm not sure it changed after I
> downloaded it), the setFocus doesn't make any AWT Calls. It simple checks
> to see if it is focusable and calls super.setFocus()... strange.
>
> > It's now pretty clear that Component.requestFocus has to be used
> > carefully to avoid deadlock (and in our case other problems). The main
> > thing is to make sure that it is always called from the AWT event
> > thread. Unfortunately, the article code calls it from the SWT thread in
> > two places. For example, I've now re-implemented
> > EmbeddedSwingComposite.setFocus() as follows:
> >
> > public boolean setFocus() {
> > checkWidget();
> >
> > //if (!isFocusable()) {
> > // return false;
> > //}
> > if (swtHandler != null) {
> > // Setting focus on the embedded component must posted to
the
> > // AWT thread because:
> > // 1) The AWT Component.requestFocus method can deadlock if
> > // called simultaneously from different threads.
> > // 2) The embedded component is created asynhronously (on
the
> > // AWT thread), so it may not exist yet.
> > // The call below does the appropriate posting. Since it is
> > done
> > // asynchronously, it is impossible to know the result, so
> > // always return true.
> > swtHandler.transferFocusToAwt();
> > return true;
> > } else {
> > return super.setFocus();
> > }
> > }
> >
> > transferFocusToAwt is what you would expect:
> >
> > void transferFocusToAwt() {
> > EventQueue.invokeLater(new Runnable() {
> > public void run() {
> > awtHandler.gainFocus();
> > }
> > });
> > }
> >
> > A similar change is needed to the EmbeddedSwingComposite.forceFocus
> method.
> >
> > I suspect these fixes will eliminate the deadlock problem you saw and
> > that your solution to #3, though useful in its own right, simply made
> > the deadlock less likely.
> >
|
|
|
Re: More tips for the sample code [message #3240 is a reply to message #1435] |
Sun, 07 October 2007 18:10 |
Gordon Hirsch Messages: 100 Registered: July 2009 |
Senior Member |
|
|
James wrote:
> Aside from not seeming to make an AWT call out side of the AWT Thread, this
> alternate implementation you have proposed breaks the fix for keyboard
> navigation I describe (the SWT Component never really gains focus so it can
> never lose it).
You're right. After looking a little closer, I don't think the
implementations of setFocus/forceFocus are necessary at all.
By the way, the extra code in setFocus/forceFocus was not part of the
original article. Sorry for any confusion I might have caused.
>
>> In my version of the article code (I'm not sure it changed after I
>> downloaded it), the setFocus doesn't make any AWT Calls. It simple checks
>> to see if it is focusable and calls super.setFocus()... strange.
>>
>>> It's now pretty clear that Component.requestFocus has to be used
>>> carefully to avoid deadlock (and in our case other problems). The main
>>> thing is to make sure that it is always called from the AWT event
>>> thread. Unfortunately, the article code calls it from the SWT thread in
>>> two places. For example, I've now re-implemented
>>> EmbeddedSwingComposite.setFocus() as follows:
>>>
>>> public boolean setFocus() {
>>> checkWidget();
>>>
>>> //if (!isFocusable()) {
>>> // return false;
>>> //}
>>> if (swtHandler != null) {
>>> // Setting focus on the embedded component must posted to
> the
>>> // AWT thread because:
>>> // 1) The AWT Component.requestFocus method can deadlock if
>>> // called simultaneously from different threads.
>>> // 2) The embedded component is created asynhronously (on
> the
>>> // AWT thread), so it may not exist yet.
>>> // The call below does the appropriate posting. Since it is
>>> done
>>> // asynchronously, it is impossible to know the result, so
>>> // always return true.
>>> swtHandler.transferFocusToAwt();
>>> return true;
>>> } else {
>>> return super.setFocus();
>>> }
>>> }
>>>
>>> transferFocusToAwt is what you would expect:
>>>
>>> void transferFocusToAwt() {
>>> EventQueue.invokeLater(new Runnable() {
>>> public void run() {
>>> awtHandler.gainFocus();
>>> }
>>> });
>>> }
>>>
>>> A similar change is needed to the EmbeddedSwingComposite.forceFocus
>> method.
>>> I suspect these fixes will eliminate the deadlock problem you saw and
>>> that your solution to #3, though useful in its own right, simply made
>>> the deadlock less likely.
>>>
>
>
|
|
|
Re: More tips for the sample code [message #5247 is a reply to message #1412] |
Tue, 27 November 2007 02:35 |
Eclipse User |
|
|
|
Originally posted by: canadianguy.gmail.com
Gordon (or anyone),
As you suspected, my workaround for the requestFocus deadlock issue is not a
solution 100% of the time. In fact, lately the issue is happening
frequently enough to prevent my next software release.
Have you any idea why I might be getting deadlock in
WComponentPeer._requestFocus when calling it from the AWT EDT after an
invokeLater from the SWT EDT? I could really use some help with this one.
Naturally, as with most timing bugs, I don't really have a snipped that I
can post.
-James
"Gordon Hirsch" <gordon.hirsch@sas.com> wrote in message
news:fdh53e$j7i$1@build.eclipse.org...
> James wrote:
>> I have found several more issues relating to focus and the SWT/Swing
>> integration. I have breifly outlined each issue below and posted my code
>> modifications at the bottom. I suspect I may not be clear enough in
>> describing both the issues, the solutions, and how they work, so please
>> ask
>> any questions you might have. I would imagine others have periodically
>> noticed at least some of these issues as well.
>>
>> Any thoughts on these Gordon?
>
> James, first of all, thank you for sharing your fixes and improvements. I
> have some comments and questions below.
>
>>
>> My workarounds affect EmbeddedSwingComposite, SwtFocusHandler, and
>> AwtFocusHandler classes.
>>
>> The issues:
>> #1
>> When using keyboard navigation, the default code misses sending the focus
>> to
>> the AWT control on its first pass through (the returned focus component
>> is
>> null). This can be solved by setting awtHasFocus to true at the top of
>> the
>> gainFocus method instead of at the bottom. This will ensure that an
>> attempt
>> is made to find a focusable swing control on the first focus attempt.
>
> Yes, this is definitely a bug in the article. Another solution is to
> change the EmbeddedChildFocusTraversalPolicy.getCurrentComponent() method
> to call super.getDefaultComponent, rather than this.getDefaultComponent.
>
>>
>> #2
>> I use an EmbeddedSwingComponent as the full contents of an editor
>> (consequently, the IWorkbenchPart's setFocus method sets the focus to the
>> EmbeddedSwingComponent). When issue #1 is fixed (ie, the AWT control
>> automatically gets the focus when the SWT control gets the focus), there
>> is
>> occasionally a deadlock in Java 1.6 when several editors are opened at
>> once
>> (even though only asycExec and invokeLater calls are used). The deadlock
>> is
>> happening way down in AWT Code in the WPanelPeer class and is triggered
>> by
>> the component.requestFocus inside of the awtHandler's gainFocus method.
>> This seems to be solved when issue #3 is solved.
>
> It's now pretty clear that Component.requestFocus has to be used carefully
> to avoid deadlock (and in our case other problems). The main thing is to
> make sure that it is always called from the AWT event thread.
> Unfortunately, the article code calls it from the SWT thread in two
> places. For example, I've now re-implemented
> EmbeddedSwingComposite.setFocus() as follows:
>
> public boolean setFocus() {
> checkWidget();
>
> //if (!isFocusable()) {
> // return false;
> //}
> if (swtHandler != null) {
> // Setting focus on the embedded component must posted to the
> // AWT thread because:
> // 1) The AWT Component.requestFocus method can deadlock if
> // called simultaneously from different threads.
> // 2) The embedded component is created asynhronously (on the
> // AWT thread), so it may not exist yet.
> // The call below does the appropriate posting. Since it is
> done
> // asynchronously, it is impossible to know the result, so
> // always return true.
> swtHandler.transferFocusToAwt();
> return true;
> } else {
> return super.setFocus();
> }
> }
>
> transferFocusToAwt is what you would expect:
>
> void transferFocusToAwt() {
> EventQueue.invokeLater(new Runnable() {
> public void run() {
> awtHandler.gainFocus();
> }
> });
> }
>
> A similar change is needed to the EmbeddedSwingComposite.forceFocus
> method.
>
> I suspect these fixes will eliminate the deadlock problem you saw and that
> your solution to #3, though useful in its own right, simply made the
> deadlock less likely.
>
>>
>> #3
>> When the EmbeddedSwingComponent is the only focusable component inside of
>> a
>> Tab Folder, the awtHandler.gainFocus call causes a malfunction in
>> keyboard
>> navigation. When the tab labels get the focus (a tab's label is
>> underlined), typically one can switch between tabs by using the arrow
>> keys
>> and then dive into the current tab using the 'tab' key. To do this, the
>> SWT
>> Tab Folder seems to momentarily set the focus to the tab's contents and
>> then
>> return focus to the tab label.
>>
>> The problem is that we are telling AWT to take the focus when the tab's
>> contents gets the focus, so the focus doesn't go back to tab's label. I
>> have added set/get AbortFocus methods to the SwtFocusHandler. The abort
>> focus value is set whenever the SWT Control's focus is gained or lost.
>> This
>> way if the SWT control loses focus before AWT has a chance to set its
>> focus
>> we can decide not to set the AWT focus.
>>
>> I suspect the deadlock also has something to do with this quick transfer
>> of
>> focus.
>
> I didn't know you could navigate this way, so it clearly wasn't tested
> :-). Your solution looks like a good one.
>
>>
>> #4
>> There is a memory leak when you dispose of the SWT Control even if you
>> set
>> the frame to null. This leak is present in Java 1.5 update 11 and Java
>> 1.6.
>> To remove the memory leak, the frame needs to have its
>> FocusableWindowState
>> set to false and it should be disposed of when the EmbeddedSwingComponent
>> is
>> disposed of. The frame should be disposed of in the Swing EDT.
>
> Interesting. SWT_AWT.new_Frame() installs a listener that is supposed to
> dispose the frame (on the AWT event thread) when the composite is
> disposed. Any ideas on why this is not happening?
>
> Is the need to set FocusableWindowState to false maybe due to this bug?
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6469530.
>
> Or something else? I'm wondering if there's something that needs to be
> reported to Sun...
>
> I ran into a similar leak that was triggered by adding components to the
> frame from outside the AWT EDT. See
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6411042.
>
|
|
| |
Re: More tips for the sample code [message #5368 is a reply to message #5313] |
Tue, 27 November 2007 23:31 |
Eclipse User |
|
|
|
Originally posted by: canadianguy.gmail.com
Unfortunately I seem the Debugger seems to throw errors whenever I try to
suspend execution. I have changed my Eclipse version from 3.2.2 to 3.3.1.1
and the issue has gone back into hiding. I'll try to get more information
to you.
-James
"Gordon Hirsch" <gordon.hirsch@sas.com> wrote in message
news:fihg2f$rkr$1@build.eclipse.org...
> James Peltzer wrote:
>> Gordon (or anyone),
>> As you suspected, my workaround for the requestFocus deadlock issue is
>> not a solution 100% of the time. In fact, lately the issue is happening
>> frequently enough to prevent my next software release.
>>
>> Have you any idea why I might be getting deadlock in
>> WComponentPeer._requestFocus when calling it from the AWT EDT after an
>> invokeLater from the SWT EDT? I could really use some help with this
>> one. Naturally, as with most timing bugs, I don't really have a snipped
>> that I can post.
>
> Could you post stack traces from the deadlocked JVM? They would be
> extremely helpful in diagnosing what the two EDTs (and possibly other
> threads) are doing at that point.
|
|
| | | |
Re: More tips for the sample code [message #11052 is a reply to message #1412] |
Tue, 23 June 2009 23:46 |
Ken Messages: 36 Registered: July 2009 |
Member |
|
|
Gordon - has this fix been applied to 0.0.3? I took a look, but it seems
like things have changed a lot and I was not able to identify if these
changes are in the latest release. Or are they no longer even necessary?
Thanks!
- Ken
"Gordon Hirsch" <gordon.hirsch@sas.com> wrote in message
news:fdh53e$j7i$1@build.eclipse.org...
> James wrote:
>> I have found several more issues relating to focus and the SWT/Swing
>> integration. I have breifly outlined each issue below and posted my code
>> modifications at the bottom. I suspect I may not be clear enough in
>> describing both the issues, the solutions, and how they work, so please
>> ask
>> any questions you might have. I would imagine others have periodically
>> noticed at least some of these issues as well.
>>
>> Any thoughts on these Gordon?
>
> James, first of all, thank you for sharing your fixes and improvements. I
> have some comments and questions below.
>
>>
>> My workarounds affect EmbeddedSwingComposite, SwtFocusHandler, and
>> AwtFocusHandler classes.
>>
>> The issues:
>> #1
>> When using keyboard navigation, the default code misses sending the focus
>> to
>> the AWT control on its first pass through (the returned focus component
>> is
>> null). This can be solved by setting awtHasFocus to true at the top of
>> the
>> gainFocus method instead of at the bottom. This will ensure that an
>> attempt
>> is made to find a focusable swing control on the first focus attempt.
>
> Yes, this is definitely a bug in the article. Another solution is to
> change the EmbeddedChildFocusTraversalPolicy.getCurrentComponent() method
> to call super.getDefaultComponent, rather than this.getDefaultComponent.
>
>>
>> #2
>> I use an EmbeddedSwingComponent as the full contents of an editor
>> (consequently, the IWorkbenchPart's setFocus method sets the focus to the
>> EmbeddedSwingComponent). When issue #1 is fixed (ie, the AWT control
>> automatically gets the focus when the SWT control gets the focus), there
>> is
>> occasionally a deadlock in Java 1.6 when several editors are opened at
>> once
>> (even though only asycExec and invokeLater calls are used). The deadlock
>> is
>> happening way down in AWT Code in the WPanelPeer class and is triggered
>> by
>> the component.requestFocus inside of the awtHandler's gainFocus method.
>> This seems to be solved when issue #3 is solved.
>
> It's now pretty clear that Component.requestFocus has to be used carefully
> to avoid deadlock (and in our case other problems). The main thing is to
> make sure that it is always called from the AWT event thread.
> Unfortunately, the article code calls it from the SWT thread in two
> places. For example, I've now re-implemented
> EmbeddedSwingComposite.setFocus() as follows:
>
> public boolean setFocus() {
> checkWidget();
>
> //if (!isFocusable()) {
> // return false;
> //}
> if (swtHandler != null) {
> // Setting focus on the embedded component must posted to the
> // AWT thread because:
> // 1) The AWT Component.requestFocus method can deadlock if
> // called simultaneously from different threads.
> // 2) The embedded component is created asynhronously (on the
> // AWT thread), so it may not exist yet.
> // The call below does the appropriate posting. Since it is
> done
> // asynchronously, it is impossible to know the result, so
> // always return true.
> swtHandler.transferFocusToAwt();
> return true;
> } else {
> return super.setFocus();
> }
> }
>
> transferFocusToAwt is what you would expect:
>
> void transferFocusToAwt() {
> EventQueue.invokeLater(new Runnable() {
> public void run() {
> awtHandler.gainFocus();
> }
> });
> }
>
> A similar change is needed to the EmbeddedSwingComposite.forceFocus
> method.
>
> I suspect these fixes will eliminate the deadlock problem you saw and that
> your solution to #3, though useful in its own right, simply made the
> deadlock less likely.
>
>>
>> #3
>> When the EmbeddedSwingComponent is the only focusable component inside of
>> a
>> Tab Folder, the awtHandler.gainFocus call causes a malfunction in
>> keyboard
>> navigation. When the tab labels get the focus (a tab's label is
>> underlined), typically one can switch between tabs by using the arrow
>> keys
>> and then dive into the current tab using the 'tab' key. To do this, the
>> SWT
>> Tab Folder seems to momentarily set the focus to the tab's contents and
>> then
>> return focus to the tab label.
>>
>> The problem is that we are telling AWT to take the focus when the tab's
>> contents gets the focus, so the focus doesn't go back to tab's label. I
>> have added set/get AbortFocus methods to the SwtFocusHandler. The abort
>> focus value is set whenever the SWT Control's focus is gained or lost.
>> This
>> way if the SWT control loses focus before AWT has a chance to set its
>> focus
>> we can decide not to set the AWT focus.
>>
>> I suspect the deadlock also has something to do with this quick transfer
>> of
>> focus.
>
> I didn't know you could navigate this way, so it clearly wasn't tested
> :-). Your solution looks like a good one.
>
>>
>> #4
>> There is a memory leak when you dispose of the SWT Control even if you
>> set
>> the frame to null. This leak is present in Java 1.5 update 11 and Java
>> 1.6.
>> To remove the memory leak, the frame needs to have its
>> FocusableWindowState
>> set to false and it should be disposed of when the EmbeddedSwingComponent
>> is
>> disposed of. The frame should be disposed of in the Swing EDT.
>
> Interesting. SWT_AWT.new_Frame() installs a listener that is supposed to
> dispose the frame (on the AWT event thread) when the composite is
> disposed. Any ideas on why this is not happening?
>
> Is the need to set FocusableWindowState to false maybe due to this bug?
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6469530.
>
> Or something else? I'm wondering if there's something that needs to be
> reported to Sun...
>
> I ran into a similar leak that was triggered by adding components to the
> frame from outside the AWT EDT. See
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6411042.
>
|
|
| |
Re: More tips for the sample code [message #572420 is a reply to message #1401] |
Thu, 27 September 2007 20:50 |
Gordon Hirsch Messages: 100 Registered: July 2009 |
Senior Member |
|
|
James wrote:
> I have found several more issues relating to focus and the SWT/Swing
> integration. I have breifly outlined each issue below and posted my code
> modifications at the bottom. I suspect I may not be clear enough in
> describing both the issues, the solutions, and how they work, so please ask
> any questions you might have. I would imagine others have periodically
> noticed at least some of these issues as well.
>
> Any thoughts on these Gordon?
James, first of all, thank you for sharing your fixes and improvements.
I have some comments and questions below.
>
> My workarounds affect EmbeddedSwingComposite, SwtFocusHandler, and
> AwtFocusHandler classes.
>
> The issues:
> #1
> When using keyboard navigation, the default code misses sending the focus to
> the AWT control on its first pass through (the returned focus component is
> null). This can be solved by setting awtHasFocus to true at the top of the
> gainFocus method instead of at the bottom. This will ensure that an attempt
> is made to find a focusable swing control on the first focus attempt.
Yes, this is definitely a bug in the article. Another solution is to
change the EmbeddedChildFocusTraversalPolicy.getCurrentComponent()
method to call super.getDefaultComponent, rather than
this.getDefaultComponent.
>
> #2
> I use an EmbeddedSwingComponent as the full contents of an editor
> (consequently, the IWorkbenchPart's setFocus method sets the focus to the
> EmbeddedSwingComponent). When issue #1 is fixed (ie, the AWT control
> automatically gets the focus when the SWT control gets the focus), there is
> occasionally a deadlock in Java 1.6 when several editors are opened at once
> (even though only asycExec and invokeLater calls are used). The deadlock is
> happening way down in AWT Code in the WPanelPeer class and is triggered by
> the component.requestFocus inside of the awtHandler's gainFocus method.
> This seems to be solved when issue #3 is solved.
It's now pretty clear that Component.requestFocus has to be used
carefully to avoid deadlock (and in our case other problems). The main
thing is to make sure that it is always called from the AWT event
thread. Unfortunately, the article code calls it from the SWT thread in
two places. For example, I've now re-implemented
EmbeddedSwingComposite.setFocus() as follows:
public boolean setFocus() {
checkWidget();
//if (!isFocusable()) {
// return false;
//}
if (swtHandler != null) {
// Setting focus on the embedded component must posted to the
// AWT thread because:
// 1) The AWT Component.requestFocus method can deadlock if
// called simultaneously from different threads.
// 2) The embedded component is created asynhronously (on the
// AWT thread), so it may not exist yet.
// The call below does the appropriate posting. Since it is
done
// asynchronously, it is impossible to know the result, so
// always return true.
swtHandler.transferFocusToAwt();
return true;
} else {
return super.setFocus();
}
}
transferFocusToAwt is what you would expect:
void transferFocusToAwt() {
EventQueue.invokeLater(new Runnable() {
public void run() {
awtHandler.gainFocus();
}
});
}
A similar change is needed to the EmbeddedSwingComposite.forceFocus method.
I suspect these fixes will eliminate the deadlock problem you saw and
that your solution to #3, though useful in its own right, simply made
the deadlock less likely.
>
> #3
> When the EmbeddedSwingComponent is the only focusable component inside of a
> Tab Folder, the awtHandler.gainFocus call causes a malfunction in keyboard
> navigation. When the tab labels get the focus (a tab's label is
> underlined), typically one can switch between tabs by using the arrow keys
> and then dive into the current tab using the 'tab' key. To do this, the SWT
> Tab Folder seems to momentarily set the focus to the tab's contents and then
> return focus to the tab label.
>
> The problem is that we are telling AWT to take the focus when the tab's
> contents gets the focus, so the focus doesn't go back to tab's label. I
> have added set/get AbortFocus methods to the SwtFocusHandler. The abort
> focus value is set whenever the SWT Control's focus is gained or lost. This
> way if the SWT control loses focus before AWT has a chance to set its focus
> we can decide not to set the AWT focus.
>
> I suspect the deadlock also has something to do with this quick transfer of
> focus.
I didn't know you could navigate this way, so it clearly wasn't tested
:-). Your solution looks like a good one.
>
> #4
> There is a memory leak when you dispose of the SWT Control even if you set
> the frame to null. This leak is present in Java 1.5 update 11 and Java 1.6.
> To remove the memory leak, the frame needs to have its FocusableWindowState
> set to false and it should be disposed of when the EmbeddedSwingComponent is
> disposed of. The frame should be disposed of in the Swing EDT.
Interesting. SWT_AWT.new_Frame() installs a listener that is supposed to
dispose the frame (on the AWT event thread) when the composite is
disposed. Any ideas on why this is not happening?
Is the need to set FocusableWindowState to false maybe due to this bug?
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6469530
Or something else? I'm wondering if there's something that needs to be
reported to Sun...
I ran into a similar leak that was triggered by adding components to the
frame from outside the AWT EDT. See
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6411042
|
|
|
Re: One more issue [message #572442 is a reply to message #1407] |
Thu, 27 September 2007 21:20 |
Gordon Hirsch Messages: 100 Registered: July 2009 |
Senior Member |
|
|
James,
Excellent, thanks! I had noticed this problem, but my attempted solution
had bad side effects. You can still find it (partially) in the
commented-out code. I think you are doing a better job of using the
right thread in all cases, so that may be what avoids the side effects.
As I recall, the problem with my attempt was that the AWT frame would
grab focus in cases where it shouldn't. For example, if I tried to
activate a different application's window, suddenly the RCP app with the
embedded AWT frame would pop up on top of it. I assume you haven't seen
anything like this with your fix?
James wrote:
> This also has to do with putting the EmbeddedSwingComposite under a tab
> folder.
>
> When AWT has focus and the tab is clicked, AWT loses focus but the composite
> does not get a focusGained event (as far as SWT is concerned, it never lost
> focus).
>
> I have added a check when the AWT window loses focus to inform the SWT
> handler that the backing composite may have re-gained the focus.
>
> At the end of AwtFocusHandler.windowLostFocus:
> if (!swtHandler.getDisplay().isDisposed())
> {
> Runnable runnable = new Runnable()
> {
> public void run()
> {
> swtHandler.reApplyFocus();
> }
> };
> swtHandler.getDisplay().asyncExec(runnable);
> }
>
> In SwtFocusHandler:
> public void reApplyFocus()
> {
> assert awtHandler != null;
> assert Display.getCurrent() != null; // On SWT event thread
>
>
> if (Display.getCurrent() != null &&
> !Display.getCurrent().isDisposed() && composite ==
> Display.getCurrent().getFocusControl())
> {
> setAbortFocus(false);
>
> // System.out.println("Gained: " + e.toString() + " (" +
> e.widget.getClass().getName() + ")");
> EventQueue.invokeLater(new Runnable() {
> public void run() {
> // System.out.println("Gain Focus - SWT Focus Handler
> EDT");
> awtHandler.gainFocus();
> }
> });
> }
> }
>
>
|
|
|
Re: More tips for the sample code [message #572456 is a reply to message #1401] |
Thu, 27 September 2007 21:25 |
Gordon Hirsch Messages: 100 Registered: July 2009 |
Senior Member |
|
|
James wrote:
> #4
> There is a memory leak when you dispose of the SWT Control even if you set
> the frame to null. This leak is present in Java 1.5 update 11 and Java 1.6.
> To remove the memory leak, the frame needs to have its FocusableWindowState
> set to false and it should be disposed of when the EmbeddedSwingComponent is
> disposed of. The frame should be disposed of in the Swing EDT.
>
> In EmbeddedSwingComposite:
>
> public EmbeddedSwingComposite(Composite parent, int style) {
> super(parent, style | SWT.EMBEDDED | SWT.NO_BACKGROUND);
> getDisplay().addListener(SWT.Settings, settingsListener);
> setLayout(new FillLayout());
> this.addDisposeListener(new DisposeListener()
> {
> public void widgetDisposed(DisposeEvent e)
> {
One other thing I forgot to mention... in the article, I had an
implementation of EmbeddedSwingComposite.dispose like this:
public void dispose() {
if (!isDisposed()) {
getDisplay().removeListener(SWT.Settings, settingsListener);
getDisplay().removeFilter(SWT.Show, menuListener);
super.dispose();
}
}
This is the wrong way to write code that runs at dispose time. The two
listeners should be removed in a dispose listener, just like the one
you've created here, so you should add them to your widgetDisposed() and
remove the dispose() method.
> final Frame frame = getFrame();
> Runnable disposeEDTRunnable = new Runnable()
> {
> public void run()
> {
> disposeInEDT(frame);
> }
> };
> if (SwingUtilities.isEventDispatchThread())
> disposeEDTRunnable.run();
> else
> SwingUtilities.invokeLater(disposeEDTRunnable);
> }
> });
> currentSystemFont = getFont();
> }
>
>
|
|
|
Re: One more issue [message #572494 is a reply to message #1416] |
Fri, 28 September 2007 11:33 |
James Messages: 272 Registered: July 2009 |
Senior Member |
|
|
Gordon,
I haven't seen anything like that but that doesn't guarantee that it won't
happen in a kind of 'perfect storm' of the two UI Threads. When the RCP
application loses focus to another application, this causes the SWT's focus
component to become null, so the AWT component shouldn't re-grab the focus.
-James
"Gordon Hirsch" <gordon.hirsch@sas.com> wrote in message
news:fdh6qi$v82$1@build.eclipse.org...
> James,
>
> Excellent, thanks! I had noticed this problem, but my attempted solution
> had bad side effects. You can still find it (partially) in the
> commented-out code. I think you are doing a better job of using the
> right thread in all cases, so that may be what avoids the side effects.
>
> As I recall, the problem with my attempt was that the AWT frame would
> grab focus in cases where it shouldn't. For example, if I tried to
> activate a different application's window, suddenly the RCP app with the
> embedded AWT frame would pop up on top of it. I assume you haven't seen
> anything like this with your fix?
>
> James wrote:
> > This also has to do with putting the EmbeddedSwingComposite under a tab
> > folder.
> >
> > When AWT has focus and the tab is clicked, AWT loses focus but the
composite
> > does not get a focusGained event (as far as SWT is concerned, it never
lost
> > focus).
> >
> > I have added a check when the AWT window loses focus to inform the SWT
> > handler that the backing composite may have re-gained the focus.
> >
> > At the end of AwtFocusHandler.windowLostFocus:
> > if (!swtHandler.getDisplay().isDisposed())
> > {
> > Runnable runnable = new Runnable()
> > {
> > public void run()
> > {
> > swtHandler.reApplyFocus();
> > }
> > };
> > swtHandler.getDisplay().asyncExec(runnable);
> > }
> >
> > In SwtFocusHandler:
> > public void reApplyFocus()
> > {
> > assert awtHandler != null;
> > assert Display.getCurrent() != null; // On SWT event thread
> >
> >
> > if (Display.getCurrent() != null &&
> > !Display.getCurrent().isDisposed() && composite ==
> > Display.getCurrent().getFocusControl())
> > {
> > setAbortFocus(false);
> >
> > // System.out.println("Gained: " + e.toString() + " (" +
> > e.widget.getClass().getName() + ")");
> > EventQueue.invokeLater(new Runnable() {
> > public void run() {
> > // System.out.println("Gain Focus - SWT Focus
Handler
> > EDT");
> > awtHandler.gainFocus();
> > }
> > });
> > }
> > }
> >
> >
|
|
|
Re: More tips for the sample code [message #572565 is a reply to message #1420] |
Fri, 28 September 2007 11:40 |
James Messages: 272 Registered: July 2009 |
Senior Member |
|
|
I thought that was the case (I noticed that the dispose code wasn't getting
called). I have already moved the dispose code elsewhere and call it from
the dispose listener.
"Gordon Hirsch" <gordon.hirsch@sas.com> wrote in message
news:fdh750$un$1@build.eclipse.org...
> James wrote:
> > #4
> > There is a memory leak when you dispose of the SWT Control even if you
set
> > the frame to null. This leak is present in Java 1.5 update 11 and Java
1.6.
> > To remove the memory leak, the frame needs to have its
FocusableWindowState
> > set to false and it should be disposed of when the
EmbeddedSwingComponent is
> > disposed of. The frame should be disposed of in the Swing EDT.
> >
> > In EmbeddedSwingComposite:
> >
> > public EmbeddedSwingComposite(Composite parent, int style) {
> > super(parent, style | SWT.EMBEDDED | SWT.NO_BACKGROUND);
> > getDisplay().addListener(SWT.Settings, settingsListener);
> > setLayout(new FillLayout());
> > this.addDisposeListener(new DisposeListener()
> > {
> > public void widgetDisposed(DisposeEvent e)
> > {
>
> One other thing I forgot to mention... in the article, I had an
> implementation of EmbeddedSwingComposite.dispose like this:
>
> public void dispose() {
> if (!isDisposed()) {
> getDisplay().removeListener(SWT.Settings, settingsListener);
> getDisplay().removeFilter(SWT.Show, menuListener);
> super.dispose();
> }
> }
>
> This is the wrong way to write code that runs at dispose time. The two
> listeners should be removed in a dispose listener, just like the one
> you've created here, so you should add them to your widgetDisposed() and
> remove the dispose() method.
>
> > final Frame frame = getFrame();
> > Runnable disposeEDTRunnable = new Runnable()
> > {
> > public void run()
> > {
> > disposeInEDT(frame);
> > }
> > };
> > if (SwingUtilities.isEventDispatchThread())
> > disposeEDTRunnable.run();
> > else
> > SwingUtilities.invokeLater(disposeEDTRunnable);
> > }
> > });
> > currentSystemFont = getFont();
> > }
> >
> >
|
|
|
Re: More tips for the sample code [message #572628 is a reply to message #1412] |
Fri, 28 September 2007 11:54 |
James Messages: 272 Registered: July 2009 |
Senior Member |
|
|
"Gordon Hirsch" <gordon.hirsch@sas.com> wrote in message
news:fdh53e$j7i$1@build.eclipse.org...
> James wrote:
> > I have found several more issues relating to focus and the SWT/Swing
> > integration. I have breifly outlined each issue below and posted my
code
> > modifications at the bottom. I suspect I may not be clear enough in
> > describing both the issues, the solutions, and how they work, so please
ask
> > any questions you might have. I would imagine others have periodically
> > noticed at least some of these issues as well.
> >
> > Any thoughts on these Gordon?
>
> James, first of all, thank you for sharing your fixes and improvements.
> I have some comments and questions below.
Not a problem. Your article code allowed us to have a product that was at
least usable (I was going crazy dealing with modal dialogs). We all benefit
from making these two UIs play well together.
>
> >
> > My workarounds affect EmbeddedSwingComposite, SwtFocusHandler, and
> > AwtFocusHandler classes.
> >
> > The issues:
> > #1
> > When using keyboard navigation, the default code misses sending the
focus to
> > the AWT control on its first pass through (the returned focus component
is
> > null). This can be solved by setting awtHasFocus to true at the top of
the
> > gainFocus method instead of at the bottom. This will ensure that an
attempt
> > is made to find a focusable swing control on the first focus attempt.
>
> Yes, this is definitely a bug in the article. Another solution is to
> change the EmbeddedChildFocusTraversalPolicy.getCurrentComponent()
> method to call super.getDefaultComponent, rather than
> this.getDefaultComponent.
>
> >
> > #2
> > I use an EmbeddedSwingComponent as the full contents of an editor
> > (consequently, the IWorkbenchPart's setFocus method sets the focus to
the
> > EmbeddedSwingComponent). When issue #1 is fixed (ie, the AWT control
> > automatically gets the focus when the SWT control gets the focus), there
is
> > occasionally a deadlock in Java 1.6 when several editors are opened at
once
> > (even though only asycExec and invokeLater calls are used). The
deadlock is
> > happening way down in AWT Code in the WPanelPeer class and is triggered
by
> > the component.requestFocus inside of the awtHandler's gainFocus method.
> > This seems to be solved when issue #3 is solved.
>
In my version of the article code (I'm not sure it changed after I
downloaded it), the setFocus doesn't make any AWT Calls. It simple checks
to see if it is focusable and calls super.setFocus()... strange.
> It's now pretty clear that Component.requestFocus has to be used
> carefully to avoid deadlock (and in our case other problems). The main
> thing is to make sure that it is always called from the AWT event
> thread. Unfortunately, the article code calls it from the SWT thread in
> two places. For example, I've now re-implemented
> EmbeddedSwingComposite.setFocus() as follows:
>
> public boolean setFocus() {
> checkWidget();
>
> //if (!isFocusable()) {
> // return false;
> //}
> if (swtHandler != null) {
> // Setting focus on the embedded component must posted to the
> // AWT thread because:
> // 1) The AWT Component.requestFocus method can deadlock if
> // called simultaneously from different threads.
> // 2) The embedded component is created asynhronously (on the
> // AWT thread), so it may not exist yet.
> // The call below does the appropriate posting. Since it is
> done
> // asynchronously, it is impossible to know the result, so
> // always return true.
> swtHandler.transferFocusToAwt();
> return true;
> } else {
> return super.setFocus();
> }
> }
>
> transferFocusToAwt is what you would expect:
>
> void transferFocusToAwt() {
> EventQueue.invokeLater(new Runnable() {
> public void run() {
> awtHandler.gainFocus();
> }
> });
> }
>
> A similar change is needed to the EmbeddedSwingComposite.forceFocus
method.
>
> I suspect these fixes will eliminate the deadlock problem you saw and
> that your solution to #3, though useful in its own right, simply made
> the deadlock less likely.
>
> >
> > #3
> > When the EmbeddedSwingComponent is the only focusable component inside
of a
> > Tab Folder, the awtHandler.gainFocus call causes a malfunction in
keyboard
> > navigation. When the tab labels get the focus (a tab's label is
> > underlined), typically one can switch between tabs by using the arrow
keys
> > and then dive into the current tab using the 'tab' key. To do this, the
SWT
> > Tab Folder seems to momentarily set the focus to the tab's contents and
then
> > return focus to the tab label.
> >
> > The problem is that we are telling AWT to take the focus when the tab's
> > contents gets the focus, so the focus doesn't go back to tab's label. I
> > have added set/get AbortFocus methods to the SwtFocusHandler. The abort
> > focus value is set whenever the SWT Control's focus is gained or lost.
This
> > way if the SWT control loses focus before AWT has a chance to set its
focus
> > we can decide not to set the AWT focus.
> >
> > I suspect the deadlock also has something to do with this quick transfer
of
> > focus.
>
> I didn't know you could navigate this way, so it clearly wasn't tested
> :-). Your solution looks like a good one.
>
> >
> > #4
> > There is a memory leak when you dispose of the SWT Control even if you
set
> > the frame to null. This leak is present in Java 1.5 update 11 and Java
1.6.
> > To remove the memory leak, the frame needs to have its
FocusableWindowState
> > set to false and it should be disposed of when the
EmbeddedSwingComponent is
> > disposed of. The frame should be disposed of in the Swing EDT.
>
> Interesting. SWT_AWT.new_Frame() installs a listener that is supposed to
> dispose the frame (on the AWT event thread) when the composite is
> disposed. Any ideas on why this is not happening?
>
> Is the need to set FocusableWindowState to false maybe due to this bug?
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6469530
Yes, I'm pretty sure that this is the same bug (as I recall from the last
time I ran this through a profiler). The GlobalRef stays in place until
another component gets focus. In our case (probably some of the special
world of the SWT/AWT mix), it is reproducable 100% of the time. I have
found that setting the setFocusableWindowState to false before the frame is
disposed is also a work-around to the problem. To be honest, I don't know
if the other explicit call to dispose is necessary.
> Or something else? I'm wondering if there's something that needs to be
> reported to Sun...
>
> I ran into a similar leak that was triggered by adding components to the
> frame from outside the AWT EDT. See
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6411042
>
|
|
|
Re: More tips for the sample code [message #572661 is a reply to message #1432] |
Fri, 28 September 2007 12:05 |
James Messages: 272 Registered: July 2009 |
Senior Member |
|
|
Aside from not seeming to make an AWT call out side of the AWT Thread, this
alternate implementation you have proposed breaks the fix for keyboard
navigation I describe (the SWT Component never really gains focus so it can
never lose it).
> In my version of the article code (I'm not sure it changed after I
> downloaded it), the setFocus doesn't make any AWT Calls. It simple checks
> to see if it is focusable and calls super.setFocus()... strange.
>
> > It's now pretty clear that Component.requestFocus has to be used
> > carefully to avoid deadlock (and in our case other problems). The main
> > thing is to make sure that it is always called from the AWT event
> > thread. Unfortunately, the article code calls it from the SWT thread in
> > two places. For example, I've now re-implemented
> > EmbeddedSwingComposite.setFocus() as follows:
> >
> > public boolean setFocus() {
> > checkWidget();
> >
> > //if (!isFocusable()) {
> > // return false;
> > //}
> > if (swtHandler != null) {
> > // Setting focus on the embedded component must posted to
the
> > // AWT thread because:
> > // 1) The AWT Component.requestFocus method can deadlock if
> > // called simultaneously from different threads.
> > // 2) The embedded component is created asynhronously (on
the
> > // AWT thread), so it may not exist yet.
> > // The call below does the appropriate posting. Since it is
> > done
> > // asynchronously, it is impossible to know the result, so
> > // always return true.
> > swtHandler.transferFocusToAwt();
> > return true;
> > } else {
> > return super.setFocus();
> > }
> > }
> >
> > transferFocusToAwt is what you would expect:
> >
> > void transferFocusToAwt() {
> > EventQueue.invokeLater(new Runnable() {
> > public void run() {
> > awtHandler.gainFocus();
> > }
> > });
> > }
> >
> > A similar change is needed to the EmbeddedSwingComposite.forceFocus
> method.
> >
> > I suspect these fixes will eliminate the deadlock problem you saw and
> > that your solution to #3, though useful in its own right, simply made
> > the deadlock less likely.
> >
|
|
|
Re: More tips for the sample code [message #572762 is a reply to message #1435] |
Sun, 07 October 2007 18:10 |
Gordon Hirsch Messages: 100 Registered: July 2009 |
Senior Member |
|
|
James wrote:
> Aside from not seeming to make an AWT call out side of the AWT Thread, this
> alternate implementation you have proposed breaks the fix for keyboard
> navigation I describe (the SWT Component never really gains focus so it can
> never lose it).
You're right. After looking a little closer, I don't think the
implementations of setFocus/forceFocus are necessary at all.
By the way, the extra code in setFocus/forceFocus was not part of the
original article. Sorry for any confusion I might have caused.
>
>> In my version of the article code (I'm not sure it changed after I
>> downloaded it), the setFocus doesn't make any AWT Calls. It simple checks
>> to see if it is focusable and calls super.setFocus()... strange.
>>
>>> It's now pretty clear that Component.requestFocus has to be used
>>> carefully to avoid deadlock (and in our case other problems). The main
>>> thing is to make sure that it is always called from the AWT event
>>> thread. Unfortunately, the article code calls it from the SWT thread in
>>> two places. For example, I've now re-implemented
>>> EmbeddedSwingComposite.setFocus() as follows:
>>>
>>> public boolean setFocus() {
>>> checkWidget();
>>>
>>> //if (!isFocusable()) {
>>> // return false;
>>> //}
>>> if (swtHandler != null) {
>>> // Setting focus on the embedded component must posted to
> the
>>> // AWT thread because:
>>> // 1) The AWT Component.requestFocus method can deadlock if
>>> // called simultaneously from different threads.
>>> // 2) The embedded component is created asynhronously (on
> the
>>> // AWT thread), so it may not exist yet.
>>> // The call below does the appropriate posting. Since it is
>>> done
>>> // asynchronously, it is impossible to know the result, so
>>> // always return true.
>>> swtHandler.transferFocusToAwt();
>>> return true;
>>> } else {
>>> return super.setFocus();
>>> }
>>> }
>>>
>>> transferFocusToAwt is what you would expect:
>>>
>>> void transferFocusToAwt() {
>>> EventQueue.invokeLater(new Runnable() {
>>> public void run() {
>>> awtHandler.gainFocus();
>>> }
>>> });
>>> }
>>>
>>> A similar change is needed to the EmbeddedSwingComposite.forceFocus
>> method.
>>> I suspect these fixes will eliminate the deadlock problem you saw and
>>> that your solution to #3, though useful in its own right, simply made
>>> the deadlock less likely.
>>>
>
>
|
|
|
Re: More tips for the sample code [message #573612 is a reply to message #1412] |
Tue, 27 November 2007 02:35 |
James Peltzer Messages: 43 Registered: July 2009 |
Member |
|
|
Gordon (or anyone),
As you suspected, my workaround for the requestFocus deadlock issue is not a
solution 100% of the time. In fact, lately the issue is happening
frequently enough to prevent my next software release.
Have you any idea why I might be getting deadlock in
WComponentPeer._requestFocus when calling it from the AWT EDT after an
invokeLater from the SWT EDT? I could really use some help with this one.
Naturally, as with most timing bugs, I don't really have a snipped that I
can post.
-James
"Gordon Hirsch" <gordon.hirsch@sas.com> wrote in message
news:fdh53e$j7i$1@build.eclipse.org...
> James wrote:
>> I have found several more issues relating to focus and the SWT/Swing
>> integration. I have breifly outlined each issue below and posted my code
>> modifications at the bottom. I suspect I may not be clear enough in
>> describing both the issues, the solutions, and how they work, so please
>> ask
>> any questions you might have. I would imagine others have periodically
>> noticed at least some of these issues as well.
>>
>> Any thoughts on these Gordon?
>
> James, first of all, thank you for sharing your fixes and improvements. I
> have some comments and questions below.
>
>>
>> My workarounds affect EmbeddedSwingComposite, SwtFocusHandler, and
>> AwtFocusHandler classes.
>>
>> The issues:
>> #1
>> When using keyboard navigation, the default code misses sending the focus
>> to
>> the AWT control on its first pass through (the returned focus component
>> is
>> null). This can be solved by setting awtHasFocus to true at the top of
>> the
>> gainFocus method instead of at the bottom. This will ensure that an
>> attempt
>> is made to find a focusable swing control on the first focus attempt.
>
> Yes, this is definitely a bug in the article. Another solution is to
> change the EmbeddedChildFocusTraversalPolicy.getCurrentComponent() method
> to call super.getDefaultComponent, rather than this.getDefaultComponent.
>
>>
>> #2
>> I use an EmbeddedSwingComponent as the full contents of an editor
>> (consequently, the IWorkbenchPart's setFocus method sets the focus to the
>> EmbeddedSwingComponent). When issue #1 is fixed (ie, the AWT control
>> automatically gets the focus when the SWT control gets the focus), there
>> is
>> occasionally a deadlock in Java 1.6 when several editors are opened at
>> once
>> (even though only asycExec and invokeLater calls are used). The deadlock
>> is
>> happening way down in AWT Code in the WPanelPeer class and is triggered
>> by
>> the component.requestFocus inside of the awtHandler's gainFocus method.
>> This seems to be solved when issue #3 is solved.
>
> It's now pretty clear that Component.requestFocus has to be used carefully
> to avoid deadlock (and in our case other problems). The main thing is to
> make sure that it is always called from the AWT event thread.
> Unfortunately, the article code calls it from the SWT thread in two
> places. For example, I've now re-implemented
> EmbeddedSwingComposite.setFocus() as follows:
>
> public boolean setFocus() {
> checkWidget();
>
> //if (!isFocusable()) {
> // return false;
> //}
> if (swtHandler != null) {
> // Setting focus on the embedded component must posted to the
> // AWT thread because:
> // 1) The AWT Component.requestFocus method can deadlock if
> // called simultaneously from different threads.
> // 2) The embedded component is created asynhronously (on the
> // AWT thread), so it may not exist yet.
> // The call below does the appropriate posting. Since it is
> done
> // asynchronously, it is impossible to know the result, so
> // always return true.
> swtHandler.transferFocusToAwt();
> return true;
> } else {
> return super.setFocus();
> }
> }
>
> transferFocusToAwt is what you would expect:
>
> void transferFocusToAwt() {
> EventQueue.invokeLater(new Runnable() {
> public void run() {
> awtHandler.gainFocus();
> }
> });
> }
>
> A similar change is needed to the EmbeddedSwingComposite.forceFocus
> method.
>
> I suspect these fixes will eliminate the deadlock problem you saw and that
> your solution to #3, though useful in its own right, simply made the
> deadlock less likely.
>
>>
>> #3
>> When the EmbeddedSwingComponent is the only focusable component inside of
>> a
>> Tab Folder, the awtHandler.gainFocus call causes a malfunction in
>> keyboard
>> navigation. When the tab labels get the focus (a tab's label is
>> underlined), typically one can switch between tabs by using the arrow
>> keys
>> and then dive into the current tab using the 'tab' key. To do this, the
>> SWT
>> Tab Folder seems to momentarily set the focus to the tab's contents and
>> then
>> return focus to the tab label.
>>
>> The problem is that we are telling AWT to take the focus when the tab's
>> contents gets the focus, so the focus doesn't go back to tab's label. I
>> have added set/get AbortFocus methods to the SwtFocusHandler. The abort
>> focus value is set whenever the SWT Control's focus is gained or lost.
>> This
>> way if the SWT control loses focus before AWT has a chance to set its
>> focus
>> we can decide not to set the AWT focus.
>>
>> I suspect the deadlock also has something to do with this quick transfer
>> of
>> focus.
>
> I didn't know you could navigate this way, so it clearly wasn't tested
> :-). Your solution looks like a good one.
>
>>
>> #4
>> There is a memory leak when you dispose of the SWT Control even if you
>> set
>> the frame to null. This leak is present in Java 1.5 update 11 and Java
>> 1.6.
>> To remove the memory leak, the frame needs to have its
>> FocusableWindowState
>> set to false and it should be disposed of when the EmbeddedSwingComponent
>> is
>> disposed of. The frame should be disposed of in the Swing EDT.
>
> Interesting. SWT_AWT.new_Frame() installs a listener that is supposed to
> dispose the frame (on the AWT event thread) when the composite is
> disposed. Any ideas on why this is not happening?
>
> Is the need to set FocusableWindowState to false maybe due to this bug?
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6469530
>
> Or something else? I'm wondering if there's something that needs to be
> reported to Sun...
>
> I ran into a similar leak that was triggered by adding components to the
> frame from outside the AWT EDT. See
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6411042
>
|
|
| | | | | |
Re: More tips for the sample code [message #575209 is a reply to message #1412] |
Tue, 23 June 2009 23:46 |
Ken Messages: 36 Registered: July 2009 |
Member |
|
|
Gordon - has this fix been applied to 0.0.3? I took a look, but it seems
like things have changed a lot and I was not able to identify if these
changes are in the latest release. Or are they no longer even necessary?
Thanks!
- Ken
"Gordon Hirsch" <gordon.hirsch@sas.com> wrote in message
news:fdh53e$j7i$1@build.eclipse.org...
> James wrote:
>> I have found several more issues relating to focus and the SWT/Swing
>> integration. I have breifly outlined each issue below and posted my code
>> modifications at the bottom. I suspect I may not be clear enough in
>> describing both the issues, the solutions, and how they work, so please
>> ask
>> any questions you might have. I would imagine others have periodically
>> noticed at least some of these issues as well.
>>
>> Any thoughts on these Gordon?
>
> James, first of all, thank you for sharing your fixes and improvements. I
> have some comments and questions below.
>
>>
>> My workarounds affect EmbeddedSwingComposite, SwtFocusHandler, and
>> AwtFocusHandler classes.
>>
>> The issues:
>> #1
>> When using keyboard navigation, the default code misses sending the focus
>> to
>> the AWT control on its first pass through (the returned focus component
>> is
>> null). This can be solved by setting awtHasFocus to true at the top of
>> the
>> gainFocus method instead of at the bottom. This will ensure that an
>> attempt
>> is made to find a focusable swing control on the first focus attempt.
>
> Yes, this is definitely a bug in the article. Another solution is to
> change the EmbeddedChildFocusTraversalPolicy.getCurrentComponent() method
> to call super.getDefaultComponent, rather than this.getDefaultComponent.
>
>>
>> #2
>> I use an EmbeddedSwingComponent as the full contents of an editor
>> (consequently, the IWorkbenchPart's setFocus method sets the focus to the
>> EmbeddedSwingComponent). When issue #1 is fixed (ie, the AWT control
>> automatically gets the focus when the SWT control gets the focus), there
>> is
>> occasionally a deadlock in Java 1.6 when several editors are opened at
>> once
>> (even though only asycExec and invokeLater calls are used). The deadlock
>> is
>> happening way down in AWT Code in the WPanelPeer class and is triggered
>> by
>> the component.requestFocus inside of the awtHandler's gainFocus method.
>> This seems to be solved when issue #3 is solved.
>
> It's now pretty clear that Component.requestFocus has to be used carefully
> to avoid deadlock (and in our case other problems). The main thing is to
> make sure that it is always called from the AWT event thread.
> Unfortunately, the article code calls it from the SWT thread in two
> places. For example, I've now re-implemented
> EmbeddedSwingComposite.setFocus() as follows:
>
> public boolean setFocus() {
> checkWidget();
>
> //if (!isFocusable()) {
> // return false;
> //}
> if (swtHandler != null) {
> // Setting focus on the embedded component must posted to the
> // AWT thread because:
> // 1) The AWT Component.requestFocus method can deadlock if
> // called simultaneously from different threads.
> // 2) The embedded component is created asynhronously (on the
> // AWT thread), so it may not exist yet.
> // The call below does the appropriate posting. Since it is
> done
> // asynchronously, it is impossible to know the result, so
> // always return true.
> swtHandler.transferFocusToAwt();
> return true;
> } else {
> return super.setFocus();
> }
> }
>
> transferFocusToAwt is what you would expect:
>
> void transferFocusToAwt() {
> EventQueue.invokeLater(new Runnable() {
> public void run() {
> awtHandler.gainFocus();
> }
> });
> }
>
> A similar change is needed to the EmbeddedSwingComposite.forceFocus
> method.
>
> I suspect these fixes will eliminate the deadlock problem you saw and that
> your solution to #3, though useful in its own right, simply made the
> deadlock less likely.
>
>>
>> #3
>> When the EmbeddedSwingComponent is the only focusable component inside of
>> a
>> Tab Folder, the awtHandler.gainFocus call causes a malfunction in
>> keyboard
>> navigation. When the tab labels get the focus (a tab's label is
>> underlined), typically one can switch between tabs by using the arrow
>> keys
>> and then dive into the current tab using the 'tab' key. To do this, the
>> SWT
>> Tab Folder seems to momentarily set the focus to the tab's contents and
>> then
>> return focus to the tab label.
>>
>> The problem is that we are telling AWT to take the focus when the tab's
>> contents gets the focus, so the focus doesn't go back to tab's label. I
>> have added set/get AbortFocus methods to the SwtFocusHandler. The abort
>> focus value is set whenever the SWT Control's focus is gained or lost.
>> This
>> way if the SWT control loses focus before AWT has a chance to set its
>> focus
>> we can decide not to set the AWT focus.
>>
>> I suspect the deadlock also has something to do with this quick transfer
>> of
>> focus.
>
> I didn't know you could navigate this way, so it clearly wasn't tested
> :-). Your solution looks like a good one.
>
>>
>> #4
>> There is a memory leak when you dispose of the SWT Control even if you
>> set
>> the frame to null. This leak is present in Java 1.5 update 11 and Java
>> 1.6.
>> To remove the memory leak, the frame needs to have its
>> FocusableWindowState
>> set to false and it should be disposed of when the EmbeddedSwingComponent
>> is
>> disposed of. The frame should be disposed of in the Swing EDT.
>
> Interesting. SWT_AWT.new_Frame() installs a listener that is supposed to
> dispose the frame (on the AWT event thread) when the composite is
> disposed. Any ideas on why this is not happening?
>
> Is the need to set FocusableWindowState to false maybe due to this bug?
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6469530
>
> Or something else? I'm wondering if there's something that needs to be
> reported to Sun...
>
> I ran into a similar leak that was triggered by adding components to the
> frame from outside the AWT EDT. See
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6411042
>
|
|
|
Goto Forum:
Current Time: Sat Oct 19 14:37:01 GMT 2024
Powered by FUDForum. Page generated in 0.05716 seconds
|