[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Newsgroup Home]
[news.eclipse.technology.albireo] Re: More tips for the sample code

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@xxxxxxx> wrote in message 
news:fdh53e$j7i$1@xxxxxxxxxxxxxxxxxxxx
> 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.
>