Bug 541850 - [GTK] mouseUp event not fired if MenuDetect listener adds a Menu
Summary: [GTK] mouseUp event not fired if MenuDetect listener adds a Menu
Status: NEW
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 3.8.2   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Platform-SWT-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: triaged
Depends on:
Blocks:
 
Reported: 2018-12-03 09:36 EST by Andrey Loskutov CLA
Modified: 2020-01-21 08:14 EST (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andrey Loskutov CLA 2018-12-03 09:36:27 EST
Mouse UP event for the right mouse button is not fired if there is a MenuDetect listener with a menu added and menu is shown on right click.

This works on Windows and does not work on Linux GTK3/GTK2. I've tried back to 3.8.2, same result. Seem to be always the case on GTK.

In the snippet above, just do the right click to show the menu and check the printed events:

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MenuDetectEvent;
import org.eclipse.swt.events.MenuDetectListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;

public class NoMouseUpEvent {

	public static void main(String[] args) {
		Display display = new Display();
		Shell shell = new Shell(display);
		shell.setLayout(new FillLayout(SWT.VERTICAL));
		shell.setSize(400, 200);

		Composite c = new Composite(shell, 0);
		c.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
		Label lbl = new Label(c, 0);
		lbl.setText("Right click to see the menu");
		lbl.setSize(400, 200);

		lbl.addMouseListener(new MouseListener() {
			public void mouseUp(MouseEvent e) {
				System.out.println("Mouse Up: " + e);
			}

			public void mouseDown(MouseEvent e) {
				System.out.println("Mouse Down: " + e);
			}

			public void mouseDoubleClick(MouseEvent e) {
				System.out.println("Double click: " + e);
			}
		});

		final Menu menu = new Menu(shell, SWT.POP_UP);
		MenuItem item = new MenuItem(menu, SWT.PUSH);
		item.setText("Menu Item");

		lbl.addMenuDetectListener(new MenuDetectListener() {
			public void menuDetected(MenuDetectEvent e) {
				System.out.println("Menu detected: " + e);
			}
		});

		lbl.addMenuDetectListener(new MenuDetectListener() {
			public void menuDetected(MenuDetectEvent e) {
				System.out.println("Menu visible: " + e);
				// The line below prevents mouseUp events :-(
				menu.setVisible(true);
			}
		});

		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		display.dispose();
	}
}
Comment 1 Andrey Loskutov CLA 2019-01-15 11:19:03 EST
Eric, any ideas?
Comment 2 Eric Williams CLA 2019-01-15 13:47:09 EST
Sorry, I missed this ticket somehow.

I can reproduce the issue on my machine. It likely has something to do with how menus are shown in SWT. Menu.setVisible() doesn't actually show the menu right away, it adds the Menu to the Display.popups array, which gets processed at some later point (look at Display.runPopups()).

My guess is that the menu processing somehow manages to eat events on the queue, and thus they are never fired. There's definitely a bug here somewhere.
Comment 3 Simeon Andreev CLA 2019-02-01 05:37:34 EST
Windows 10:

java.lang.Exception: Mouse Down: MouseEvent{Label {Right click to see the menu} time=-1794077187 data=null button=3 stateMask=0x0 x=172 y=71 count=1}
	at swt.problems.Bug541850_NoMouseUpEvent$1.mouseDown(Bug541850_NoMouseUpEvent.java:35)
	at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:196)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4131)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1055)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3944)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3547)
	at swt.problems.Bug541850_NoMouseUpEvent.main(Bug541850_NoMouseUpEvent.java:63)
