diff --git a/atom/browser/api/atom_api_menu.cc b/atom/browser/api/atom_api_menu.cc index 2eb1a816adf8..a76d77b0f3e4 100644 --- a/atom/browser/api/atom_api_menu.cc +++ b/atom/browser/api/atom_api_menu.cc @@ -44,7 +44,9 @@ v8::Handle CallDelegate(v8::Handle default_value, } // namespace -Menu::Menu() : model_(new ui::SimpleMenuModel(this)) { +Menu::Menu() + : model_(new ui::SimpleMenuModel(this)), + parent_(NULL) { } Menu::~Menu() { @@ -167,6 +169,7 @@ void Menu::InsertSubMenuAt(int index, int command_id, const base::string16& label, Menu* menu) { + menu->parent_ = this; model_->InsertSubMenuAt(index, command_id, label, menu->model_.get()); } @@ -231,6 +234,9 @@ void Menu::BuildPrototype(v8::Isolate* isolate, .SetMethod("isVisibleAt", &Menu::IsVisibleAt) #if defined(OS_WIN) || defined(TOOLKIT_GTK) .SetMethod("_attachToWindow", &Menu::AttachToWindow) +#endif +#if defined(OS_WIN) + .SetMethod("_updateStates", &Menu::UpdateStates) #endif .SetMethod("_popup", &Menu::Popup); } diff --git a/atom/browser/api/atom_api_menu.h b/atom/browser/api/atom_api_menu.h index a9e9e926ba0b..a309e1b1eb40 100644 --- a/atom/browser/api/atom_api_menu.h +++ b/atom/browser/api/atom_api_menu.h @@ -54,6 +54,7 @@ class Menu : public mate::Wrappable, virtual void Popup(Window* window) = 0; scoped_ptr model_; + Menu* parent_; private: void InsertItemAt(int index, int command_id, const base::string16& label); @@ -80,8 +81,12 @@ class Menu : public mate::Wrappable, bool IsEnabledAt(int index) const; bool IsVisibleAt(int index) const; +#if defined(OS_WIN) + virtual void UpdateStates() = 0; +#endif + #if defined(OS_WIN) || defined(TOOLKIT_GTK) - void AttachToWindow(Window* window); + virtual void AttachToWindow(Window* window) = 0; #endif DISALLOW_COPY_AND_ASSIGN(Menu); diff --git a/atom/browser/api/atom_api_menu_gtk.cc b/atom/browser/api/atom_api_menu_gtk.cc index 86076bcc4160..acaca4b2f8e8 100644 --- a/atom/browser/api/atom_api_menu_gtk.cc +++ b/atom/browser/api/atom_api_menu_gtk.cc @@ -37,7 +37,7 @@ void MenuGtk::Popup(Window* window) { menu_gtk_->PopupAsContext(point, triggering_event_time); } -void Menu::AttachToWindow(Window* window) { +void MenuGtk::AttachToWindow(Window* window) { static_cast(window->window())->SetMenu(model_.get()); } diff --git a/atom/browser/api/atom_api_menu_gtk.h b/atom/browser/api/atom_api_menu_gtk.h index 3c39fb730b7b..eb6c94c9932b 100644 --- a/atom/browser/api/atom_api_menu_gtk.h +++ b/atom/browser/api/atom_api_menu_gtk.h @@ -19,6 +19,7 @@ class MenuGtk : public Menu, protected: virtual void Popup(Window* window) OVERRIDE; + virtual void AttachToWindow(Window* window) OVERRIDE; private: scoped_ptr<::MenuGtk> menu_gtk_; diff --git a/atom/browser/api/atom_api_menu_win.cc b/atom/browser/api/atom_api_menu_win.cc index d5a24ceadb77..6bf515c7bdd5 100644 --- a/atom/browser/api/atom_api_menu_win.cc +++ b/atom/browser/api/atom_api_menu_win.cc @@ -15,17 +15,28 @@ namespace atom { namespace api { -MenuWin::MenuWin() { +MenuWin::MenuWin() : menu_(NULL) { } void MenuWin::Popup(Window* window) { gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint(); - menu_.reset(new atom::Menu2(model_.get())); + popup_menu_.reset(new atom::Menu2(model_.get())); + menu_ = popup_menu_.get(); menu_->RunContextMenuAt(cursor); } -void Menu::AttachToWindow(Window* window) { - static_cast(window->window())->SetMenu(model_.get()); +void MenuWin::UpdateStates() { + MenuWin* top = this; + while (top->parent_) + top = static_cast(top->parent_); + if (top->menu_) + top->menu_->UpdateStates(); +} + +void MenuWin::AttachToWindow(Window* window) { + NativeWindowWin* nw = static_cast(window->window()); + nw->SetMenu(model_.get()); + menu_ = nw->menu(); } // static diff --git a/atom/browser/api/atom_api_menu_win.h b/atom/browser/api/atom_api_menu_win.h index 965aa5983141..1dd66c488ee8 100644 --- a/atom/browser/api/atom_api_menu_win.h +++ b/atom/browser/api/atom_api_menu_win.h @@ -19,9 +19,12 @@ class MenuWin : public Menu { protected: virtual void Popup(Window* window) OVERRIDE; + virtual void UpdateStates() OVERRIDE; + virtual void AttachToWindow(Window* window) OVERRIDE; private: - scoped_ptr menu_; + atom::Menu2* menu_; // Weak ref, could be window menu or popup menu. + scoped_ptr popup_menu_; DISALLOW_COPY_AND_ASSIGN(MenuWin); }; diff --git a/atom/browser/api/lib/menu.coffee b/atom/browser/api/lib/menu.coffee index a119d9fdabf1..0e7b4c263f9c 100644 --- a/atom/browser/api/lib/menu.coffee +++ b/atom/browser/api/lib/menu.coffee @@ -64,7 +64,18 @@ Menu::insert = (pos, item) -> switch item.type when 'normal' then @insertItem pos, item.commandId, item.label - when 'checkbox' then @insertCheckItem pos, item.commandId, item.label + when 'checkbox' + # Update states when clicked on Windows. + if process.platform is 'win32' + v8Util.setHiddenValue item, 'checked', item.checked + Object.defineProperty item, 'checked', + enumerable: true + get: -> v8Util.getHiddenValue item, 'checked' + set: (val) => + v8Util.setHiddenValue item, 'checked', val + @_updateStates() if process.platform is 'win32' + + @insertCheckItem pos, item.commandId, item.label when 'separator' then @insertSeparator pos when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu when 'radio' @@ -83,6 +94,9 @@ Menu::insert = (pos, item) -> v8Util.setHiddenValue otherItem, 'checked', false v8Util.setHiddenValue item, 'checked', true + # Update states when clicked on Windows. + @_updateStates() if process.platform is 'win32' + @insertRadioItem pos, item.commandId, item.label, item.groupId @setSublabel pos, item.sublabel if item.sublabel? diff --git a/atom/browser/native_window_win.h b/atom/browser/native_window_win.h index 47984c4c61f4..8d25fcba8c87 100644 --- a/atom/browser/native_window_win.h +++ b/atom/browser/native_window_win.h @@ -81,6 +81,7 @@ class NativeWindowWin : public NativeWindow, void SetMenu(ui::MenuModel* menu_model); views::Widget* window() const { return window_.get(); } + atom::Menu2* menu() const { return menu_.get(); } SkRegion* draggable_region() { return draggable_region_.get(); } protected: