Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

334 lines
9.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 7 technical preview.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For the technical preview this file cannot be licensed commercially.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. AccessibilityHandler* AccessibilityHandler::currentlyFocusedHandler = nullptr;
  16. enum class InternalAccessibilityEvent
  17. {
  18. elementCreated,
  19. elementDestroyed,
  20. elementMovedOrResized,
  21. focusChanged,
  22. windowOpened,
  23. windowClosed
  24. };
  25. void notifyAccessibilityEventInternal (const AccessibilityHandler&, InternalAccessibilityEvent);
  26. inline String getAccessibleApplicationOrPluginName()
  27. {
  28. #if defined (JucePlugin_Name)
  29. return JucePlugin_Name;
  30. #else
  31. if (auto* app = JUCEApplicationBase::getInstance())
  32. return app->getApplicationName();
  33. return "JUCE Application";
  34. #endif
  35. }
  36. AccessibilityHandler::AccessibilityHandler (Component& comp,
  37. AccessibilityRole accessibilityRole,
  38. AccessibilityActions accessibilityActions,
  39. Interfaces interfacesIn)
  40. : component (comp),
  41. typeIndex (typeid (component)),
  42. role (accessibilityRole),
  43. actions (std::move (accessibilityActions)),
  44. interfaces (std::move (interfacesIn)),
  45. nativeImpl (createNativeImpl (*this))
  46. {
  47. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::elementCreated);
  48. }
  49. AccessibilityHandler::~AccessibilityHandler()
  50. {
  51. giveAwayFocus();
  52. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::elementDestroyed);
  53. }
  54. //==============================================================================
  55. AccessibleState AccessibilityHandler::getCurrentState() const
  56. {
  57. if (component.isCurrentlyBlockedByAnotherModalComponent()
  58. && Component::getCurrentlyModalComponent()->isVisible())
  59. return {};
  60. auto state = AccessibleState().withFocusable();
  61. return hasFocus (false) ? state.withFocused() : state;
  62. }
  63. bool AccessibilityHandler::isIgnored() const
  64. {
  65. return role == AccessibilityRole::ignored || getCurrentState().isIgnored();
  66. }
  67. static bool isComponentVisibleWithinWindow (const Component& comp)
  68. {
  69. if (auto* peer = comp.getPeer())
  70. return ! peer->getAreaCoveredBy (comp).getIntersection (peer->getComponent().getLocalBounds()).isEmpty();
  71. return false;
  72. }
  73. static bool isComponentVisibleWithinParent (Component* comp)
  74. {
  75. if (auto* parent = comp->getParentComponent())
  76. {
  77. if (comp->getBoundsInParent().getIntersection (parent->getLocalBounds()).isEmpty())
  78. return false;
  79. return isComponentVisibleWithinParent (parent);
  80. }
  81. return true;
  82. }
  83. bool AccessibilityHandler::isVisibleWithinParent() const
  84. {
  85. return getCurrentState().isAccessibleOffscreen()
  86. || (isComponentVisibleWithinParent (&component) && isComponentVisibleWithinWindow (component));
  87. }
  88. //==============================================================================
  89. const AccessibilityActions& AccessibilityHandler::getActions() const noexcept
  90. {
  91. return actions;
  92. }
  93. AccessibilityValueInterface* AccessibilityHandler::getValueInterface() const
  94. {
  95. return interfaces.value.get();
  96. }
  97. AccessibilityTableInterface* AccessibilityHandler::getTableInterface() const
  98. {
  99. return interfaces.table.get();
  100. }
  101. AccessibilityCellInterface* AccessibilityHandler::getCellInterface() const
  102. {
  103. return interfaces.cell.get();
  104. }
  105. AccessibilityTextInterface* AccessibilityHandler::getTextInterface() const
  106. {
  107. return interfaces.text.get();
  108. }
  109. //==============================================================================
  110. static AccessibilityHandler* findEnclosingHandler (Component* comp)
  111. {
  112. if (comp != nullptr)
  113. {
  114. if (auto* handler = comp->getAccessibilityHandler())
  115. return handler;
  116. return findEnclosingHandler (comp->getParentComponent());
  117. }
  118. return nullptr;
  119. }
  120. static AccessibilityHandler* getUnignoredAncestor (AccessibilityHandler* handler)
  121. {
  122. while (handler != nullptr
  123. && (handler->isIgnored() || ! handler->isVisibleWithinParent())
  124. && handler->getParent() != nullptr)
  125. {
  126. handler = handler->getParent();
  127. }
  128. return handler;
  129. }
  130. static AccessibilityHandler* findFirstUnignoredChild (const std::vector<AccessibilityHandler*>& handlers)
  131. {
  132. if (! handlers.empty())
  133. {
  134. const auto iter = std::find_if (handlers.cbegin(), handlers.cend(),
  135. [] (const AccessibilityHandler* handler) { return ! handler->isIgnored() && handler->isVisibleWithinParent(); });
  136. if (iter != handlers.cend())
  137. return *iter;
  138. for (auto* handler : handlers)
  139. if (auto* unignored = findFirstUnignoredChild (handler->getChildren()))
  140. return unignored;
  141. }
  142. return nullptr;
  143. }
  144. static AccessibilityHandler* getFirstUnignoredDescendant (AccessibilityHandler* handler)
  145. {
  146. if (handler != nullptr && (handler->isIgnored() || ! handler->isVisibleWithinParent()))
  147. return findFirstUnignoredChild (handler->getChildren());
  148. return handler;
  149. }
  150. AccessibilityHandler* AccessibilityHandler::getParent() const
  151. {
  152. if (auto* focusContainer = component.findFocusContainer())
  153. return getUnignoredAncestor (findEnclosingHandler (focusContainer));
  154. return nullptr;
  155. }
  156. std::vector<AccessibilityHandler*> AccessibilityHandler::getChildren() const
  157. {
  158. if (! component.isFocusContainer() && component.getParentComponent() != nullptr)
  159. return {};
  160. const auto addChildComponentHandler = [this] (Component* focusableComponent,
  161. std::vector<AccessibilityHandler*>& childHandlers)
  162. {
  163. if (focusableComponent == nullptr)
  164. return;
  165. if (auto* handler = findEnclosingHandler (focusableComponent))
  166. {
  167. if (! handler->getCurrentState().isFocusable() || ! isParentOf (handler))
  168. return;
  169. if (auto* unignored = getFirstUnignoredDescendant (handler))
  170. if (std::find (childHandlers.cbegin(), childHandlers.cend(), unignored) == childHandlers.cend())
  171. childHandlers.push_back (unignored);
  172. }
  173. };
  174. std::vector<AccessibilityHandler*> children;
  175. if (auto traverser = component.createFocusTraverser())
  176. {
  177. addChildComponentHandler (traverser->getDefaultComponent (&component), children);
  178. for (auto* focusableChild : traverser->getAllComponents (&component))
  179. addChildComponentHandler (focusableChild, children);
  180. }
  181. return children;
  182. }
  183. bool AccessibilityHandler::isParentOf (const AccessibilityHandler* possibleChild) const noexcept
  184. {
  185. while (possibleChild != nullptr)
  186. {
  187. possibleChild = possibleChild->getParent();
  188. if (possibleChild == this)
  189. return true;
  190. }
  191. return false;
  192. }
  193. AccessibilityHandler* AccessibilityHandler::getChildAt (Point<int> screenPoint)
  194. {
  195. if (auto* comp = Desktop::getInstance().findComponentAt (screenPoint))
  196. {
  197. if (auto* handler = getUnignoredAncestor (findEnclosingHandler (comp)))
  198. if (isParentOf (handler))
  199. return handler;
  200. }
  201. return nullptr;
  202. }
  203. AccessibilityHandler* AccessibilityHandler::getChildFocus()
  204. {
  205. return hasFocus (true) ? getUnignoredAncestor (currentlyFocusedHandler)
  206. : nullptr;
  207. }
  208. bool AccessibilityHandler::hasFocus (bool trueIfChildFocused) const
  209. {
  210. return currentlyFocusedHandler != nullptr
  211. && (currentlyFocusedHandler == this
  212. || (trueIfChildFocused && isParentOf (currentlyFocusedHandler)));
  213. }
  214. void AccessibilityHandler::grabFocus()
  215. {
  216. if (! hasFocus (false))
  217. grabFocusInternal (true);
  218. }
  219. void AccessibilityHandler::giveAwayFocus() const
  220. {
  221. if (hasFocus (true))
  222. giveAwayFocusInternal();
  223. }
  224. void AccessibilityHandler::grabFocusInternal (bool canTryParent)
  225. {
  226. if (getCurrentState().isFocusable() && ! isIgnored())
  227. {
  228. takeFocus();
  229. return;
  230. }
  231. if (isParentOf (currentlyFocusedHandler))
  232. return;
  233. if (auto traverser = component.createFocusTraverser())
  234. {
  235. if (auto* defaultComp = traverser->getDefaultComponent (&component))
  236. {
  237. if (auto* handler = getUnignoredAncestor (findEnclosingHandler (defaultComp)))
  238. {
  239. if (isParentOf (handler))
  240. {
  241. handler->grabFocusInternal (false);
  242. return;
  243. }
  244. }
  245. }
  246. }
  247. if (canTryParent)
  248. if (auto* parent = getParent())
  249. parent->grabFocusInternal (true);
  250. }
  251. void AccessibilityHandler::giveAwayFocusInternal() const
  252. {
  253. currentlyFocusedHandler = nullptr;
  254. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::focusChanged);
  255. }
  256. void AccessibilityHandler::takeFocus()
  257. {
  258. currentlyFocusedHandler = this;
  259. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::focusChanged);
  260. if ((component.isShowing() || component.isOnDesktop())
  261. && component.getWantsKeyboardFocus()
  262. && ! component.hasKeyboardFocus (true))
  263. {
  264. component.grabKeyboardFocus();
  265. }
  266. }
  267. } // namespace juce