Menu detected: MenuDetectEvent{Label {Right click to see the menu} time=-1794077093 data=null x=270 y=217 doit=true detail=0}
Menu visible: MenuDetectEvent{Label {Right click to see the menu} time=-1794077093 data=null x=270 y=217 doit=true detail=0}
java.lang.Exception: Mouse Up: MouseEvent{Label {Right click to see the menu} time=-1794077093 data=null button=3 stateMask=0x200000 x=158 y=82 count=1}
	at swt.problems.Bug541850_NoMouseUpEvent$1.mouseUp(Bug541850_NoMouseUpEvent.java:31)
	at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:224)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4131)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1055)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3944)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3547)
	at swt.problems.Bug541850_NoMouseUpEvent.main(Bug541850_NoMouseUpEvent.java:63)


RHEL 7.4 (GTK 3.22.10):


(SWT:32616): Gtk-WARNING **: Allocating size to SwtFixed 0x7ffff057e410 without calling gtk_widget_get_preferred_width/height(). How does the code know the size to allocate?
Menu detected: MenuDetectEvent{Label {Right click to see the menu} time=688795212 data=null x=272 y=118 doit=true detail=0}
Menu visible: MenuDetectEvent{Label {Right click to see the menu} time=688795212 data=null x=272 y=118 doit=true detail=0}
java.lang.Exception: Mouse Down: MouseEvent{Label {Right click to see the menu} time=688795212 data=null button=3 stateMask=0x0 x=272 y=94 count=1}
	at swt.problems.Bug541850_NoMouseUpEvent$1.mouseDown(Bug541850_NoMouseUpEvent.java:35)
	at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:196)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:5769)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1401)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:5037)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4567)
	at swt.problems.Bug541850_NoMouseUpEvent.main(Bug541850_NoMouseUpEvent.java:63)

Looks like a missing GTK+ event, I'll write a GTK+ snippet with a label and see what events are sent on mouse right-click.
Comment 4 Simeon Andreev CLA 2019-02-01 06:37:05 EST
Very basic GTK+ snippet:

#include <iostream>

#include <gtk/gtk.h>

// g++ -g label_mouse_events.cpp  `pkg-config --cflags --libs gtk+-3.0`  -o LabelMouseEvents && ./LabelMouseEvents

static gboolean mouse_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
    printf("press!\n");
    if (event->type == GDK_BUTTON_PRESS  &&  event->button == 3)
    {//3 is right mouse btn
        printf("right mouse press!\n");
    }
    if (event->type == GDK_BUTTON_PRESS  &&  event->button == 1)
    {//1 is left mouse btn
        printf("left mouse press!\n");
    }
    return true;
}

static gboolean mouse_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
    printf("release!\n");
    if (event->type == GDK_BUTTON_RELEASE  &&  event->button == 3)
    {//3 is right mouse btn
        printf("right mouse release!\n");
    }
    if (event->type == GDK_BUTTON_RELEASE  &&  event->button == 1)
    {//1 is left mouse btn
        printf("left mouse release!\n");
    }
    return true;
}

int
main (int argc, char **argv)
{
  GtkWidget *window, *scrolled_window, *label, *event_box;
  GtkTextBuffer *buffer;
  GtkTextIter iter;

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  g_signal_connect(window, "delete_event", gtk_main_quit, NULL); /* dirty */
  gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);

  scrolled_window = gtk_scrolled_window_new (NULL, NULL);

  gtk_container_add(GTK_CONTAINER(window), scrolled_window);

  event_box = gtk_event_box_new ();
  gtk_container_add (GTK_CONTAINER(scrolled_window), event_box);
  
  label = gtk_label_new ("some label");
  gtk_container_add (GTK_CONTAINER (event_box), label);
  gtk_widget_show (label);
  
  /* And bind an action to it */
  gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
  g_signal_connect(GTK_WIDGET(event_box), "button-press-event", G_CALLBACK(mouse_press), NULL);
  g_signal_connect(GTK_WIDGET(event_box), "button-release-event", G_CALLBACK(mouse_release), NULL);

  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_widget_show_all(window);
 
  gtk_main();

  return 0;
}

I've added some outputs to Control code:

Right-click:

