1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.h"
9 #include "chrome/browser/extensions/api/commands/command_service.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "extensions/common/extension.h"
13 #include "ui/base/accelerators/platform_accelerator_gtk.h"
16 void extensions::ExtensionKeybindingRegistry::SetShortcutHandlingSuspended(
18 ExtensionKeybindingRegistryGtk::set_shortcut_handling_suspended(suspended
);
21 bool ExtensionKeybindingRegistryGtk::shortcut_handling_suspended_
= false;
23 ExtensionKeybindingRegistryGtk::ExtensionKeybindingRegistryGtk(
25 gfx::NativeWindow window
,
26 ExtensionFilter extension_filter
,
28 : ExtensionKeybindingRegistry(profile
, extension_filter
, delegate
),
35 ExtensionKeybindingRegistryGtk::~ExtensionKeybindingRegistryGtk() {
37 gtk_accel_group_disconnect(accel_group_
,
38 NULL
); // Remove all closures.
39 event_targets_
.clear();
41 gtk_window_remove_accel_group(window_
, accel_group_
);
42 g_object_unref(accel_group_
);
47 gboolean
ExtensionKeybindingRegistryGtk::HasPriorityHandler(
48 const GdkEventKey
* event
) const {
49 if (shortcut_handling_suspended_
)
52 ui::Accelerator accelerator
= ui::AcceleratorForGdkKeyCodeAndModifier(
53 event
->keyval
, static_cast<GdkModifierType
>(event
->state
));
55 return event_targets_
.find(accelerator
) != event_targets_
.end();
58 void ExtensionKeybindingRegistryGtk::AddExtensionKeybinding(
59 const extensions::Extension
* extension
,
60 const std::string
& command_name
) {
61 extensions::CommandService
* command_service
=
62 extensions::CommandService::Get(profile_
);
63 extensions::CommandMap commands
;
64 command_service
->GetNamedCommands(
66 extensions::CommandService::ACTIVE_ONLY
,
67 extensions::CommandService::REGULAR
,
70 for (extensions::CommandMap::const_iterator iter
= commands
.begin();
71 iter
!= commands
.end(); ++iter
) {
72 if (!command_name
.empty() && (iter
->second
.command_name() != command_name
))
75 ui::Accelerator
accelerator(iter
->second
.accelerator());
76 event_targets_
[accelerator
].push_back(
77 std::make_pair(extension
->id(), iter
->second
.command_name()));
79 // Shortcuts except media keys have only one target in the list. See comment
80 // about |event_targets_|.
81 if (!extensions::CommandService::IsMediaKey(iter
->second
.accelerator()))
82 DCHECK_EQ(1u, event_targets_
[accelerator
].size());
85 accel_group_
= gtk_accel_group_new();
86 gtk_window_add_accel_group(window_
, accel_group_
);
89 gtk_accel_group_connect(
91 ui::GetGdkKeyCodeForAccelerator(accelerator
),
92 ui::GetGdkModifierForAccelerator(accelerator
),
94 g_cclosure_new(G_CALLBACK(OnGtkAcceleratorThunk
), this, NULL
));
97 // Unlike on Windows, we need to explicitly add the browser action and page
98 // action to the event_targets_, even though we don't register them as
99 // handlers. See http://crbug.com/124873.
100 extensions::Command browser_action
;
101 if (command_service
->GetBrowserActionCommand(
103 extensions::CommandService::ACTIVE_ONLY
,
106 ui::Accelerator
accelerator(browser_action
.accelerator());
107 event_targets_
[accelerator
].push_back(
108 std::make_pair(extension
->id(), browser_action
.command_name()));
109 // We should have only one target. See comment about |event_targets_|.
110 DCHECK_EQ(1u, event_targets_
[accelerator
].size());
113 // Add the Page Action (if any).
114 extensions::Command page_action
;
115 if (command_service
->GetPageActionCommand(
117 extensions::CommandService::ACTIVE_ONLY
,
120 ui::Accelerator
accelerator(page_action
.accelerator());
121 event_targets_
[accelerator
].push_back(
122 std::make_pair(extension
->id(), page_action
.command_name()));
123 // We should have only one target. See comment about |event_targets_|.
124 DCHECK_EQ(1u, event_targets_
[accelerator
].size());
127 // Add the Script Badge (if any).
128 extensions::Command script_badge
;
129 if (command_service
->GetScriptBadgeCommand(
131 extensions::CommandService::ACTIVE_ONLY
,
134 ui::Accelerator
accelerator(script_badge
.accelerator());
135 event_targets_
[accelerator
].push_back(
136 std::make_pair(extension
->id(), script_badge
.command_name()));
137 // We should have only one target. See comment about |event_targets_|.
138 DCHECK_EQ(1u, event_targets_
[accelerator
].size());
142 void ExtensionKeybindingRegistryGtk::RemoveExtensionKeybindingImpl(
143 const ui::Accelerator
& accelerator
,
144 const std::string
& command_name
) {
145 // On GTK, unlike Windows, the Event Targets contain all events but we must
146 // only unregister the ones we registered targets for.
147 if (!ShouldIgnoreCommand(command_name
)) {
148 gtk_accel_group_disconnect_key(
150 ui::GetGdkKeyCodeForAccelerator(accelerator
),
151 ui::GetGdkModifierForAccelerator(accelerator
));
155 gboolean
ExtensionKeybindingRegistryGtk::OnGtkAccelerator(
156 GtkAccelGroup
* group
,
157 GObject
* acceleratable
,
159 GdkModifierType modifier
) {
160 ui::Accelerator accelerator
= ui::AcceleratorForGdkKeyCodeAndModifier(
163 return ExtensionKeybindingRegistry::NotifyEventTargets(accelerator
);