File indexing completed on 2024-11-10 04:57:54
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, [this, window]() { 0042 saveGeometry(window); 0043 }); 0044 connect(window, &Window::maximizedChanged, this, [this, window]() { 0045 saveMaximize(window); 0046 }); 0047 connect(window, &Window::quickTileModeChanged, this, [this, window]() { 0048 saveQuickTile(window); 0049 }); 0050 connect(window, &Window::fullScreenChanged, this, [this, window]() { 0051 saveFullscreen(window); 0052 }); 0053 connect(window, &Window::interactiveMoveResizeFinished, this, [this, window]() { 0054 saveInteractionCounter(window); 0055 }); 0056 WindowData data = dataForWindow(window); 0057 m_data[m_currentKey][window] = data; 0058 m_savedWindows.push_back(window); 0059 } 0060 0061 void PlacementTracker::remove(Window *window) 0062 { 0063 if (m_savedWindows.contains(window)) { 0064 disconnect(window, nullptr, this, nullptr); 0065 for (auto &dataMap : m_data) { 0066 dataMap.remove(window); 0067 } 0068 m_savedWindows.removeOne(window); 0069 } 0070 } 0071 0072 void PlacementTracker::restore(const QString &key) 0073 { 0074 if (key == m_currentKey) { 0075 return; 0076 } 0077 auto &dataMap = m_data[key]; 0078 auto &oldDataMap = m_data[m_currentKey]; 0079 const auto outputs = m_workspace->outputs(); 0080 0081 inhibit(); 0082 for (const auto window : std::as_const(m_savedWindows)) { 0083 const auto it = dataMap.find(window); 0084 if (it != dataMap.end()) { 0085 const WindowData &newData = it.value(); 0086 0087 // don't touch windows where the user intentionally changed their state 0088 bool restore = window->interactiveMoveResizeCount() == newData.interactiveMoveResizeCount 0089 && window->requestedMaximizeMode() == newData.maximize 0090 && window->quickTileMode() == newData.quickTile 0091 && window->isFullScreen() == newData.fullscreen; 0092 if (!restore) { 0093 // the logic above can have false negatives if PlacementTracker changed the window state 0094 // to prevent that, also restore if the window still has the same state from that 0095 if (const auto it = m_lastRestoreData.find(window); it != m_lastRestoreData.end()) { 0096 restore = window->interactiveMoveResizeCount() == it->interactiveMoveResizeCount 0097 && window->requestedMaximizeMode() == it->maximize 0098 && window->quickTileMode() == it->quickTile 0099 && window->isFullScreen() == it->fullscreen 0100 && window->moveResizeOutput()->uuid() == it->outputUuid; 0101 } 0102 } 0103 if (!restore) { 0104 // restore anyways if the output the window was on got removed 0105 if (const auto oldData = oldDataMap.find(window); oldData != oldDataMap.end()) { 0106 restore = std::none_of(outputs.begin(), outputs.end(), [&oldData](const auto output) { 0107 return output->uuid() == oldData->outputUuid; 0108 }); 0109 } 0110 } 0111 if (restore) { 0112 window->setFullScreen(false); 0113 window->setQuickTileMode(QuickTileFlag::None, true); 0114 window->setMaximize(false, false); 0115 if (newData.quickTile || newData.maximize) { 0116 window->moveResize(newData.geometryRestore); 0117 window->setQuickTileMode(newData.quickTile, true); 0118 window->setMaximize(newData.maximize & MaximizeMode::MaximizeVertical, newData.maximize & MaximizeMode::MaximizeHorizontal); 0119 } 0120 if (newData.fullscreen) { 0121 window->moveResize(newData.fullscreenGeometryRestore); 0122 window->setFullScreen(newData.fullscreen); 0123 } 0124 if (newData.quickTile || newData.maximize || newData.fullscreen) { 0125 // restore geometry isn't necessarily on the output the window was, so explicitly restore it 0126 const auto outputIt = std::find_if(outputs.begin(), outputs.end(), [&newData](const auto output) { 0127 return output->uuid() == newData.outputUuid; 0128 }); 0129 if (outputIt != outputs.end()) { 0130 window->sendToOutput(*outputIt); 0131 } 0132 } else { 0133 window->moveResize(newData.geometry); 0134 } 0135 m_lastRestoreData[window] = dataForWindow(window); 0136 } 0137 } 0138 // ensure data in current map is always up to date 0139 dataMap[window] = dataForWindow(window); 0140 } 0141 uninhibit(); 0142 m_currentKey = key; 0143 } 0144 0145 void PlacementTracker::init(const QString &key) 0146 { 0147 m_currentKey = key; 0148 } 0149 0150 void PlacementTracker::saveGeometry(Window *window) 0151 { 0152 if (m_inhibitCount == 0) { 0153 auto &data = m_data[m_currentKey][window]; 0154 data.geometry = window->moveResizeGeometry(); 0155 data.outputUuid = window->moveResizeOutput()->uuid(); 0156 } 0157 } 0158 0159 void PlacementTracker::saveInteractionCounter(Window *window) 0160 { 0161 if (m_inhibitCount == 0) { 0162 m_data[m_currentKey][window].interactiveMoveResizeCount = window->interactiveMoveResizeCount(); 0163 } 0164 } 0165 0166 void PlacementTracker::saveMaximize(Window *window) 0167 { 0168 if (m_inhibitCount == 0) { 0169 auto &data = m_data[m_currentKey][window]; 0170 data.maximize = window->maximizeMode(); 0171 data.geometryRestore = window->geometryRestore(); 0172 } 0173 } 0174 0175 void PlacementTracker::saveQuickTile(Window *window) 0176 { 0177 if (m_inhibitCount == 0) { 0178 auto &data = m_data[m_currentKey][window]; 0179 data.quickTile = window->quickTileMode(); 0180 data.geometryRestore = window->geometryRestore(); 0181 } 0182 } 0183 0184 void PlacementTracker::saveFullscreen(Window *window) 0185 { 0186 if (m_inhibitCount == 0) { 0187 auto &data = m_data[m_currentKey][window]; 0188 data.fullscreen = window->isFullScreen(); 0189 data.fullscreenGeometryRestore = window->fullscreenGeometryRestore(); 0190 } 0191 } 0192 0193 void PlacementTracker::inhibit() 0194 { 0195 m_inhibitCount++; 0196 } 0197 0198 void PlacementTracker::uninhibit() 0199 { 0200 Q_ASSERT(m_inhibitCount > 0); 0201 m_inhibitCount--; 0202 } 0203 } 0204 0205 #include "moc_placementtracker.cpp"