java.lang.Exception: BUTTON PRESS EVENT
	at org.eclipse.swt.widgets.Control.gtk_button_press_event(Control.java:3371)
	at org.eclipse.swt.widgets.Control.gtk_button_press_event(Control.java:3367)
	at org.eclipse.swt.widgets.Widget.windowProc(Widget.java:2154)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:6615)
	at org.eclipse.swt.widgets.Label.windowProc(Label.java:729)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:6014)
	at org.eclipse.swt.internal.gtk.GTK._gtk_main_do_event(Native Method)
	at org.eclipse.swt.internal.gtk.GTK.gtk_main_do_event(GTK.java:4084)
	at org.eclipse.swt.widgets.Display.eventProc(Display.java:1402)
	at org.eclipse.swt.internal.gtk.OS._g_main_context_iteration(Native Method)
	at org.eclipse.swt.internal.gtk.OS.g_main_context_iteration(OS.java:1582)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4565)
	at swt.problems.Bug541850_NoMouseUpEvent.main(Bug541850_NoMouseUpEvent.java:63)
Menu detected: MenuDetectEvent{Label {Right click to see the menu} time=691776427 data=null x=1394 y=61 doit=true detail=0}
Menu visible: MenuDetectEvent{Label {Right click to see the menu} time=691776427 data=null x=1394 y=61 doit=true detail=0}
Mouse Down: MouseEvent{Label {Right click to see the menu} time=691776427 data=null button=3 stateMask=0x0 x=114 y=37 count=1}

Left-click:

java.lang.Exception: BUTTON PRESS EVENT
	at org.eclipse.swt.widgets.Control.gtk_button_press_event(Control.java:3371)
	at org.eclipse.swt.widgets.Control.gtk_button_press_event(Control.java:3367)
	at org.eclipse.swt.widgets.Widget.windowProc(Widget.java:2154)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:6615)
	at org.eclipse.swt.widgets.Label.windowProc(Label.java:729)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:6014)
	at org.eclipse.swt.internal.gtk.GTK._gtk_main_do_event(Native Method)
	at org.eclipse.swt.internal.gtk.GTK.gtk_main_do_event(GTK.java:4084)
	at org.eclipse.swt.widgets.Display.eventProc(Display.java:1402)
	at org.eclipse.swt.internal.gtk.OS._g_main_context_iteration(Native Method)
	at org.eclipse.swt.internal.gtk.OS.g_main_context_iteration(OS.java:1582)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4565)
	at swt.problems.Bug541850_NoMouseUpEvent.main(Bug541850_NoMouseUpEvent.java:63)
Mouse Down: MouseEvent{Label {Right click to see the menu} time=691778179 data=null button=1 stateMask=0x0 x=71 y=44 count=1}
java.lang.Exception: BUTTON RELEASE EVENT
	at org.eclipse.swt.widgets.Control.gtk_button_release_event(Control.java:3470)
	at org.eclipse.swt.widgets.Widget.windowProc(Widget.java:2155)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:6615)
	at org.eclipse.swt.widgets.Label.windowProc(Label.java:729)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:6014)
	at org.eclipse.swt.internal.gtk.GTK._gtk_main_do_event(Native Method)
	at org.eclipse.swt.internal.gtk.GTK.gtk_main_do_event(GTK.java:4084)
	at org.eclipse.swt.widgets.Display.eventProc(Display.java:1402)
	at org.eclipse.swt.internal.gtk.OS._g_main_context_iteration(Native Method)
	at org.eclipse.swt.internal.gtk.OS.g_main_context_iteration(OS.java:1582)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4565)
	at swt.problems.Bug541850_NoMouseUpEvent.main(Bug541850_NoMouseUpEvent.java:63)
Mouse Up: MouseEvent{Label {Right click to see the menu} time=691778251 data=null button=1 stateMask=0x80000 x=71 y=44 count=1}


