The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

717 lines
23KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../../../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "../../../application/juce_Application.h"
  21. #include "../juce_Component.h"
  22. #include "../juce_ComponentDeletionWatcher.h"
  23. #include "../juce_Desktop.h"
  24. #include "../../../events/juce_MessageManager.h"
  25. #include "../../../core/juce_Time.h"
  26. #include "../../../core/juce_Random.h"
  27. #include "../layout/juce_ComponentBoundsConstrainer.h"
  28. #include "../mouse/juce_FileDragAndDropTarget.h"
  29. //#define JUCE_ENABLE_REPAINT_DEBUGGING 1
  30. //==============================================================================
  31. static const int fakeMouseMoveMessage = 0x7fff00ff;
  32. static VoidArray heavyweightPeers;
  33. //==============================================================================
  34. ComponentPeer::ComponentPeer (Component* const component_,
  35. const int styleFlags_) throw()
  36. : component (component_),
  37. styleFlags (styleFlags_),
  38. lastPaintTime (0),
  39. constrainer (0),
  40. lastFocusedComponent (0),
  41. lastDragAndDropCompUnderMouse (0),
  42. fakeMouseMessageSent (false),
  43. isWindowMinimised (false)
  44. {
  45. heavyweightPeers.add (this);
  46. }
  47. ComponentPeer::~ComponentPeer()
  48. {
  49. heavyweightPeers.removeValue (this);
  50. Desktop::getInstance().triggerFocusCallback();
  51. }
  52. //==============================================================================
  53. int ComponentPeer::getNumPeers() throw()
  54. {
  55. return heavyweightPeers.size();
  56. }
  57. ComponentPeer* ComponentPeer::getPeer (const int index) throw()
  58. {
  59. return (ComponentPeer*) heavyweightPeers [index];
  60. }
  61. ComponentPeer* ComponentPeer::getPeerFor (const Component* const component) throw()
  62. {
  63. for (int i = heavyweightPeers.size(); --i >= 0;)
  64. {
  65. ComponentPeer* const peer = (ComponentPeer*) heavyweightPeers.getUnchecked(i);
  66. if (peer->getComponent() == component)
  67. return peer;
  68. }
  69. return 0;
  70. }
  71. bool ComponentPeer::isValidPeer (const ComponentPeer* const peer) throw()
  72. {
  73. return heavyweightPeers.contains (const_cast <ComponentPeer*> (peer));
  74. }
  75. void ComponentPeer::updateCurrentModifiers() throw()
  76. {
  77. ModifierKeys::updateCurrentModifiers();
  78. }
  79. //==============================================================================
  80. void ComponentPeer::handleMouseEnter (const Point<int>& position, const int64 time)
  81. {
  82. jassert (component->isValidComponent());
  83. updateCurrentModifiers();
  84. Component* c = component->getComponentAt (position);
  85. const ComponentDeletionWatcher deletionChecker (component);
  86. if (c != Component::componentUnderMouse && Component::componentUnderMouse != 0)
  87. {
  88. jassert (Component::componentUnderMouse->isValidComponent());
  89. const Point<int> relPos (component->relativePositionToOtherComponent (Component::componentUnderMouse, position));
  90. Component::componentUnderMouse->internalMouseExit (relPos.getX(), relPos.getY(), time);
  91. Component::componentUnderMouse = 0;
  92. if (deletionChecker.hasBeenDeleted())
  93. return;
  94. c = component->getComponentAt (position);
  95. }
  96. Component::componentUnderMouse = c;
  97. if (Component::componentUnderMouse != 0)
  98. {
  99. const Point<int> relPos (component->relativePositionToOtherComponent (Component::componentUnderMouse, position));
  100. Component::componentUnderMouse->internalMouseEnter (relPos.getX(), relPos.getY(), time);
  101. }
  102. }
  103. void ComponentPeer::handleMouseMove (const Point<int>& position, const int64 time)
  104. {
  105. jassert (component->isValidComponent());
  106. updateCurrentModifiers();
  107. fakeMouseMessageSent = false;
  108. const ComponentDeletionWatcher deletionChecker (component);
  109. Component* c = component->getComponentAt (position);
  110. if (c != Component::componentUnderMouse)
  111. {
  112. if (Component::componentUnderMouse != 0)
  113. {
  114. const Point<int> relPos (component->relativePositionToOtherComponent (Component::componentUnderMouse, position));
  115. Component::componentUnderMouse->internalMouseExit (relPos.getX(), relPos.getY(), time);
  116. Component::componentUnderMouse = 0;
  117. if (deletionChecker.hasBeenDeleted())
  118. return; // if this window has just been deleted..
  119. c = component->getComponentAt (position);
  120. }
  121. Component::componentUnderMouse = c;
  122. if (c != 0)
  123. {
  124. const Point<int> relPos (component->relativePositionToOtherComponent (c, position));
  125. c->internalMouseEnter (relPos.getX(), relPos.getY(), time);
  126. if (deletionChecker.hasBeenDeleted())
  127. return; // if this window has just been deleted..
  128. }
  129. }
  130. if (Component::componentUnderMouse != 0)
  131. {
  132. const Point<int> relPos (component->relativePositionToOtherComponent (Component::componentUnderMouse, position));
  133. Component::componentUnderMouse->internalMouseMove (relPos.getX(), relPos.getY(), time);
  134. }
  135. }
  136. void ComponentPeer::handleMouseDown (const Point<int>& position, const int64 time)
  137. {
  138. Desktop::getInstance().incrementMouseClickCounter();
  139. updateCurrentModifiers();
  140. if (ModifierKeys::getCurrentModifiers().getNumMouseButtonsDown() == 1)
  141. {
  142. Component::componentUnderMouse = component->getComponentAt (position);
  143. if (Component::componentUnderMouse != 0)
  144. {
  145. const Point<int> relPos (component->relativePositionToOtherComponent (Component::componentUnderMouse, position));
  146. Component::componentUnderMouse->internalMouseDown (relPos.getX(), relPos.getY(), time);
  147. }
  148. }
  149. }
  150. void ComponentPeer::handleMouseDrag (const Point<int>& position, const int64 time)
  151. {
  152. updateCurrentModifiers();
  153. if (Component::componentUnderMouse != 0)
  154. {
  155. const Point<int> relPos (component->relativePositionToOtherComponent (Component::componentUnderMouse, position));
  156. Component::componentUnderMouse->internalMouseDrag (relPos.getX(), relPos.getY(), time);
  157. }
  158. }
  159. void ComponentPeer::handleMouseUp (const int oldModifiers, const Point<int>& position, const int64 time)
  160. {
  161. updateCurrentModifiers();
  162. if (ModifierKeys (oldModifiers).getNumMouseButtonsDown() == 1)
  163. {
  164. const ComponentDeletionWatcher deletionChecker (component);
  165. Component* c = component->getComponentAt (position);
  166. if (c != Component::componentUnderMouse)
  167. {
  168. if (Component::componentUnderMouse != 0)
  169. {
  170. const Point<int> relPos (component->relativePositionToOtherComponent (Component::componentUnderMouse, position));
  171. Component::componentUnderMouse->internalMouseUp (oldModifiers, relPos.getX(), relPos.getY(), time);
  172. if (Component::componentUnderMouse != 0)
  173. Component::componentUnderMouse->internalMouseExit (relPos.getX(), relPos.getY(), time);
  174. if (deletionChecker.hasBeenDeleted())
  175. return;
  176. c = component->getComponentAt (position);
  177. }
  178. Component::componentUnderMouse = c;
  179. if (Component::componentUnderMouse != 0)
  180. {
  181. const Point<int> relPos (component->relativePositionToOtherComponent (Component::componentUnderMouse, position));
  182. Component::componentUnderMouse->internalMouseEnter (relPos.getX(), relPos.getY(), time);
  183. }
  184. }
  185. else
  186. {
  187. if (Component::componentUnderMouse != 0)
  188. {
  189. const Point<int> relPos (component->relativePositionToOtherComponent (Component::componentUnderMouse, position));
  190. Component::componentUnderMouse->internalMouseUp (oldModifiers, relPos.getX(), relPos.getY(), time);
  191. }
  192. }
  193. }
  194. }
  195. void ComponentPeer::handleMouseExit (const Point<int>& position, const int64 time)
  196. {
  197. jassert (component->isValidComponent());
  198. updateCurrentModifiers();
  199. if (Component::componentUnderMouse != 0)
  200. {
  201. const Point<int> relPos (component->relativePositionToOtherComponent (Component::componentUnderMouse, position));
  202. Component::componentUnderMouse->internalMouseExit (relPos.getX(), relPos.getY(), time);
  203. Component::componentUnderMouse = 0;
  204. }
  205. }
  206. void ComponentPeer::handleMouseWheel (const int amountX, const int amountY, const int64 time)
  207. {
  208. updateCurrentModifiers();
  209. if (Component::componentUnderMouse != 0)
  210. Component::componentUnderMouse->internalMouseWheel (amountX, amountY, time);
  211. }
  212. void ComponentPeer::sendFakeMouseMove() throw()
  213. {
  214. if ((! fakeMouseMessageSent)
  215. && component->flags.hasHeavyweightPeerFlag
  216. && ! ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown())
  217. {
  218. if (! isMinimised())
  219. component->bounds_ = getBounds();
  220. const Point<int> pos (component->getMouseXYRelative());
  221. if (((unsigned int) pos.getX()) < (unsigned int) component->getWidth()
  222. && ((unsigned int) pos.getY()) < (unsigned int) component->getHeight()
  223. && contains (pos.getX(), pos.getY(), false))
  224. {
  225. postMessage (new Message (fakeMouseMoveMessage, pos.getX(), pos.getY(), 0));
  226. }
  227. fakeMouseMessageSent = true;
  228. }
  229. }
  230. void ComponentPeer::handleMessage (const Message& message)
  231. {
  232. if (message.intParameter1 == fakeMouseMoveMessage)
  233. {
  234. if (! ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown())
  235. handleMouseMove (Point<int> (message.intParameter2, message.intParameter3),
  236. Time::currentTimeMillis());
  237. }
  238. }
  239. //==============================================================================
  240. void ComponentPeer::handlePaint (LowLevelGraphicsContext& contextToPaintTo)
  241. {
  242. Graphics g (&contextToPaintTo);
  243. #if JUCE_ENABLE_REPAINT_DEBUGGING
  244. g.saveState();
  245. #endif
  246. JUCE_TRY
  247. {
  248. component->paintEntireComponent (g);
  249. }
  250. JUCE_CATCH_EXCEPTION
  251. #if JUCE_ENABLE_REPAINT_DEBUGGING
  252. // enabling this code will fill all areas that get repainted with a colour overlay, to show
  253. // clearly when things are being repainted.
  254. {
  255. g.restoreState();
  256. g.fillAll (Colour ((uint8) Random::getSystemRandom().nextInt (255),
  257. (uint8) Random::getSystemRandom().nextInt (255),
  258. (uint8) Random::getSystemRandom().nextInt (255),
  259. (uint8) 0x50));
  260. }
  261. #endif
  262. }
  263. bool ComponentPeer::handleKeyPress (const int keyCode,
  264. const juce_wchar textCharacter)
  265. {
  266. updateCurrentModifiers();
  267. Component* target = Component::currentlyFocusedComponent->isValidComponent()
  268. ? Component::currentlyFocusedComponent
  269. : component;
  270. if (target->isCurrentlyBlockedByAnotherModalComponent())
  271. {
  272. Component* const currentModalComp = Component::getCurrentlyModalComponent();
  273. if (currentModalComp != 0)
  274. target = currentModalComp;
  275. }
  276. const KeyPress keyInfo (keyCode,
  277. ModifierKeys::getCurrentModifiers().getRawFlags()
  278. & ModifierKeys::allKeyboardModifiers,
  279. textCharacter);
  280. bool keyWasUsed = false;
  281. while (target != 0)
  282. {
  283. const ComponentDeletionWatcher deletionChecker (target);
  284. if (target->keyListeners_ != 0)
  285. {
  286. for (int i = target->keyListeners_->size(); --i >= 0;)
  287. {
  288. keyWasUsed = ((KeyListener*) target->keyListeners_->getUnchecked(i))->keyPressed (keyInfo, target);
  289. if (keyWasUsed || deletionChecker.hasBeenDeleted())
  290. return keyWasUsed;
  291. i = jmin (i, target->keyListeners_->size());
  292. }
  293. }
  294. keyWasUsed = target->keyPressed (keyInfo);
  295. if (keyWasUsed || deletionChecker.hasBeenDeleted())
  296. break;
  297. if (keyInfo.isKeyCode (KeyPress::tabKey) && Component::getCurrentlyFocusedComponent() != 0)
  298. {
  299. Component* const currentlyFocused = Component::getCurrentlyFocusedComponent();
  300. currentlyFocused->moveKeyboardFocusToSibling (! keyInfo.getModifiers().isShiftDown());
  301. keyWasUsed = (currentlyFocused != Component::getCurrentlyFocusedComponent());
  302. break;
  303. }
  304. target = target->parentComponent_;
  305. }
  306. return keyWasUsed;
  307. }
  308. bool ComponentPeer::handleKeyUpOrDown (const bool isKeyDown)
  309. {
  310. updateCurrentModifiers();
  311. Component* target = Component::currentlyFocusedComponent->isValidComponent()
  312. ? Component::currentlyFocusedComponent
  313. : component;
  314. if (target->isCurrentlyBlockedByAnotherModalComponent())
  315. {
  316. Component* const currentModalComp = Component::getCurrentlyModalComponent();
  317. if (currentModalComp != 0)
  318. target = currentModalComp;
  319. }
  320. bool keyWasUsed = false;
  321. while (target != 0)
  322. {
  323. const ComponentDeletionWatcher deletionChecker (target);
  324. keyWasUsed = target->keyStateChanged (isKeyDown);
  325. if (keyWasUsed || deletionChecker.hasBeenDeleted())
  326. break;
  327. if (target->keyListeners_ != 0)
  328. {
  329. for (int i = target->keyListeners_->size(); --i >= 0;)
  330. {
  331. keyWasUsed = ((KeyListener*) target->keyListeners_->getUnchecked(i))->keyStateChanged (isKeyDown, target);
  332. if (keyWasUsed || deletionChecker.hasBeenDeleted())
  333. return keyWasUsed;
  334. i = jmin (i, target->keyListeners_->size());
  335. }
  336. }
  337. target = target->parentComponent_;
  338. }
  339. return keyWasUsed;
  340. }
  341. void ComponentPeer::handleModifierKeysChange()
  342. {
  343. updateCurrentModifiers();
  344. Component* target = Component::getComponentUnderMouse();
  345. if (target == 0)
  346. target = Component::getCurrentlyFocusedComponent();
  347. if (target == 0)
  348. target = component;
  349. if (target->isValidComponent())
  350. target->internalModifierKeysChanged();
  351. }
  352. //==============================================================================
  353. void ComponentPeer::handleBroughtToFront()
  354. {
  355. updateCurrentModifiers();
  356. if (component != 0)
  357. component->internalBroughtToFront();
  358. }
  359. void ComponentPeer::setConstrainer (ComponentBoundsConstrainer* const newConstrainer) throw()
  360. {
  361. constrainer = newConstrainer;
  362. }
  363. void ComponentPeer::handleMovedOrResized()
  364. {
  365. jassert (component->isValidComponent());
  366. updateCurrentModifiers();
  367. const bool nowMinimised = isMinimised();
  368. if (component->flags.hasHeavyweightPeerFlag && ! nowMinimised)
  369. {
  370. const ComponentDeletionWatcher deletionChecker (component);
  371. const Rectangle<int> newBounds (getBounds());
  372. const bool wasMoved = (component->getPosition() != newBounds.getPosition());
  373. const bool wasResized = (component->getWidth() != newBounds.getWidth() || component->getHeight() != newBounds.getHeight());
  374. if (wasMoved || wasResized)
  375. {
  376. component->bounds_ = newBounds;
  377. if (wasResized)
  378. component->repaint();
  379. component->sendMovedResizedMessages (wasMoved, wasResized);
  380. if (deletionChecker.hasBeenDeleted())
  381. return;
  382. }
  383. }
  384. if (isWindowMinimised != nowMinimised)
  385. {
  386. isWindowMinimised = nowMinimised;
  387. component->minimisationStateChanged (nowMinimised);
  388. component->sendVisibilityChangeMessage();
  389. }
  390. if (! isFullScreen())
  391. lastNonFullscreenBounds = component->getBounds();
  392. }
  393. void ComponentPeer::handleFocusGain()
  394. {
  395. updateCurrentModifiers();
  396. if (component->isParentOf (lastFocusedComponent))
  397. {
  398. Component::currentlyFocusedComponent = lastFocusedComponent;
  399. Desktop::getInstance().triggerFocusCallback();
  400. lastFocusedComponent->internalFocusGain (Component::focusChangedDirectly);
  401. }
  402. else
  403. {
  404. if (! component->isCurrentlyBlockedByAnotherModalComponent())
  405. component->grabKeyboardFocus();
  406. else
  407. Component::bringModalComponentToFront();
  408. }
  409. }
  410. void ComponentPeer::handleFocusLoss()
  411. {
  412. updateCurrentModifiers();
  413. if (component->hasKeyboardFocus (true))
  414. {
  415. lastFocusedComponent = Component::currentlyFocusedComponent;
  416. if (lastFocusedComponent != 0)
  417. {
  418. Component::currentlyFocusedComponent = 0;
  419. Desktop::getInstance().triggerFocusCallback();
  420. lastFocusedComponent->internalFocusLoss (Component::focusChangedByMouseClick);
  421. }
  422. }
  423. }
  424. Component* ComponentPeer::getLastFocusedSubcomponent() const throw()
  425. {
  426. return (component->isParentOf (lastFocusedComponent) && lastFocusedComponent->isShowing())
  427. ? lastFocusedComponent
  428. : component;
  429. }
  430. void ComponentPeer::handleScreenSizeChange()
  431. {
  432. updateCurrentModifiers();
  433. component->parentSizeChanged();
  434. handleMovedOrResized();
  435. }
  436. void ComponentPeer::setNonFullScreenBounds (const Rectangle<int>& newBounds) throw()
  437. {
  438. lastNonFullscreenBounds = newBounds;
  439. }
  440. const Rectangle<int>& ComponentPeer::getNonFullScreenBounds() const throw()
  441. {
  442. return lastNonFullscreenBounds;
  443. }
  444. //==============================================================================
  445. static FileDragAndDropTarget* findDragAndDropTarget (Component* c,
  446. const StringArray& files,
  447. FileDragAndDropTarget* const lastOne)
  448. {
  449. while (c != 0)
  450. {
  451. FileDragAndDropTarget* const t = dynamic_cast <FileDragAndDropTarget*> (c);
  452. if (t != 0 && (t == lastOne || t->isInterestedInFileDrag (files)))
  453. return t;
  454. c = c->getParentComponent();
  455. }
  456. return 0;
  457. }
  458. void ComponentPeer::handleFileDragMove (const StringArray& files, const Point<int>& position)
  459. {
  460. updateCurrentModifiers();
  461. FileDragAndDropTarget* lastTarget = 0;
  462. if (dragAndDropTargetComponent != 0 && ! dragAndDropTargetComponent->hasBeenDeleted())
  463. lastTarget = const_cast <FileDragAndDropTarget*> (dynamic_cast <const FileDragAndDropTarget*> (dragAndDropTargetComponent->getComponent()));
  464. FileDragAndDropTarget* newTarget = 0;
  465. Component* const compUnderMouse = component->getComponentAt (position);
  466. if (compUnderMouse != lastDragAndDropCompUnderMouse)
  467. {
  468. lastDragAndDropCompUnderMouse = compUnderMouse;
  469. newTarget = findDragAndDropTarget (compUnderMouse, files, lastTarget);
  470. if (newTarget != lastTarget)
  471. {
  472. if (lastTarget != 0)
  473. lastTarget->fileDragExit (files);
  474. dragAndDropTargetComponent = 0;
  475. if (newTarget != 0)
  476. {
  477. Component* const targetComp = dynamic_cast <Component*> (newTarget);
  478. const Point<int> pos (component->relativePositionToOtherComponent (targetComp, position));
  479. dragAndDropTargetComponent = new ComponentDeletionWatcher (dynamic_cast <Component*> (newTarget));
  480. newTarget->fileDragEnter (files, pos.getX(), pos.getY());
  481. }
  482. }
  483. }
  484. else
  485. {
  486. newTarget = lastTarget;
  487. }
  488. if (newTarget != 0)
  489. {
  490. Component* const targetComp = dynamic_cast <Component*> (newTarget);
  491. const Point<int> pos (component->relativePositionToOtherComponent (targetComp, position));
  492. newTarget->fileDragMove (files, pos.getX(), pos.getY());
  493. }
  494. }
  495. void ComponentPeer::handleFileDragExit (const StringArray& files)
  496. {
  497. handleFileDragMove (files, Point<int> (-1, -1));
  498. jassert (dragAndDropTargetComponent == 0);
  499. lastDragAndDropCompUnderMouse = 0;
  500. }
  501. void ComponentPeer::handleFileDragDrop (const StringArray& files, const Point<int>& position)
  502. {
  503. handleFileDragMove (files, position);
  504. if (dragAndDropTargetComponent != 0 && ! dragAndDropTargetComponent->hasBeenDeleted())
  505. {
  506. FileDragAndDropTarget* const target = const_cast <FileDragAndDropTarget*> (dynamic_cast <const FileDragAndDropTarget*> (dragAndDropTargetComponent->getComponent()));
  507. dragAndDropTargetComponent = 0;
  508. lastDragAndDropCompUnderMouse = 0;
  509. if (target != 0)
  510. {
  511. Component* const targetComp = dynamic_cast <Component*> (target);
  512. if (targetComp->isCurrentlyBlockedByAnotherModalComponent())
  513. {
  514. targetComp->internalModalInputAttempt();
  515. if (targetComp->isCurrentlyBlockedByAnotherModalComponent())
  516. return;
  517. }
  518. const Point<int> pos (component->relativePositionToOtherComponent (targetComp, position));
  519. target->filesDropped (files, pos.getX(), pos.getY());
  520. }
  521. }
  522. }
  523. //==============================================================================
  524. void ComponentPeer::handleUserClosingWindow()
  525. {
  526. updateCurrentModifiers();
  527. component->userTriedToCloseWindow();
  528. }
  529. //==============================================================================
  530. void ComponentPeer::bringModalComponentToFront()
  531. {
  532. Component::bringModalComponentToFront();
  533. }
  534. //==============================================================================
  535. void ComponentPeer::clearMaskedRegion() throw()
  536. {
  537. maskedRegion.clear();
  538. }
  539. void ComponentPeer::addMaskedRegion (int x, int y, int w, int h) throw()
  540. {
  541. maskedRegion.add (x, y, w, h);
  542. }
  543. //==============================================================================
  544. const StringArray ComponentPeer::getAvailableRenderingEngines() throw()
  545. {
  546. StringArray s;
  547. s.add ("Software Renderer");
  548. return s;
  549. }
  550. int ComponentPeer::getCurrentRenderingEngine() throw()
  551. {
  552. return 0;
  553. }
  554. void ComponentPeer::setCurrentRenderingEngine (int /*index*/) throw()
  555. {
  556. }
  557. END_JUCE_NAMESPACE