File indexing completed on 2024-05-12 16:01:58
0001 /* 0002 * SPDX-FileCopyrightText: 2018 Jouni Pentikäinen <joupent@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "KisWindowLayoutManager.h" 0008 0009 #include <QWidget> 0010 #include <QDesktopWidget> 0011 #include <QScreen> 0012 0013 #include <kconfiggroup.h> 0014 #include <ksharedconfig.h> 0015 0016 #include <KisApplication.h> 0017 #include <KisMainWindow.h> 0018 #include <KisPart.h> 0019 #include <kis_dom_utils.h> 0020 #include <KisResourceServerProvider.h> 0021 #include <KisSessionResource.h> 0022 0023 Q_GLOBAL_STATIC(KisWindowLayoutManager, s_instance) 0024 0025 struct KisWindowLayoutManager::Private { 0026 bool showImageInAllWindows{false}; 0027 bool primaryWorkspaceFollowsFocus{false}; 0028 QUuid primaryWindow; 0029 0030 QVector<DisplayLayout*> displayLayouts; 0031 0032 void loadDisplayLayouts() { 0033 KConfigGroup layoutsCfg(KSharedConfig::openConfig(), "DisplayLayouts"); 0034 QStringList groups = layoutsCfg.groupList(); 0035 0036 Q_FOREACH(QString name, groups) { 0037 loadDisplayLayout(name, layoutsCfg.group(name)); 0038 } 0039 } 0040 0041 void loadDisplayLayout(const QString &name, KConfigGroup layoutCfg) { 0042 DisplayLayout *layout = new DisplayLayout(); 0043 layout->name = name; 0044 0045 int displayNumber = 1; 0046 0047 while (true) { 0048 const QString displayDefinition = layoutCfg.readEntry(QString("Display%1").arg(displayNumber++), QString()); 0049 if (displayDefinition.isEmpty()) break; 0050 0051 // Just the resolution for now. Later we might want to split by a separator and include things like serial number, etc. 0052 const QString &resolutionStr = displayDefinition; 0053 0054 QStringList dimensions = resolutionStr.split('x'); 0055 if (dimensions.size() != 2) { 0056 qWarning() << "Invalid display definition: " << displayDefinition; 0057 break; 0058 } 0059 0060 QSize resolution = QSize( 0061 KisDomUtils::toInt(dimensions[0]), 0062 KisDomUtils::toInt(dimensions[1]) 0063 ); 0064 0065 layout->displays.append(Display{resolution}); 0066 } 0067 0068 layout->preferredWindowLayout = layoutCfg.readEntry("PreferredLayout", ""); 0069 0070 displayLayouts.append(layout); 0071 } 0072 0073 void saveDisplayLayout(const DisplayLayout &layout) { 0074 KConfigGroup layoutsCfg(KSharedConfig::openConfig(), "DisplayLayouts"); 0075 KConfigGroup layoutCfg = layoutsCfg.group(layout.name); 0076 layoutCfg.writeEntry("PreferredLayout", layout.preferredWindowLayout); 0077 } 0078 }; 0079 0080 bool KisWindowLayoutManager::Display::matches(QScreen* screen) const 0081 { 0082 return resolution == screen->geometry().size(); 0083 } 0084 0085 bool KisWindowLayoutManager::DisplayLayout::matches(QList<QScreen*> screens) const 0086 { 0087 if (screens.size() != displays.size()) return false; 0088 0089 QVector<bool> matchedScreens(screens.size()); 0090 Q_FOREACH(auto &expectedDisplay, displays) { 0091 int i; 0092 for (i = 0; i < screens.size(); i++) { 0093 if (matchedScreens[i]) continue; 0094 0095 if (expectedDisplay.matches(screens[i])) { 0096 matchedScreens[i] = true; 0097 break; 0098 } 0099 } 0100 0101 if (i == screens.size()) { 0102 return false; 0103 } 0104 } 0105 0106 return true; 0107 } 0108 0109 KisWindowLayoutManager * KisWindowLayoutManager::instance() 0110 { 0111 return s_instance; 0112 } 0113 0114 KisWindowLayoutManager::KisWindowLayoutManager() 0115 : d(new Private) 0116 { 0117 d->loadDisplayLayouts(); 0118 0119 connect(qobject_cast<KisApplication*>(KisApplication::instance()), 0120 SIGNAL(focusChanged(QWidget*,QWidget*)), 0121 this, SLOT(slotFocusChanged(QWidget*,QWidget*))); 0122 0123 connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(slotScreensChanged())); 0124 connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), this, SLOT(slotScreensChanged())); 0125 } 0126 0127 KisWindowLayoutManager::~KisWindowLayoutManager() { 0128 Q_FOREACH(DisplayLayout *layout, d->displayLayouts) { 0129 delete layout; 0130 } 0131 } 0132 0133 void KisWindowLayoutManager::setShowImageInAllWindowsEnabled(bool showInAll) 0134 { 0135 bool wasEnabled = d->showImageInAllWindows; 0136 0137 d->showImageInAllWindows = showInAll; 0138 0139 if (!wasEnabled && showInAll) { 0140 KisMainWindow *currentMainWindow = KisPart::instance()->currentMainwindow(); 0141 if (currentMainWindow) { 0142 KisView *activeView = currentMainWindow->activeView(); 0143 if (activeView) { 0144 KisDocument *document = activeView->document(); 0145 if (document) { 0146 activeDocumentChanged(document); 0147 } 0148 } 0149 } 0150 } 0151 } 0152 0153 bool KisWindowLayoutManager::isShowImageInAllWindowsEnabled() const 0154 { 0155 return d->showImageInAllWindows; 0156 } 0157 0158 bool KisWindowLayoutManager::primaryWorkspaceFollowsFocus() const 0159 { 0160 return d->primaryWorkspaceFollowsFocus; 0161 } 0162 0163 void KisWindowLayoutManager::setPrimaryWorkspaceFollowsFocus(bool enabled, QUuid primaryWindow) 0164 { 0165 d->primaryWorkspaceFollowsFocus = enabled; 0166 d->primaryWindow = primaryWindow; 0167 } 0168 0169 QUuid KisWindowLayoutManager::primaryWindowId() const 0170 { 0171 return d->primaryWindow; 0172 } 0173 0174 void KisWindowLayoutManager::activeDocumentChanged(KisDocument *document) 0175 { 0176 if (d->showImageInAllWindows) { 0177 Q_FOREACH(QPointer<KisMainWindow> window, KisPart::instance()->mainWindows()) { 0178 if (window->isHidden()) continue; 0179 0180 const auto view = window->activeView(); 0181 if (!view || view->document() != document) { 0182 window->showDocument(document); 0183 } 0184 } 0185 } 0186 } 0187 0188 void KisWindowLayoutManager::slotFocusChanged(QWidget *old, QWidget *now) 0189 { 0190 Q_UNUSED(old); 0191 0192 if (!now) return; 0193 KisMainWindow *newMainWindow = qobject_cast<KisMainWindow*>(now->window()); 0194 if (!newMainWindow) return; 0195 0196 newMainWindow->windowFocused(); 0197 } 0198 0199 void KisWindowLayoutManager::setLastUsedLayout(KisWindowLayoutResource *layout) 0200 { 0201 // For automatic switching, only allow a window layout proper 0202 KisSessionResource *session = dynamic_cast<KisSessionResource*>(layout); 0203 if (session) return; 0204 0205 QList<QScreen*> screens = QGuiApplication::screens(); 0206 Q_FOREACH(DisplayLayout *displayLayout, d->displayLayouts) { 0207 if (displayLayout->matches(screens)) { 0208 displayLayout->preferredWindowLayout = layout->name(); 0209 d->saveDisplayLayout(*displayLayout); 0210 break; 0211 } 0212 } 0213 } 0214 0215 void KisWindowLayoutManager::slotScreensChanged() 0216 { 0217 QList<QScreen*> screens = QGuiApplication::screens(); 0218 0219 Q_FOREACH(const DisplayLayout *displayLayout, d->displayLayouts) { 0220 if (displayLayout->matches(screens)) { 0221 KoResourceServer<KisWindowLayoutResource> *windowLayoutServer = KisResourceServerProvider::instance()->windowLayoutServer(); 0222 KisWindowLayoutResourceSP layout = windowLayoutServer->resource("", "", displayLayout->preferredWindowLayout); 0223 0224 if (layout) { 0225 setLastUsedLayout(layout.data()); 0226 layout->applyLayout(); 0227 return; 0228 } 0229 } 0230 } 0231 }