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. 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:
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); }