GNOME Bugzilla – Bug 711709
goocanvas signal handling corrupted after using a simple dialog
Last modified: 2017-08-30 10:28:59 UTC
Created attachment 259298 [details] complete source for reproduction I use a simple goocanvas application. After using a dialog called from a goocanvas signal handler the signal handling is completely broken for the goocanvas. How to reproduce: I compile with: /opt/linux-gnu_4.8.1/bin/g++ `pkg-config gtkmm-3.0 --cflags` `pkg-config goocanvasmm-2.0 --cflags` --std=c++11 -Wall --pedantic -O2 -c -o main.o main.cpp /opt/linux-gnu_4.8.1/bin/g++ `pkg-config gtkmm-3.0 --cflags` `pkg-config goocanvasmm-2.0 --cflags` --std=c++11 -Wall --pedantic -O2 `pkg-config gtkmm-3.0 --libs` `pkg-config goocanvasmm-2.0 --libs` main.o -g -o go Expected behavior: Click on the canvas area: no reaction. Click on the circle: call dialog, after closing dialog->same behavior as before. Bug: After the dialog was used once you can click anywhere and the dialog comes up again. The signalhandler is now called on the complete canvas area which is wrong. It should still only be called if the click goes to the circle widget! In my real application the signal handler is sometimes not longer called, also on the circle widget where it should do. So I expect the signal handling is totally broken after the dialog closes.
Yes, I can reproduce that with your test case. Would you like to create a C version of the test case that does not use gtkmm or goocanvasmm?
OK, I add a c-version. Sorry that this version compiles with tons of warnings. I need a lot of time to get the example to work with c and I could not find the correct header files for casting the pointers?! But the effect is the same. I hope that the example is readable for you. It is quite hard for me to get to using the c-lib as beginner. Sorry for that!
Created attachment 259346 [details] c example file ( full code ) for reproduction the bug compiled with: /opt/linux-gnu_4.8.1/bin/gcc `pkg-config gtk+-3.0 --cflags` `pkg-config goocanvas-2.0 --cflags` -Wall --pedantic -O2 `pkg-config gtk+-3.0 --libs` `pkg-config goocanvas-2.0 --libs` m.c -g -o goc
Created attachment 259543 [details] goocanvas_signals.c Here is slightly simplified version of that C test case, with the compiler warnings fixed. You can build it like so: gcc goocanvas_signals.c `pkg-config goocanvas-2.0 --cflags --libs`
Reassigning to goocanvas rather than goocanvasmm. By the way, valgrind does not report any problems while running this test code.
It's a pointer grab problem. When you click on an item goocanvas starts an implicit pointer grab, so the item gets all mouse events until the button release. But since you opened a dialog, that got the mouse focus, and goocanvas never got the button release event, and got confused. The workaround is to ungrab the pointer after showing the dialog, In C: goo_canvas_pointer_ungrab (canvas, item, event->time); I'm not sure what we should do in GooCanvas to avoid this. I'll think about it.
Showing the dialog in the button release handler would work too.
@comment7: If I use it with button release I got the same behavior as before. If I use goo_canvas_pointer_ungrab in C it works. If I use it with c++ it did not work at all! Maybe my problem. The behavior is quite strange: I press the circle, got the dialog as expected, press ok, and now the complete window hangs on the mouse pointer until I press the mouse button again. if I compile with To reproduce it: compile prog with: /opt/linux-gnu_4.8.2/bin/g++ `pkg-config gtkmm-3.0 --cflags` `pkg-config goocanvasmm-2.0 --cflags` --std=c++11 -Wall --pedantic -Wextra -O2 `pkg-config gtkmm-3.0 --libs` `pkg-config goocanvasmm-2.0 --libs` main.cpp -g -o go and main.cpp is:#include <gtkmm.h> #include <goocanvasmm.h> #include <gtkmm/stock.h> Goocanvas::Canvas* canvas; bool ShowDialog( const Glib::RefPtr<Goocanvas::Item>& item, GdkEventButton* ev) { enum { OK }; Gtk::Dialog dialog; dialog.add_button( Gtk::Stock::OK, OK); dialog.show_all_children(); dialog.run(); // this line should fix the problem with 711709 canvas->pointer_ungrab( item, ev->time); return false; } int main(int argc, char *argv[]) { Gtk::Main kit(argc, argv); Goocanvas::init("Simu", "0.1", argc, argv); canvas=new Goocanvas::Canvas; canvas->set_size_request(300, 300); canvas->set_bounds(0, 0, 300, 300); Glib::RefPtr<Goocanvas::Item> root = canvas->get_root_item(); Glib::RefPtr<Goocanvas::Ellipse> outer = Goocanvas::Ellipse::create( 100,100,20,20); outer->property_line_width() = 5; outer->property_stroke_color() = "red"; outer->property_fill_color()="blue"; root->add_child( outer ); sigc::connection conn2= outer->signal_button_press_event().connect( sigc::ptr_fun(&ShowDialog)); Gtk::VBox hbox; hbox.add(*canvas); Gtk::Window win; win.add(hbox); win.show_all_children(); Gtk::Main::run(win); delete canvas; }
Additional Problem found: If I use an overwrite for the "on_button_press_event" I have no 'item' which I could use in the call to pointer_ungrab( -->item<--, time). I have no idea how to deal with this situation! My problem is that I have the canvas as drawing area and if I press a mouse button on the empty canvas I want to raise the dialog to select something. But after the dialog closes every next mouse button event goes to the event handler from the circle, also if it was not pressed ( press in empty area). So this is the problem as before. So I hope you have an advice how to find an "item" parameter which can help in this situation. So we have two problems now: 1 ) After pressing a mouse button in the canvas and raising an dialog the complete window is hanging on the mouse pointer until next press. 2) After first press all follwoing mouse button presses are going to the circle item also if mouse was not above the circle when the mouse button was pressed. #include <iostream> #include <gtkmm.h> #include <goocanvasmm.h> #include <gtkmm/stock.h> Goocanvas::Canvas* canvas; void DialogShow() { enum { OK }; Gtk::Dialog dialog; dialog.add_button( Gtk::Stock::OK, OK); dialog.show_all_children(); dialog.run(); } class MyCanvas: public Goocanvas::Canvas { public: bool on_button_press_event( GdkEventButton* event ) { std::cout << "Yepp!" << std::endl; DialogShow(); // How to ungrep the pointer here? I have no "item" object. root is not working! this->pointer_ungrab( this->get_root_item(), event->time); return Goocanvas::Canvas::on_button_press_event( event ); } }; bool ShowMessage( const Glib::RefPtr<Goocanvas::Item>& item, GdkEventButton* ev) { std::cout << "Circle Pressed" << std::endl; } int main(int argc, char *argv[]) { Gtk::Main kit(argc, argv); Goocanvas::init("Simu", "0.1", argc, argv); //canvas=new Goocanvas::Canvas; canvas=new MyCanvas; canvas->set_size_request(300, 300); canvas->set_bounds(0, 0, 300, 300); Glib::RefPtr<Goocanvas::Item> root = canvas->get_root_item(); Glib::RefPtr<Goocanvas::Ellipse> outer = Goocanvas::Ellipse::create( 100,100,20,20); outer->property_line_width() = 5; outer->property_stroke_color() = "red"; outer->property_fill_color()="blue"; root->add_child( outer ); //sigc::connection conn2= outer->signal_button_press_event().connect( sigc::ptr_fun(&ShowDialogConnect)); sigc::connection conn2= outer->signal_button_press_event().connect( sigc::ptr_fun(&ShowMessage)); Gtk::VBox hbox; hbox.add(*canvas); Gtk::Window win; win.add(hbox); win.show_all_children(); Gtk::Main::run(win); delete canvas; }
The test program in comment 8 works fine for me. Also, if I connect to the button release event it works without doing an ungrab. Try moving canvas->pointer_ungrab() to the top of ShowDialog() I haven't tried the second test yet, but one idea is to grab the pointer to the root item and then ungrab it. That should hopefully clear the grab. this->pointer_grab( this->get_root_item(), event->time) this->pointer_ungrab( this->get_root_item(), event->time)
I add to DialogShow() in the first line canvas->pointer_ungrab( canvas->get_root_item(),0); and also canvas->pointer_ungrab( canvas->get_root_item(),event->time); Both change nothing. For your second hint I got no idea how to get parameters for pointer_grab() const Glib::RefPtr<Item>& item -> maybe also canvas->get_root_item()? Gdk::EventMask mask -> which mask I have to use? const Glib::RefPtr<Gdk::Cursor>& cursor -> where I get the cursor? guint32 time -> should I use the event->time , 0 ? Sorry, I never used such deep underlying functions until know.
OK, I checked with: before Dialog starts: this->pointer_grab( this->get_root_item(), Gdk::BUTTON_PRESS_MASK, event->time); this->pointer_ungrab( this->get_root_item(),event->time); and the problem 2) is fixed! Thanks a lot! The problem 1) that the application is hanging on the mouse pointer is still present.
Is the problem with the test app in comment 8 in comment 9? Please post the latest version. It's not a window focus issue is it? Do you normally have to click on windows to give them the focus?
This is my last test version which results in hanging the application on the mouse pointer. Actions to reproduce: Start app Press mouse on circle -> Dialog appears press space bar to leave dialog -> Dialog closes press mouse OUTSIDE circle in canvas -> Dialog appears press space bar -> Dialog closes -> Application hangs on mouse!! Press mouse somewhere -> Application is dropped, reacts normal. Compiled with: /opt/linux-gnu_4.9.2/bin/g++ `pkg-config gtkmm-3.0 --cflags` `pkg-config goocanvasmm-2.0 --cflags` --std=c++11 `pkg-config gtkmm-3.0 --libs` `pkg-config goocanvasmm-2.0 --libs` main.cpp -g -o go #include <iostream> #include <gtkmm.h> #include <goocanvasmm.h> #include <gtkmm/stock.h> Goocanvas::Canvas* canvas; void DialogShow(GdkEventButton* event) { canvas->pointer_grab( canvas->get_root_item(), Gdk::BUTTON_PRESS_MASK, event->time); canvas->pointer_ungrab( canvas->get_root_item(),event->time); enum { OK }; Gtk::Dialog dialog; dialog.add_button( Gtk::Stock::OK, OK); dialog.show_all_children(); dialog.run(); } class MyCanvas: public Goocanvas::Canvas { public: bool on_button_press_event( GdkEventButton* event ) { std::cout << "Yepp!" << std::endl; DialogShow(event); // How to ungrep the pointer here? I have no "item" object. root is not working! //this->pointer_ungrab( this->get_root_item(), event->time); return Goocanvas::Canvas::on_button_press_event( event ); } }; bool ShowMessage( const Glib::RefPtr<Goocanvas::Item>& item, GdkEventButton* ev) { std::cout << "Circle Pressed" << std::endl; } int main(int argc, char *argv[]) { Gtk::Main kit(argc, argv); Goocanvas::init("Simu", "0.1", argc, argv); //canvas=new Goocanvas::Canvas; canvas=new MyCanvas; canvas->set_size_request(300, 300); canvas->set_bounds(0, 0, 300, 300); Glib::RefPtr<Goocanvas::Item> root = canvas->get_root_item(); Glib::RefPtr<Goocanvas::Ellipse> outer = Goocanvas::Ellipse::create( 100,100,20,20); outer->property_line_width() = 5; outer->property_stroke_color() = "red"; outer->property_fill_color()="blue"; root->add_child( outer ); //sigc::connection conn2= outer->signal_button_press_event().connect( sigc::ptr_fun(&ShowDialogConnect)); sigc::connection conn2= outer->signal_button_press_event().connect( sigc::ptr_fun(&ShowMessage)); Gtk::VBox hbox; hbox.add(*canvas); Gtk::Window win; win.add(hbox); win.show_all_children(); Gtk::Main::run(win); delete canvas; }
Unfortunately I can't reproduce the problem. It works OK for me. When you say the "Application hangs on mouse" do you mean the window moves around as the mouse moves? What window manager do you use? GNOME Shell? Or Unity?
OK, I retested with gnome unity and the application runs fine! Running in kde plasma the problem comes up. With "Application hangs on mouse" I mean that the complete application main window is moved with the mouse cursor on the desktop, including the window frame, the close box and so on. In between I placed the found workaround from the demo application ( which is copied here ) in my target code. On my real world application the problem is NOT existing. Is it now the time to dig into wm specific details? Maybe write a bug report on KDE? This maybe starts a ping pong from gtk to kde people :-) I have no idea what I can do now? I can support any kind of testing but I have no idea who can be asked now.
Again a quick test: under fvwm it runs also without problems :-)
Thanks for testing it with unity & fvwm. We know it's a plasma problem now. I'm not sure it is worth reporting the bug - it is very complicated! If your real application works, then you're OK, aren't you? I'll leave the bug open though since it would be nice to fix GooCanvas to avoid this situation.
I think the bug in GooCanvas should be fixed first. To fix the problems which come up from a workaround sounds not very nice :-) Thanks for your great support!
Created attachment 353127 [details] [review] Integrate the example in the doc I just lost three hours of my life because of this issue. At the very least I think a mention in the doc would be useful (it would have been for me). The provided patch updates "Simple Canvas Example" (it does not build out of the box) and integrates it with a message dialog that highligths this problem and solves it with the workaround provided in comment #6.
Created attachment 353128 [details] [review] Integrate the example in the doc Fix some spacing issues (sorry, I have a hard time switching between different code conventions).
I think I found a fix for the underlying problem. If we receive a LEAVE_NOTIFY event with a mode of GDK_CROSSING_GRAB or GDK_CROSSING_GTK_GRAB it means we lost our passive grab so we cancel it. It seems to fix the issue with the simple canvas test. Reopen if someone spots a problem.