GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Tue Sep 23, 2014 10:25 pm

All times are UTC




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: [SOLVED] gtk_menu_popup() works once then fails silently?
PostPosted: Thu Dec 20, 2012 11:38 pm 
Offline
Familiar Face

Joined: Thu Sep 13, 2012 10:49 pm
Posts: 6
Seasons Greetings, fellow GTKers.

I have this experimental little app that is supposed to pop up a menu on SIGUSR1. It's pretty much right out of the tutorial:
Code:
GtkWidget *create_menu(void) {
    GtkWidget *menu1, *menuitem1;
    menu1 = gtk_menu_new ();

    menuitem1 = gtk_image_menu_item_new_with_mnemonic ("Menu Item _1");
    gtk_menu_shell_append (GTK_MENU_SHELL (menu1), menuitem1);
    menuitem1 = gtk_image_menu_item_new_with_mnemonic ("Menu Item _2");
    gtk_menu_shell_append (GTK_MENU_SHELL (menu1), menuitem1);

    gtk_widget_show_all (menu1);
    gtk_menu_popup (GTK_MENU (menu1), NULL, NULL, NULL, NULL, 0,
        gtk_get_current_event_time ());

    return menu1;
}

It works properly when first called. The silly little menu pops up under the mouse. Click an entry or hit ESCAPE and it goes away. Perfect.

I send a SIGUSR1 to the app, it catches it, prints a little confirmation that it did indeed catch it, then calls gtk_widget_show_all(menu1) and gtk_menu_popup(menu1, ...), and nothing. The menu doesn't reappear. First I thought the widgets were being destroyed, but then I'd surely get a segfault or CRITICAL on the gtk_widget_show_all().

As an addendum, if I don't call gtk_menu_popup() in this function, then SIGUSR1 works the first time, but never again. Why does gtk_menu_popup() only work once and then fail silently?

I've been digging through the gtk c code looking for clues, and of course I've googled many many pages thinking some else must have tried to do this very same thing, but to no avail.

Any notion why this would be?


Last edited by Miven on Thu Jan 03, 2013 10:51 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: gtk_menu_popup() only works once, then fails silently?
PostPosted: Fri Dec 21, 2012 7:50 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 747
Location: UK
Hello and welcome,

It confused me at first until I saw that you are using SIGUSR1.

I expect that you are calling all your GTK+ code to do the pop-up menu from the UNIX signal handler. If so then this is what has caused your problem. There are very few functions that you can call from within a UNIX signal handler have a look at the man page for it signal(7)
Code:
man -s 7 signal


What has happened is -
1 - First time the UNIX signal handler is called GTK+ is interrupted mid flow, the pop-up menu is generated and some of the internal structures used by GTK+ are now corrupted.
2 - Second time the UNIX signal handler is called GTK+ is again interrupted mid flow. Because the required internal data structures are now corrupt the menu can not be now shown.

Best would be to avoid the use of UNIX signals. If you can not have you GTK+ main loop monitor a pipe for data coming in. Whenever the expected data comes in using the GTK+ handler to display your pop-up menu. In your UNIX signal handler have it send data on the pipe (this should be OK to do).

_________________
E.


Top
 Profile  
 
 Post subject: Re: gtk_menu_popup() only works once, then fails silently?
PostPosted: Fri Dec 21, 2012 4:58 pm 
Offline
Familiar Face

Joined: Thu Sep 13, 2012 10:49 pm
Posts: 6
That totally makes sense. Thank you. I hadn't thought about the interaction of signals rudely interrupting the main loop.

The funny thing is that this trick completely works if I make gtk_window, populate it with widgets (buttons and stuff), and widget_show() everything but the window. When the SIGUSR1 comes through, it just calls widget_show() on the top level window which has GTK_WIN_POS_MOUSE set. Bang. It pops up at the mouse. Lovely. Grab some signals and ESC/F10, button-press or leave-notify makes it disappear.

