Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Menu accelerators not working #15094

Merged
merged 8 commits into from Nov 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion atom/browser/native_window_views.cc
Expand Up @@ -899,14 +899,18 @@ void NativeWindowViews::SetFocusable(bool focusable) {

void NativeWindowViews::SetMenu(AtomMenuModel* menu_model) {
#if defined(USE_X11)
if (menu_model == nullptr)
if (menu_model == nullptr) {
global_menu_bar_.reset();
root_view_->UnregisterAcceleratorsWithFocusManager();
return;
}

if (!global_menu_bar_ && ShouldUseGlobalMenuBar())
global_menu_bar_.reset(new GlobalMenuBarX11(this));

// Use global application menu bar when possible.
if (global_menu_bar_ && global_menu_bar_->IsServerStarted()) {
root_view_->RegisterAcceleratorsWithFocusManager(menu_model);
global_menu_bar_->SetMenu(menu_model);
return;
}
Expand Down
20 changes: 13 additions & 7 deletions atom/browser/ui/views/root_view.cc
Expand Up @@ -46,15 +46,14 @@ RootView::~RootView() {}
void RootView::SetMenu(AtomMenuModel* menu_model) {
if (menu_model == nullptr) {
// Remove accelerators
accelerator_table_.clear();
GetFocusManager()->UnregisterAccelerators(this);
UnregisterAcceleratorsWithFocusManager();
// and menu bar.
SetMenuBarVisibility(false);
menu_bar_.reset();
return;
}

RegisterAccelerators(menu_model);
RegisterAcceleratorsWithFocusManager(menu_model);

// Do not show menu bar in frameless window.
if (!window_->has_frame())
Expand Down Expand Up @@ -197,12 +196,13 @@ bool RootView::AcceleratorPressed(const ui::Accelerator& accelerator) {
accelerator);
}

void RootView::RegisterAccelerators(AtomMenuModel* menu_model) {
void RootView::RegisterAcceleratorsWithFocusManager(AtomMenuModel* menu_model) {
if (!menu_model)
return;
// Clear previous accelerators.
views::FocusManager* focus_manager = GetFocusManager();
accelerator_table_.clear();
focus_manager->UnregisterAccelerators(this);
UnregisterAcceleratorsWithFocusManager();

views::FocusManager* focus_manager = GetFocusManager();
// Register accelerators with focus manager.
accelerator_util::GenerateAcceleratorTable(&accelerator_table_, menu_model);
for (const auto& iter : accelerator_table_) {
Expand All @@ -211,4 +211,10 @@ void RootView::RegisterAccelerators(AtomMenuModel* menu_model) {
}
}

void RootView::UnregisterAcceleratorsWithFocusManager() {
views::FocusManager* focus_manager = GetFocusManager();
accelerator_table_.clear();
focus_manager->UnregisterAccelerators(this);
}

} // namespace atom
6 changes: 3 additions & 3 deletions atom/browser/ui/views/root_view.h
Expand Up @@ -36,6 +36,9 @@ class RootView : public views::View {
void HandleKeyEvent(const content::NativeWebKeyboardEvent& event);
void ResetAltState();
void RestoreFocus();
// Register/Unregister accelerators supported by the menu model.
void RegisterAcceleratorsWithFocusManager(AtomMenuModel* menu_model);
void UnregisterAcceleratorsWithFocusManager();

// views::View:
void Layout() override;
Expand All @@ -44,9 +47,6 @@ class RootView : public views::View {
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;

private:
// Register accelerators supported by the menu model.
void RegisterAccelerators(AtomMenuModel* menu_model);

// Parent window, weak ref.
NativeWindow* window_;

Expand Down
42 changes: 42 additions & 0 deletions spec/api-menu-spec.js
Expand Up @@ -742,4 +742,46 @@ describe('Menu module', () => {
expect(Menu.getApplicationMenu()).to.be.null()
})
})

describe('menu accelerators', () => {
let testFn = it
try {
// We have other tests that check if native modules work, if we fail to require
// robotjs let's skip this test to avoid false negatives
require('robotjs')
} catch (err) {
testFn = it.skip
}
const sendRobotjsKey = (key, modifiers = [], delay = 500) => {
return new Promise((resolve, reject) => {
require('robotjs').keyTap(key, modifiers)
setTimeout(() => {
resolve()
}, delay)
})
}

testFn('menu accelerators perform the specified action', async () => {
const menu = Menu.buildFromTemplate([
{
label: 'Test',
submenu: [
{
label: 'Test Item',
accelerator: 'Ctrl+T',
click: () => {
// Test will succeed, only when the menu accelerator action
// is triggered
Promise.resolve()
},
id: 'test'
}
]
}
])
Menu.setApplicationMenu(menu)
expect(Menu.getApplicationMenu()).to.not.be.null()
await sendRobotjsKey('t', 'control')
})
})
})