diff --git a/appshell/appshell_extensions_gtk.cpp b/appshell/appshell_extensions_gtk.cpp index f101c513e..43136c475 100644 --- a/appshell/appshell_extensions_gtk.cpp +++ b/appshell/appshell_extensions_gtk.cpp @@ -95,6 +95,8 @@ typedef char s8; +bool StMenuCommandSkipper::sSkipMenuCommand = false; + extern CefRefPtr g_handler; // Supported browsers (order matters): @@ -1098,16 +1100,57 @@ int32 GetMenuItemState(CefRefPtr browser, ExtensionString commandId, return NO_ERROR; } +int _getMenuItemPosition(GtkWidget* parent, GtkWidget* menuItem) +{ + GList* children = gtk_container_get_children(GTK_CONTAINER(parent)); + int index = 0; + do { + GtkWidget* widget = (GtkWidget*) children->data; + if (widget == menuItem) { + return index; + } + index++; + } while ((children = g_list_next(children)) != NULL); + + return -1; +} + int32 SetMenuItemState(CefRefPtr browser, ExtensionString command, bool& enabled, bool& checked) { - // TODO: Implement functionality for checked NativeMenuModel& model = NativeMenuModel::getInstance(getMenuParent(browser)); int tag = model.getTag(command); if (tag == kTagNotFound) { return ERR_NOT_FOUND; } GtkWidget* menuItem = (GtkWidget*) model.getOsItem(tag); - gtk_widget_set_sensitive(menuItem, enabled); + if (menuItem == NULL) { + return ERR_UNKNOWN; + } + GtkWidget* parent = gtk_widget_get_parent(menuItem); + if (parent == NULL) { + return ERR_UNKNOWN; + } + int position = _getMenuItemPosition(parent, menuItem); + if (position < 0) { + return ERR_UNKNOWN; + } + const gchar* label = gtk_menu_item_get_label(GTK_MENU_ITEM(menuItem)); + + GtkWidget* newMenuItem; + if (checked == true) { + newMenuItem = gtk_check_menu_item_new_with_label(label); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(newMenuItem), true); + } else if (checked == false){ + newMenuItem = gtk_menu_item_new_with_label(label); + } + gtk_widget_destroy(menuItem); + + InstallMenuHandler(newMenuItem, browser, tag); + model.setOsItem(tag, newMenuItem); + gtk_menu_shell_insert(GTK_MENU_SHELL(parent), newMenuItem, position); + gtk_widget_set_sensitive(newMenuItem, enabled); + gtk_widget_show(newMenuItem); + return NO_ERROR; } diff --git a/appshell/appshell_extensions_platform.h b/appshell/appshell_extensions_platform.h index b2cea7b51..843bbbc67 100644 --- a/appshell/appshell_extensions_platform.h +++ b/appshell/appshell_extensions_platform.h @@ -108,6 +108,20 @@ class CharSetEncode void operator()(std::string &contents); }; +#if defined(OS_LINUX) +class StMenuCommandSkipper { +public: + + StMenuCommandSkipper() { sSkipMenuCommand = true; } + ~StMenuCommandSkipper() { sSkipMenuCommand = false;} + + static bool GetMenuCmdSkipFlag () { return sSkipMenuCommand;} + +private: + static bool sSkipMenuCommand; +}; +#endif + #if defined(OS_MACOSX) || defined(OS_LINUX) void DecodeContents(std::string &contents, const std::string& encoding); #endif diff --git a/appshell/browser/root_window_gtk.cc b/appshell/browser/root_window_gtk.cc index d566bbdd3..60f66302e 100644 --- a/appshell/browser/root_window_gtk.cc +++ b/appshell/browser/root_window_gtk.cc @@ -601,13 +601,49 @@ void RootWindowGtk::MenubarSizeAllocated(GtkWidget* widget, self->menubar_height_ = allocation->height; } +// Brackets specific change. +// GTK is toggling the menu state just by +// clicking on the menu entry. So posting a task to undo that +// unwanted side effect. This is a @nethip hack. +void DelayedMenuMarkToggle(GtkWidget *menuItem){ + + if (GTK_IS_CHECK_MENU_ITEM(menuItem)) { + // It is important to make sure our MenuItemACtivated + // knows that we are only changing the state and not + // firing any command as such. + StMenuCommandSkipper skipCmd; + + // Get the current state of the menu. + gboolean menuState = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuItem)); + + // Now go about toggling the state. If Brackets is triggering a menu state change, + // that will get executed later than DelayedMenuMarkToggle, as this task would have been + // posted prior to shell call to fire a command, so need not worry about this function + // getting executed after the shell call. + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuItem), !menuState); + } +} + // static gboolean RootWindowGtk::MenuItemActivated(GtkWidget* widget, RootWindowGtk* self) { - // Retrieve the menu ID set in AddMenuEntry. - int tag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), kMenuIdKey)); - if (self && self->browser_window_) - self->browser_window_->DispatchCommandToBrowser(self->GetBrowser(), tag); + // Since we have migrated to checked menu items, setting the + // state of the menu is triggering a menu activation. So made + // sure we actually execute a command only when is menu is + // actually activated by the user and not when setting the menu + // state. + if(!StMenuCommandSkipper::GetMenuCmdSkipFlag()){ + + // Post a message to undo the undesired menu state change. + // See the comments above for explanation. + CefPostTask(TID_UI, base::Bind(&DelayedMenuMarkToggle, widget)); + + // Retrieve the menu ID set in AddMenuEntry. + int tag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), kMenuIdKey)); + if (self && self->browser_window_) + self->browser_window_->DispatchCommandToBrowser(self->GetBrowser(), tag); + } + } // static