Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 141893

Summary: SWT/AWT Bridge : Problems with drop target on EditorPart using bridge (Linux Only)
Product: [Eclipse Project] Platform Reporter: Tom Porcaro <tporcaro>
Component: SWTAssignee: Silenio Quarti <Silenio_Quarti>
Status: CLOSED WONTFIX QA Contact:
Severity: major    
Priority: P3 CC: bsd, ericwill, gsmith, joekhan10, ncasas, nicolas.richeton, snorthov, yves.pasche
Version: 3.1.2Keywords: triaged
Target Milestone: ---   
Hardware: PC   
OS: Linux-GTK   
Whiteboard: stalebug
Attachments:
Description Flags
snippet
none
source attachement none

Description Tom Porcaro CLA 2006-05-15 17:16:50 EDT
SUMMARY:

When more than one eclipse editor that uses the SWT/AWT bridge is open simultaneously, drag and drop does not work correctly. The first editor opened receives all drag and drop events regardless of whether or not it is the current editor displayed in the workbench. If you subsequently open another editor (that uses the bridge) on top of the editor that was previously opened and perform a drag and drop onto that second editor, the DND events will fall thru and be handled by the underlying editor (the 1st opened) which is not currently visible in the editor area of eclipse workbench.

This behavior only occurs on the Linux SWT/AWT bridge. The Windows bridge works fine. I am using Red Hat 4 Advanced Server with GTK/Gnome.

STEPS TO REPRODUCE:

1) Build a plugin with EditorPart that uses SWT/AWT bridge and contains an AWT or Swing Component that is a valid drop target.

a) Extend EditorPart and implement createPartControl(Composite parent) method. 
b) Add a new embedded Composite to the parent. (i.e. Use the SWT.EMBEDDED style when instantiating Composite) 
c) Use SWT_AWT.new_Frame(embeddedComposite) to get the AWT bridge Frame.
d) Add your Panel or JPanel containing your AWT or Swing component view to the AWT Frame returned. 
e) Add an AWT or Swing component that is a valid DropTarget onto your panel. Provide listeners to handle DND events appropriately.
f) Create your plugin.xml for your plugin. Add an "org.eclipse.ui.editors" extension that references your new EditorPart class and associates your editor with an IResource extension type.
g) Launch eclipse with a runtime workspace that has your plugin loaded and create some resources of the extension type recognized by your editor.

2) Now use the Navigator view to open a resource that your editor recognizes. Your initial (first) editor instance will appear in the editor area of the eclipse workbench.
3) Now drag a valid object (depending on your application) from the navigator or some other view onto your editor. Your editor handles the drag acceptance and drop successfully.
4) Next use the Navigator view to open a different resource that your editor recognizes. Your subsequent (second) editor instance will appear in the editor area of the eclipse workbench on top of your initial (first) editor instance. (i.e. both editor instances are open simultaneously but only the second instance you opened is currently visible in the editor area on top of the first instance)
5) Now drag a valid object (depending on your application) from the navigator or some other view onto your second (now visible) editor instance. Your visible editor instance no longer appears show the drag acceptance icon in the expected places of the view and the drop does not appear to occur when releasing the mouse over an area of the view that shows drag acceptance.
6) Finally use the workbench editor area tabs to bring your initial (first) editor to the surface. You will see where your drop went. Strange but true. 

USER WORKAROUND: 

Only keep a single editor instance that uses the SWT/AWT bridge opened at any one time if these editors support drag and drop OR avoid performing drag and drop operations altogether if possible.

FOR DEVELOPERS:

If you are a plugin developer creating products using the SWT/AWT bridge, here is a summary of a potential Linux bridge patch that you can implement. Although tricky to implement, I found that it overcomes this problem without any noticeable side effects. This may also help the SWT/AWT bridge developer to diagnose this problem.

Diagnosis:

Although I do not know for sure what is causing this problem, I have 
definitely isolated the source of the problem to the XEmbeddedFrame of the 
SWT_AWT bridge on Linux. I have decompiled the bridge code on Linux and 
noticed that within the XWindowPeer (base class of XEmbeddedFramePeer) there 
are public methods called addDropTarget() and removeDropTarget(). It appears 
that when addDropTarget() is called for more than one XEmbeddedFramePeer at a 
time (the case when mutliple bridge editors are simultaneously open), just 
the first one called becomes an active droptarget and the calls for 
subsequent peers fail to become active drop targets.

Temporary Patch:

In order to workaround the SWT_AWT bridge problem I must enforce a restriction in my editor code that only one XEmbeddedFramePeer drop target is active at any one time for the my bridge editors. This means that drop targets are now added (via addDropTarget()) and removed (via removeDropTarget()) as the user switches focus between bridge editors. Unfortunately these methods in the peer did not work consistently for me since they use reference counting and there were unmatched adds and removes as the user switches focus from one editor to another. So in many case, the calls were being ignored and in turn not calling the XDropTargetRegistry to add and remove drop target windows to/from the registry. In addition, I found a bug in the XDropTargetRegistry.unregisterDropSite(handle) method where it removes the window handle from the XDropTargetProtocol but then fails to call XDropTargetRegistry.unregisterEmbeddedDropSite(thandle, whandle) to unregister the window handle as a valid site from the embedded drop site registry. This caused the unregisterDropSite() method to be unaffective.

Here is a summary of the steps required to add the workaround above and patch the necessary bridge methods:

1) Created a new patched embedded frame peer class that extends XEmbeddedFramePeer and overides/implements the following methods:

Note: For much of this you will need to use reflection and accessibility overrides to get at package protected or private methods and fields. As long as your a standalone app without a security manager this isn't a problem.

a) Override XEmbeddedFramePeer.addDropTarget() method to override the behavior in XWindowPeer and eliminate the reference counter such that XDropTargetRegistry.registerDropSite(handle) is called directly. In addition this method is NOOPed if the peer's target embedded frame is not currently the eclipse active workbench window. This eliminates implicit calling of this method when addNotify() is called on the peer as a result of adding components to the embedded frame.
b) Override XEmbeddedFramePeer.removeDropTarget() method to override the behavior in XWindowPeer and eliminate the reference counter such that XDropTargetRegistry.unregisterDropSite(handle) is called directly. Again, this method is NOOPed if the peer's target embedded frame is not currently the eclipse active workbench window. This eliminates implicit calling of this method when removeNotify() is called on the peer.
c) Also modified the overidden XEmbeddedFramePeer.removeDropTarget() method such that XDropTargetRegistry.unregisterEmbeddedDropSite(thandle, whandle) is called directly. This fixes the bug in the XDropTargetRegistry.unregisterDropSite(handle) described above.
d) Added property methods isActive() and setActive(b) to set the state of XEmbeddedFramePeer so that add and remove drop target invocations are only performed on the active editor (NOOPED for others)

2) Created a new patched embedded frame class that extends XEmbeddedFrame and installs an instance of your new patched peer (via setPeer(p)) in the constructor. Be sure to set the base class' handle field in your constructor and intialize your embedded frame appropriately (i.e. addNotify(), show(), peer.setVisible(true)). Use reflection and accessibility overrides to get at package protected or private methods and fields. 
3) Created a patched version of SWT_AWT class by extending and overriding the 
SWT_AWT.new_Frame(c) method to instantiate and return your patched XEmbeddedFrame. Keep other parts of the method the same. Again, use reflection and accessibility overrides to invoke package protected or private methods in the base class.
4) Modified the patched SWT_AWT class to add a method 
activateEmbeddedFrame(frame) that uses a static member to keep track of the 
current embedded bridge frame which is active in the workbench window. When called, it deactivates the previous bridge embedded frame and activates the new one such that only one peer has active state at any one time.
5) Modify my EditorPart such that my patched SWT_AWT activateEmbeddedFrame(frame) method is called for the editor's bridge Frame whenever setFocus() is called on the editor part. This deactivates the patched bridge peer for the previously shown embedded peer and subsequently activates the embedded peer for the editor currently visible. (The workaround)
Comment 1 Grant Gayed CLA 2006-05-17 14:32:26 EDT
This still happens in the latest.  SSQ, a snippet is attached in the next comment.  Just drag from somewhere (eg.- an eclipse navigator) into the visible editor, and you'll see that all "drop" messages get written to editor #1 regardless of whether editor #1 or #2 is visible.
Comment 2 Grant Gayed CLA 2006-05-17 14:33:04 EDT
Created attachment 41772 [details]
snippet
Comment 3 Steve Northover CLA 2007-04-29 10:57:07 EDT
Seems like a problem in the AWT code.  Did anyone enter a bug report against them?
Comment 4 noe casas CLA 2007-12-14 03:18:02 EST
This bug has been accepted by Sun. You can monitor the bug on the Java Bug Database at http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6640765
Please vote for it! :-)
Comment 5 Brian de Alwis CLA 2013-09-04 16:59:09 EDT
The example in attachment 41772 [details] now seems to work properly on JDK 7 -- at least, I see the dropped text appearing in the correct editor.  But I see the original problem in my app using SWT_AWT.
Comment 6 Joe Khan CLA 2013-11-29 13:36:23 EST
I have provided a workable solution where I'm working right now. This Linux bug only happens when editors are stacking in CTabFolder, the drop target is always the editor which was opened first and not the one which is on the top (selected in CTabFolder). Everything is fine if editors are not stacking together. 

The solution is to use java reflection to remove dropTarget if an editor is not on the top of the stacking group of editors(grouped by cTabFolder).

I'm not extending XEmbeddedFramePeer or XEmbeddedFrame, because that's not a simple change maintainability wise, instead achieving the same purpose via reflection. This workaround also takes care of the inconsistent drop target count in the Window peer class.

To use this solution
(1)modify your plugin.xml
<extension
      point="org.eclipse.ui.startup">
     <startup class="com.lgc.dsp.ui.swtbridge.util.LinuxDndControllerStartup"></startup>
</extension>

(2)whenever you create an embedded swing component use LinuxDndCopntroller#register
Comment 7 Joe Khan CLA 2013-11-29 13:39:37 EST
Created attachment 237878 [details]
source  attachement

source code for the solution I was talking about in my last comment.
Comment 8 Nicolas Richeton CLA 2016-08-03 07:44:33 EDT
Problem still exists in Eclipse Neon + jdk 7/8

We have to remove our Part from the part stack which contains other parts using SWT_AWT bridge to make DND work. 

Putting back the pack in the stack disables DND.
Comment 9 Eric Williams CLA 2019-02-15 15:41:01 EST
Still reproducible with SWT master from today, GTK3.24, and Fedora 29.
Comment 10 Eclipse Genie CLA 2021-02-05 13:57:30 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. As such, we're closing this bug.

If you have further information on the current state of the bug, please add it and reopen this bug. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.