Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 328396 - MouseDown not delivered until drag started if a DragDetect listener is attached
Summary: MouseDown not delivered until drag started if a DragDetect listener is attached
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 3.7   Edit
Hardware: Macintosh Mac OS X
: P3 normal (vote)
Target Milestone: 3.7 M3   Edit
Assignee: Scott Kovatch CLA
QA Contact: Silenio Quarti CLA
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-10-21 15:21 EDT by Scott Kovatch CLA
Modified: 2010-10-27 10:47 EDT (History)
4 users (show)

See Also:


Attachments
Patch (1.17 KB, patch)
2010-10-21 18:06 EDT, Scott Kovatch CLA
no flags Details | Diff
Patch for linux (1.59 KB, patch)
2010-10-21 18:07 EDT, Scott Kovatch CLA
no flags Details | Diff
Patch for win32 (5.79 KB, patch)
2010-10-21 18:56 EDT, Scott Kovatch CLA
no flags Details | Diff
Drag detect timeout for cocoa (1.13 KB, patch)
2010-10-22 13:39 EDT, Scott Kovatch CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Scott Kovatch CLA 2010-10-21 15:21:09 EDT
From <http://stackoverflow.com/questions/3908290/> :

Run this code with 3.7:
==================================
    package swttest;

    import org.eclipse.swt.dnd.DND;
    import org.eclipse.swt.dnd.DragSource;
    import org.eclipse.swt.dnd.DragSourceEvent;
    import org.eclipse.swt.dnd.DragSourceListener;
    import org.eclipse.swt.events.MouseEvent;
    import org.eclipse.swt.events.MouseListener;
    import org.eclipse.swt.widgets.Display;
    import org.eclipse.swt.widgets.Shell;

    public class SwtTest {
        public static void main(String[] args) {
            final Display display = new Display();
            final Shell shell = new Shell(display);
            shell.addMouseListener(new MouseListener() {
                public void mouseUp(MouseEvent e) {
                    System.out.println("mouseUp");
                }

                public void mouseDown(MouseEvent e) {
                    System.out.println("mouseDown");
                }

                public void mouseDoubleClick(MouseEvent e) {
                    System.out.println("mouseDoubleClick");
                }
            });
            DragSourceListener dragListener = new DragSourceListener() {

                public void dragFinished(DragSourceEvent event) {
                    System.out.println("dragFinished");

                }

                public void dragSetData(DragSourceEvent event) {
                    System.out.println("dragSetData");

                }

                public void dragStart(DragSourceEvent event) {
                    System.out.println("dragStart");
                }
            };
            DragSource dragSource = new DragSource(shell, DND.DROP_COPY | DND.DROP_MOVE);
            dragSource.addDragListener(dragListener);
            shell.pack();
            shell.open();
            while (!shell.isDisposed()) {
                if (!display.readAndDispatch())
                    display.sleep();
            }
            display.dispose();
        }
    }

========================

The mouseDown doesn't arrive until the drag is underway or until you release the mouse. At that point you get a mouseDown and an immediate mouseUp afterwards.

Now, comment out these lines and run again:

            DragSource dragSource = new DragSource(shell, DND.DROP_COPY | DND.DROP_MOVE);
            dragSource.addDragListener(dragListener);

The mouseDown is delivered immediately, on click.

This seems to be an issue across all platforms, but I only tested it with Cocoa.
Comment 1 Ian Bull CLA 2010-10-21 16:57:59 EDT
I can confirm at on GTK+ you do get the mouseDown, but it is delayed a few seconds (or if you release the button, then you get the mouseDown/mouseUp together like on Cocoa).
Comment 2 Scott Kovatch CLA 2010-10-21 18:06:39 EDT
Created attachment 181455 [details]
Patch

Fix for Cocoa. Other platforms will have a similar fix; deliver the mousedown right away if the component is watching for DragDetect.
Comment 3 Scott Kovatch CLA 2010-10-21 18:07:34 EDT
Created attachment 181456 [details]
Patch for linux
Comment 4 Scott Kovatch CLA 2010-10-21 18:56:01 EDT
One difference I've noticed is that the drag detection on GTK and Windows times out. In GTK, click and hold cancels the drag and on Win32 click and hold initiates a drag. On Cocoa it does neither -- we continue until either a mouseup happens or the mouse is dragged out of the 5x5 box to indicate a real drag has started.

These patches harmonize the behavior by sending the SWT.MouseDown immediately before checking for the drag start if the control is listening for SWT.DragDetect but also keeps the current behavior of posting the event and not dispatching it until the current native event has been handled.

Bug #26605 implies that should be the current behavior, but it doesn't look like it to me.
Comment 5 Scott Kovatch CLA 2010-10-21 18:56:37 EDT
Created attachment 181457 [details]
Patch for win32
Comment 6 Felipe Heidrich CLA 2010-10-22 11:18:59 EDT
The code in HEAD is right.
If the control is a drag source it has to determine if a drag start should
happen before proceeding with the mouse down.

It seems the win32 patch is not the correct file for this bug. I suspect fixing
this problem (based on the comments above) will break the workbench.
Comment 7 Scott Kovatch CLA 2010-10-22 12:09:49 EDT
Is the problem then that we're not consistent about drag detection timeout? Maybe on Cocoa I need to add a timeout similar to GTK where we stop looking for a drag after a half second or so.