Commenting all the call which shows the context menu (org.eclipse.swt.widgets.Control.showMenu(int, int)) in org.eclipse.swt.widgets.Control.gtk_event_after(long, long) results in seen release event. I'll see if I can add similar context menu handling to the GTK+ snippet...

Call stack to bring up the menu:

java.lang.Exception: menu becoming visible
	at org.eclipse.swt.widgets.Menu.setVisible(Menu.java:1303)
	at swt.problems.Bug541850_NoMouseUpEvent$3.menuDetected(Bug541850_NoMouseUpEvent.java:57)
	at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:188)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:5769)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1401)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1427)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1410)
	at org.eclipse.swt.widgets.Control.showMenu(Control.java:6085)
	at org.eclipse.swt.widgets.Control.showMenu(Control.java:6077)
	at org.eclipse.swt.widgets.Control.gtk_event_after(Control.java:3587)
	at org.eclipse.swt.widgets.Widget.windowProc(Widget.java:2161)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:6615)
	at org.eclipse.swt.widgets.Label.windowProc(Label.java:729)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:6014)
	at org.eclipse.swt.internal.gtk.GTK._gtk_main_do_event(Native Method)
	at org.eclipse.swt.internal.gtk.GTK.gtk_main_do_event(GTK.java:4084)
	at org.eclipse.swt.widgets.Display.eventProc(Display.java:1402)
	at org.eclipse.swt.internal.gtk.OS._g_main_context_iteration(Native Method)
	at org.eclipse.swt.internal.gtk.OS.g_main_context_iteration(OS.java:1582)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4565)
	at swt.problems.Bug541850_NoMouseUpEvent.main(Bug541850_NoMouseUpEvent.java:63)
Comment 5 Simeon Andreev CLA 2019-02-01 06:54:19 EST
BTW, I notice the following code in org.eclipse.swt.widgets.Menu._setVisible(boolean):

diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java
index 9eb7d92f94..5b2a44e0cc 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java 
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java 
@@ -308,6 +308,7 @@ void _setVisible (boolean visible) {
                                         *  immediately and not as a post event in display, requiring the current event.
                                         */
                                        eventPtr = GTK.gtk_get_current_event();
+                                       boolean wasCreated = false;
                                        if (eventPtr == 0) {
                                                eventPtr = GDK.gdk_event_new(GDK.GDK_BUTTON_PRESS);
                                                GdkEventButton event = new GdkEventButton ();
@@ -319,11 +320,14 @@ void _setVisible (boolean visible) {
                                                event.device = GDK.gdk_get_pointer(GDK.gdk_display_get_default ());
                                                event.time = display.getLastEventTime ();
                                                OS.memmove (eventPtr, event, GdkEventButton.sizeof);
+                                               wasCreated = true;
                                        }
                                        adjustParentWindowWayland(eventPtr);
                                        verifyMenuPosition(getItemCount());
                                        GTK.gtk_menu_popup_at_pointer(handle, eventPtr);
-                                       GDK.gdk_event_free (eventPtr);
+                                       if (wasCreated) {
+                                               GDK.gdk_event_free (eventPtr);
+                                       }
                                }
                        }
                        poppedUpCount = getItemCount();

