/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2022 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. By using JUCE, you agree to the terms of both the JUCE 7 End-User License Agreement and JUCE Privacy Policy. End User License Agreement: www.juce.com/juce-7-licence Privacy Policy: www.juce.com/juce-privacy-policy Or: You may also use this code under the terms of the GPL v3 (see www.gnu.org/licenses). JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE DISCLAIMED. ============================================================================== */ namespace juce::detail { /** Keeps track of the active top level window. */ class TopLevelWindowManager : private Timer, private DeletedAtShutdown { public: TopLevelWindowManager() = default; ~TopLevelWindowManager() override { clearSingletonInstance(); } JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (TopLevelWindowManager) static void checkCurrentlyFocusedTopLevelWindow() { if (auto* wm = TopLevelWindowManager::getInstanceWithoutCreating()) wm->checkFocusAsync(); } void checkFocusAsync() { startTimer (10); } void checkFocus() { startTimer (jmin (1731, getTimerInterval() * 2)); auto* newActive = findCurrentlyActiveWindow(); if (newActive != currentActive) { currentActive = newActive; for (int i = windows.size(); --i >= 0;) if (auto* tlw = windows[i]) tlw->setWindowActive (isWindowActive (tlw)); Desktop::getInstance().triggerFocusCallback(); } } bool addWindow (TopLevelWindow* const w) { windows.add (w); checkFocusAsync(); return isWindowActive (w); } void removeWindow (TopLevelWindow* const w) { checkFocusAsync(); if (currentActive == w) currentActive = nullptr; windows.removeFirstMatchingValue (w); if (windows.isEmpty()) deleteInstance(); } Array windows; private: TopLevelWindow* currentActive = nullptr; void timerCallback() override { checkFocus(); } bool isWindowActive (TopLevelWindow* const tlw) const { return (tlw == currentActive || tlw->isParentOf (currentActive) || tlw->hasKeyboardFocus (true)) && tlw->isShowing(); } TopLevelWindow* findCurrentlyActiveWindow() const { if (Process::isForegroundProcess()) { auto* focusedComp = Component::getCurrentlyFocusedComponent(); auto* w = dynamic_cast (focusedComp); if (w == nullptr && focusedComp != nullptr) w = focusedComp->findParentComponentOfClass(); if (w == nullptr) w = currentActive; if (w != nullptr && w->isShowing()) return w; } return nullptr; } JUCE_DECLARE_NON_COPYABLE (TopLevelWindowManager) }; JUCE_IMPLEMENT_SINGLETON (TopLevelWindowManager) } // namespace juce::detail