Skip to content
This repository has been archived by the owner on Sep 2, 2021. It is now read-only.

Commit

Permalink
Merge pull request #633 from pelatx/linux-native-menus-checked-state
Browse files Browse the repository at this point in the history
Linux native menus checked entries
  • Loading branch information
nethip authored Mar 8, 2018
2 parents 8ee733b + 5d821c0 commit ce6fc09
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 6 deletions.
47 changes: 45 additions & 2 deletions appshell/appshell_extensions_gtk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@

typedef char s8;

bool StMenuCommandSkipper::sSkipMenuCommand = false;

extern CefRefPtr<ClientHandler> g_handler;

// Supported browsers (order matters):
Expand Down Expand Up @@ -1098,16 +1100,57 @@ int32 GetMenuItemState(CefRefPtr<CefBrowser> 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<CefBrowser> 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;
}

Expand Down
14 changes: 14 additions & 0 deletions appshell/appshell_extensions_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
44 changes: 40 additions & 4 deletions appshell/browser/root_window_gtk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit ce6fc09

Please sign in to comment.