Menus behave differently. A lot of their function is controlled internally, unlike a button which is mostly user-controlled. With a menu, gtk_widget_show() isn't good enough, you must call menu_popup() which then pretty much takes over control.

For now, as an experiment, I skip the SIGUSR1 bit and use a different approach. In my gtk_window/button version of this app, I have also installed a g_timeout_add() that lazily polls the pointer every 10th of a second:
Code:
#define TIMER_DELAY 100
    dmenu.timer =
        g_timeout_add(TIMER_DELAY, (GSourceFunc) desktop_timer, menu1);

and
Code:
gint desktop_timer(GtkWidget * win)
{
    static int count = 1;
    static Display *display;
    static gint screen;
    static Window w, thisw = 0;
    Window root, child;
    int rx, ry, wx, wy;
    unsigned int mask;
    if ( ! dmenu.win_visible ) {
        if (!display) {
            display = XOpenDisplay(NULL);
            screen = XDefaultScreen(display);
            w = XRootWindow(display, screen);
        }
        XQueryPointer(display, w, &root, &child, &rx, &ry, &wx, &wy, &mask);
        fprintf ( stderr, "root:%p child:%p rx:%i ry:%i wx:%i wy:%i mask:%i count:%i\n",
            root, child, rx, ry, wx, wy, mask, count );
        menuX = rx; menuY = ry;
        if (child == 0) { // we're in the root window
            if (mask == Button3Mask) {  // X.h: Button3Mask 1<<10, no modifiers
                window_show(GTK_WIDGET(win), NULL, (gpointer) win);
            }
        } else {
            if (!thisw) {
                thisw = child;
            }
        }
    }
    if ( (count%100) == 0 ) {
        window_show(GTK_WIDGET(win), NULL, (gpointer) win);
    }
    count++;
    return TRUE;
}

window_show() is designed as a signal callback, and just sets a couple flags then calls gtk_widget_show_all() or gtk_menu_popup(), whichever is appropriate.

What is supposed to happen here is that when you right click an empty spot of the root window, my button window pops up under the mouse. No problem. Not so when it's a menu.

Now, if you'll notice, I've hacked this routine to count, and every 100(~10 seconds) it shows the menu. Strangely this works perfectly. Every 10 seconds gtk_menu_popup() does it's thing, and my gtk_menu pops up under your mouse. Awesome. But when I right click, it still calls menu_popup() but fails.

What I've discovered is that menu_popup() succeeds when it's called passively from the app, but but fails when called actively from UNIX signals or mouse clicks. It seems that all the gtk_menu's automagic gets confused by the spurious events going on.

This ties right into all the chat I've seen about gtk-menu-popup-delay and getting it set just right. I was curious if this might help. Perhaps giving a small delay to the popup would lets things clear. So I tried a trick someone said. echo "gtk-menu-popup-delay = 10000" >> ~/.gtkrc-2.0. But that doesn't seem to do anything. I tried usleep(100000) right before calling gtk_menu_popup(), and you know what? *IT WORKS*! But only for right-click. Still not for SIGUSR1.

So, I decided to try another trick. In my signal handler, instead of just abruptly calling window_show(), I did this:
Code:
g_timeout_add(100, (GSourceFunc) window_show_timer, dmenu.window);

The main loop keeps right on rolling, and a moment later there is a friendly knock on the door to menu_popup(), and you know what? It now works for SIGUSR1 also.

So, after MUCH experimentation, I believe I found the official answer to my original query:

gtk_menu and friends get confused by spurious events, so if you're going to be calling gtk_menu_popup(), do it with a leisurely g_timeout_add() and a GSourceFunc that returns FALSE, so it only calls once. The correct timer delays seem to be 200 for SIGUSR1 and 100 for right click.

Perhaps someone else can benefit from this little tidbit of gtk esoterica.

Have a very Merry Christmas.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group