tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsCommandManager.cpp (7862B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "nsCommandManager.h"
      8 
      9 #include "nsCOMArray.h"
     10 #include "nsContentUtils.h"
     11 #include "nsIController.h"
     12 #include "nsIControllers.h"
     13 #include "nsIObserver.h"
     14 #include "nsPIDOMWindow.h"
     15 #include "nsPIWindowRoot.h"
     16 #include "nsServiceManagerUtils.h"
     17 #include "nsString.h"
     18 
     19 nsCommandManager::nsCommandManager(mozIDOMWindowProxy* aWindow)
     20    : mWindow(aWindow) {
     21  MOZ_DIAGNOSTIC_ASSERT(mWindow);
     22 }
     23 
     24 nsCommandManager::~nsCommandManager() = default;
     25 
     26 NS_IMPL_CYCLE_COLLECTION_CLASS(nsCommandManager)
     27 
     28 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCommandManager)
     29  tmp->mObserversTable.Clear();
     30  NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
     31 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     32 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCommandManager)
     33  for (const auto& entry : tmp->mObserversTable) {
     34    nsCommandManager::ObserverList* observers = entry.GetWeak();
     35    int32_t numItems = observers->Length();
     36    for (int32_t i = 0; i < numItems; ++i) {
     37      cb.NoteXPCOMChild(observers->ElementAt(i));
     38    }
     39  }
     40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     41 
     42 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCommandManager)
     43 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCommandManager)
     44 
     45 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCommandManager)
     46  NS_INTERFACE_MAP_ENTRY(nsICommandManager)
     47  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     48  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICommandManager)
     49 NS_INTERFACE_MAP_END
     50 
     51 void nsCommandManager::CommandStatusChanged(const char* aCommandName) {
     52  ObserverList* commandObservers;
     53  mObserversTable.Get(aCommandName, &commandObservers);
     54 
     55  if (commandObservers) {
     56    // XXX Should we worry about observers removing themselves from Observe()?
     57    int32_t i, numItems = commandObservers->Length();
     58    for (i = 0; i < numItems; ++i) {
     59      nsCOMPtr<nsIObserver> observer = commandObservers->ElementAt(i);
     60      // should we get the command state to pass here? This might be expensive.
     61      observer->Observe(NS_ISUPPORTS_CAST(nsICommandManager*, this),
     62                        aCommandName, u"command_status_changed");
     63    }
     64  }
     65 }
     66 
     67 #if 0
     68 #  pragma mark -
     69 #endif
     70 
     71 NS_IMETHODIMP
     72 nsCommandManager::AddCommandObserver(nsIObserver* aCommandObserver,
     73                                     const char* aCommandToObserve) {
     74  NS_ENSURE_ARG(aCommandObserver);
     75 
     76  // XXX todo: handle special cases of aCommandToObserve being null, or empty
     77 
     78  // for each command in the table, we make a list of observers for that command
     79  auto* const commandObservers =
     80      mObserversTable.GetOrInsertNew(aCommandToObserve);
     81 
     82  // need to check that this command observer hasn't already been registered
     83  int32_t existingIndex = commandObservers->IndexOf(aCommandObserver);
     84  if (existingIndex == -1) {
     85    commandObservers->AppendElement(aCommandObserver);
     86  } else {
     87    NS_WARNING("Registering command observer twice on the same command");
     88  }
     89 
     90  return NS_OK;
     91 }
     92 
     93 NS_IMETHODIMP
     94 nsCommandManager::RemoveCommandObserver(nsIObserver* aCommandObserver,
     95                                        const char* aCommandObserved) {
     96  NS_ENSURE_ARG(aCommandObserver);
     97 
     98  // XXX todo: handle special cases of aCommandToObserve being null, or empty
     99 
    100  ObserverList* commandObservers;
    101  if (!mObserversTable.Get(aCommandObserved, &commandObservers)) {
    102    return NS_ERROR_UNEXPECTED;
    103  }
    104 
    105  commandObservers->RemoveElement(aCommandObserver);
    106 
    107  return NS_OK;
    108 }
    109 
    110 NS_IMETHODIMP
    111 nsCommandManager::IsCommandSupported(const char* aCommandName,
    112                                     mozIDOMWindowProxy* aTargetWindow,
    113                                     bool* aResult) {
    114  NS_ENSURE_ARG_POINTER(aResult);
    115 
    116  nsCOMPtr<nsIController> controller;
    117  GetControllerForCommand(aCommandName, aTargetWindow,
    118                          getter_AddRefs(controller));
    119  *aResult = (controller.get() != nullptr);
    120  return NS_OK;
    121 }
    122 
    123 NS_IMETHODIMP
    124 nsCommandManager::IsCommandEnabled(const char* aCommandName,
    125                                   mozIDOMWindowProxy* aTargetWindow,
    126                                   bool* aResult) {
    127  NS_ENSURE_ARG_POINTER(aResult);
    128  if (!aCommandName) {
    129    *aResult = false;
    130    return NS_OK;
    131  }
    132  *aResult = IsCommandEnabled(nsDependentCString(aCommandName), aTargetWindow);
    133  return NS_OK;
    134 }
    135 
    136 bool nsCommandManager::IsCommandEnabled(const nsCString& aCommandName,
    137                                        mozIDOMWindowProxy* aTargetWindow) {
    138  nsCOMPtr<nsIController> controller;
    139  GetControllerForCommand(aCommandName.get(), aTargetWindow,
    140                          getter_AddRefs(controller));
    141  if (!controller) {
    142    return false;
    143  }
    144 
    145  bool enabled = false;
    146  controller->IsCommandEnabled(aCommandName.get(), &enabled);
    147  return enabled;
    148 }
    149 
    150 NS_IMETHODIMP
    151 nsCommandManager::GetCommandState(const char* aCommandName,
    152                                  mozIDOMWindowProxy* aTargetWindow,
    153                                  nsICommandParams* aCommandParams) {
    154  nsCOMPtr<nsIController> controller;
    155  nsAutoString tValue;
    156  nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow,
    157                                        getter_AddRefs(controller));
    158  if (!controller) {
    159    return NS_ERROR_FAILURE;
    160  }
    161 
    162  nsCOMPtr<nsICommandController> commandController =
    163      do_QueryInterface(controller);
    164  if (commandController) {
    165    rv = commandController->GetCommandStateWithParams(aCommandName,
    166                                                      aCommandParams);
    167  } else {
    168    rv = NS_ERROR_NOT_IMPLEMENTED;
    169  }
    170  return rv;
    171 }
    172 
    173 NS_IMETHODIMP
    174 nsCommandManager::DoCommand(const char* aCommandName,
    175                            nsICommandParams* aCommandParams,
    176                            mozIDOMWindowProxy* aTargetWindow) {
    177  nsCOMPtr<nsIController> controller;
    178  nsresult rv = GetControllerForCommand(aCommandName, aTargetWindow,
    179                                        getter_AddRefs(controller));
    180  if (!controller) {
    181    return NS_ERROR_FAILURE;
    182  }
    183 
    184  nsCOMPtr<nsICommandController> commandController =
    185      do_QueryInterface(controller);
    186  if (commandController && aCommandParams) {
    187    rv = commandController->DoCommandWithParams(aCommandName, aCommandParams);
    188  } else {
    189    rv = controller->DoCommand(aCommandName);
    190  }
    191  return rv;
    192 }
    193 
    194 nsresult nsCommandManager::GetControllerForCommand(
    195    const char* aCommand, mozIDOMWindowProxy* aTargetWindow,
    196    nsIController** aResult) {
    197  nsresult rv = NS_ERROR_FAILURE;
    198  *aResult = nullptr;
    199 
    200  // check if we're in content or chrome
    201  // if we're not chrome we must have a target window or we bail
    202  if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
    203    if (!aTargetWindow) {
    204      return rv;
    205    }
    206 
    207    // if a target window is specified, it must be the window we expect
    208    if (aTargetWindow != mWindow) {
    209      return NS_ERROR_FAILURE;
    210    }
    211  }
    212 
    213  if (auto* targetWindow = nsPIDOMWindowOuter::From(aTargetWindow)) {
    214    // get the controller for this particular window
    215    nsCOMPtr<nsIControllers> controllers;
    216    rv = targetWindow->GetControllers(getter_AddRefs(controllers));
    217    if (NS_FAILED(rv)) {
    218      return rv;
    219    }
    220    if (!controllers) {
    221      return NS_ERROR_FAILURE;
    222    }
    223 
    224    // dispatch the command
    225    return controllers->GetControllerForCommand(aCommand, aResult);
    226  }
    227 
    228  auto* window = nsPIDOMWindowOuter::From(mWindow);
    229  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
    230  nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
    231  NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
    232 
    233  // no target window; send command to focus controller
    234  return root->GetControllerForCommand(aCommand, false /* for any window */,
    235                                       aResult);
    236 }