Nautilus Menu Provider - Issue in hierarchial submenus (2 levels)



Hello,

I am trying to develop a nautilus extension in C, to provide a context
menu. I am using Nautilus Menu Provider interface and related APIs.

Nautilus version: 3.4.2
Gtk: 3.0
OS: Ubuntu 12.04 LTS

My menu organization is something like below:

1) I have added a menu item "My menu" to file/folder context menu.
2) The "My menu" has a submenu with menu items as "One 1", "Two 2",
"Three3",Four 4".
3) "One 1" has another submenu which has menu items "Sub Menu One 1",
"Sub Menu Two 2"

My requirement  is as below:
1) If I right-click on a "Folder", I must see "My menu", when I place
curser there it must open submenu, but only "One 1" and "Four4" must
be sensitive (clickable), but "Two 2" and "Three 3" must  be grayed
out.
2) If I right click on a "File", I must see "My menu", but only "Four
4" must be sensitive/clickable, everything else must be grayed out.

Current behavior:

1) Quite frequently, I see that, when I right-click on a file, I see
that "One 1" menu item gets completely disappeared.
2) If I right click on a folder, "One 1", will be appearing to be in
gray color (but still clickable, because I am able to click on it),
but its sub menu items "Sub Menu One1" and "Sub Menu Two 2", would be
in clickable and highlighted state. Also the link of submenus get
broken and "Sub Menu One 1" and "Sub Menu Two 2" would appear in the
same menu of "My menu". This happens once in 10 times or 15 times,
sometimes very frequently.

Crude workaround:
1) If I right click on background (where there are no files/folders),
nautilus gets reloaded and I can see things start working as per my
requirement without menu items getting messed up.

I am attaching the code and also the screen shots. Please let me know
if I am doing anything wrong (probably not cleaning up memory) or if
it is a bug.

Thanks,
-Sandeep
#include <glib.h>
/* Nautilus extension headers */
#include <libnautilus-extension/nautilus-extension-types.h>
#include <libnautilus-extension/nautilus-file-info.h>
#include <libnautilus-extension/nautilus-info-provider.h>
#include <libnautilus-extension/nautilus-menu-provider.h>
#include <libnautilus-extension/nautilus-property-page-provider.h>

/*#include <gtk/gtktable.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtklabel.h>*/
#include <string.h>
#include <time.h>
#include <list>
#include <string>

#include "nautilus-sample.h"


static GType nautilus_sample_type;

static void nautilus_sample_class_init (NautilusObjClass *obj)
{
    /* Nothing as of now */
}

static void nautilus_sample_class_finalize (NautilusObjClass *obj) 
{
    /* Nothing as of now */
}

static void nautilus_sample_instance_init (NautilusObj *object)
{

}

static void menu1Cb(NautilusMenuItem *item,
						 NautilusObj *instance) 
{
}

static void menu2Cb(NautilusMenuItem *item,
						 NautilusObj *instance) 
{
}

static void menu3Cb(NautilusMenuItem *item,
						 NautilusObj *instance) 
{
}

static void menu4Cb(NautilusMenuItem *item,
						 NautilusObj *instance) 
{
}

