1// Copyright (c) 2013 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.
4
5#include "chrome/browser/extensions/extension_commands_global_registry.h"
6
7#include "base/lazy_instance.h"
8#include "chrome/browser/extensions/api/commands/command_service.h"
9#include "chrome/browser/extensions/global_shortcut_listener.h"
10#include "extensions/common/extension.h"
11
12namespace extensions {
13
14ExtensionCommandsGlobalRegistry::ExtensionCommandsGlobalRegistry(
15    content::BrowserContext* context)
16    : ExtensionKeybindingRegistry(context,
17                                  ExtensionKeybindingRegistry::ALL_EXTENSIONS,
18                                  NULL),
19      browser_context_(context),
20      registry_for_active_window_(NULL) {
21  Init();
22}
23
24ExtensionCommandsGlobalRegistry::~ExtensionCommandsGlobalRegistry() {
25  if (!IsEventTargetsEmpty()) {
26    GlobalShortcutListener* global_shortcut_listener =
27        GlobalShortcutListener::GetInstance();
28
29    // Resume GlobalShortcutListener before we clean up if the shortcut handling
30    // is currently suspended.
31    if (global_shortcut_listener->IsShortcutHandlingSuspended())
32      global_shortcut_listener->SetShortcutHandlingSuspended(false);
33
34    global_shortcut_listener->UnregisterAccelerators(this);
35  }
36}
37
38static base::LazyInstance<
39    BrowserContextKeyedAPIFactory<ExtensionCommandsGlobalRegistry> > g_factory =
40    LAZY_INSTANCE_INITIALIZER;
41
42// static
43BrowserContextKeyedAPIFactory<ExtensionCommandsGlobalRegistry>*
44ExtensionCommandsGlobalRegistry::GetFactoryInstance() {
45  return g_factory.Pointer();
46}
47
48// static
49ExtensionCommandsGlobalRegistry* ExtensionCommandsGlobalRegistry::Get(
50    content::BrowserContext* context) {
51  return BrowserContextKeyedAPIFactory<ExtensionCommandsGlobalRegistry>::Get(
52      context);
53}
54
55// static
56void ExtensionCommandsGlobalRegistry::SetShortcutHandlingSuspended(
57    bool suspended) {
58  GlobalShortcutListener::GetInstance()->SetShortcutHandlingSuspended(
59      suspended);
60}
61
62bool ExtensionCommandsGlobalRegistry::IsRegistered(
63    const ui::Accelerator& accelerator) {
64  return (registry_for_active_window() &&
65          registry_for_active_window()->IsAcceleratorRegistered(accelerator)) ||
66         IsAcceleratorRegistered(accelerator);
67}
68
69void ExtensionCommandsGlobalRegistry::AddExtensionKeybinding(
70    const extensions::Extension* extension,
71    const std::string& command_name) {
72  // This object only handles named commands, not browser/page actions.
73  if (ShouldIgnoreCommand(command_name))
74    return;
75
76  extensions::CommandService* command_service =
77      extensions::CommandService::Get(browser_context_);
78  // Add all the active global keybindings, if any.
79  extensions::CommandMap commands;
80  if (!command_service->GetNamedCommands(
81          extension->id(),
82          extensions::CommandService::ACTIVE_ONLY,
83          extensions::CommandService::GLOBAL,
84          &commands))
85    return;
86
87  extensions::CommandMap::const_iterator iter = commands.begin();
88  for (; iter != commands.end(); ++iter) {
89    if (!command_name.empty() && (iter->second.command_name() != command_name))
90      continue;
91    const ui::Accelerator& accelerator = iter->second.accelerator();
92
93    VLOG(0) << "Adding global keybinding for " << extension->name().c_str()
94            << " " << command_name.c_str()
95            << " key: " << accelerator.GetShortcutText();
96
97    if (!IsAcceleratorRegistered(accelerator)) {
98      if (!GlobalShortcutListener::GetInstance()->RegisterAccelerator(
99              accelerator, this))
100        continue;
101    }
102
103    AddEventTarget(accelerator, extension->id(), iter->second.command_name());
104  }
105}
106
107void ExtensionCommandsGlobalRegistry::RemoveExtensionKeybindingImpl(
108    const ui::Accelerator& accelerator,
109    const std::string& command_name) {
110  VLOG(0) << "Removing keybinding for " << command_name.c_str();
111
112  GlobalShortcutListener::GetInstance()->UnregisterAccelerator(
113      accelerator, this);
114}
115
116void ExtensionCommandsGlobalRegistry::OnKeyPressed(
117    const ui::Accelerator& accelerator) {
118  ExtensionKeybindingRegistry::NotifyEventTargets(accelerator);
119}
120
121}  // namespace extensions
122