Freeing the current event without any condition (see the added one in the diff above) is maybe bad? Its not the cause for the problem here though.
Comment 6 Eric Williams CLA 2019-02-01 09:45:37 EST
(In reply to Simeon Andreev from comment #5)
> Freeing the current event without any condition (see the added one in the
> diff above) is maybe bad? Its not the cause for the problem here though.

I don't think so, gtk_get_current_event() just returns a copy so it shouldn't be an issue. All calls to gtk_get_current_event() have to free the result otherwise there will be leaks.

https://developer.gnome.org/gtk3/stable/gtk3-General.html#gtk-get-current-event

As for this bug, it will probably be really hard to reproduce it natively. SWT's menu system is pretty strange, see Display.runPopups().
Comment 7 Simeon Andreev CLA 2019-02-01 10:04:57 EST
If I make _setVisible() public (just to test) and call this directly in the mouse-down listener in the snippet from Andrey, I still see the problem (I've removed the menu detection listener, so there should be no Display pop-up logic).

However if I create a menu in my GTK+ snippet and pop it up during mouse down (button pressed), there still is a mouse up (button released) event. This is somewhat confusing?
Comment 8 Simeon Andreev CLA 2019-02-01 10:15:23 EST
In particular the current GTK event is null in that scenario, while in my snippet it is not. Definitely clear why it could be null with the display pop-ups, but if called directly on mouse event handling?

Eric would it make sense for me to try using gtk_menu_popup_for_device() instead of gtk_menu_popup_at_pointer() in the _setVisible() method? It doesn't mess with creating GDK button press events. Or it wouldn't make any difference?
Comment 9 Eric Williams CLA 2019-02-01 10:20:07 EST
(In reply to Simeon Andreev from comment #7)
> If I make _setVisible() public (just to test) and call this directly in the
> mouse-down listener in the snippet from Andrey, I still see the problem
> (I've removed the menu detection listener, so there should be no Display
> pop-up logic).
> 
> However if I create a menu in my GTK+ snippet and pop it up during mouse
> down (button pressed), there still is a mouse up (button released) event.
> This is somewhat confusing?

Weird. BTW you can use GtkInspector to check for events being sent, this is useful if trying to determine whether GTK is missing events or if SWT is eating them somewhere.

Open GtkInspector -> Target the widget -> Select "Signals" from the dropdown menu -> then click the black dot next to the menu. It will trace signal emissions and show a count in the table -- very useful.

(In reply to Simeon Andreev from comment #8)
> In particular the current GTK event is null in that scenario, while in my
> snippet it is not. Definitely clear why it could be null with the display
> pop-ups, but if called directly on mouse event handling?
> 
> Eric would it make sense for me to try using gtk_menu_popup_for_device()
> instead of gtk_menu_popup_at_pointer() in the _setVisible() method? It
> doesn't mess with creating GDK button press events. Or it wouldn't make any
> difference?

You can try it, but I think it will end up with the same result. Try looking with GtkInspector to see if the event is being emitted in the first place (with your SWT snippet).
Comment 10 Simeon Andreev CLA 2019-02-01 10:45:07 EST
When I try clicking on the dot next to the menu (its red and its hover says "trace  signal emissions on this object"), the snippet from Andrey crashes with this message on standard error:

Gtk:ERROR:inspector/signals-list.c:250:start_tracing_cb: assertion failed: (hook_id == 0)

If I select the label specifically before starting to trace, there are a bunch of outputs on standard error warning me about non-hooked signals. I see no output when right-clicking.

Am I using the tracing wrong?
Comment 11 Eric Williams CLA 2019-02-01 10:54:48 EST
(In reply to Simeon Andreev from comment #10)
> When I try clicking on the dot next to the menu (its red and its hover says
> "trace  signal emissions on this object"), the snippet from Andrey crashes
> with this message on standard error:
> 
> Gtk:ERROR:inspector/signals-list.c:250:start_tracing_cb: assertion failed:
> (hook_id == 0)
> 
> If I select the label specifically before starting to trace, there are a
> bunch of outputs on standard error warning me about non-hooked signals. I
> see no output when right-clicking.
> 
> Am I using the tracing wrong?

Not sure, this is how I do it.

1) Run the SWT snippet from Andrey.
2) Press Ctrl + Shift + i to get GtkInspector open.
3) Click the target icon and select the "GtkEventBox" widget (this is handle for Labels)
4) Go to the signals menu, click the black dot.
5) Click the Label.

On my machine I *do not* see button-release-events being sent for the GtkEventBox at all. If I left click I do, but not for right clicks.