Warning, file /plasma/kwin/src/placementtracker.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "placementtracker.h" 0010 #include "core/output.h" 0011 #include "window.h" 0012 #include "workspace.h" 0013 0014 namespace KWin 0015 { 0016 0017 PlacementTracker::PlacementTracker(Workspace *workspace) 0018 : m_workspace(workspace) 0019 { 0020 } 0021 0022 PlacementTracker::WindowData PlacementTracker::dataForWindow(Window *window) const 0023 { 0024 return WindowData{ 0025 .outputUuid = window->moveResizeOutput()->uuid(), 0026 .geometry = window->moveResizeGeometry(), 0027 .maximize = window->requestedMaximizeMode(), 0028 .quickTile = window->quickTileMode(), 0029 .geometryRestore = window->geometryRestore(), 0030 .fullscreen = window->isFullScreen(), 0031 .fullscreenGeometryRestore = window->fullscreenGeometryRestore(), 0032 .interactiveMoveResizeCount = window->interactiveMoveResizeCount(), 0033 }; 0034 } 0035 0036 void PlacementTracker::add(Window *window) 0037 { 0038 if (window->isUnmanaged() || window->isAppletPopup() || window->isSpecialWindow()) { 0039 return; 0040 } 0041 connect(window, &Window::frameGeometryChanged, this, &PlacementTracker::saveGeometry); 0042 connect(window, qOverload<Window *, MaximizeMode>(&Window::clientMaximizedStateChanged), this, &PlacementTracker::saveMaximize); 0043 connect(window, &Window::quickTileModeChanged, this, &PlacementTracker::saveQuickTile); 0044 connect(window, &Window::fullScreenChanged, this, &PlacementTracker::saveFullscreen); 0045 connect(window, &Window::clientFinishUserMovedResized, this, &PlacementTracker::saveInteractionCounter); 0046 WindowData data = dataForWindow(window); 0047 m_data[m_currentKey][window] = data; 0048 m_savedWindows.push_back(window); 0049 } 0050 0051 void PlacementTracker::remove(Window *window) 0052 { 0053 if (m_savedWindows.contains(window)) { 0054 disconnect(window, &Window::frameGeometryChanged, this, &PlacementTracker::saveGeometry); 0055 disconnect(window, qOverload<Window *, MaximizeMode>(&Window::clientMaximizedStateChanged), this, &PlacementTracker::saveMaximize); 0056 disconnect(window, &Window::quickTileModeChanged, this, &PlacementTracker::saveQuickTile); 0057 disconnect(window, &Window::fullScreenChanged, this, &PlacementTracker::saveFullscreen); 0058 disconnect(window, &Window::clientFinishUserMovedResized, this, &PlacementTracker::saveInteractionCounter); 0059 for (auto &dataMap : m_data) { 0060 dataMap.remove(window); 0061 } 0062 m_savedWindows.removeOne(window); 0063 } 0064 } 0065 0066 void PlacementTracker::restore(const QString &key) 0067 { 0068 if (key == m_currentKey) { 0069 return; 0070 } 0071 auto &dataMap = m_data[key]; 0072 auto &oldDataMap = m_data[m_currentKey]; 0073 const auto outputs = m_workspace->outputs(); 0074 0075 inhibit(); 0076 for (const auto window : std::as_const(m_savedWindows)) { 0077 const auto it = dataMap.find(window); 0078 if (it != dataMap.end()) { 0079 const WindowData &newData = it.value(); 0080 0081 // don't touch windows where the user intentionally changed their state 0082 bool restore = window->interactiveMoveResizeCount() == newData.interactiveMoveResizeCount 0083 && window->requestedMaximizeMode() == newData.maximize 0084 && window->quickTileMode() == newData.quickTile 0085 && window->isFullScreen() == newData.fullscreen; 0086 if (!restore) { 0087 // the logic above can have false negatives if PlacementTracker changed the window state 0088 // to prevent that, also restore if the window still has the same state from that 0089 if (const auto it = m_lastRestoreData.find(window); it != m_lastRestoreData.end()) { 0090 restore = window->interactiveMoveResizeCount() == it->interactiveMoveResizeCount 0091 && window->requestedMaximizeMode() == it->maximize 0092 && window->quickTileMode() == it->quickTile 0093 && window->isFullScreen() == it->fullscreen 0094 && window->moveResizeOutput()->uuid() == it->outputUuid; 0095 } 0096 } 0097 if (!restore) { 0098 // restore anyways if the output the window was on got removed 0099 if (const auto oldData = oldDataMap.find(window); oldData != oldDataMap.end()) { 0100 restore = std::none_of(outputs.begin(), outputs.end(), [&oldData](const auto output) { 0101 return output->uuid() == oldData->outputUuid; 0102 }); 0103 } 0104 } 0105 if (restore) { 0106 window->setFullScreen(false); 0107 window->setQuickTileMode(QuickTileFlag::None, true); 0108 window->setMaximize(false, false); 0109 if (newData.quickTile || newData.maximize) { 0110 window->moveResize(newData.geometryRestore); 0111 window->setQuickTileMode(newData.quickTile, true); 0112 window->setMaximize(newData.maximize & MaximizeMode::MaximizeVertical, newData.maximize & MaximizeMode::MaximizeHorizontal); 0113 } 0114 if (newData.fullscreen) { 0115 window->moveResize(newData.fullscreenGeometryRestore); 0116 window->setFullScreen(newData.fullscreen); 0117 } 0118 if (newData.quickTile || newData.maximize || newData.fullscreen) { 0119 // restore geometry isn't necessarily on the output the window was, so explicitly restore it 0120 const auto outputIt = std::find_if(outputs.begin(), outputs.end(), [&newData](const auto output) { 0121 return output->uuid() == newData.outputUuid; 0122 }); 0123 if (outputIt != outputs.end()) { 0124 window->sendToOutput(*outputIt); 0125 } 0126 } else { 0127 window->moveResize(newData.geometry); 0128 } 0129 m_lastRestoreData[window] = dataForWindow(window); 0130 } 0131 } 0132 // ensure data in current map is always up to date 0133 dataMap[window] = dataForWindow(window); 0134 } 0135 uninhibit(); 0136 m_currentKey = key; 0137 } 0138 0139 void PlacementTracker::init(const QString &key) 0140 { 0141 m_currentKey = key; 0142 } 0143 0144 void PlacementTracker::saveGeometry(Window *window) 0145 { 0146 if (m_inhibitCount == 0) { 0147 auto &data = m_data[m_currentKey][window]; 0148 data.geometry = window->moveResizeGeometry(); 0149 data.outputUuid = window->moveResizeOutput()->uuid(); 0150 } 0151 } 0152 0153 void PlacementTracker::saveInteractionCounter(Window *window) 0154 { 0155 if (m_inhibitCount == 0) { 0156 m_data[m_currentKey][window].interactiveMoveResizeCount = window->interactiveMoveResizeCount(); 0157 } 0158 } 0159 0160 void PlacementTracker::saveMaximize(Window *window, MaximizeMode mode) 0161 { 0162 if (m_inhibitCount == 0) { 0163 auto &data = m_data[m_currentKey][window]; 0164 data.maximize = mode; 0165 data.geometryRestore = window->geometryRestore(); 0166 } 0167 } 0168 0169 void PlacementTracker::saveQuickTile() 0170 { 0171 Window *window = qobject_cast<Window *>(QObject::sender()); 0172 Q_ASSERT(window); 0173 if (m_inhibitCount == 0) { 0174 auto &data = m_data[m_currentKey][window]; 0175 data.quickTile = window->quickTileMode(); 0176 data.geometryRestore = window->geometryRestore(); 0177 } 0178 } 0179 0180 void PlacementTracker::saveFullscreen() 0181 { 0182 Window *window = qobject_cast<Window *>(QObject::sender()); 0183 Q_ASSERT(window); 0184 if (m_inhibitCount == 0) { 0185 auto &data = m_data[m_currentKey][window]; 0186 data.fullscreen = window->isFullScreen(); 0187 data.fullscreenGeometryRestore = window->fullscreenGeometryRestore(); 0188 } 0189 } 0190 0191 void PlacementTracker::inhibit() 0192 { 0193 m_inhibitCount++; 0194 } 0195 0196 void PlacementTracker::uninhibit() 0197 { 0198 Q_ASSERT(m_inhibitCount > 0); 0199 m_inhibitCount--; 0200 } 0201 }