Home | History | Annotate | Download | only in extensions
      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.
      4 
      5 #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_H_
      6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_H_
      7 
      8 #include <list>
      9 #include <map>
     10 #include <string>
     11 
     12 #include "base/compiler_specific.h"
     13 #include "base/scoped_observer.h"
     14 #include "content/public/browser/notification_details.h"
     15 #include "content/public/browser/notification_observer.h"
     16 #include "content/public/browser/notification_registrar.h"
     17 #include "content/public/browser/notification_source.h"
     18 #include "extensions/browser/extension_registry_observer.h"
     19 
     20 namespace content {
     21 class BrowserContext;
     22 }
     23 
     24 namespace ui {
     25 class Accelerator;
     26 }
     27 
     28 namespace extensions {
     29 
     30 class ActiveTabPermissionGranter;
     31 class Extension;
     32 class ExtensionRegistry;
     33 
     34 // The ExtensionKeybindingRegistry is a class that handles the cross-platform
     35 // logic for keyboard accelerators. See platform-specific implementations for
     36 // implementation details for each platform.
     37 class ExtensionKeybindingRegistry : public content::NotificationObserver,
     38                                     public ExtensionRegistryObserver {
     39  public:
     40   enum ExtensionFilter {
     41     ALL_EXTENSIONS,
     42     PLATFORM_APPS_ONLY
     43   };
     44 
     45   class Delegate {
     46    public:
     47     // Gets the ActiveTabPermissionGranter for the active tab, if any.
     48     // If there is no active tab then returns NULL.
     49     virtual ActiveTabPermissionGranter* GetActiveTabPermissionGranter() = 0;
     50   };
     51 
     52   // If |extension_filter| is not ALL_EXTENSIONS, only keybindings by
     53   // by extensions that match the filter will be registered.
     54   ExtensionKeybindingRegistry(content::BrowserContext* context,
     55                               ExtensionFilter extension_filter,
     56                               Delegate* delegate);
     57 
     58   virtual ~ExtensionKeybindingRegistry();
     59 
     60   // Enables/Disables general shortcut handling in Chrome. Implemented in
     61   // platform-specific ExtensionKeybindingsRegistry* files.
     62   static void SetShortcutHandlingSuspended(bool suspended);
     63 
     64   // Execute the command bound to |accelerator| and provided by the extension
     65   // with |extension_id|, if it exists.
     66   void ExecuteCommand(const std::string& extension_id,
     67                       const ui::Accelerator& accelerator);
     68 
     69   // Check whether the specified |accelerator| has been registered.
     70   bool IsAcceleratorRegistered(const ui::Accelerator& accelerator) const;
     71 
     72  protected:
     73   // Add extension keybinding for the events defined by the |extension|.
     74   // |command_name| is optional, but if not blank then only the command
     75   // specified will be added.
     76   virtual void AddExtensionKeybinding(
     77       const Extension* extension,
     78       const std::string& command_name) = 0;
     79   // Remove extension bindings for |extension|. |command_name| is optional,
     80   // but if not blank then only the command specified will be removed.
     81   void RemoveExtensionKeybinding(
     82       const Extension* extension,
     83       const std::string& command_name);
     84   // Overridden by platform specific implementations to provide additional
     85   // unregistration (which varies between platforms).
     86   virtual void RemoveExtensionKeybindingImpl(
     87       const ui::Accelerator& accelerator,
     88       const std::string& command_name) = 0;
     89 
     90   // Make sure all extensions registered have keybindings added.
     91   void Init();
     92 
     93   // Whether to ignore this command. Only browserAction commands and pageAction
     94   // commands are currently ignored, since they are handled elsewhere.
     95   bool ShouldIgnoreCommand(const std::string& command) const;
     96 
     97   // Fire event targets which the specified |accelerator| is binding with.
     98   // Returns true if we can find the appropriate event targets.
     99   bool NotifyEventTargets(const ui::Accelerator& accelerator);
    100 
    101   // Notifies appropriate parties that a command has been executed.
    102   void CommandExecuted(const std::string& extension_id,
    103                        const std::string& command);
    104 
    105   // Add event target (extension_id, command name) to the target list of
    106   // |accelerator|. Note that only media keys can have more than one event
    107   // target.
    108   void AddEventTarget(const ui::Accelerator& accelerator,
    109                       const std::string& extension_id,
    110                       const std::string& command_name);
    111 
    112   // Get the first event target by the given |accelerator|. For a valid
    113   // accelerator it should have only one event target, except for media keys.
    114   // Returns true if we can find it, |extension_id| and |command_name| will be
    115   // set to the right target; otherwise, false is returned and |extension_id|,
    116   // |command_name| are unchanged.
    117   bool GetFirstTarget(const ui::Accelerator& accelerator,
    118                       std::string* extension_id,
    119                       std::string* command_name) const;
    120 
    121   // Returns true if the |event_targets_| is empty; otherwise returns false.
    122   bool IsEventTargetsEmpty() const;
    123 
    124   // Returns the BrowserContext for this registry.
    125   content::BrowserContext* browser_context() const { return browser_context_; }
    126 
    127  private:
    128   // Overridden from content::NotificationObserver:
    129   virtual void Observe(int type,
    130                        const content::NotificationSource& source,
    131                        const content::NotificationDetails& details) OVERRIDE;
    132 
    133   // ExtensionRegistryObserver implementation.
    134   virtual void OnExtensionLoaded(content::BrowserContext* browser_context,
    135                                  const Extension* extension) OVERRIDE;
    136   virtual void OnExtensionUnloaded(
    137       content::BrowserContext* browser_context,
    138       const Extension* extension,
    139       UnloadedExtensionInfo::Reason reason) OVERRIDE;
    140 
    141   // Returns true if the |extension| matches our extension filter.
    142   bool ExtensionMatchesFilter(const extensions::Extension* extension);
    143 
    144   // Execute commands for |accelerator|. If |extension_id| is empty, execute all
    145   // commands bound to |accelerator|, otherwise execute only commands bound by
    146   // the corresponding extension. Returns true if at least one command was
    147   // executed.
    148   bool ExecuteCommands(const ui::Accelerator& accelerator,
    149                        const std::string& extension_id);
    150 
    151   // The content notification registrar for listening to extension events.
    152   content::NotificationRegistrar registrar_;
    153 
    154   content::BrowserContext* browser_context_;
    155 
    156   // What extensions to register keybindings for.
    157   ExtensionFilter extension_filter_;
    158 
    159   // Weak pointer to our delegate. Not owned by us. Must outlive this class.
    160   Delegate* delegate_;
    161 
    162   // Maps an accelerator to a list of string pairs (extension id, command name)
    163   // for commands that have been registered. This keeps track of the targets for
    164   // the keybinding event (which named command to call in which extension). On
    165   // GTK this map contains registration for pageAction and browserAction
    166   // commands, whereas on other platforms it does not. Note that normal
    167   // accelerator (which isn't media keys) has only one target, while the media
    168   // keys can have more than one.
    169   typedef std::list<std::pair<std::string, std::string> > TargetList;
    170   typedef std::map<ui::Accelerator, TargetList> EventTargets;
    171   EventTargets event_targets_;
    172 
    173   // Listen to extension load, unloaded notifications.
    174   ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
    175       extension_registry_observer_;
    176 
    177   DISALLOW_COPY_AND_ASSIGN(ExtensionKeybindingRegistry);
    178 };
    179 
    180 }  // namespace extensions
    181 
    182 #endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_H_
    183