diff options
36 files changed, 1133 insertions, 107 deletions
diff --git a/chrome/browser/extensions/api/commands/command_service.cc b/chrome/browser/extensions/api/commands/command_service.cc index 5d38936..4b3ef78 100644 --- a/chrome/browser/extensions/api/commands/command_service.cc +++ b/chrome/browser/extensions/api/commands/command_service.cc @@ -9,6 +9,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/api/commands/commands.h" +#include "chrome/browser/extensions/extension_commands_global_registry.h" #include "chrome/browser/extensions/extension_function_registry.h" #include "chrome/browser/extensions/extension_keybinding_registry.h" #include "chrome/browser/extensions/extension_service.h" @@ -57,6 +58,17 @@ bool InitialBindingsHaveBeenAssigned( return assigned; } +bool IsWhitelistedGlobalShortcut(const extensions::Command& command) { + if (!command.global()) + return true; + if (!command.accelerator().IsCtrlDown()) + return false; + if (!command.accelerator().IsShiftDown()) + return false; + return (command.accelerator().key_code() >= ui::VKEY_0 && + command.accelerator().key_code() <= ui::VKEY_9); +} + } // namespace namespace extensions { @@ -125,9 +137,13 @@ bool CommandService::GetScriptBadgeCommand( bool CommandService::GetNamedCommands(const std::string& extension_id, QueryType type, + CommandScope scope, extensions::CommandMap* command_map) { - const ExtensionSet* extensions = - ExtensionSystem::Get(profile_)->extension_service()->extensions(); + ExtensionService* extension_service = + ExtensionSystem::Get(profile_)->extension_service(); + if (!extension_service) + return false; // Can occur during testing. + const ExtensionSet* extensions = extension_service->extensions(); const Extension* extension = extensions->GetByID(extension_id); CHECK(extension); @@ -146,6 +162,9 @@ bool CommandService::GetNamedCommands(const std::string& extension_id, continue; extensions::Command command = iter->second; + if (scope != ANY_SCOPE && ((scope == GLOBAL) != command.global())) + continue; + if (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN) command.set_accelerator(shortcut_assigned); @@ -265,7 +284,8 @@ void CommandService::AssignInitialKeybindings(const Extension* extension) { extensions::CommandMap::const_iterator iter = commands->begin(); for (; iter != commands->end(); ++iter) { if (!chrome::IsChromeAccelerator( - iter->second.accelerator(), profile_)) { + iter->second.accelerator(), profile_) && + IsWhitelistedGlobalShortcut(iter->second)) { AddKeybindingPref(iter->second.accelerator(), extension->id(), iter->second.command_name(), @@ -404,4 +424,9 @@ bool CommandService::GetExtensionActionCommand( return true; } +template <> +void ProfileKeyedAPIFactory<CommandService>::DeclareFactoryDependencies() { + DependsOn(ExtensionCommandsGlobalRegistry::GetFactoryInstance()); +} + } // namespace extensions diff --git a/chrome/browser/extensions/api/commands/command_service.h b/chrome/browser/extensions/api/commands/command_service.h index d857eb7..ac553aa 100644 --- a/chrome/browser/extensions/api/commands/command_service.h +++ b/chrome/browser/extensions/api/commands/command_service.h @@ -45,6 +45,15 @@ class CommandService : public ProfileKeyedAPI, ACTIVE_ONLY, }; + // An enum specifying whether the command is global in scope or not. Global + // commands -- unlike regular commands -- have a global keyboard hook + // associated with them (and therefore work when Chrome doesn't have focus). + enum CommandScope { + REGULAR, // Regular (non-globally scoped) command. + GLOBAL, // Global command (works when Chrome doesn't have focus) + ANY_SCOPE, // All commands, regardless of scope (used when querying). + }; + // Register prefs for keybinding. static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); @@ -94,10 +103,11 @@ class CommandService : public ProfileKeyedAPI, // Gets the active command (if any) for the named commands of an extension // given its |extension_id|. The function consults the master list to see if // the command is active. Returns an empty map if the extension has no - // named commands or no active named commands when |type| requested is - // ACTIVE_ONLY. + // named commands of the right |scope| or no such active named commands when + // |type| requested is ACTIVE_ONLY. bool GetNamedCommands(const std::string& extension_id, QueryType type, + CommandScope scope, extensions::CommandMap* command_map); // Records a keybinding |accelerator| as active for an extension with id @@ -175,6 +185,9 @@ class CommandService : public ProfileKeyedAPI, DISALLOW_COPY_AND_ASSIGN(CommandService); }; +template <> +void ProfileKeyedAPIFactory<CommandService>::DeclareFactoryDependencies(); + } // namespace extensions #endif // CHROME_BROWSER_EXTENSIONS_API_COMMANDS_COMMAND_SERVICE_H_ diff --git a/chrome/browser/extensions/api/commands/commands.cc b/chrome/browser/extensions/api/commands/commands.cc index 1bfe054..7e2a10b 100644 --- a/chrome/browser/extensions/api/commands/commands.cc +++ b/chrome/browser/extensions/api/commands/commands.cc @@ -55,6 +55,7 @@ bool GetAllCommandsFunction::RunImpl() { extensions::CommandMap named_commands; command_service->GetNamedCommands(extension_->id(), extensions::CommandService::ALL, + extensions::CommandService::ANY_SCOPE, &named_commands); for (extensions::CommandMap::const_iterator iter = named_commands.begin(); diff --git a/chrome/browser/extensions/extension_commands_global_registry.cc b/chrome/browser/extensions/extension_commands_global_registry.cc new file mode 100644 index 0000000..a7ebd89 --- /dev/null +++ b/chrome/browser/extensions/extension_commands_global_registry.cc @@ -0,0 +1,107 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/extension_commands_global_registry.h" + +#include "base/lazy_instance.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/extensions/api/commands/command_service.h" +#include "chrome/browser/extensions/extension_keybinding_registry.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/global_shortcut_listener.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/extensions/extension.h" + +namespace extensions { + +ExtensionCommandsGlobalRegistry::ExtensionCommandsGlobalRegistry( + Profile* profile) + : ExtensionKeybindingRegistry( + profile, ExtensionKeybindingRegistry::ALL_EXTENSIONS, NULL), + profile_(profile) { + Init(); +} + +ExtensionCommandsGlobalRegistry::~ExtensionCommandsGlobalRegistry() { + EventTargets::const_iterator iter; + for (iter = event_targets_.begin(); iter != event_targets_.end(); ++iter) { + GlobalShortcutListener::GetInstance()->UnregisterAccelerator( + iter->first, this); + } +} + +static base::LazyInstance< + ProfileKeyedAPIFactory<ExtensionCommandsGlobalRegistry> > +g_factory = LAZY_INSTANCE_INITIALIZER; + +// static +ProfileKeyedAPIFactory<ExtensionCommandsGlobalRegistry>* +ExtensionCommandsGlobalRegistry::GetFactoryInstance() { + return &g_factory.Get(); +} + +// static +ExtensionCommandsGlobalRegistry* +ExtensionCommandsGlobalRegistry::Get(Profile* profile) { + return ProfileKeyedAPIFactory< + ExtensionCommandsGlobalRegistry>::GetForProfile(profile); +} + + +void ExtensionCommandsGlobalRegistry::AddExtensionKeybinding( + const extensions::Extension* extension, + const std::string& command_name) { + // This object only handles named commands, not browser/page actions. + if (ShouldIgnoreCommand(command_name)) + return; + + extensions::CommandService* command_service = + extensions::CommandService::Get(profile_); + // Add all the active global keybindings, if any. + extensions::CommandMap commands; + if (!command_service->GetNamedCommands( + extension->id(), + extensions::CommandService::ACTIVE_ONLY, + extensions::CommandService::GLOBAL, + &commands)) + return; + + extensions::CommandMap::const_iterator iter = commands.begin(); + for (; iter != commands.end(); ++iter) { + if (!command_name.empty() && (iter->second.command_name() != command_name)) + continue; + + VLOG(0) << "Adding global keybinding for " << extension->name().c_str() + << " " << command_name.c_str() + << " key: " << iter->second.accelerator().GetShortcutText(); + + event_targets_[iter->second.accelerator()] = + std::make_pair(extension->id(), iter->second.command_name()); + + GlobalShortcutListener::GetInstance()->RegisterAccelerator( + iter->second.accelerator(), this); + } +} + +void ExtensionCommandsGlobalRegistry::RemoveExtensionKeybindingImpl( + const ui::Accelerator& accelerator, + const std::string& command_name) { + VLOG(0) << "Removing keybinding for " << command_name.c_str(); + + GlobalShortcutListener::GetInstance()->UnregisterAccelerator( + accelerator, this); +} + +void ExtensionCommandsGlobalRegistry::OnKeyPressed( + const ui::Accelerator& accelerator) { + EventTargets::iterator it = event_targets_.find(accelerator); + if (it == event_targets_.end()) { + NOTREACHED(); // Shouldn't get this event for something not registered. + return; + } + + CommandExecuted(it->second.first, it->second.second); +} + +} // namespace extensions diff --git a/chrome/browser/extensions/extension_commands_global_registry.h b/chrome/browser/extensions/extension_commands_global_registry.h new file mode 100644 index 0000000..04e8bd8 --- /dev/null +++ b/chrome/browser/extensions/extension_commands_global_registry.h @@ -0,0 +1,76 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_COMMANDS_GLOBAL_REGISTRY_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_COMMANDS_GLOBAL_REGISTRY_H_ + +#include <map> +#include <string> + +#include "base/compiler_specific.h" +#include "chrome/browser/extensions/api/profile_keyed_api_factory.h" +#include "chrome/browser/extensions/extension_keybinding_registry.h" +#include "chrome/browser/extensions/global_shortcut_listener.h" +#include "ui/base/accelerators/accelerator.h" + +class Profile; + +namespace extensions { +class Extension; +} + +namespace extensions { + +// ExtensionCommandsGlobalRegistry is a class that handles the cross-platform +// implementation of the global shortcut registration for the Extension Commands +// API). +// Note: It handles regular extension commands (not browserAction and pageAction +// popups, which are not bindable to global shortcuts). This class registers the +// accelerators on behalf of the extensions and routes the commands to them via +// the BrowserEventRouter. +class ExtensionCommandsGlobalRegistry + : public ProfileKeyedAPI, + public ExtensionKeybindingRegistry, + public GlobalShortcutListener::Observer { + public: + // ProfileKeyedAPI implementation. + static ProfileKeyedAPIFactory< + ExtensionCommandsGlobalRegistry>* GetFactoryInstance(); + + // Convenience method to get the ExtensionCommandsGlobalRegistry for a + // profile. + static ExtensionCommandsGlobalRegistry* Get(Profile* profile); + + explicit ExtensionCommandsGlobalRegistry(Profile* profile); + virtual ~ExtensionCommandsGlobalRegistry(); + + private: + friend class ProfileKeyedAPIFactory<ExtensionCommandsGlobalRegistry>; + + // ProfileKeyedAPI implementation. + static const char* service_name() { + return "ExtensionCommandsGlobalRegistry"; + } + + // Overridden from ExtensionKeybindingRegistry: + virtual void AddExtensionKeybinding( + const Extension* extension, + const std::string& command_name) OVERRIDE; + virtual void RemoveExtensionKeybindingImpl( + const ui::Accelerator& accelerator, + const std::string& command_name) OVERRIDE; + + // Called by the GlobalShortcutListener object when a shortcut this class has + // registered for has been pressed. + virtual void OnKeyPressed(const ui::Accelerator& accelerator) OVERRIDE; + + // Weak pointer to our profile. Not owned by us. + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionCommandsGlobalRegistry); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_COMMANDS_GLOBAL_REGISTRY_H_ diff --git a/chrome/browser/extensions/extension_keybinding_registry.cc b/chrome/browser/extensions/extension_keybinding_registry.cc index 43ad281..a819ab4 100644 --- a/chrome/browser/extensions/extension_keybinding_registry.cc +++ b/chrome/browser/extensions/extension_keybinding_registry.cc @@ -34,6 +34,30 @@ ExtensionKeybindingRegistry::ExtensionKeybindingRegistry( ExtensionKeybindingRegistry::~ExtensionKeybindingRegistry() { } +void ExtensionKeybindingRegistry::RemoveExtensionKeybinding( + const Extension* extension, + const std::string& command_name) { + EventTargets::iterator iter = event_targets_.begin(); + while (iter != event_targets_.end()) { + if (iter->second.first != extension->id() || + (!command_name.empty() && (iter->second.second != command_name))) { + ++iter; + continue; // Not the extension or command we asked for. + } + + // Let each platform-specific implementation get a chance to clean up. + RemoveExtensionKeybindingImpl(iter->first, command_name); + + EventTargets::iterator old = iter++; + event_targets_.erase(old); + + // If a specific command_name was requested, it has now been deleted so + // no further work is required. + if (!command_name.empty()) + break; + } +} + void ExtensionKeybindingRegistry::Init() { ExtensionService* service = extensions::ExtensionSystem::Get(profile_)->extension_service(); @@ -64,9 +88,11 @@ void ExtensionKeybindingRegistry::CommandExecuted( return; // Grant before sending the event so that the permission is granted before - // the extension acts on the command. + // the extension acts on the command. NOTE: The Global Commands handler does + // not set the delegate as it deals only with named commands (not page/browser + // actions that are associated with the current page directly). ActiveTabPermissionGranter* granter = - delegate_->GetActiveTabPermissionGranter(); + delegate_ ? delegate_->GetActiveTabPermissionGranter() : NULL; if (granter) granter->GrantIfRequested(extension); diff --git a/chrome/browser/extensions/extension_keybinding_registry.h b/chrome/browser/extensions/extension_keybinding_registry.h index 7acd7f5..723a6bb 100644 --- a/chrome/browser/extensions/extension_keybinding_registry.h +++ b/chrome/browser/extensions/extension_keybinding_registry.h @@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_H_ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_H_ +#include <map> #include <string> #include "base/compiler_specific.h" @@ -15,6 +16,10 @@ class Profile; +namespace ui { +class Accelerator; +} + namespace extensions { class ActiveTabPermissionGranter; @@ -63,8 +68,13 @@ class ExtensionKeybindingRegistry : public content::NotificationObserver { const std::string& command_name) = 0; // Remove extension bindings for |extension|. |command_name| is optional, // but if not blank then only the command specified will be removed. - virtual void RemoveExtensionKeybinding( + void RemoveExtensionKeybinding( const Extension* extension, + const std::string& command_name); + // Overridden by platform specific implementations to provide additional + // unregistration (which varies between platforms). + virtual void RemoveExtensionKeybindingImpl( + const ui::Accelerator& accelerator, const std::string& command_name) = 0; // Make sure all extensions registered have keybindings added. @@ -78,6 +88,15 @@ class ExtensionKeybindingRegistry : public content::NotificationObserver { void CommandExecuted(const std::string& extension_id, const std::string& command); + // Maps an accelerator to a string pair (extension id, command name) for + // commands that have been registered. This keeps track of the targets for the + // keybinding event (which named command to call in which extension). On GTK, + // this map contains registration for pageAction and browserAction commands, + // whereas on other platforms it does not. + typedef std::map< ui::Accelerator, + std::pair<std::string, std::string> > EventTargets; + EventTargets event_targets_; + private: // Returns true if the |extension| matches our extension filter. bool ExtensionMatchesFilter(const extensions::Extension* extension); diff --git a/chrome/browser/extensions/global_shortcut_listener.cc b/chrome/browser/extensions/global_shortcut_listener.cc new file mode 100644 index 0000000..94547ad --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener.cc @@ -0,0 +1,62 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/global_shortcut_listener.h"
+#include "chrome/browser/profiles/profile.h"
+#include "ui/base/accelerators/accelerator.h"
+
+namespace extensions {
+
+GlobalShortcutListener::GlobalShortcutListener() {
+}
+
+GlobalShortcutListener::~GlobalShortcutListener() {
+ DCHECK(accelerator_map_.empty()); // Make sure we've cleaned up.
+}
+
+void GlobalShortcutListener::RegisterAccelerator(
+ const ui::Accelerator& accelerator, Observer* observer) {
+ AcceleratorMap::const_iterator it = accelerator_map_.find(accelerator);
+ if (it == accelerator_map_.end()) {
+ if (accelerator_map_.empty())
+ GlobalShortcutListener::GetInstance()->StartListening();
+ Observers* observers = new Observers;
+ observers->AddObserver(observer);
+ accelerator_map_[accelerator] = observers;
+ } else {
+ // Make sure we don't register the same accelerator twice.
+ DCHECK(!accelerator_map_[accelerator]->HasObserver(observer));
+ accelerator_map_[accelerator]->AddObserver(observer);
+ }
+}
+
+void GlobalShortcutListener::UnregisterAccelerator(
+ const ui::Accelerator& accelerator, Observer* observer) {
+ AcceleratorMap::iterator it = accelerator_map_.find(accelerator);
+ DCHECK(it != accelerator_map_.end());
+ DCHECK(it->second->HasObserver(observer));
+ it->second->RemoveObserver(observer);
+ if (!it->second->might_have_observers()) {
+ accelerator_map_.erase(it);
+ if (accelerator_map_.empty())
+ GlobalShortcutListener::GetInstance()->StopListening();
+ }
+}
+
+void GlobalShortcutListener::NotifyKeyPressed(
+ const ui::Accelerator& accelerator) {
+ AcceleratorMap::iterator iter = accelerator_map_.find(accelerator);
+ if (iter == accelerator_map_.end()) {
+ // This should never occur, because if it does, we have failed to unregister
+ // or failed to clean up the map after unregistering the shortcut.
+ NOTREACHED();
+ return; // No-one is listening to this key.
+ }
+ // The observer list should not be empty.
+ DCHECK(iter->second->might_have_observers());
+
+ FOR_EACH_OBSERVER(Observer, *(iter->second), OnKeyPressed(accelerator));
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/global_shortcut_listener.h b/chrome/browser/extensions/global_shortcut_listener.h new file mode 100644 index 0000000..4ca6921 --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener.h @@ -0,0 +1,65 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
+#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
+
+#include <map>
+
+#include "base/observer_list.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace ui {
+class Accelerator;
+}
+
+namespace extensions {
+
+// Platform-neutral implementation of a class that keeps track of observers and
+// monitors keystrokes. It relays messages to the appropriate observers when a
+// global shortcut has been struck by the user.
+class GlobalShortcutListener {
+ public:
+ class Observer {
+ public:
+ // Called when your global shortcut (|accelerator|) is struck.
+ virtual void OnKeyPressed(const ui::Accelerator& accelerator) = 0;
+ };
+
+ virtual ~GlobalShortcutListener();
+
+ static GlobalShortcutListener* GetInstance();
+
+ // Implemented by platform-specific implementations of this class.
+ virtual void StartListening() = 0;
+ virtual void StopListening() = 0;
+
+ // Register an observer for when a certain |accelerator| is struck.
+ virtual void RegisterAccelerator(
+ const ui::Accelerator& accelerator, Observer* observer);
+ // Stop listening for the given |accelerator|.
+ virtual void UnregisterAccelerator(
+ const ui::Accelerator& accelerator, Observer* observer);
+
+ protected:
+ GlobalShortcutListener();
+
+ // Called by platform specific implementations of this class whenever a key
+ // is struck. Only called for keys that have observers registered.
+ void NotifyKeyPressed(const ui::Accelerator& accelerator);
+
+ // The map of accelerators that have been successfully registered as global
+ // shortcuts and their observer lists.
+ typedef ObserverList<Observer> Observers;
+ typedef std::map< ui::Accelerator, Observers* > AcceleratorMap;
+ AcceleratorMap accelerator_map_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListener);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
diff --git a/chrome/browser/extensions/global_shortcut_listener_aurax11.cc b/chrome/browser/extensions/global_shortcut_listener_aurax11.cc new file mode 100644 index 0000000..bfeeac9 --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener_aurax11.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/global_shortcut_listener_aurax11.h" + +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +namespace { + +static base::LazyInstance<extensions::GlobalShortcutListenerAuraX11> instance = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +namespace extensions { + +// static +GlobalShortcutListener* GlobalShortcutListener::GetInstance() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return instance.Pointer(); +} + +GlobalShortcutListenerAuraX11::GlobalShortcutListenerAuraX11() + : is_listening_(false) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // TODO(implementor): Remove this. + LOG(ERROR) << "GlobalShortcutListenerAuraX11 object created"; +} + +GlobalShortcutListenerAuraX11::~GlobalShortcutListenerAuraX11() { + if (is_listening_) + StopListening(); +} + +void GlobalShortcutListenerAuraX11::StartListening() { + DCHECK(!is_listening_); // Don't start twice. + NOTIMPLEMENTED(); + is_listening_ = true; +} + +void GlobalShortcutListenerAuraX11::StopListening() { + DCHECK(is_listening_); // No point if we are not already listening. + NOTIMPLEMENTED(); + is_listening_ = false; +} + +void GlobalShortcutListenerAuraX11::RegisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) { + NOTIMPLEMENTED(); + // To implement: + // 1) Convert modifiers to platform specific modifiers. + // 2) Register for the hotkey. + // 3) If not successful, log why. + // 4) Else, call base class RegisterAccelerator. + + GlobalShortcutListener::RegisterAccelerator(accelerator, observer); +} + +void GlobalShortcutListenerAuraX11::UnregisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) { + NOTIMPLEMENTED(); + // To implement: + // 1) Unregister for the hotkey. + // 2) Call base class UnregisterAccelerator. + + GlobalShortcutListener::UnregisterAccelerator(accelerator, observer); +} + +} // namespace extensions diff --git a/chrome/browser/extensions/global_shortcut_listener_aurax11.h b/chrome/browser/extensions/global_shortcut_listener_aurax11.h new file mode 100644 index 0000000..bc353c2 --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener_aurax11.h @@ -0,0 +1,46 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_AURAX11_H_ +#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_AURAX11_H_ + +#include "base/lazy_instance.h" +#include "chrome/browser/extensions/global_shortcut_listener.h" + +namespace extensions { + +// Linux-specific implementation of the GlobalShortcutListener class that +// listens for global shortcuts. Handles basic keyboard intercepting and +// forwards its output to the base class for processing. +// TODO(finnur): Implement this class. +class GlobalShortcutListenerAuraX11 : public GlobalShortcutListener { + public: + virtual ~GlobalShortcutListenerAuraX11(); + + virtual void StartListening() OVERRIDE; + virtual void StopListening() OVERRIDE; + + private: + friend struct base::DefaultLazyInstanceTraits<GlobalShortcutListenerAuraX11>; + + GlobalShortcutListenerAuraX11(); + + // Register an |accelerator| with the particular |observer|. + virtual void RegisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) OVERRIDE; + // Unregister an |accelerator| with the particular |observer|. + virtual void UnregisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) OVERRIDE; + + // Whether this object is listening for global shortcuts. + bool is_listening_; + + DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerAuraX11); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_AURAX11_H_ diff --git a/chrome/browser/extensions/global_shortcut_listener_chromeos.cc b/chrome/browser/extensions/global_shortcut_listener_chromeos.cc new file mode 100644 index 0000000..af97100 --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener_chromeos.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/global_shortcut_listener_chromeos.h" + +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +namespace { + +static base::LazyInstance<extensions::GlobalShortcutListenerChromeOS> instance = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +namespace extensions { + +// static +GlobalShortcutListener* GlobalShortcutListener::GetInstance() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return instance.Pointer(); +} + +GlobalShortcutListenerChromeOS::GlobalShortcutListenerChromeOS() + : is_listening_(false) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // TODO(implementor): Remove this. + LOG(ERROR) << "GlobalShortcutListenerChromeOS object created"; +} + +GlobalShortcutListenerChromeOS::~GlobalShortcutListenerChromeOS() { + if (is_listening_) + StopListening(); +} + +void GlobalShortcutListenerChromeOS::StartListening() { + DCHECK(!is_listening_); // Don't start twice. + NOTIMPLEMENTED(); + is_listening_ = true; +} + +void GlobalShortcutListenerChromeOS::StopListening() { + DCHECK(is_listening_); // No point if we are not already listening. + NOTIMPLEMENTED(); + is_listening_ = false; +} + +void GlobalShortcutListenerChromeOS::RegisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) { + NOTIMPLEMENTED(); + // To implement: + // 1) Convert modifiers to platform specific modifiers. + // 2) Register for the hotkey. + // 3) If not successful, log why. + // 4) Else, call base class RegisterAccelerator. + + GlobalShortcutListener::RegisterAccelerator(accelerator, observer); +} + +void GlobalShortcutListenerChromeOS::UnregisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) { + NOTIMPLEMENTED(); + // To implement: + // 1) Unregister for the hotkey. + // 2) Call base class UnregisterAccelerator. + + GlobalShortcutListener::UnregisterAccelerator(accelerator, observer); +} + +} // namespace extensions diff --git a/chrome/browser/extensions/global_shortcut_listener_chromeos.h b/chrome/browser/extensions/global_shortcut_listener_chromeos.h new file mode 100644 index 0000000..f052ed65 --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener_chromeos.h @@ -0,0 +1,48 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_CHROMEOS_H_ +#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_CHROMEOS_H_ + +#include "base/lazy_instance.h" +#include "chrome/browser/extensions/global_shortcut_listener.h" + +// TODO(finnur): Figure out what to do on ChromeOS, where the Commands API kind +// of is global already... + +namespace extensions { + +// ChromeOS-specific implementation of the GlobalShortcutListener class that +// listens for global shortcuts. Handles basic keyboard intercepting and +// forwards its output to the base class for processing. +class GlobalShortcutListenerChromeOS : public GlobalShortcutListener { + public: + virtual ~GlobalShortcutListenerChromeOS(); + + virtual void StartListening() OVERRIDE; + virtual void StopListening() OVERRIDE; + + private: + friend struct base::DefaultLazyInstanceTraits<GlobalShortcutListenerChromeOS>; + + GlobalShortcutListenerChromeOS(); + + // Register an |accelerator| with the particular |observer|. + virtual void RegisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) OVERRIDE; + // Unregister an |accelerator| with the particular |observer|. + virtual void UnregisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) OVERRIDE; + + // Whether this object is listening for global shortcuts. + bool is_listening_; + + DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerChromeOS); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_CHROMEOS_H_ diff --git a/chrome/browser/extensions/global_shortcut_listener_gtk.cc b/chrome/browser/extensions/global_shortcut_listener_gtk.cc new file mode 100644 index 0000000..bfb00ce --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener_gtk.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/global_shortcut_listener_gtk.h" + +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +namespace { + +static base::LazyInstance<extensions::GlobalShortcutListenerGtk> instance = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +namespace extensions { + +// static +GlobalShortcutListener* GlobalShortcutListener::GetInstance() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return instance.Pointer(); +} + +GlobalShortcutListenerGtk::GlobalShortcutListenerGtk() + : is_listening_(false) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // TODO(implementor): Remove this. + LOG(ERROR) << "GlobalShortcutListenerGtk object created"; +} + +GlobalShortcutListenerGtk::~GlobalShortcutListenerGtk() { + if (is_listening_) + StopListening(); +} + +void GlobalShortcutListenerGtk::StartListening() { + DCHECK(!is_listening_); // Don't start twice. + NOTIMPLEMENTED(); + is_listening_ = true; +} + +void GlobalShortcutListenerGtk::StopListening() { + DCHECK(is_listening_); // No point if we are not already listening. + NOTIMPLEMENTED(); + is_listening_ = false; +} + +void GlobalShortcutListenerGtk::RegisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) { + NOTIMPLEMENTED(); + // To implement: + // 1) Convert modifiers to platform specific modifiers. + // 2) Register for the hotkey. + // 3) If not successful, log why. + // 4) Else, call base class RegisterAccelerator. + + GlobalShortcutListener::RegisterAccelerator(accelerator, observer); +} + +void GlobalShortcutListenerGtk::UnregisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) { + NOTIMPLEMENTED(); + // To implement: + // 1) Unregister for the hotkey. + // 2) Call base class UnregisterAccelerator. + + GlobalShortcutListener::UnregisterAccelerator(accelerator, observer); +} + +} // namespace extensions diff --git a/chrome/browser/extensions/global_shortcut_listener_gtk.h b/chrome/browser/extensions/global_shortcut_listener_gtk.h new file mode 100644 index 0000000..81e97bf --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener_gtk.h @@ -0,0 +1,46 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_GTK_H_ +#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_GTK_H_ + +#include "base/lazy_instance.h" +#include "chrome/browser/extensions/global_shortcut_listener.h" + +namespace extensions { + +// Linux-specific implementation of the GlobalShortcutListener class that +// listens for global shortcuts. Handles basic keyboard intercepting and +// forwards its output to the base class for processing. +// TODO(zhaobin): Implement this class. +class GlobalShortcutListenerGtk : public GlobalShortcutListener { + public: + virtual ~GlobalShortcutListenerGtk(); + + virtual void StartListening() OVERRIDE; + virtual void StopListening() OVERRIDE; + + private: + friend struct base::DefaultLazyInstanceTraits<GlobalShortcutListenerGtk>; + + GlobalShortcutListenerGtk(); + + // Register an |accelerator| with the particular |observer|. + virtual void RegisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) OVERRIDE; + // Unregister an |accelerator| with the particular |observer|. + virtual void UnregisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) OVERRIDE; + + // Whether this object is listening for global shortcuts. + bool is_listening_; + + DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerGtk); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_GTK_H_ diff --git a/chrome/browser/extensions/global_shortcut_listener_mac.cc b/chrome/browser/extensions/global_shortcut_listener_mac.cc new file mode 100644 index 0000000..3604c85 --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener_mac.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/global_shortcut_listener_mac.h" + +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +namespace { + +static base::LazyInstance<extensions::GlobalShortcutListenerMac> instance = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +namespace extensions { + +// static +GlobalShortcutListener* GlobalShortcutListener::GetInstance() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return instance.Pointer(); +} + +GlobalShortcutListenerMac::GlobalShortcutListenerMac() + : is_listening_(false) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // TODO(implementor): Remove this. + LOG(ERROR) << "GlobalShortcutListenerMac object created"; +} + +GlobalShortcutListenerMac::~GlobalShortcutListenerMac() { + if (is_listening_) + StopListening(); +} + +void GlobalShortcutListenerMac::StartListening() { + DCHECK(!is_listening_); // Don't start twice. + NOTIMPLEMENTED(); + is_listening_ = true; +} + +void GlobalShortcutListenerMac::StopListening() { + DCHECK(is_listening_); // No point if we are not already listening. + NOTIMPLEMENTED(); + is_listening_ = false; +} + +void GlobalShortcutListenerMac::RegisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) { + NOTIMPLEMENTED(); + // To implement: + // 1) Convert modifiers to platform specific modifiers. + // 2) Register for the hotkey. + // 3) If not successful, log why. + // 4) Else, call base class RegisterAccelerator. + + GlobalShortcutListener::RegisterAccelerator(accelerator, observer); +} + +void GlobalShortcutListenerMac::UnregisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) { + NOTIMPLEMENTED(); + // To implement: + // 1) Unregister for the hotkey. + // 2) Call base class UnregisterAccelerator. + + GlobalShortcutListener::UnregisterAccelerator(accelerator, observer); +} + +} // namespace extensions diff --git a/chrome/browser/extensions/global_shortcut_listener_mac.h b/chrome/browser/extensions/global_shortcut_listener_mac.h new file mode 100644 index 0000000..8c1b5db --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener_mac.h @@ -0,0 +1,46 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_ +#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_ + +#include "base/lazy_instance.h" +#include "chrome/browser/extensions/global_shortcut_listener.h" + +namespace extensions { + +// Mac-specific implementation of the GlobalShortcutListener class that +// listens for global shortcuts. Handles basic keyboard intercepting and +// forwards its output to the base class for processing. +// TODO(finnur/smus): Implement this class. +class GlobalShortcutListenerMac : public GlobalShortcutListener { + public: + virtual ~GlobalShortcutListenerMac(); + + virtual void StartListening() OVERRIDE; + virtual void StopListening() OVERRIDE; + + private: + friend struct base::DefaultLazyInstanceTraits<GlobalShortcutListenerMac>; + + GlobalShortcutListenerMac(); + + // Register an |accelerator| with the particular |observer|. + virtual void RegisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) OVERRIDE; + // Unregister an |accelerator| with the particular |observer|. + virtual void UnregisterAccelerator( + const ui::Accelerator& accelerator, + GlobalShortcutListener::Observer* observer) OVERRIDE; + + // Whether this object is listening for global shortcuts. + bool is_listening_; + + DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerMac); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_ diff --git a/chrome/browser/extensions/global_shortcut_listener_win.cc b/chrome/browser/extensions/global_shortcut_listener_win.cc new file mode 100644 index 0000000..462ff67 --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener_win.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/global_shortcut_listener_win.h"
+
+#include "base/win/win_util.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/keyboard_code_conversion_win.h"
+
+using content::BrowserThread;
+
+namespace {
+
+static base::LazyInstance<extensions::GlobalShortcutListenerWin> instance =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+namespace extensions {
+
+// static
+GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return instance.Pointer();
+}
+
+GlobalShortcutListenerWin::GlobalShortcutListenerWin()
+ : is_listening_(false) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+GlobalShortcutListenerWin::~GlobalShortcutListenerWin() {
+ if (is_listening_)
+ StopListening();
+}
+
+void GlobalShortcutListenerWin::StartListening() {
+ DCHECK(!is_listening_); // Don't start twice.
+ DCHECK(!hotkey_ids_.empty()); // Also don't start if no hotkey is registered.
+ gfx::SingletonHwnd::GetInstance()->AddObserver(this);
+ is_listening_ = true;
+}
+
+void GlobalShortcutListenerWin::StopListening() {
+ DCHECK(is_listening_); // No point if we are not already listening.
+ DCHECK(hotkey_ids_.empty()); // Make sure the map is clean before ending.
+ gfx::SingletonHwnd::GetInstance()->RemoveObserver(this);
+ is_listening_ = false;
+}
+
+void GlobalShortcutListenerWin::OnWndProc(HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam) {
+ if (message != WM_HOTKEY)
+ return;
+
+ int key_code = HIWORD(lparam);
+ int modifiers = 0;
+ modifiers |= (LOWORD(lparam) & MOD_SHIFT) ? ui::EF_SHIFT_DOWN : 0;
+ modifiers |= (LOWORD(lparam) & MOD_ALT) ? ui::EF_ALT_DOWN : 0;
+ modifiers |= (LOWORD(lparam) & MOD_CONTROL) ? ui::EF_CONTROL_DOWN : 0;
+ ui::Accelerator accelerator(
+ ui::KeyboardCodeForWindowsKeyCode(key_code), modifiers);
+
+ instance.Get().NotifyKeyPressed(accelerator);
+}
+
+void GlobalShortcutListenerWin::RegisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) {
+ int modifiers = 0;
+ modifiers |= accelerator.IsShiftDown() ? MOD_SHIFT : 0;
+ modifiers |= accelerator.IsCtrlDown() ? MOD_CONTROL : 0;
+ modifiers |= accelerator.IsAltDown() ? MOD_ALT : 0;
+ static int hotkey_id = 0;
+ bool success = !!RegisterHotKey(
+ gfx::SingletonHwnd::GetInstance()->hwnd(),
+ hotkey_id,
+ modifiers,
+ accelerator.key_code());
+
+ if (!success) {
+ // Most likely error: 1409 (Hotkey already registered).
+ LOG(ERROR) << "RegisterHotKey failed, error: " << GetLastError();
+ return;
+ }
+
+ hotkey_ids_[accelerator] = hotkey_id++;
+ GlobalShortcutListener::RegisterAccelerator(accelerator, observer);
+}
+
+void GlobalShortcutListenerWin::UnregisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) {
+ // We may get asked to unregister something that we couldn't register (for
+ // example if the shortcut was already taken by another app), so we
+ // need to handle that gracefully.
+ HotkeyIdMap::iterator it = hotkey_ids_.find(accelerator);
+ if (it == hotkey_ids_.end())
+ return;
+
+ UnregisterHotKey(gfx::SingletonHwnd::GetInstance()->hwnd(), it->second);
+ hotkey_ids_.erase(it);
+
+ GlobalShortcutListener::UnregisterAccelerator(accelerator, observer);
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/global_shortcut_listener_win.h b/chrome/browser/extensions/global_shortcut_listener_win.h new file mode 100644 index 0000000..1844ee4 --- /dev/null +++ b/chrome/browser/extensions/global_shortcut_listener_win.h @@ -0,0 +1,59 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
+#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
+
+#include <windows.h>
+
+#include "base/lazy_instance.h"
+#include "chrome/browser/extensions/global_shortcut_listener.h"
+#include "ui/gfx/win/singleton_hwnd.h"
+
+namespace extensions {
+
+// Windows-specific implementation of the GlobalShortcutListener class that
+// listens for global shortcuts. Handles setting up a keyboard hook and
+// forwarding its output to the base class for processing.
+class GlobalShortcutListenerWin : public GlobalShortcutListener,
+ public gfx::SingletonHwnd::Observer {
+ public:
+ virtual ~GlobalShortcutListenerWin();
+
+ virtual void StartListening() OVERRIDE;
+ virtual void StopListening() OVERRIDE;
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<GlobalShortcutListenerWin>;
+
+ GlobalShortcutListenerWin();
+
+ // The implementation of our Window Proc, called by SingletonHwnd.
+ virtual void OnWndProc(HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam) OVERRIDE;
+
+ // Register an |accelerator| with the particular |observer|.
+ virtual void RegisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) OVERRIDE;
+ // Unregister an |accelerator| with the particular |observer|.
+ virtual void UnregisterAccelerator(
+ const ui::Accelerator& accelerator,
+ GlobalShortcutListener::Observer* observer) OVERRIDE;
+
+ // Whether this object is listening for global shortcuts.
+ bool is_listening_;
+
+ // A map of registered accelerators and their registration ids.
+ typedef std::map< ui::Accelerator, int > HotkeyIdMap;
+ HotkeyIdMap hotkey_ids_;
+
+ DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerWin);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
diff --git a/chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa.h b/chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa.h index 41f98df..f3fdcc9 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa.h +++ b/chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa.h @@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_COCOA_H_ #define CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_COCOA_H_ -#include <map> #include <string> #include <utility> @@ -56,8 +55,8 @@ class ExtensionKeybindingRegistryCocoa virtual void AddExtensionKeybinding( const extensions::Extension* extension, const std::string& command_name) OVERRIDE; - virtual void RemoveExtensionKeybinding( - const extensions::Extension* extension, + virtual void RemoveExtensionKeybindingImpl( + const ui::Accelerator& accelerator, const std::string& command_name) OVERRIDE; private: @@ -74,14 +73,6 @@ class ExtensionKeybindingRegistryCocoa // The window we are associated with. gfx::NativeWindow window_; - // Maps an accelerator to a string pair (extension id, command name) for - // commands that have been registered. Unlike its Views counterpart, this map - // contains browserAction and pageAction commands (but does not route those - // events), so that we can query priority handlers in HasPriorityHandler(...). - typedef std::map< ui::Accelerator, - std::pair<std::string, std::string> > EventTargets; - EventTargets event_targets_; - // The content notification registrar for listening to extension events. content::NotificationRegistrar registrar_; diff --git a/chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa.mm b/chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa.mm index 839635a..54b0d3d 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa.mm @@ -84,6 +84,7 @@ void ExtensionKeybindingRegistryCocoa::AddExtensionKeybinding( command_service->GetNamedCommands( extension->id(), extensions::CommandService::ACTIVE_ONLY, + extensions::CommandService::REGULAR, &commands); for (extensions::CommandMap::const_iterator iter = commands.begin(); @@ -135,14 +136,7 @@ void ExtensionKeybindingRegistryCocoa::AddExtensionKeybinding( } } -void ExtensionKeybindingRegistryCocoa::RemoveExtensionKeybinding( - const extensions::Extension* extension, +void ExtensionKeybindingRegistryCocoa::RemoveExtensionKeybindingImpl( + const ui::Accelerator& accelerator, const std::string& command_name) { - EventTargets::iterator iter = event_targets_.begin(); - while (iter != event_targets_.end()) { - EventTargets::iterator old = iter++; - if (old->second.first == extension->id() && - (command_name.empty() || (old->second.second == command_name))) - event_targets_.erase(old); - } } diff --git a/chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.cc b/chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.cc index ccb0256..4637dd0 100644 --- a/chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.cc +++ b/chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.cc @@ -64,6 +64,7 @@ void ExtensionKeybindingRegistryGtk::AddExtensionKeybinding( command_service->GetNamedCommands( extension->id(), extensions::CommandService::ACTIVE_ONLY, + extensions::CommandService::REGULAR, &commands); for (extensions::CommandMap::const_iterator iter = commands.begin(); @@ -127,28 +128,16 @@ void ExtensionKeybindingRegistryGtk::AddExtensionKeybinding( } } -void ExtensionKeybindingRegistryGtk::RemoveExtensionKeybinding( - const extensions::Extension* extension, +void ExtensionKeybindingRegistryGtk::RemoveExtensionKeybindingImpl( + const ui::Accelerator& accelerator, const std::string& command_name) { - EventTargets::iterator iter = event_targets_.begin(); - while (iter != event_targets_.end()) { - if (iter->second.first != extension->id() || - (!command_name.empty() && iter->second.second != command_name)) { - ++iter; - continue; // Not the extension or command we asked for. - } - - // On GTK, unlike Windows, the Event Targets contain all events but we must - // only unregister the ones we registered targets for. - if (!ShouldIgnoreCommand(iter->second.second)) { - gtk_accel_group_disconnect_key( - accel_group_, - ui::GetGdkKeyCodeForAccelerator(iter->first), - ui::GetGdkModifierForAccelerator(iter->first)); - } - - EventTargets::iterator old = iter++; - event_targets_.erase(old); + // On GTK, unlike Windows, the Event Targets contain all events but we must + // only unregister the ones we registered targets for. + if (!ShouldIgnoreCommand(command_name)) { + gtk_accel_group_disconnect_key( + accel_group_, + ui::GetGdkKeyCodeForAccelerator(accelerator), + ui::GetGdkModifierForAccelerator(accelerator)); } } diff --git a/chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.h b/chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.h index 8b3ac20..63c94b5 100644 --- a/chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.h +++ b/chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.h @@ -6,7 +6,6 @@ #define CHROME_BROWSER_UI_GTK_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_GTK_H_ #include <gdk/gdk.h> -#include <map> #include <string> #include "base/compiler_specific.h" @@ -59,8 +58,8 @@ class ExtensionKeybindingRegistryGtk virtual void AddExtensionKeybinding( const extensions::Extension* extension, const std::string& command_name) OVERRIDE; - virtual void RemoveExtensionKeybinding( - const extensions::Extension* extension, + virtual void RemoveExtensionKeybindingImpl( + const ui::Accelerator& accelerator, const std::string& command_name) OVERRIDE; private: @@ -85,14 +84,6 @@ class ExtensionKeybindingRegistryGtk // The accelerator group used to handle accelerators, owned by this object. GtkAccelGroup* accel_group_; - // Maps an accelerator to a string pair (extension id, command name) for - // commands that have been registered. Unlike its Views counterpart, this map - // contains browserAction and pageAction commands (but does not route those - // events), so that we can query priority handlers in HasPriorityHandler(...). - typedef std::map< ui::Accelerator, - std::pair<std::string, std::string> > EventTargets; - EventTargets event_targets_; - // The content notification registrar for listening to extension events. content::NotificationRegistrar registrar_; diff --git a/chrome/browser/ui/views/browser_actions_container.cc b/chrome/browser/ui/views/browser_actions_container.cc index 7e011b5..8501897 100644 --- a/chrome/browser/ui/views/browser_actions_container.cc +++ b/chrome/browser/ui/views/browser_actions_container.cc @@ -84,7 +84,7 @@ BrowserActionsContainer::BrowserActionsContainer(Browser* browser, browser->profile(), owner_view->GetFocusManager(), extensions::ExtensionKeybindingRegistry::ALL_EXTENSIONS, - this)), + this)); resize_animation_.reset(new gfx::SlideAnimation(this)); resize_area_ = new views::ResizeArea(this); diff --git a/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.cc b/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.cc index 1531847..61f4915 100644 --- a/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.cc +++ b/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.cc @@ -47,7 +47,10 @@ void ExtensionKeybindingRegistryViews::AddExtensionKeybinding( // which are handled elsewhere). extensions::CommandMap commands; if (!command_service->GetNamedCommands( - extension->id(), extensions::CommandService::ACTIVE_ONLY, &commands)) + extension->id(), + extensions::CommandService::ACTIVE_ONLY, + extensions::CommandService::REGULAR, + &commands)) return; extensions::CommandMap::const_iterator iter = commands.begin(); for (; iter != commands.end(); ++iter) { @@ -62,26 +65,10 @@ void ExtensionKeybindingRegistryViews::AddExtensionKeybinding( } } -void ExtensionKeybindingRegistryViews::RemoveExtensionKeybinding( - const extensions::Extension* extension, +void ExtensionKeybindingRegistryViews::RemoveExtensionKeybindingImpl( + const ui::Accelerator& accelerator, const std::string& command_name) { - // This object only handles named commands, not browser/page actions. - if (ShouldIgnoreCommand(command_name)) - return; - - EventTargets::iterator iter = event_targets_.begin(); - while (iter != event_targets_.end()) { - if (iter->second.first != extension->id() || - (!command_name.empty() && (iter->second.second != command_name))) { - ++iter; - continue; // Not the extension or command we asked for. - } - - focus_manager_->UnregisterAccelerator(iter->first, this); - - EventTargets::iterator old = iter++; - event_targets_.erase(old); - } + focus_manager_->UnregisterAccelerator(accelerator, this); } bool ExtensionKeybindingRegistryViews::AcceleratorPressed( diff --git a/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h b/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h index 3615a61..4e2fc87 100644 --- a/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h +++ b/chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h @@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_VIEWS_H_ #define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_VIEWS_H_ -#include <map> #include <string> #include "base/compiler_specific.h" @@ -47,8 +46,8 @@ class ExtensionKeybindingRegistryViews virtual void AddExtensionKeybinding( const extensions::Extension* extension, const std::string& command_name) OVERRIDE; - virtual void RemoveExtensionKeybinding( - const extensions::Extension* extension, + virtual void RemoveExtensionKeybindingImpl( + const ui::Accelerator& accelerator, const std::string& command_name) OVERRIDE; // Weak pointer to the our profile. Not owned by us. @@ -58,13 +57,6 @@ class ExtensionKeybindingRegistryViews // accelerators with. Not owned by us. views::FocusManager* focus_manager_; - // Maps an accelerator to a string pair (extension id, command name) for - // commands that have been registered. Unlike its GTK counterpart, this map - // contains no registration for pageAction and browserAction commands. - typedef std::map< ui::Accelerator, - std::pair<std::string, std::string> > EventTargets; - EventTargets event_targets_; - // The content notification registrar for listening to extension events. content::NotificationRegistrar registrar_; diff --git a/chrome/browser/ui/webui/extensions/command_handler.cc b/chrome/browser/ui/webui/extensions/command_handler.cc index 15df2d8..f89634c 100644 --- a/chrome/browser/ui/webui/extensions/command_handler.cc +++ b/chrome/browser/ui/webui/extensions/command_handler.cc @@ -149,6 +149,7 @@ void CommandHandler::GetAllCommands(base::DictionaryValue* commands) { extensions::CommandMap named_commands; if (command_service->GetNamedCommands((*extension)->id(), CommandService::ALL, + extensions::CommandService::ANY_SCOPE, &named_commands)) { for (extensions::CommandMap::const_iterator iter = named_commands.begin(); iter != named_commands.end(); ++iter) { diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index aa832f1..4e4536e 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -640,6 +640,8 @@ 'browser/extensions/extension_action_icon_factory.h', 'browser/extensions/extension_action_manager.cc', 'browser/extensions/extension_action_manager.h', + 'browser/extensions/extension_commands_global_registry.cc', + 'browser/extensions/extension_commands_global_registry.h', 'browser/extensions/extension_context_menu_model.cc', 'browser/extensions/extension_context_menu_model.h', 'browser/extensions/extension_creator.cc', @@ -750,6 +752,18 @@ 'browser/extensions/external_provider_interface.h', 'browser/extensions/external_registry_loader_win.cc', 'browser/extensions/external_registry_loader_win.h', + 'browser/extensions/global_shortcut_listener.cc', + 'browser/extensions/global_shortcut_listener.h', + 'browser/extensions/global_shortcut_listener_aurax11.cc', + 'browser/extensions/global_shortcut_listener_aurax11.h', + 'browser/extensions/global_shortcut_listener_chromeos.cc', + 'browser/extensions/global_shortcut_listener_chromeos.h', + 'browser/extensions/global_shortcut_listener_gtk.cc', + 'browser/extensions/global_shortcut_listener_gtk.h', + 'browser/extensions/global_shortcut_listener_mac.cc', + 'browser/extensions/global_shortcut_listener_mac.h', + 'browser/extensions/global_shortcut_listener_win.cc', + 'browser/extensions/global_shortcut_listener_win.h', 'browser/extensions/image_loader.cc', 'browser/extensions/image_loader.h', 'browser/extensions/image_loader_factory.cc', diff --git a/chrome/common/extensions/api/_manifest_features.json b/chrome/common/extensions/api/_manifest_features.json index 3393d34..98a124d 100644 --- a/chrome/common/extensions/api/_manifest_features.json +++ b/chrome/common/extensions/api/_manifest_features.json @@ -80,6 +80,11 @@ "extension_types": ["extension"], "min_manifest_version": 2 }, + "commands.global": { + "channel": "dev", + "extension_types": ["extension"], + "min_manifest_version": 2 + }, "content_pack": { "channel": "dev", "extension_types": ["extension"] diff --git a/chrome/common/extensions/api/commands/commands_handler.cc b/chrome/common/extensions/api/commands/commands_handler.cc index 731af99..852f152 100644 --- a/chrome/common/extensions/api/commands/commands_handler.cc +++ b/chrome/common/extensions/api/commands/commands_handler.cc @@ -140,7 +140,8 @@ void CommandsHandler::MaybeSetBrowserActionDefault(const Extension* extension, info->browser_action_command.reset( new Command(manifest_values::kBrowserActionCommandEvent, string16(), - std::string())); + std::string(), + false)); } } diff --git a/chrome/common/extensions/command.cc b/chrome/common/extensions/command.cc index 038705b..6e87d7a 100644 --- a/chrome/common/extensions/command.cc +++ b/chrome/common/extensions/command.cc @@ -250,13 +250,15 @@ std::string NormalizeShortcutSuggestion(const std::string& suggestion, } // namespace -Command::Command() {} +Command::Command() : global_(false) {} Command::Command(const std::string& command_name, const string16& description, - const std::string& accelerator) + const std::string& accelerator, + bool global) : command_name_(command_name), - description_(description) { + description_(description), + global_(global) { string16 error; accelerator_ = ParseImpl(accelerator, CommandPlatform(), 0, IsNamedCommand(command_name), &error); @@ -432,6 +434,10 @@ bool Command::Parse(const base::DictionaryValue* command, } } + // Check if this is a global or a regular shortcut. + bool global = false; + command->GetBoolean(keys::kGlobal, &global); + // Normalize the suggestions. for (SuggestionMap::iterator iter = suggestions.begin(); iter != suggestions.end(); ++iter) { @@ -494,6 +500,7 @@ bool Command::Parse(const base::DictionaryValue* command, accelerator_ = accelerator; command_name_ = command_name; description_ = description; + global_ = global; } } return true; diff --git a/chrome/common/extensions/command.h b/chrome/common/extensions/command.h index 963d26b..97107d4 100644 --- a/chrome/common/extensions/command.h +++ b/chrome/common/extensions/command.h @@ -26,7 +26,8 @@ class Command { Command(); Command(const std::string& command_name, const string16& description, - const std::string& accelerator); + const std::string& accelerator, + bool global); ~Command(); // The platform value for the Command. @@ -56,6 +57,7 @@ class Command { const std::string& command_name() const { return command_name_; } const ui::Accelerator& accelerator() const { return accelerator_; } const string16& description() const { return description_; } + bool global() const { return global_; } // Setter: void set_accelerator(ui::Accelerator accelerator) { @@ -66,6 +68,7 @@ class Command { std::string command_name_; ui::Accelerator accelerator_; string16 description_; + bool global_; }; // A mapping of command name (std::string) to a command object. diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc index dccf628..c03e3f4 100644 --- a/extensions/common/manifest_constants.cc +++ b/extensions/common/manifest_constants.cc @@ -45,6 +45,7 @@ const char kFileHandlers[] = "file_handlers"; const char kFileHandlerExtensions[] = "extensions"; const char kFileHandlerTitle[] = "title"; const char kFileHandlerTypes[] = "types"; +const char kGlobal[] = "global"; const char kHomepageURL[] = "homepage_url"; const char kIcons[] = "icons"; const char kId[] = "id"; diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h index ca70780..bf78fa5 100644 --- a/extensions/common/manifest_constants.h +++ b/extensions/common/manifest_constants.h @@ -47,6 +47,7 @@ extern const char kFileHandlerTitle[]; extern const char kFileHandlerTypes[]; extern const char kFileFilters[]; extern const char kFileBrowserHandlers[]; +extern const char kGlobal[]; extern const char kMediaGalleriesHandlers[]; extern const char kHomepageURL[]; extern const char kIcons[]; diff --git a/ui/gfx/win/singleton_hwnd.cc b/ui/gfx/win/singleton_hwnd.cc index 37993e8..2de6a8b 100644 --- a/ui/gfx/win/singleton_hwnd.cc +++ b/ui/gfx/win/singleton_hwnd.cc @@ -15,16 +15,6 @@ SingletonHwnd* SingletonHwnd::GetInstance() { } void SingletonHwnd::AddObserver(Observer* observer) { - if (!hwnd()) { - if (!base::MessageLoop::current() || - base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { - // Creating this window in (e.g.) a renderer inhibits shutdown on - // Windows. See http://crbug.com/230122 and http://crbug.com/236039. - DLOG(ERROR) << "Cannot create windows on non-UI thread!"; - return; - } - WindowImpl::Init(NULL, Rect()); - } observer_list_.AddObserver(observer); } @@ -47,6 +37,14 @@ BOOL SingletonHwnd::ProcessWindowMessage(HWND window, } SingletonHwnd::SingletonHwnd() { + if (!base::MessageLoop::current() || + base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { + // Creating this window in (e.g.) a renderer inhibits shutdown on + // Windows. See http://crbug.com/230122 and http://crbug.com/236039. + DLOG(ERROR) << "Cannot create windows on non-UI thread!"; + return; + } + WindowImpl::Init(NULL, Rect()); } SingletonHwnd::~SingletonHwnd() { diff --git a/ui/gfx/win/singleton_hwnd.h b/ui/gfx/win/singleton_hwnd.h index 96af6e7..50fb9fd 100644 --- a/ui/gfx/win/singleton_hwnd.h +++ b/ui/gfx/win/singleton_hwnd.h @@ -19,7 +19,7 @@ namespace gfx { // Singleton message-only HWND that allows interested clients to receive WM_* // notifications. -class SingletonHwnd : public WindowImpl { +class GFX_EXPORT SingletonHwnd : public WindowImpl { public: static SingletonHwnd* GetInstance(); |