XBoard GTK+ signal problem

Hi,

I seem to have a similar problem to this case:

I made recent_title a global variable as explained in the link. But I still get gibberish message. Parts of code:

gtk/xboard.h

extern GtkRecentInfo *recents_ptr[RECENTS_COUNT+1];
extern gchar recent_title[20];

gtk/xboard.c

GtkRecentInfo *recents_ptr[RECENTS_COUNT+1];
gchar recent_title[20];

[...]
void show_message_dialog(const gchar * const message)
{

    GtkWidget*  dialog = gtk_message_dialog_new (GTK_WINDOW(mainwindow),
                                     GTK_DIALOG_DESTROY_WITH_PARENT,
                                     GTK_MESSAGE_INFO,
                                     GTK_BUTTONS_CLOSE,
                                     "Message: %s",
                                     message);

    /* Destroy the dialog when the user responds to it (e.g. clicks a button) */
    g_signal_connect_swapped (dialog, "response",
                              G_CALLBACK (gtk_widget_destroy),
                              dialog);
    gtk_widget_show_all (dialog);
    return;
}
void show_message_dialog_event(GtkWidget*label_1,gpointer message)
{
    show_message_dialog(message);
    return;
}

gtk/xoptions.c

[...]
    produce_recent_items();
        for(i=0; i<RECENTS_COUNT && recents_ptr[i] ; i++)
        {
            GtkRecentInfo *recent_wid=recents_ptr[i];
                        
            g_stpcpy(recent_title,"TTT3_\n");
                show_message_dialog(recent_title); // Works OK

                const gchar *fn;
                fn=gtk_recent_info_get_uri(recent_wid);
                //show_message_dialog(fn); // TODO broken
                g_signal_connect(G_OBJECT(recent_wid),"activate"
                ,G_CALLBACK(show_message_dialog_event),(gpointer)recent_title);// recent_title shows gibberish
        }

backend.c

void produce_recent_items(void) 
{
#include <stdbool.h>
    GtkRecentManager *recent_files;
    GtkRecentInfo *ri;
    GList *rf_list;
    const gchar *rf_str;
    //GtkWidget *rf_widget;
    GtkRecentInfo *rf_widget;

    recent_files=gtk_recent_manager_get_default(); 
    gtk_recent_manager_set_limit(recent_files,RECENTS_COUNT);
    rf_list=gtk_recent_manager_get_items(recent_files);

    int i;
    for(i=0; i<RECENTS_COUNT; )
    {
        recents_ptr[i]=NULL;
        if(rf_list==NULL)
            break;

        ri=rf_list->data;
        bool this_app ;
        gchar * name = gtk_recent_info_last_application(ri);
        if(strstr(name,"xboard"))
            this_app=true;
        else
            this_app=false;
        if(this_app)
        {
            rf_str=gtk_recent_info_get_uri(ri); 
            rf_widget=gtk_menu_item_new_with_label(rf_str); // TODO warning here
            recents_ptr[i]=rf_widget;
            i++;
        }
        rf_list=rf_list->next;
    }
   return;
}

What to do ?
Thanks.

Your problem (and likely the case you linked) has nothing to do with encoding: it is a straight memory corruption. This is because the way you connect the callback is wrong.

Use g_signal_connect_swapped instead of g_signal_connect to be able to use recent_title as first parameter in your callback.

To explain a bit , my l1 sub-menu works correctly with this part:

[...]
g_signal_connect(G_OBJECT(l1),"activate"
    ,G_CALLBACK(show_message_dialog_event),(gpointer)"l1_activated\n");
[...]

Now following your suggestion I changed signal to this:

g_signal_connect_swapped (G_OBJECT(recent_wid),"activate"
                            ,G_CALLBACK(show_message_dialog),(gpointer)recent_title);

But I do not get expected result after “activating” sub-menus. In fact nothing happens.

Hi Mehdi,

What does the following print out?


g_print("%s\n", G_OBJECT_TYPE_NAME(recent_wid));
g_signal_connect(G_OBJECT(recent_wid),“activate”,G_CALLBACK(show_message_dialog_event),(gpointer)recent_title);

It looks like you might be supplying the wrong gobject type to a GtkMenuItem “activate” callback.

Eric

Yesterday I was likely on drugs: I totally missed the show_message_dialog_event function. I read show_message_dialog everywhere.

