File indexing completed on 2024-11-10 04:57:51
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org> 0006 SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org> 0007 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 // own 0012 #include "netinfo.h" 0013 // kwin 0014 #include "rootinfo_filter.h" 0015 #include "virtualdesktops.h" 0016 #include "workspace.h" 0017 #include "x11window.h" 0018 // Qt 0019 #include <QDebug> 0020 0021 namespace KWin 0022 { 0023 0024 std::unique_ptr<RootInfo> RootInfo::s_self; 0025 0026 RootInfo *RootInfo::create() 0027 { 0028 Q_ASSERT(!s_self); 0029 xcb_window_t supportWindow = xcb_generate_id(kwinApp()->x11Connection()); 0030 const uint32_t values[] = {true}; 0031 xcb_create_window(kwinApp()->x11Connection(), XCB_COPY_FROM_PARENT, supportWindow, kwinApp()->x11RootWindow(), 0032 0, 0, 1, 1, 0, XCB_COPY_FROM_PARENT, 0033 XCB_COPY_FROM_PARENT, XCB_CW_OVERRIDE_REDIRECT, values); 0034 const uint32_t lowerValues[] = {XCB_STACK_MODE_BELOW}; // See usage in layers.cpp 0035 // we need to do the lower window with a roundtrip, otherwise NETRootInfo is not functioning 0036 UniqueCPtr<xcb_generic_error_t> error(xcb_request_check(kwinApp()->x11Connection(), 0037 xcb_configure_window_checked(kwinApp()->x11Connection(), supportWindow, XCB_CONFIG_WINDOW_STACK_MODE, lowerValues))); 0038 if (error) { 0039 qCDebug(KWIN_CORE) << "Error occurred while lowering support window: " << error->error_code; 0040 } 0041 0042 const NET::Properties properties = NET::Supported 0043 | NET::SupportingWMCheck 0044 | NET::ClientList 0045 | NET::ClientListStacking 0046 | NET::DesktopGeometry 0047 | NET::NumberOfDesktops 0048 | NET::CurrentDesktop 0049 | NET::ActiveWindow 0050 | NET::WorkArea 0051 | NET::CloseWindow 0052 | NET::DesktopNames 0053 | NET::WMName 0054 | NET::WMVisibleName 0055 | NET::WMDesktop 0056 | NET::WMWindowType 0057 | NET::WMState 0058 | NET::WMStrut 0059 | NET::WMIconGeometry 0060 | NET::WMIcon 0061 | NET::WMPid 0062 | NET::WMMoveResize 0063 | NET::WMFrameExtents 0064 | NET::WMPing; 0065 const NET::WindowTypes types = NET::NormalMask 0066 | NET::DesktopMask 0067 | NET::DockMask 0068 | NET::ToolbarMask 0069 | NET::MenuMask 0070 | NET::DialogMask 0071 | NET::OverrideMask 0072 | NET::UtilityMask 0073 | NET::SplashMask; // No compositing window types here unless we support them also as managed window types 0074 const NET::States states = NET::Modal 0075 // | NET::Sticky // Large desktops not supported (and probably never will be) 0076 | NET::MaxVert 0077 | NET::MaxHoriz 0078 | NET::Shaded 0079 | NET::SkipTaskbar 0080 | NET::KeepAbove 0081 // | NET::StaysOnTop // The same like KeepAbove 0082 | NET::SkipPager 0083 | NET::Hidden 0084 | NET::FullScreen 0085 | NET::KeepBelow 0086 | NET::DemandsAttention 0087 | NET::SkipSwitcher 0088 | NET::Focused; 0089 NET::Properties2 properties2 = NET::WM2UserTime 0090 | NET::WM2StartupId 0091 | NET::WM2AllowedActions 0092 | NET::WM2RestackWindow 0093 | NET::WM2MoveResizeWindow 0094 | NET::WM2ExtendedStrut 0095 | NET::WM2ShowingDesktop 0096 | NET::WM2DesktopLayout 0097 | NET::WM2FullPlacement 0098 | NET::WM2FullscreenMonitors 0099 | NET::WM2KDEShadow 0100 | NET::WM2OpaqueRegion 0101 | NET::WM2GTKFrameExtents 0102 | NET::WM2GTKShowWindowMenu 0103 | NET::WM2Opacity; 0104 #if KWIN_BUILD_ACTIVITIES 0105 properties2 |= NET::WM2Activities; 0106 #endif 0107 const NET::Actions actions = NET::ActionMove 0108 | NET::ActionResize 0109 | NET::ActionMinimize 0110 | NET::ActionShade 0111 // | NET::ActionStick // Sticky state is not supported 0112 | NET::ActionMaxVert 0113 | NET::ActionMaxHoriz 0114 | NET::ActionFullScreen 0115 | NET::ActionChangeDesktop 0116 | NET::ActionClose; 0117 0118 s_self = std::make_unique<RootInfo>(supportWindow, "KWin", properties, types, states, properties2, actions); 0119 return s_self.get(); 0120 } 0121 0122 void RootInfo::destroy() 0123 { 0124 if (!s_self) { 0125 return; 0126 } 0127 xcb_window_t supportWindow = s_self->supportWindow(); 0128 s_self.reset(); 0129 xcb_destroy_window(kwinApp()->x11Connection(), supportWindow); 0130 } 0131 0132 RootInfo::RootInfo(xcb_window_t w, const char *name, NET::Properties properties, NET::WindowTypes types, 0133 NET::States states, NET::Properties2 properties2, NET::Actions actions, int scr) 0134 : NETRootInfo(kwinApp()->x11Connection(), w, name, properties, types, states, properties2, actions, scr) 0135 , m_activeWindow(activeWindow()) 0136 , m_eventFilter(std::make_unique<RootInfoFilter>(this)) 0137 { 0138 } 0139 0140 void RootInfo::changeNumberOfDesktops(int n) 0141 { 0142 VirtualDesktopManager::self()->setCount(n); 0143 } 0144 0145 void RootInfo::changeCurrentDesktop(int d) 0146 { 0147 VirtualDesktopManager::self()->setCurrent(d); 0148 } 0149 0150 void RootInfo::changeActiveWindow(xcb_window_t w, NET::RequestSource src, xcb_timestamp_t timestamp, xcb_window_t active_window) 0151 { 0152 Workspace *workspace = Workspace::self(); 0153 if (X11Window *c = workspace->findClient(Predicate::WindowMatch, w)) { 0154 if (timestamp == XCB_CURRENT_TIME) { 0155 timestamp = c->userTime(); 0156 } 0157 if (src != NET::FromApplication && src != FromTool) { 0158 src = NET::FromTool; 0159 } 0160 if (src == NET::FromTool) { 0161 workspace->activateWindow(c, true); // force 0162 } else if (c == workspace->mostRecentlyActivatedWindow()) { 0163 return; // WORKAROUND? With > 1 plasma activities, we cause this ourselves. bug #240673 0164 } else { // NET::FromApplication 0165 X11Window *c2; 0166 if (c->allowWindowActivation(timestamp, false)) { 0167 workspace->activateWindow(c); 0168 // if activation of the requestor's window would be allowed, allow activation too 0169 } else if (active_window != XCB_WINDOW_NONE 0170 && (c2 = workspace->findClient(Predicate::WindowMatch, active_window)) != nullptr 0171 && c2->allowWindowActivation(timestampCompare(timestamp, c2->userTime() > 0 ? timestamp : c2->userTime()), false)) { 0172 workspace->activateWindow(c); 0173 } else { 0174 c->demandAttention(); 0175 } 0176 } 0177 } 0178 } 0179 0180 void RootInfo::restackWindow(xcb_window_t w, RequestSource src, xcb_window_t above, int detail, xcb_timestamp_t timestamp) 0181 { 0182 if (X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w)) { 0183 if (timestamp == XCB_CURRENT_TIME) { 0184 timestamp = c->userTime(); 0185 } 0186 if (src != NET::FromApplication && src != FromTool) { 0187 src = NET::FromTool; 0188 } 0189 c->restackWindow(above, detail, src, timestamp, true); 0190 } 0191 } 0192 0193 void RootInfo::closeWindow(xcb_window_t w) 0194 { 0195 X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w); 0196 if (c) { 0197 c->closeWindow(); 0198 } 0199 } 0200 0201 void RootInfo::moveResize(xcb_window_t w, int x_root, int y_root, unsigned long direction) 0202 { 0203 X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w); 0204 if (c) { 0205 kwinApp()->updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp 0206 c->NETMoveResize(Xcb::fromXNative(x_root), Xcb::fromXNative(y_root), (Direction)direction); 0207 } 0208 } 0209 0210 void RootInfo::moveResizeWindow(xcb_window_t w, int flags, int x, int y, int width, int height) 0211 { 0212 X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w); 0213 if (c) { 0214 c->NETMoveResizeWindow(flags, Xcb::fromXNative(x), Xcb::fromXNative(y), Xcb::fromXNative(width), Xcb::fromXNative(height)); 0215 } 0216 } 0217 0218 void RootInfo::showWindowMenu(xcb_window_t w, int device_id, int x_root, int y_root) 0219 { 0220 if (X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w)) { 0221 c->GTKShowWindowMenu(Xcb::fromXNative(x_root), Xcb::fromXNative(y_root)); 0222 } 0223 } 0224 0225 void RootInfo::gotPing(xcb_window_t w, xcb_timestamp_t timestamp) 0226 { 0227 if (X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w)) { 0228 c->gotPing(timestamp); 0229 } 0230 } 0231 0232 void RootInfo::changeShowingDesktop(bool showing) 0233 { 0234 Workspace::self()->setShowingDesktop(showing); 0235 } 0236 0237 void RootInfo::setActiveClient(Window *client) 0238 { 0239 xcb_window_t windowId = XCB_WINDOW_NONE; 0240 if (auto x11Window = qobject_cast<X11Window *>(client)) { 0241 windowId = x11Window->window(); 0242 } 0243 if (m_activeWindow == windowId) { 0244 return; 0245 } 0246 m_activeWindow = windowId; 0247 setActiveWindow(m_activeWindow); 0248 } 0249 0250 // **************************************** 0251 // WinInfo 0252 // **************************************** 0253 0254 WinInfo::WinInfo(X11Window *c, xcb_window_t window, 0255 xcb_window_t rwin, NET::Properties properties, NET::Properties2 properties2) 0256 : NETWinInfo(kwinApp()->x11Connection(), window, rwin, properties, properties2, NET::WindowManager) 0257 , m_client(c) 0258 { 0259 } 0260 0261 void WinInfo::changeDesktop(int desktopId) 0262 { 0263 if (VirtualDesktop *desktop = VirtualDesktopManager::self()->desktopForX11Id(desktopId)) { 0264 Workspace::self()->sendWindowToDesktops(m_client, {desktop}, true); 0265 } 0266 } 0267 0268 void WinInfo::changeFullscreenMonitors(NETFullscreenMonitors topology) 0269 { 0270 m_client->updateFullscreenMonitors(topology); 0271 } 0272 0273 void WinInfo::changeState(NET::States state, NET::States mask) 0274 { 0275 mask &= ~NET::Sticky; // KWin doesn't support large desktops, ignore 0276 mask &= ~NET::Hidden; // clients are not allowed to change this directly 0277 state &= mask; // for safety, clear all other bits 0278 0279 if ((mask & NET::FullScreen) != 0 && (state & NET::FullScreen) == 0) { 0280 m_client->setFullScreen(false); 0281 } 0282 if ((mask & NET::Max) == NET::Max) { 0283 m_client->setMaximize(state & NET::MaxVert, state & NET::MaxHoriz); 0284 } else if (mask & NET::MaxVert) { 0285 m_client->setMaximize(state & NET::MaxVert, m_client->maximizeMode() & MaximizeHorizontal); 0286 } else if (mask & NET::MaxHoriz) { 0287 m_client->setMaximize(m_client->maximizeMode() & MaximizeVertical, state & NET::MaxHoriz); 0288 } 0289 0290 if (mask & NET::Shaded) { 0291 m_client->setShade(state & NET::Shaded ? ShadeNormal : ShadeNone); 0292 } 0293 if (mask & NET::KeepAbove) { 0294 m_client->setKeepAbove((state & NET::KeepAbove) != 0); 0295 } 0296 if (mask & NET::KeepBelow) { 0297 m_client->setKeepBelow((state & NET::KeepBelow) != 0); 0298 } 0299 if (mask & NET::SkipTaskbar) { 0300 m_client->setOriginalSkipTaskbar((state & NET::SkipTaskbar) != 0); 0301 } 0302 if (mask & NET::SkipPager) { 0303 m_client->setSkipPager((state & NET::SkipPager) != 0); 0304 } 0305 if (mask & NET::SkipSwitcher) { 0306 m_client->setSkipSwitcher((state & NET::SkipSwitcher) != 0); 0307 } 0308 if (mask & NET::DemandsAttention) { 0309 m_client->demandAttention((state & NET::DemandsAttention) != 0); 0310 } 0311 if (mask & NET::Modal) { 0312 m_client->setModal((state & NET::Modal) != 0); 0313 } 0314 // unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() ) 0315 if ((mask & NET::FullScreen) != 0 && (state & NET::FullScreen) != 0) { 0316 m_client->setFullScreen(true); 0317 } 0318 } 0319 0320 void WinInfo::disable() 0321 { 0322 m_client = nullptr; // only used when the object is passed to Deleted 0323 } 0324 0325 } // namespace