static GList * nautilus_sample_get_file_items (NautilusMenuProvider *provider,
                                                    GtkWidget *window,
                                                    GList *files)
{
    /*
    * 1. Convert files to filenames.
    */


    int file_count = g_list_length(files);

    if (file_count != 1) 
        return NULL;

    GList *elem = files;
    gchar **paths = g_new0(gchar *, file_count + 1);
    GList *return_list = NULL;
    bool isDir = false;

    gchar *uri = nautilus_file_info_get_uri((NautilusFile*)elem->data);
    gchar *filename_un = uri ? g_filename_from_uri(uri, NULL, NULL) : NULL;
    gchar *filename = filename_un ? g_filename_to_utf8(filename_un, -1, NULL, NULL, NULL) : NULL;

    g_free(uri);
    g_free(filename_un);

    if (filename == NULL) 
    {
        // filename wasn't correctly encoded, or isn't a local file.  
        g_strfreev(paths);
        return NULL;
    }

    if(g_file_test(filename, G_FILE_TEST_IS_DIR))
    {
        isDir = true;
        paths[0] = filename;
    }

    std::list<std::string> listofMenuItems;
    listofMenuItems.push_back("Sub Menu One 1");
    listofMenuItems.push_back("Sub Menu Two 2");

	NautilusMenuItem *root_menu_item = nautilus_menu_item_new("NautilusObj::root_menu_item",
                                            "My menu", 
                                            "Fun time", 
                                            "folder");

	return_list = g_list_append(return_list, root_menu_item);

    /* Adding items to submenu */

    NautilusMenu *subMenu = nautilus_menu_new();

    nautilus_menu_item_set_submenu(root_menu_item, subMenu); //Connect submenu to root menu item

    NautilusMenuItem *menuitem1 = nautilus_menu_item_new("NautilusObj::menuItem1",
                                                             "One 1", 
                                                             "One 1", 
                                                             "folder");
    

    NautilusMenuItem *menuitem2 = nautilus_menu_item_new("NautilusObj::menuItem2",
                                                                 "Two 2", 
                                                                 "Two 2", 
                                                                 "folder");

    NautilusMenuItem *menuitem3 = nautilus_menu_item_new("NautilusObj::menuItem3",
                                                                 "Three 3", 
                                                                 "Three 3", 
                                                                 "folder");

    NautilusMenuItem *menuitem4 = nautilus_menu_item_new("NautilusObj::menuItem4",
                                                                 "Four 4", 
                                                                 "Four 4", 
                                                                 "folder");                                                                     

    nautilus_menu_append_item(subMenu, menuitem1);
    nautilus_menu_append_item(subMenu, menuitem2);
    nautilus_menu_append_item(subMenu, menuitem3);
    nautilus_menu_append_item(subMenu, menuitem4);

    g_signal_connect (menuitem4, "activate", G_CALLBACK (menu4Cb), provider);

    /* Done adding items to submenu */

    NautilusMenu *driveMenu = nautilus_menu_new();

    if(isDir)
    {

        if(1)
        {

            nautilus_menu_item_set_submenu(menuitem1, driveMenu);

            if(listofMenuItems.size() > 1)
            {

                for(std::list<std::string>::iterator itr = listofMenuItems.begin(); itr != listofMenuItems.end(); itr++)
                {
                    std::string itemName = std::string("NautilusObj::") + *itr;
                    NautilusMenuItem *driveItems = nautilus_menu_item_new(itemName.c_str(),
                                                                             (*itr).c_str(), 
                                                                             "Sub menus", 
                                                                             "folder");
                    nautilus_menu_append_item(driveMenu, driveItems);
                }

            }

            GValue sensitive = G_VALUE_INIT;
            g_value_init (&sensitive, G_TYPE_BOOLEAN);
            g_value_set_boolean (&sensitive, FALSE);
           
            g_object_set_property (G_OBJECT(menuitem2), "sensitive", &sensitive);
            g_object_set_property (G_OBJECT(menuitem3), "sensitive", &sensitive);

            g_signal_connect (menuitem1, "activate", G_CALLBACK (menu1Cb), provider);

        }
    }
    else
    {
        GValue sensitive = G_VALUE_INIT;
        g_value_init (&sensitive, G_TYPE_BOOLEAN);
        g_value_set_boolean (&sensitive, FALSE);

        g_object_set_property (G_OBJECT(menuitem1), "sensitive", &sensitive);
        g_object_set_property (G_OBJECT(menuitem2), "sensitive", &sensitive);
        g_object_set_property (G_OBJECT(menuitem3), "sensitive", &sensitive);

    }


    GList *drivemenus = nautilus_menu_get_items(driveMenu);
    nautilus_menu_item_list_free(drivemenus);
    g_object_unref(driveMenu);

    GList *submenus = nautilus_menu_get_items(subMenu);
    nautilus_menu_item_list_free(submenus);
    g_object_unref(subMenu);

    return return_list;
}

static void nautilus_sample_menu_provider_iface_init (NautilusMenuProviderIface *iface)
{
    iface->get_file_items = nautilus_sample_get_file_items;
}

