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.

365 lines
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../../../juce_core/basics/juce_StandardHeader.h"
  24. BEGIN_JUCE_NAMESPACE
  25. #include "juce_TopLevelWindow.h"
  26. #include "../juce_Desktop.h"
  27. #include "../lookandfeel/juce_LookAndFeel.h"
  28. #include "../special/juce_DropShadower.h"
  29. #include "../../../../juce_core/threads/juce_Process.h"
  30. #include "../../../../juce_core/basics/juce_Singleton.h"
  31. //==============================================================================
  32. /** Keeps track of the active top level window.
  33. */
  34. class TopLevelWindowManager : public Timer,
  35. public DeletedAtShutdown
  36. {
  37. public:
  38. //==============================================================================
  39. TopLevelWindowManager()
  40. : windows (8),
  41. currentActive (0)
  42. {
  43. }
  44. ~TopLevelWindowManager()
  45. {
  46. clearSingletonInstance();
  47. }
  48. juce_DeclareSingleton_SingleThreaded_Minimal (TopLevelWindowManager)
  49. void timerCallback()
  50. {
  51. startTimer (1731);
  52. TopLevelWindow* active = 0;
  53. if (Process::isForegroundProcess())
  54. {
  55. active = currentActive;
  56. Component* const c = Component::getCurrentlyFocusedComponent();
  57. TopLevelWindow* tlw = dynamic_cast <TopLevelWindow*> (c);
  58. if (tlw == 0 && c != 0)
  59. // (unable to use the syntax findParentComponentOfClass <TopLevelWindow> () because of a VC6 compiler bug)
  60. tlw = c->findParentComponentOfClass ((TopLevelWindow*) 0);
  61. if (tlw != 0)
  62. active = tlw;
  63. }
  64. if (active != currentActive)
  65. {
  66. currentActive = active;
  67. for (int i = windows.size(); --i >= 0;)
  68. {
  69. TopLevelWindow* const tlw = (TopLevelWindow*) windows.getUnchecked (i);
  70. tlw->setWindowActive (isWindowActive (tlw));
  71. i = jmin (i, windows.size() - 1);
  72. }
  73. Desktop::getInstance().triggerFocusCallback();
  74. }
  75. }
  76. bool addWindow (TopLevelWindow* const w) throw()
  77. {
  78. windows.add (w);
  79. startTimer (10);
  80. return isWindowActive (w);
  81. }
  82. void removeWindow (TopLevelWindow* const w) throw()
  83. {
  84. startTimer (10);
  85. if (currentActive == w)
  86. currentActive = 0;
  87. windows.removeValue (w);
  88. if (windows.size() == 0)
  89. deleteInstance();
  90. }
  91. VoidArray windows;
  92. private:
  93. TopLevelWindow* currentActive;
  94. bool isWindowActive (TopLevelWindow* const tlw) const throw()
  95. {
  96. return (tlw == currentActive
  97. || tlw->isParentOf (currentActive)
  98. || tlw->hasKeyboardFocus (true))
  99. && tlw->isShowing();
  100. }
  101. TopLevelWindowManager (const TopLevelWindowManager&);
  102. const TopLevelWindowManager& operator= (const TopLevelWindowManager&);
  103. };
  104. juce_ImplementSingleton_SingleThreaded (TopLevelWindowManager)
  105. void juce_CheckCurrentlyFocusedTopLevelWindow() throw()
  106. {
  107. if (TopLevelWindowManager::getInstanceWithoutCreating() != 0)
  108. TopLevelWindowManager::getInstanceWithoutCreating()->startTimer (20);
  109. }
  110. //==============================================================================
  111. TopLevelWindow::TopLevelWindow (const String& name,
  112. const bool addToDesktop_)
  113. : Component (name),
  114. useDropShadow (true),
  115. useNativeTitleBar (false),
  116. windowIsActive_ (false),
  117. shadower (0)
  118. {
  119. setOpaque (true);
  120. if (addToDesktop_)
  121. Component::addToDesktop (getDesktopWindowStyleFlags());
  122. else
  123. setDropShadowEnabled (true);
  124. setWantsKeyboardFocus (true);
  125. setBroughtToFrontOnMouseClick (true);
  126. windowIsActive_ = TopLevelWindowManager::getInstance()->addWindow (this);
  127. }
  128. TopLevelWindow::~TopLevelWindow()
  129. {
  130. deleteAndZero (shadower);
  131. TopLevelWindowManager::getInstance()->removeWindow (this);
  132. }
  133. //==============================================================================
  134. void TopLevelWindow::focusOfChildComponentChanged (FocusChangeType)
  135. {
  136. if (hasKeyboardFocus (true))
  137. TopLevelWindowManager::getInstance()->timerCallback();
  138. else
  139. TopLevelWindowManager::getInstance()->startTimer (10);
  140. }
  141. void TopLevelWindow::setWindowActive (const bool isNowActive) throw()
  142. {
  143. if (windowIsActive_ != isNowActive)
  144. {
  145. windowIsActive_ = isNowActive;
  146. activeWindowStatusChanged();
  147. }
  148. }
  149. void TopLevelWindow::activeWindowStatusChanged()
  150. {
  151. }
  152. void TopLevelWindow::parentHierarchyChanged()
  153. {
  154. setDropShadowEnabled (useDropShadow);
  155. }
  156. void TopLevelWindow::visibilityChanged()
  157. {
  158. if (isShowing())
  159. toFront (true);
  160. }
  161. int TopLevelWindow::getDesktopWindowStyleFlags() const
  162. {
  163. int flags = ComponentPeer::windowAppearsOnTaskbar;
  164. if (useDropShadow)
  165. flags |= ComponentPeer::windowHasDropShadow;
  166. if (useNativeTitleBar)
  167. flags |= ComponentPeer::windowHasTitleBar;
  168. return flags;
  169. }
  170. void TopLevelWindow::setDropShadowEnabled (const bool useShadow)
  171. {
  172. useDropShadow = useShadow;
  173. if (isOnDesktop())
  174. {
  175. deleteAndZero (shadower);
  176. Component::addToDesktop (getDesktopWindowStyleFlags());
  177. }
  178. else
  179. {
  180. if (useShadow && isOpaque())
  181. {
  182. if (shadower == 0)
  183. {
  184. shadower = getLookAndFeel().createDropShadowerForComponent (this);
  185. if (shadower != 0)
  186. shadower->setOwner (this);
  187. }
  188. }
  189. else
  190. {
  191. deleteAndZero (shadower);
  192. }
  193. }
  194. }
  195. void TopLevelWindow::setUsingNativeTitleBar (const bool useNativeTitleBar_)
  196. {
  197. if (useNativeTitleBar != useNativeTitleBar_)
  198. {
  199. useNativeTitleBar = useNativeTitleBar_;
  200. recreateDesktopWindow();
  201. sendLookAndFeelChange();
  202. }
  203. }
  204. void TopLevelWindow::recreateDesktopWindow()
  205. {
  206. if (isOnDesktop())
  207. {
  208. Component::addToDesktop (getDesktopWindowStyleFlags());
  209. toFront (true);
  210. }
  211. }
  212. void TopLevelWindow::addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo)
  213. {
  214. /* It's not recommended to change the desktop window flags directly for a TopLevelWindow,
  215. because this class needs to make sure its layout corresponds with settings like whether
  216. it's got a native title bar or not.
  217. If you need custom flags for your window, you can override the getDesktopWindowStyleFlags()
  218. method. If you do this, it's best to call the base class's getDesktopWindowStyleFlags()
  219. method, then add or remove whatever flags are necessary from this value before returning it.
  220. */
  221. jassert (windowStyleFlags == getDesktopWindowStyleFlags());
  222. Component::addToDesktop (windowStyleFlags, nativeWindowToAttachTo);
  223. if (windowStyleFlags != getDesktopWindowStyleFlags())
  224. sendLookAndFeelChange();
  225. }
  226. //==============================================================================
  227. void TopLevelWindow::centreAroundComponent (Component* c, const int width, const int height)
  228. {
  229. if (c == 0)
  230. c = TopLevelWindow::getActiveTopLevelWindow();
  231. if (c == 0)
  232. {
  233. centreWithSize (width, height);
  234. }
  235. else
  236. {
  237. int x = (c->getWidth() - width) / 2;
  238. int y = (c->getHeight() - height) / 2;
  239. c->relativePositionToGlobal (x, y);
  240. Rectangle parentArea (c->getParentMonitorArea());
  241. if (getParentComponent() != 0)
  242. {
  243. getParentComponent()->globalPositionToRelative (x, y);
  244. parentArea.setBounds (0, 0, getParentWidth(), getParentHeight());
  245. }
  246. setBounds (parentArea.getX() + jlimit (0, jmax (0, parentArea.getWidth() - width), x),
  247. parentArea.getY() + jlimit (0, jmax (0, parentArea.getHeight() - height), y),
  248. width, height);
  249. }
  250. }
  251. //==============================================================================
  252. int TopLevelWindow::getNumTopLevelWindows() throw()
  253. {
  254. return TopLevelWindowManager::getInstance()->windows.size();
  255. }
  256. TopLevelWindow* TopLevelWindow::getTopLevelWindow (const int index) throw()
  257. {
  258. return (TopLevelWindow*) TopLevelWindowManager::getInstance()->windows [index];
  259. }
  260. TopLevelWindow* TopLevelWindow::getActiveTopLevelWindow() throw()
  261. {
  262. TopLevelWindow* best = 0;
  263. int bestNumTWLParents = -1;
  264. for (int i = TopLevelWindow::getNumTopLevelWindows(); --i >= 0;)
  265. {
  266. TopLevelWindow* const tlw = TopLevelWindow::getTopLevelWindow (i);
  267. if (tlw->isActiveWindow())
  268. {
  269. int numTWLParents = 0;
  270. const Component* c = tlw->getParentComponent();
  271. while (c != 0)
  272. {
  273. if (dynamic_cast <const TopLevelWindow*> (c) != 0)
  274. ++numTWLParents;
  275. c = c->getParentComponent();
  276. }
  277. if (bestNumTWLParents < numTWLParents)
  278. {
  279. best = tlw;
  280. bestNumTWLParents = numTWLParents;
  281. }
  282. }
  283. }
  284. return best;
  285. }
  286. END_JUCE_NAMESPACE