If l1 is a GtkMenuItem that code works because GtkMenuItem has an “activate” signal. The following code would work as well, avoiding the bogus show_message_dialog_event wrapper function:

g_signal_connect_swapped(G_OBJECT(l1), "activate", G_CALLBACK(show_message_dialog), "l1_activated\n");

recent_wid is not a submenu, it is a GtkRecentInfo! In other words nothing happens because GtkRecentInfo does not have any “activate” signal. It is not even a GObject: you should get a plain assertion error at startup.

My current effort is:

else if(mb[i].handle == RECENT_SUBMENU)
                {
                    GtkWidget *vbox;

                    show_message_dialog("XO1");
                    GtkWidget *sub_menu;
                    GtkWidget *sub_menuMI;
                    GtkWidget * l1;
                    GtkWidget * l2;

                    vbox=gtk_vbox_new(FALSE,0); 
                    gtk_container_add(GTK_CONTAINER(mainwindow), vbox);

                    sub_menu = gtk_menu_new();
                    sub_menuMI=gtk_menu_item_new_with_label(RF_str);
                    
                    l1=gtk_menu_item_new_with_label ("Label1");
                    l2=gtk_menu_item_new_with_label ("Label2");
                    
                    produce_recent_items();
                    int i;
                    for(i=0; i<RECENTS_COUNT && recents_ptr[i] ; i++)
                    {
                        GtkWidget *recent_wid;
                        const gchar *fn;
                        fn=gtk_recent_info_get_uri(recents_ptr[i]);
                        show_message_dialog(fn);
                        recent_wid=gtk_menu_item_new_with_label (fn);
                        gtk_menu_shell_append(GTK_MENU_SHELL(sub_menu),GTK_WIDGET(recent_wid));
                    }

                    if(strcmp(msg, "++++"))
                        entry = gtk_menu_item_new_with_label(msg); 
                    else entry=gtk_separator_menu_item_new();

                    gtk_menu_item_set_submenu(GTK_MENU_ITEM (sub_menuMI),sub_menu);

                    gtk_menu_shell_append(GTK_MENU_SHELL(sub_menu), l1);
                    gtk_menu_shell_append(GTK_MENU_SHELL(sub_menu), l2);

                    gtk_menu_shell_append(GTK_MENU_SHELL(menu),sub_menuMI);

                    gtk_box_pack_start(GTK_BOX(vbox), mainwindow, FALSE, FALSE, 0);
                    show_message_dialog("XO2");

                    g_signal_connect(G_OBJECT(l1),"activate" // This signal works correctly
                                     ,G_CALLBACK(show_message_dialog_event),			   (gpointer)"l1_activated\n");
                    
                    produce_recent_items();
                    for(i=0; i<RECENTS_COUNT && recents_ptr[i] ; i++)
                    {

                        gchar uri[40];
                        g_stpcpy( uri,gtk_recent_info_get_uri (recents_ptr[i]) );

                        GtkWidget *recent_wid;
                        recent_wid=gtk_menu_item_new_with_label (uri);

                        g_signal_connect(G_OBJECT(recent_wid),"activate" // signal shows gibberish
                                         //,G_CALLBACK(open_recent),(gpointer)recent_title);
                                         ,G_CALLBACK(show_message_dialog_event),(gpointer)uri);

                    }
                    

                }

You are mixing many things… it is becoming quite hard to follow you.

In your last post you have at least a scope problem: uri is a local array that is destroyed after the for cycle, i.e. when show_message_dialog_event is called.

Hi Mehdi,

Not sure what the code is doing but I think that you might be trying to set up a GtkRecentChooserMenu??? If so, this is a short example that might be helpful.

Eric


/*
     Test a gtk_recent_chooser_menu with a image widget.

    Make sure on Ubuntu that Settings/Privacy/Usage and History is turned on for the recent menu
to work.

    gcc -Wall menu_recent.c -o menu_recent `pkg-config --cflags --libs gtk+-3.0`

    Tested on Ubuntu18.04 and GTK3.22
*/

#include<gtk/gtk.h>

static void item_activated(GtkRecentChooser *chooser, GtkWidget **widgets);
static void open_image_dialog(GtkWidget *menu, GtkWidget **widgets);
static void close_current_image(GtkWidget *menu, GtkWidget **widgets);

