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

Commit ce6fc09

Browse files
authored
Merge pull request #633 from pelatx/linux-native-menus-checked-state
Linux native menus checked entries
2 parents 8ee733b + 5d821c0 commit ce6fc09

File tree

3 files changed

+99
-6
lines changed

3 files changed

+99
-6
lines changed

appshell/appshell_extensions_gtk.cpp

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@
9595

9696
typedef char s8;
9797

98+
bool StMenuCommandSkipper::sSkipMenuCommand = false;
99+
98100
extern CefRefPtr<ClientHandler> g_handler;
99101

100102
// Supported browsers (order matters):
@@ -1098,16 +1100,57 @@ int32 GetMenuItemState(CefRefPtr<CefBrowser> browser, ExtensionString commandId,
10981100
return NO_ERROR;
10991101
}
11001102

1103+
int _getMenuItemPosition(GtkWidget* parent, GtkWidget* menuItem)
1104+
{
1105+
GList* children = gtk_container_get_children(GTK_CONTAINER(parent));
1106+
int index = 0;
1107+
do {
1108+
GtkWidget* widget = (GtkWidget*) children->data;
1109+
if (widget == menuItem) {
1110+
return index;
1111+
}
1112+
index++;
1113+
} while ((children = g_list_next(children)) != NULL);
1114+
1115+
return -1;
1116+
}
1117+
11011118
int32 SetMenuItemState(CefRefPtr<CefBrowser> browser, ExtensionString command, bool& enabled, bool& checked)
11021119
{
1103-
// TODO: Implement functionality for checked
11041120
NativeMenuModel& model = NativeMenuModel::getInstance(getMenuParent(browser));
11051121
int tag = model.getTag(command);
11061122
if (tag == kTagNotFound) {
11071123
return ERR_NOT_FOUND;
11081124
}
11091125
GtkWidget* menuItem = (GtkWidget*) model.getOsItem(tag);
1110-
gtk_widget_set_sensitive(menuItem, enabled);
1126+
if (menuItem == NULL) {
1127+
return ERR_UNKNOWN;
1128+
}
1129+
GtkWidget* parent = gtk_widget_get_parent(menuItem);
1130+
if (parent == NULL) {
1131+
return ERR_UNKNOWN;
1132+
}
1133+
int position = _getMenuItemPosition(parent, menuItem);
1134+
if (position < 0) {
1135+
return ERR_UNKNOWN;
1136+
}
1137+
const gchar* label = gtk_menu_item_get_label(GTK_MENU_ITEM(menuItem));
1138+
1139+
GtkWidget* newMenuItem;
1140+
if (checked == true) {
1141+
newMenuItem = gtk_check_menu_item_new_with_label(label);
1142+
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(newMenuItem), true);
1143+
} else if (checked == false){
1144+
newMenuItem = gtk_menu_item_new_with_label(label);
1145+
}
1146+
gtk_widget_destroy(menuItem);
1147+
1148+
InstallMenuHandler(newMenuItem, browser, tag);
1149+
model.setOsItem(tag, newMenuItem);
1150+
gtk_menu_shell_insert(GTK_MENU_SHELL(parent), newMenuItem, position);
1151+
gtk_widget_set_sensitive(newMenuItem, enabled);
1152+
gtk_widget_show(newMenuItem);
1153+
11111154
return NO_ERROR;
11121155
}
11131156

appshell/appshell_extensions_platform.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,20 @@ class CharSetEncode
108108
void operator()(std::string &contents);
109109
};
110110

111+
#if defined(OS_LINUX)
112+
class StMenuCommandSkipper {
113+
public:
114+
115+
StMenuCommandSkipper() { sSkipMenuCommand = true; }
116+
~StMenuCommandSkipper() { sSkipMenuCommand = false;}
117+
118+
static bool GetMenuCmdSkipFlag () { return sSkipMenuCommand;}
119+
120+
private:
121+
static bool sSkipMenuCommand;
122+
};
123+
#endif
124+
111125
#if defined(OS_MACOSX) || defined(OS_LINUX)
112126
void DecodeContents(std::string &contents, const std::string& encoding);
113127
#endif

appshell/browser/root_window_gtk.cc

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -601,13 +601,49 @@ void RootWindowGtk::MenubarSizeAllocated(GtkWidget* widget,
601601
self->menubar_height_ = allocation->height;
602602
}
603603

604+
// Brackets specific change.
605+
// GTK is toggling the menu state just by
606+
// clicking on the menu entry. So posting a task to undo that
607+
// unwanted side effect. This is a @nethip hack.
608+
void DelayedMenuMarkToggle(GtkWidget *menuItem){
609+
610+
if (GTK_IS_CHECK_MENU_ITEM(menuItem)) {
611+
// It is important to make sure our MenuItemACtivated
612+
// knows that we are only changing the state and not
613+
// firing any command as such.
614+
StMenuCommandSkipper skipCmd;
615+
616+
// Get the current state of the menu.
617+
gboolean menuState = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuItem));
618+
619+
// Now go about toggling the state. If Brackets is triggering a menu state change,
620+
// that will get executed later than DelayedMenuMarkToggle, as this task would have been
621+
// posted prior to shell call to fire a command, so need not worry about this function
622+
// getting executed after the shell call.
623+
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuItem), !menuState);
624+
}
625+
}
626+
604627
// static
605628
gboolean RootWindowGtk::MenuItemActivated(GtkWidget* widget,
606629
RootWindowGtk* self) {
607-
// Retrieve the menu ID set in AddMenuEntry.
608-
int tag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), kMenuIdKey));
609-
if (self && self->browser_window_)
610-
self->browser_window_->DispatchCommandToBrowser(self->GetBrowser(), tag);
630+
// Since we have migrated to checked menu items, setting the
631+
// state of the menu is triggering a menu activation. So made
632+
// sure we actually execute a command only when is menu is
633+
// actually activated by the user and not when setting the menu
634+
// state.
635+
if(!StMenuCommandSkipper::GetMenuCmdSkipFlag()){
636+
637+
// Post a message to undo the undesired menu state change.
638+
// See the comments above for explanation.
639+
CefPostTask(TID_UI, base::Bind(&DelayedMenuMarkToggle, widget));
640+
641+
// Retrieve the menu ID set in AddMenuEntry.
642+
int tag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), kMenuIdKey));
643+
if (self && self->browser_window_)
644+
self->browser_window_->DispatchCommandToBrowser(self->GetBrowser(), tag);
645+
}
646+
611647
}
612648

613649
// static

0 commit comments

Comments
 (0)