Show recents message

Hi,

I have this code snippet , my desired str_ptr is not shown correctly , why ?

[...]
                data* dip=g_new(data,RECENTS_COUNT+1);
                gulong hid[RECENTS_COUNT+1];
                gchar *str_ptr=NULL;

                    for(i=0; i<RECENTS_COUNT && recents_ptr[i] ; i++) 
                    {

                        
                        //str_ptr=g_strdup_printf ("si is %d\n",i); // TODO this works
                        // TODO this does not work:
                        str_ptr=g_strdup_printf("%s\n",gtk_recent_info_get_uri(recents_ptr[i]));
                        
                        (dip+i)->str=str_ptr;
                        (dip+i)->window=mainwindow;

                        hid[i]=g_signal_connect_data
                                (G_OBJECT(recents_ptr[i]),
                                "activate"
                                ,G_CALLBACK(show_message_caller),
                                (dip+i),
                                (GClosureNotify)g_free,
                                0);

                        assert(hid[i]>0);
[...]
void show_message ( data* mes_par) 
{

    GtkWidget*  dialog;
    gchar *  message=mes_par->str;
    GtkWidget* parent=GTK_WIDGET(mes_par->window);

    dialog = gtk_message_dialog_new (GTK_WINDOW(parent),
                                     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_caller(GtkWidget* choice,gpointer mes_par) 
{
    UNUSED(choice);
    data *udp=mes_par;
    show_message(udp);
    return;
}

There isn’t enough context here, but you are treating recents_ptr[i] as both a GtkRecentInfo * (passing it to gtk_recent_info_get_uri()), and as an object with an activate signal. One of those must be wrong.

Also, the memory management with g_signal_connect_data() is incorrect. Your data was allocated as a block, so it can’t be freed individually, and you would leak the string from g_strdup_printf().

Above my previous code in the same file I have:

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

Another file:

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

I replaced recents_ptr with rec_labels

//code
GtkWidget *rec_labels[RECENTS_COUNT+1];
//code
hid[i]=g_signal_connect_data
                                (G_OBJECT(rec_labels[i]),//G_OBJECT(recents_ptr[i]),
                                "activate"
                                ,G_CALLBACK(show_message_caller),
                                (dip+i),
                                (GClosureNotify)g_free,
                                0);

                        assert(hid[i]>0);

Now no event happens after clicking recent items.

Also about memory leak , is it sufficient to call g_free() after g_signal_connect_data() ?

More code snippet:

[...]
	else if(mb[i].handle == RECENT_SUBMENU)
                {

                    GtkWidget *window;
                    GtkWidget *vbox;
                    GtkWidget *rec_labels[RECENTS_COUNT+1];

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

                    GtkWidget *recent_wid;
                    const gchar *fn;

                    gchar uri[URI_SIZE];

                    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();
                    
                    vbox = gtk_vbox_new(FALSE, 0);
                    gtk_container_add(GTK_CONTAINER(window), vbox);

                    gint i;
                    for(i=0; i<RECENTS_COUNT && recents_ptr[i] ; i++) 
                    {
                        
                        const gchar *uri_l=gtk_recent_info_get_uri(recents_ptr[i]);
                        rec_labels[i]=gtk_menu_item_new_with_label(uri_l);
                    }

                    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);

                    for(i=0; i<RECENTS_COUNT; i++)
                        gtk_menu_shell_append(GTK_MENU_SHELL(sub_menu), GTK_WIDGET(recents_ptr[i]));

                    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"
                                     ,G_CALLBACK(show_message_dialog_event),(gpointer)"l1_activated\n");
                    

                    data* dip=g_new(data,RECENTS_COUNT+1);
                    gulong hid[RECENTS_COUNT+1];
                    gchar *str_ptr=NULL;


                    for(i=0; i<RECENTS_COUNT && recents_ptr[i] ; i++) 
                    {

                        

                        //str_ptr=g_strdup_printf ("si is %d\n",i); // TODO this works
                        // TODO this does not work:
                        str_ptr=g_strdup_printf("%s\n",gtk_recent_info_get_uri(recents_ptr[i]));
                        
                        (dip+i)->str=str_ptr;

                        (dip+i)->window=mainwindow;

                        hid[i]=g_signal_connect_data
                                (G_OBJECT(rec_labels[i]),
                                "activate"
                                ,G_CALLBACK(show_message_caller),
                                (dip+i),
                                (GClosureNotify)g_free,
                                0);

                        assert(hid[i]>0);

                    }
                    
                }
[...]

That should be rec_labels[i], not GTK_WIDGET(recents_ptr[i]). I would expect the GTK_WIDGET() cast to complain about that. Also, you could just create the menu items, add them to the menu, and connect the signals all in the same loop. That way, you wouldn’t need to keep the array of menu items at all.

You can’t free the memory right away because it needs to be valid when the callback fires. You can g_new0() a struct in each iteration of the loop and pass it to g_signal_connect_data() along with a free function that frees the contents and then the struct itself.

Now I get gibberish on recents submenu and also the shown message. Also another function:


extern GtkRecentInfo *recents_ptr[RECENTS_COUNT+1]; 
extern gchar recent_title[64];
void produce_recent_items(void) 
{
#include <stdbool.h>
    GtkRecentManager *manager;
    GtkRecentInfo *ri;
    GList *rf_list;
    const gchar *rf_str;
    
    GtkRecentInfo *rf_widget;

    //gtk_recent_manager_new();
    manager=gtk_recent_manager_get_default(); 
    assert(manager!=NULL);
    GtkWidget *chooser=gtk_recent_chooser_menu_new_for_manager(manager);
    assert(chooser!=NULL);

    gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER(chooser),RECENTS_COUNT);
    
    rf_list=gtk_recent_chooser_get_items (GTK_RECENT_CHOOSER(chooser) );
    assert(rf_list!=NULL);

    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(1)//(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); 
            
            recents_ptr[i]=rf_widget;
            i++;
        }
        rf_list=rf_list->next;
    }

    return;
}

Another question which one to use gtk_recent_manager_new() or gtk_recent_manager_get_default() ?

Use the get_default() singleton. Constructing a new GtkRecentManager instance should only be needed if you want to store the data into a custom file.

The root problem is that you are storing the return value of gtk_menu_item_new_with_label in rf_widget and recents_ptr[i], both of which are GtkRecentInfo *, not GtkWidget *. Your compiler should have warned about this (Maybe you need -Wall ?). Your original menu-building code works because the GTK_WIDGET() cast hides the incorrect type that is actually pointing to the correct object. However, you can’t use gtk_recent_info_get_uri() with recents_ptr[i], because that isn’t really the GtkRecentInfo, which you haven’t saved at all. This is why you get gibberish with the calls to gtk_recent_info_get_uri() when you build a second set of menu items (rec_labels) and when you populate the data structs.

Bigger picture: you can probably just use gtk_recent_chooser_menu_new() instead of most of this. If you want to build your own widgets, then use gtk_recent_manager_get_default() instead; there’s no reason to create a GtkRecentChooserMenu around it if you’re not going to use the menu.

[…]

[…]

How and where can I save that ?

Also there is a file opening menu. I can show recent files with program specific extensions to be shown there too.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.