int main(int argc, char **argv)
  {
    gtk_init(&argc, &argv);

    GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Menu Recent");
    gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
    
    GtkWidget *menu=gtk_menu_new();
    GtkWidget *open_image=gtk_menu_item_new_with_label("Open Image");
    GtkWidget *close_image=gtk_menu_item_new_with_label("Close Image");
    GtkWidget *recent_image=gtk_menu_item_new_with_label("Recent Image");
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), open_image);
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), close_image);
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), recent_image);

    GtkRecentManager *manager=gtk_recent_manager_get_default();
    GtkWidget *chooser=gtk_recent_chooser_menu_new_for_manager(manager);
    GtkRecentFilter *filter=gtk_recent_filter_new();
    gtk_recent_filter_add_pixbuf_formats(filter);
    gtk_recent_chooser_set_filter(GTK_RECENT_CHOOSER(chooser), filter);

    gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent_image), chooser);
    gtk_recent_chooser_set_show_not_found(GTK_RECENT_CHOOSER(chooser), FALSE);
    gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER(chooser), 5);
    gtk_recent_chooser_set_local_only(GTK_RECENT_CHOOSER(chooser), TRUE);
    gtk_recent_chooser_set_sort_type(GTK_RECENT_CHOOSER(chooser), GTK_RECENT_SORT_MRU);

    GtkWidget *menu_bar=gtk_menu_bar_new();
    GtkWidget *file=gtk_menu_item_new_with_label("File");
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), menu);
    gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), file);

    GtkWidget *image=gtk_image_new();
    gtk_widget_set_vexpand(image, TRUE);
    gtk_widget_set_hexpand(image, TRUE);

    GtkWidget *widgets[]={window, image};
    g_signal_connect(open_image, "activate", G_CALLBACK(open_image_dialog), widgets);
    g_signal_connect(close_image, "activate", G_CALLBACK(close_current_image), widgets);
    g_signal_connect(chooser, "item-activated", G_CALLBACK(item_activated), widgets);

    GtkWidget *scrolled_win=gtk_scrolled_window_new(NULL, NULL);
    gtk_container_add(GTK_CONTAINER(scrolled_win), image);

    GtkWidget *grid=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid), menu_bar, 0, 0, 1, 1);
    gtk_grid_attach(GTK_GRID(grid), scrolled_win, 0, 1, 1, 1);

    gtk_container_add(GTK_CONTAINER(window), grid);

    gtk_widget_show_all(window);

    gtk_main();

    return 0;  
  }
static void item_activated(GtkRecentChooser *chooser, GtkWidget **widgets)
  {
    GtkRecentInfo *info=gtk_recent_chooser_get_current_item(chooser);
    //g_print("%s\n", gtk_recent_info_get_uri(info));
    gchar *file_name=g_filename_from_uri(gtk_recent_info_get_uri(info), NULL, NULL);
    gtk_image_set_from_file(GTK_IMAGE(widgets[1]), file_name);
    gtk_recent_info_unref(info);
    g_free(file_name);
  }
static void open_image_dialog(GtkWidget *menu, GtkWidget **widgets)
  {
    GtkWidget *dialog=gtk_file_chooser_dialog_new("Open File", GTK_WINDOW(widgets[0]), GTK_FILE_CHOOSER_ACTION_OPEN, "Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
    GtkFileFilter *filter=gtk_file_filter_new();
    gtk_file_filter_add_pixbuf_formats(filter);
    gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);

    gint result=gtk_dialog_run(GTK_DIALOG(dialog));
    if(result==GTK_RESPONSE_ACCEPT)
      {
        gchar *file_name=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
        gchar *file_uri=gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
        //g_print("%s\n", file_name);
        //g_print("%s\n", file_uri);
        gtk_image_set_from_file(GTK_IMAGE(widgets[1]), file_name);
        GtkRecentManager *manager=gtk_recent_manager_get_default();
        gtk_recent_manager_add_item(manager, file_uri);        
        g_free(file_name);
        g_free(file_uri);
      }

    gtk_widget_destroy(dialog);
  }
static void close_current_image(GtkWidget *menu, GtkWidget **widgets)
  {
    gtk_image_clear(GTK_IMAGE(widgets[1]));
  }