Tor added himself to the CC list; Tor, what were you trying to do that's causing a problem here?
Comment 8 Felipe Heidrich CLA 2010-10-22 12:42:42 EDT
(In reply to comment #7)
> Is the problem then that we're not consistent about drag detection timeout?
> Maybe on Cocoa I need to add a timeout similar to GTK where we stop looking for
> a drag after a half second or so.

If you don't have a timeout on cocoa that certainly looks like a bug to me.
(note that the duration of the time out is platform specific.)

On Windows we have a OS call that does all the work us (see OS.DragDetect())
On GTK we simulate the process ourself (during the event loop and all), see Control#dragDetect().

I would expect Cocoa to have code similar to the one in GTK.
Comment 9 Scott Kovatch CLA 2010-10-22 13:10:38 EDT
(In reply to comment #8)

> If you don't have a timeout on cocoa that certainly looks like a bug to me.
> (note that the duration of the time out is platform specific.)
> 
> On Windows we have a OS call that does all the work us (see OS.DragDetect())
> On GTK we simulate the process ourself (during the event loop and all), see
> Control#dragDetect().
> 
> I would expect Cocoa to have code similar to the one in GTK.

Interesting... that's the first I've heard that this is intentional behavior.  Should be easy to fix, though.
Comment 10 Scott Kovatch CLA 2010-10-22 13:39:07 EDT
Created attachment 181526 [details]
Drag detect timeout for cocoa

Add half-second timeout for a drag detect. Works, but it feels odd to do that.
Comment 11 Tor Norbye CLA 2010-10-22 15:26:57 EDT
(In reply to comment #7)
> Tor added himself to the CC list; Tor, what were you trying to do that's
> causing a problem here?

We have a visual editor which uses drag & drop, instead of just a mouse listener, such that it can support dragging a visual element from one canvas to another canvas (even another canvas in another instance of Eclipse). Therefore, we have a drag gesture listener on the canvas such that we can find out when you start dragging something.

However, I noticed that (as a Mac user) the UI felt a bit "laggy" to me, and I realized it was because it's only acting on mouse -up-, instead of on mouse -down-. For example, context menus aren't shown until the mouse is released, which is the opposite of how menus -should- behave on Macs. I know SWT has support for handling context menus in a platform-specific way (the equivalent of Swing's isPopupTrigger), so a simple SWT program with a menu will correctly pop up the context menu on mouse down on the Mac, on on mouse up on Windows.

However, it looks like the drag gesture listener suppresses all of this and forces nothing, including popup menus, to post until mouse release.

I don't really understand why the drag gesture blocking mouse events and timeouts is necessary. If I simply hold the mouse button (but don't move the mouse) for 5 seconds I don't consider that a drag; certainly at least on the Mac in the native applications I don't get a drag cursor until I drag the mouse for a few pixels. 

From a naive perspective, it seems to me that the control should be notified immediately when a mouse is pushed, even if it will later result in a drag - definitely the context menus should work that way on the Mac.  If this cannot be fixed in this way (e.g. without the 1 second delay), it sounds like I might be better off getting rid of the drag gesture listener, and just use a plain mouse listener for visual editor interactions within the canvas, and then somehow programmatically triggering a full drag & drop interaction the minute you drag the mouse out of the canvas (a mouseLeave event with the primary button pressed). If anyone can point me to some existing code for how to trigger that, I would appreciate it; I know this bug thread isn't the right place for it, but it would help me work around this issue...  And I know it should be possible to make this work since the Eclipse package explorer does what I want - it supports native drag & drop, yet it also responds immediately to context menu clicks. I'm just not sure how to do it since the naive implementation, shown in the testcase attached to this issue, does not behave that way.
Comment 12 Scott Kovatch CLA 2010-10-22 17:15:51 EDT
(In reply to comment #11)
> (In reply to comment #7)

> However, I noticed that (as a Mac user) the UI felt a bit "laggy" to me, and I
> realized it was because it's only acting on mouse -up-, instead of on mouse
> -down-. For example, context menus aren't shown until the mouse is released,
> which is the opposite of how menus -should- behave on Macs. I know SWT has
> support for handling context menus in a platform-specific way (the equivalent
> of Swing's isPopupTrigger), so a simple SWT program with a menu will correctly
> pop up the context menu on mouse down on the Mac, on on mouse up on Windows.
> 
> However, it looks like the drag gesture listener suppresses all of this and
> forces nothing, including popup menus, to post until mouse release.

Aha, now this is making more sense. I assume you're using control-click to get the context menu, right? 
The test to see if we should detect a drag looks for DragDetect listeners and a single click on the left mouse, but if the control key is down we should skip the check because that combination can never start a drag.

> From a naive perspective, it seems to me that the control should be notified
> immediately when a mouse is pushed, even if it will later result in a drag -
> definitely the context menus should work that way on the Mac. 

I agree with you, but based on Felipe's comment above, it looks like the workbench relies on the current behavior. I didn't see any problems in my testing but I'm hesitant to make any changes.

I think we can make both of these scenarios work on Cocoa, but you'll have to wait for 3.7 for a fix from us.

> If anyone can point me to some existing code for how to
> trigger that, I would appreciate it; I know this bug thread isn't the right
> place for it, but it would help me work around this issue...

See Snippet259.java at www.eclipse.org/swt/snippets, which shows how you can call dragDetect(Event) yourself during a mouseDown.

> And I know it
> should be possible to make this work since the Eclipse package explorer does
> what I want - it supports native drag & drop, yet it also responds immediately
> to context menu clicks. I'm just not sure how to do it since the naive
> implementation, shown in the testcase attached to this issue, does not behave
> that way.

Table and Tree don't have this problem because we let Cocoa perform the drag detection and then start the drag when we get the first callback from NSTableView. I would guess that Cocoa doesn't check for a drag on control-click either.
Comment 13 Scott Kovatch CLA 2010-10-22 19:05:02 EDT
Checked in a fix that's slightly different. I pass in an NSDate that is .3 seconds in the future as a timeout. With that there's no need for special checking for the control key.

Fixed > 20101022.