diff --git a/extras/Introjucer/Source/Application/jucer_Application.h b/extras/Introjucer/Source/Application/jucer_Application.h index 50214965fa..d5f8b0f1e5 100644 --- a/extras/Introjucer/Source/Application/jucer_Application.h +++ b/extras/Introjucer/Source/Application/jucer_Application.h @@ -65,21 +65,13 @@ public: ImageCache::setCacheTimeout (30 * 1000); if (commandLine.trim().isNotEmpty() && ! commandLine.trim().startsWithChar ('-')) - { anotherInstanceStarted (commandLine); - } else - { - Array projects (StoredSettings::getInstance()->getLastProjects()); - - for (int i = 0; i < projects.size(); ++ i) - openFile (projects.getReference(i)); - } + mainWindowList.reopenLastProjects(); makeSureUserHasSelectedModuleFolder(); - if (mainWindows.size() == 0) - createNewMainWindow()->makeVisible(); + mainWindowList.createWindowIfNoneAreOpen(); #if JUCE_MAC MenuBarModel::setMacMainMenu (menuModel); @@ -94,7 +86,7 @@ public: menuModel = nullptr; StoredSettings::deleteInstance(); - mainWindows.clear(); + mainWindowList.forceCloseAllWindows(); OpenDocumentManager::deleteInstance(); commandManager = nullptr; @@ -109,35 +101,8 @@ public: return; } - while (mainWindows.size() > 0) - { - if (! mainWindows[0]->closeCurrentProject()) - return; - - mainWindows.remove (0); - } - - quit(); - } - - void closeWindow (MainWindow* w) - { - jassert (mainWindows.contains (w)); - - #if ! JUCE_MAC - if (mainWindows.size() == 1) - { - systemRequestedQuit(); - } - else - #endif - { - if (w->closeCurrentProject()) - { - mainWindows.removeObject (w); - updateRecentProjectList(); - } - } + if (mainWindowList.askAllWindowsToClose()) + quit(); } //============================================================================== @@ -293,11 +258,9 @@ public: else if (menuItemID >= 300 && menuItemID < 400) { OpenDocumentManager::Document* doc = OpenDocumentManager::getInstance()->getOpenDocument (menuItemID - 300); + jassert (doc != nullptr); - MainWindow* w = getApp()->getOrCreateFrontmostWindow(); - w->makeVisible(); - w->getProjectContentComponent()->showDocument (doc); - getApp()->avoidSuperimposedWindows (w); + getApp()->mainWindowList.openDocument (doc); } } }; @@ -389,9 +352,9 @@ public: { if (makeSureUserHasSelectedModuleFolder()) { - MainWindow* mw = getOrCreateEmptyWindow(); + MainWindow* mw = mainWindowList.getOrCreateEmptyWindow(); mw->showNewProjectWizard(); - avoidSuperimposedWindows (mw); + mainWindowList.avoidSuperimposedWindows (mw); } } @@ -405,40 +368,7 @@ public: bool openFile (const File& file) { - for (int j = mainWindows.size(); --j >= 0;) - { - if (mainWindows.getUnchecked(j)->getProject() != nullptr - && mainWindows.getUnchecked(j)->getProject()->getFile() == file) - { - mainWindows.getUnchecked(j)->toFront (true); - return true; - } - } - - if (file.hasFileExtension (Project::projectFileExtension)) - { - ScopedPointer newDoc (new Project (file)); - - if (newDoc->loadFrom (file, true)) - { - MainWindow* w = getOrCreateEmptyWindow(); - w->setProject (newDoc.release()); - w->makeVisible(); - avoidSuperimposedWindows (w); - return true; - } - } - else if (file.exists()) - { - MainWindow* w = getOrCreateFrontmostWindow(); - - const bool ok = w->openFile (file); - w->makeVisible(); - avoidSuperimposedWindows (w); - return ok; - } - - return false; + return mainWindowList.openFile (file); } bool closeAllDocuments (bool askUserToSave) @@ -446,21 +376,6 @@ public: return OpenDocumentManager::getInstance()->closeAll (askUserToSave); } - void updateRecentProjectList() - { - Array projects; - - for (int i = 0; i < mainWindows.size(); ++i) - { - MainWindow* mw = mainWindows[i]; - - if (mw != nullptr && mw->getProject() != nullptr) - projects.add (mw->getProject()->getFile()); - } - - StoredSettings::getInstance()->setLastProjects (projects); - } - bool makeSureUserHasSelectedModuleFolder() { if (! ModuleList::isLocalModulesFolderValid()) @@ -484,7 +399,7 @@ public: { ModuleList list; list.rescan (ModuleList::getDefaultModulesFolder (nullptr)); - JuceUpdater::show (list, mainWindows[0], message); + JuceUpdater::show (list, mainWindowList.windows[0], message); ModuleList::setLocalModulesFolder (list.getModulesFolder()); return ModuleList::isJuceOrModulesFolder (list.getModulesFolder()); @@ -492,79 +407,14 @@ public: ScopedPointer menuModel; - MainWindow* createNewMainWindow() - { - MainWindow* mw = new MainWindow(); - mainWindows.add (mw); - mw->restoreWindowPosition(); - avoidSuperimposedWindows (mw); - return mw; - } - virtual Component* createProjectContentComponent() const { return new ProjectContentComponent(); } + MainWindowList mainWindowList; + private: - OwnedArray mainWindows; - - MainWindow* getOrCreateFrontmostWindow() - { - if (mainWindows.size() == 0) - return createNewMainWindow(); - - for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;) - { - MainWindow* mw = dynamic_cast (Desktop::getInstance().getComponent (i)); - if (mainWindows.contains (mw)) - return mw; - } - - return mainWindows.getLast(); - } - - MainWindow* getOrCreateEmptyWindow() - { - if (mainWindows.size() == 0) - return createNewMainWindow(); - - for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;) - { - MainWindow* mw = dynamic_cast (Desktop::getInstance().getComponent (i)); - if (mainWindows.contains (mw) && mw->getProject() == nullptr) - return mw; - } - - return createNewMainWindow(); - } - - void avoidSuperimposedWindows (MainWindow* const mw) - { - for (int i = mainWindows.size(); --i >= 0;) - { - MainWindow* const other = mainWindows.getUnchecked(i); - - const Rectangle b1 (mw->getBounds()); - const Rectangle b2 (other->getBounds()); - - if (mw != other - && std::abs (b1.getX() - b2.getX()) < 3 - && std::abs (b1.getY() - b2.getY()) < 3 - && std::abs (b1.getRight() - b2.getRight()) < 3 - && std::abs (b1.getBottom() - b2.getBottom()) < 3) - { - int dx = 40, dy = 30; - - if (b1.getCentreX() >= mw->getScreenBounds().getCentreX()) dx = -dx; - if (b1.getCentreY() >= mw->getScreenBounds().getCentreY()) dy = -dy; - - mw->setBounds (b1.translated (dx, dy)); - } - } - } - - //============================================================================== class AsyncQuitRetrier : public Timer { public: diff --git a/extras/Introjucer/Source/Application/jucer_MainWindow.cpp b/extras/Introjucer/Source/Application/jucer_MainWindow.cpp index 0318b4dc0c..6a0d9b2922 100644 --- a/extras/Introjucer/Source/Application/jucer_MainWindow.cpp +++ b/extras/Introjucer/Source/Application/jucer_MainWindow.cpp @@ -100,6 +100,7 @@ void MainWindow::createProjectContentCompIfNeeded() void MainWindow::makeVisible() { + restoreWindowPosition(); setVisible (true); addToDesktop(); // (must add before restoring size so that fullscreen will work) restoreWindowPosition(); @@ -114,7 +115,7 @@ ProjectContentComponent* MainWindow::getProjectContentComponent() const void MainWindow::closeButtonPressed() { - JucerApplication::getApp()->closeWindow (this); + JucerApplication::getApp()->mainWindowList.closeWindow (this); } bool MainWindow::closeProject (Project* project) @@ -157,11 +158,6 @@ void MainWindow::setProject (Project* newProject) getProjectContentComponent()->setProject (newProject); currentProject = newProject; commandManager->commandStatusChanged(); - - // (mustn't do this when the project is 0, because that'll happen on shutdown, - // which will erase the list of recent projects) - if (newProject != nullptr) - JucerApplication::getApp()->updateRecentProjectList(); } void MainWindow::restoreWindowPosition() @@ -297,3 +293,190 @@ bool MainWindow::perform (const InvocationInfo& info) return true; } + + +//============================================================================== +MainWindowList::MainWindowList() +{ +} + +void MainWindowList::forceCloseAllWindows() +{ + windows.clear(); +} + +bool MainWindowList::askAllWindowsToClose() +{ + saveCurrentlyOpenProjectList(); + + while (windows.size() > 0) + { + if (! windows[0]->closeCurrentProject()) + return false; + + windows.remove (0); + } + + return true; +} + +void MainWindowList::createWindowIfNoneAreOpen() +{ + if (windows.size() == 0) + createNewMainWindow()->makeVisible(); +} + +void MainWindowList::closeWindow (MainWindow* w) +{ + jassert (windows.contains (w)); + + #if ! JUCE_MAC + if (windows.size() == 1) + { + JUCEApplication::getInstance()->systemRequestedQuit(); + } + else + #endif + { + if (w->closeCurrentProject()) + { + windows.removeObject (w); + saveCurrentlyOpenProjectList(); + } + } +} + +void MainWindowList::openDocument (OpenDocumentManager::Document* doc) +{ + MainWindow* const w = getOrCreateFrontmostWindow(); + w->makeVisible(); + w->getProjectContentComponent()->showDocument (doc); + avoidSuperimposedWindows (w); +} + +bool MainWindowList::openFile (const File& file) +{ + for (int i = windows.size(); --i >= 0;) + { + MainWindow* const w = windows.getUnchecked(i); + + if (w->getProject() != nullptr && w->getProject()->getFile() == file) + { + w->toFront (true); + return true; + } + } + + if (file.hasFileExtension (Project::projectFileExtension)) + { + ScopedPointer newDoc (new Project (file)); + + if (newDoc->loadFrom (file, true)) + { + MainWindow* const w = getOrCreateEmptyWindow(); + w->setProject (newDoc.release()); + w->makeVisible(); + avoidSuperimposedWindows (w); + return true; + } + } + else if (file.exists()) + { + MainWindow* const w = getOrCreateFrontmostWindow(); + + const bool ok = w->openFile (file); + w->makeVisible(); + avoidSuperimposedWindows (w); + return ok; + } + + return false; +} + +MainWindow* MainWindowList::createNewMainWindow() +{ + MainWindow* const w = new MainWindow(); + windows.add (w); + w->restoreWindowPosition(); + avoidSuperimposedWindows (w); + return w; +} + +MainWindow* MainWindowList::getOrCreateFrontmostWindow() +{ + if (windows.size() == 0) + return createNewMainWindow(); + + for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;) + { + MainWindow* mw = dynamic_cast (Desktop::getInstance().getComponent (i)); + if (windows.contains (mw)) + return mw; + } + + return windows.getLast(); +} + +MainWindow* MainWindowList::getOrCreateEmptyWindow() +{ + if (windows.size() == 0) + return createNewMainWindow(); + + for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;) + { + MainWindow* mw = dynamic_cast (Desktop::getInstance().getComponent (i)); + if (windows.contains (mw) && mw->getProject() == nullptr) + return mw; + } + + return createNewMainWindow(); +} + +void MainWindowList::avoidSuperimposedWindows (MainWindow* const mw) +{ + for (int i = windows.size(); --i >= 0;) + { + MainWindow* const other = windows.getUnchecked(i); + + const Rectangle b1 (mw->getBounds()); + const Rectangle b2 (other->getBounds()); + + if (mw != other + && std::abs (b1.getX() - b2.getX()) < 3 + && std::abs (b1.getY() - b2.getY()) < 3 + && std::abs (b1.getRight() - b2.getRight()) < 3 + && std::abs (b1.getBottom() - b2.getBottom()) < 3) + { + int dx = 40, dy = 30; + + if (b1.getCentreX() >= mw->getScreenBounds().getCentreX()) dx = -dx; + if (b1.getCentreY() >= mw->getScreenBounds().getCentreY()) dy = -dy; + + mw->setBounds (b1.translated (dx, dy)); + } + } +} + +void MainWindowList::saveCurrentlyOpenProjectList() +{ + Array projects; + + Desktop& desktop = Desktop::getInstance(); + for (int i = 0; i < desktop.getNumComponents(); ++i) + { + MainWindow* const mw = dynamic_cast (desktop.getComponent(i)); + + if (mw != nullptr && mw->getProject() != nullptr) + projects.add (mw->getProject()->getFile()); + } + + StoredSettings::getInstance()->setLastProjects (projects); +} + +void MainWindowList::reopenLastProjects() +{ + Array projects (StoredSettings::getInstance()->getLastProjects()); + + for (int i = 0; i < projects.size(); ++ i) + openFile (projects.getReference(i)); +} diff --git a/extras/Introjucer/Source/Application/jucer_MainWindow.h b/extras/Introjucer/Source/Application/jucer_MainWindow.h index 613e07f07b..d682c5bd9e 100644 --- a/extras/Introjucer/Source/Application/jucer_MainWindow.h +++ b/extras/Introjucer/Source/Application/jucer_MainWindow.h @@ -91,5 +91,34 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow); }; +//============================================================================== +class MainWindowList +{ +public: + MainWindowList(); + + void forceCloseAllWindows(); + bool askAllWindowsToClose(); + void closeWindow (MainWindow*); + + void createWindowIfNoneAreOpen(); + void openDocument (OpenDocumentManager::Document*); + bool openFile (const File& file); + + MainWindow* createNewMainWindow(); + MainWindow* getOrCreateFrontmostWindow(); + MainWindow* getOrCreateEmptyWindow(); + + void reopenLastProjects(); + void saveCurrentlyOpenProjectList(); + + void avoidSuperimposedWindows (MainWindow*); + + OwnedArray windows; + +private: + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindowList); +}; + #endif // __JUCER_MAINWINDOW_JUCEHEADER__ diff --git a/extras/Introjucer/Source/Project/jucer_NewProjectWizard.cpp b/extras/Introjucer/Source/Project/jucer_NewProjectWizard.cpp index b3f5c3d0a5..19c3d1ad3b 100644 --- a/extras/Introjucer/Source/Project/jucer_NewProjectWizard.cpp +++ b/extras/Introjucer/Source/Project/jucer_NewProjectWizard.cpp @@ -491,7 +491,7 @@ public: MainWindow* mw = dynamic_cast (getTopLevelComponent()); jassert (mw != nullptr); - JucerApplication::getApp()->closeWindow (mw); + JucerApplication::getApp()->mainWindowList.closeWindow (mw); } } diff --git a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index f8c534b528..a71409a32e 100644 --- a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -387,10 +387,7 @@ public: const Rectangle screen (getFrameSize().subtractedFrom (component->getParentMonitorArea())); const Rectangle window (component->getScreenBounds()); - fullScreen = std::abs (screen.getX() - window.getX()) <= 2 - && std::abs (screen.getY() - window.getY()) <= 2 - && std::abs (screen.getRight() - window.getRight()) <= 2 - && std::abs (screen.getBottom() - window.getBottom()) <= 2; + fullScreen = window.expanded (2, 2).contains (screen); } } diff --git a/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp b/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp index 8dcffdd556..423b221399 100644 --- a/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp +++ b/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp @@ -303,8 +303,7 @@ int DocumentWindow::getDesktopWindowStyleFlags() const void DocumentWindow::lookAndFeelChanged() { - int i; - for (i = numElementsInArray (titleBarButtons); --i >= 0;) + for (int i = numElementsInArray (titleBarButtons); --i >= 0;) titleBarButtons[i] = nullptr; if (! isUsingNativeTitleBar()) @@ -320,7 +319,7 @@ void DocumentWindow::lookAndFeelChanged() if ((requiredButtons & closeButton) != 0) titleBarButtons[2] = lf.createDocumentWindowButton (closeButton); - for (i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { if (titleBarButtons[i] != nullptr) { diff --git a/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp b/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp index 4cf0412167..cfacbd8553 100644 --- a/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp +++ b/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp @@ -171,6 +171,11 @@ void TopLevelWindow::activeWindowStatusChanged() { } +bool TopLevelWindow::isUsingNativeTitleBar() const noexcept +{ + return useNativeTitleBar && (isOnDesktop() || ! isShowing()); +} + void TopLevelWindow::visibilityChanged() { if (isShowing() diff --git a/modules/juce_gui_basics/windows/juce_TopLevelWindow.h b/modules/juce_gui_basics/windows/juce_TopLevelWindow.h index fac5bffd56..5664cc3bdc 100644 --- a/modules/juce_gui_basics/windows/juce_TopLevelWindow.h +++ b/modules/juce_gui_basics/windows/juce_TopLevelWindow.h @@ -101,33 +101,28 @@ public: bool isDropShadowEnabled() const noexcept { return useDropShadow; } /** Sets whether an OS-native title bar will be used, or a Juce one. - @see isUsingNativeTitleBar */ void setUsingNativeTitleBar (bool useNativeTitleBar); /** Returns true if the window is currently using an OS-native title bar. - @see setUsingNativeTitleBar */ - bool isUsingNativeTitleBar() const noexcept { return useNativeTitleBar && isOnDesktop(); } + bool isUsingNativeTitleBar() const noexcept; //============================================================================== /** Returns the number of TopLevelWindow objects currently in use. - @see getTopLevelWindow */ static int getNumTopLevelWindows() noexcept; /** Returns one of the TopLevelWindow objects currently in use. - The index is 0 to (getNumTopLevelWindows() - 1). */ static TopLevelWindow* getTopLevelWindow (int index) noexcept; /** Returns the currently-active top level window. - - There might not be one, of course, so this can return 0. + There might not be one, of course, so this can return nullptr. */ static TopLevelWindow* getActiveTopLevelWindow() noexcept; @@ -139,7 +134,6 @@ public: protected: //============================================================================== /** This callback happens when this window becomes active or inactive. - @see isActiveWindow */ virtual void activeWindowStatusChanged();