After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 711709 - goocanvas signal handling corrupted after using a simple dialog
goocanvas signal handling corrupted after using a simple dialog
Status: RESOLVED FIXED
Product: goocanvas
Classification: Other
Component: general
unspecified
Other Linux
: Normal normal
: ---
Assigned To: goocanvas-maint
goocanvas-maint
Depends on:
Blocks:
 
 
Reported: 2013-11-08 19:53 UTC by Klaus Rudolph
Modified: 2017-08-30 10:28 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
complete source for reproduction (1.05 KB, text/x-c++src)
2013-11-08 19:53 UTC, Klaus Rudolph
  Details
c example file ( full code ) for reproduction the bug (1.40 KB, text/x-csrc)
2013-11-09 19:34 UTC, Klaus Rudolph
  Details
goocanvas_signals.c (1.29 KB, text/x-csrc)
2013-11-11 09:58 UTC, Murray Cumming
  Details
Integrate the example in the doc (3.54 KB, patch)
2017-06-03 22:51 UTC, Nicola Fontana
none Details | Review
Integrate the example in the doc (3.55 KB, patch)
2017-06-03 22:59 UTC, Nicola Fontana
none Details | Review

Description Klaus Rudolph 2013-11-08 19:53:38 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.
Comment 1 Murray Cumming 2013-11-08 20:59:11 UTC
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?
Comment 2 Klaus Rudolph 2013-11-09 19:32:18 UTC
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!
Comment 3 Klaus Rudolph 2013-11-09 19:34:14 UTC
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
Comment 4 Murray Cumming 2013-11-11 09:58:21 UTC
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`
Comment 5 Murray Cumming 2013-11-11 09:59:23 UTC
Reassigning to goocanvas rather than goocanvasmm.

By the way, valgrind does not report any problems while running this test code.
Comment 6 Damon Chaplin 2013-11-11 10:23:20 UTC
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.
Comment 7 Damon Chaplin 2013-11-11 10:31:20 UTC
Showing the dialog in the button release handler would work too.
Comment 8 Klaus Rudolph 2014-11-28 08:34:21 UTC
@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;
}
Comment 9 Klaus Rudolph 2014-11-28 08:56:09 UTC
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;
}
Comment 10 Damon Chaplin 2014-11-28 09:45:32 UTC
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)
Comment 11 Klaus Rudolph 2014-11-28 10:08:34 UTC
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.
Comment 12 Klaus Rudolph 2014-11-28 10:42:08 UTC
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.
Comment 13 Damon Chaplin 2014-11-28 11:40:35 UTC
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?
Comment 14 Klaus Rudolph 2014-11-28 11:55:48 UTC
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;
}
Comment 15 Damon Chaplin 2014-11-28 12:24:13 UTC
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?
Comment 16 Klaus Rudolph 2014-11-28 13:24:40 UTC
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.
Comment 17 Klaus Rudolph 2014-11-28 13:34:29 UTC
Again a quick test: under fvwm it runs also without problems :-)
Comment 18 Damon Chaplin 2014-11-28 14:05:28 UTC
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.
Comment 19 Klaus Rudolph 2014-12-01 08:43:47 UTC
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!
Comment 20 Nicola Fontana 2017-06-03 22:51:56 UTC
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.
Comment 21 Nicola Fontana 2017-06-03 22:59:17 UTC
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).
Comment 22 Damon Chaplin 2017-08-30 10:28:59 UTC
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.