static NautilusOperationResult nautilus_sample_update_file_info (NautilusInfoProvider *provider,
                                                                     NautilusFileInfo         *file,
                                                                     GClosure                 *update_complete,
                                                                     NautilusOperationHandle **handle) 
{

    /* Get the file name first */
    gchar *pfilename, *uri;

    uri = nautilus_file_info_get_uri(file);
    pfilename = g_filename_from_uri(uri, NULL, NULL);

    g_free(uri);

    if (pfilename == NULL) 
    {
        return NAUTILUS_OPERATION_COMPLETE;
    }
    else 
    {

        /*nautilus_file_info_add_emblem(file, "ubuntuone-unsynchronized");*/
    }

    g_free(pfilename);


    return NAUTILUS_OPERATION_COMPLETE;
}

static void nautilus_sample_cancel_update (NautilusInfoProvider     *provider,
                                               NautilusOperationHandle  *handle) 
{
    return;
}

static void nautilus_sample_info_provider_iface_init (NautilusInfoProviderIface *iface) 
{

    iface->update_file_info = nautilus_sample_update_file_info;
    iface->cancel_update = nautilus_sample_cancel_update;

    return;
}

GType nautilus_sampleExtension_get_type (void)
{
    return nautilus_sample_type;
}


void nautilus_sampleExtension_register_type (GTypeModule *module)
{

    static const GTypeInfo info = {
        sizeof (NautilusObjClass),
        (GBaseInitFunc) NULL,
        (GBaseFinalizeFunc) NULL,
        (GClassInitFunc) nautilus_sample_class_init,
        (GClassFinalizeFunc) nautilus_sample_class_finalize,
        NULL,
        sizeof (NautilusObj),
        0,
        (GInstanceInitFunc) nautilus_sample_instance_init,
    };
    
    /* menu provider interface */
    static const GInterfaceInfo menu_provider_iface_info = {
        (GInterfaceInitFunc) nautilus_sample_menu_provider_iface_init,
        NULL,
        NULL
    };

    /* info provider interface */
    static const GInterfaceInfo info_provider_iface_info = {
        (GInterfaceInitFunc) nautilus_sample_info_provider_iface_init,
        NULL,
        NULL
    };

    
    nautilus_sample_type = g_type_module_register_type (module,
                                                            G_TYPE_OBJECT,
                                                            "NautilusObj",
                                                            &info,
                                                            (GTypeFlags)0);

    g_type_module_add_interface (module,
                                 nautilus_sample_type,
                                 NAUTILUS_TYPE_MENU_PROVIDER,
                                 &menu_provider_iface_info);

    g_type_module_add_interface (module,
                                 nautilus_sample_type,
                                 NAUTILUS_TYPE_INFO_PROVIDER,
                                 &info_provider_iface_info);
}

Attachment: File-FailureScenario.png
Description: PNG image

Attachment: File-SuccessScenario.png
Description: PNG image

Attachment: Folder-FailureScenario.png
Description: PNG image

Attachment: Folder-SuccessScenario.png
Description: PNG image

Attachment: Makefile
Description: Binary data

#ifndef NAUTILUS_SAMPLEEXTENSION_H
#define NAUTILUS_SAMPLEEXTENSION_H

#include <glib.h>
#include <glib-object.h>

#include <libnautilus-extension/nautilus-extension-types.h>
#include <libnautilus-extension/nautilus-file-info.h>
#include <libnautilus-extension/nautilus-info-provider.h>
#include <libnautilus-extension/nautilus-menu-provider.h>
#include <libnautilus-extension/nautilus-property-page-provider.h>

typedef struct 
{
    GObject parent_slot;
} NautilusObj;

typedef struct 
{
    GObjectClass parent_slot;
} NautilusObjClass;

extern "C"
{
GType nautilus_sampleExtension_get_type (void);
void nautilus_sampleExtension_register_type (GTypeModule *module);
}

#endif
#include <glib-object.h>

#include <gdk/gdk.h>
#include <gtk/gtk.h>

#include "nautilus-sample.h"

static GType provider_types[1];

void nautilus_module_initialize (GTypeModule  *module)
{
        g_print ("Initializing nautilus-sample extension\n");
        nautilus_sampleExtension_register_type (module);

        provider_types[0] = nautilus_sampleExtension_get_type ();
}

void nautilus_module_shutdown (void)
{
        g_print ("Shutting down nautilus-sample extension\n");
}

void nautilus_module_list_types (const GType **types,
                                 int *num_types)
{
        *types = provider_types;
        *num_types = G_N_ELEMENTS (provider_types);
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]