File indexing completed on 2024-04-28 16:48:55

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::WM2KDETemporaryRules
0096         | NET::WM2ShowingDesktop
0097         | NET::WM2DesktopLayout
0098         | NET::WM2FullPlacement
0099         | NET::WM2FullscreenMonitors
0100         | NET::WM2KDEShadow
0101         | NET::WM2OpaqueRegion
0102         | NET::WM2GTKFrameExtents
0103         | NET::WM2GTKShowWindowMenu
0104         | NET::WM2Opacity;
0105 #if KWIN_BUILD_ACTIVITIES
0106     properties2 |= NET::WM2Activities;
0107 #endif
0108     const NET::Actions actions = NET::ActionMove
0109         | NET::ActionResize
0110         | NET::ActionMinimize
0111         | NET::ActionShade
0112         // | NET::ActionStick // Sticky state is not supported
0113         | NET::ActionMaxVert
0114         | NET::ActionMaxHoriz
0115         | NET::ActionFullScreen
0116         | NET::ActionChangeDesktop
0117         | NET::ActionClose;
0118 
0119     s_self.reset(new RootInfo(supportWindow, "KWin", properties, types, states, properties2, actions));
0120     return s_self.get();
0121 }
0122 
0123 void RootInfo::destroy()
0124 {
0125     if (!s_self) {
0126         return;
0127     }
0128     xcb_window_t supportWindow = s_self->supportWindow();
0129     s_self.reset();
0130     xcb_destroy_window(kwinApp()->x11Connection(), supportWindow);
0131 }
0132 
0133 RootInfo::RootInfo(xcb_window_t w, const char *name, NET::Properties properties, NET::WindowTypes types,
0134                    NET::States states, NET::Properties2 properties2, NET::Actions actions, int scr)
0135     : NETRootInfo(kwinApp()->x11Connection(), w, name, properties, types, states, properties2, actions, scr)
0136     , m_activeWindow(activeWindow())
0137     , m_eventFilter(std::make_unique<RootInfoFilter>(this))
0138 {
0139 }
0140 
0141 void RootInfo::changeNumberOfDesktops(int n)
0142 {
0143     VirtualDesktopManager::self()->setCount(n);
0144 }
0145 
0146 void RootInfo::changeCurrentDesktop(int d)
0147 {
0148     VirtualDesktopManager::self()->setCurrent(d);
0149 }
0150 
0151 void RootInfo::changeActiveWindow(xcb_window_t w, NET::RequestSource src, xcb_timestamp_t timestamp, xcb_window_t active_window)
0152 {
0153     Workspace *workspace = Workspace::self();
0154     if (X11Window *c = workspace->findClient(Predicate::WindowMatch, w)) {
0155         if (timestamp == XCB_CURRENT_TIME) {
0156             timestamp = c->userTime();
0157         }
0158         if (src != NET::FromApplication && src != FromTool) {
0159             src = NET::FromTool;
0160         }
0161         if (src == NET::FromTool) {
0162             workspace->activateWindow(c, true); // force
0163         } else if (c == workspace->mostRecentlyActivatedWindow()) {
0164             return; // WORKAROUND? With > 1 plasma activities, we cause this ourselves. bug #240673
0165         } else { // NET::FromApplication
0166             X11Window *c2;
0167             if (c->allowWindowActivation(timestamp, false, true)) {
0168                 workspace->activateWindow(c);
0169                 // if activation of the requestor's window would be allowed, allow activation too
0170             } else if (active_window != XCB_WINDOW_NONE
0171                        && (c2 = workspace->findClient(Predicate::WindowMatch, active_window)) != nullptr
0172                        && c2->allowWindowActivation(timestampCompare(timestamp, c2->userTime() > 0 ? timestamp : c2->userTime()), false, true)) {
0173                 workspace->activateWindow(c);
0174             } else {
0175                 c->demandAttention();
0176             }
0177         }
0178     }
0179 }
0180 
0181 void RootInfo::restackWindow(xcb_window_t w, RequestSource src, xcb_window_t above, int detail, xcb_timestamp_t timestamp)
0182 {
0183     if (X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w)) {
0184         if (timestamp == XCB_CURRENT_TIME) {
0185             timestamp = c->userTime();
0186         }
0187         if (src != NET::FromApplication && src != FromTool) {
0188             src = NET::FromTool;
0189         }
0190         c->restackWindow(above, detail, src, timestamp, true);
0191     }
0192 }
0193 
0194 void RootInfo::closeWindow(xcb_window_t w)
0195 {
0196     X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w);
0197     if (c) {
0198         c->closeWindow();
0199     }
0200 }
0201 
0202 void RootInfo::moveResize(xcb_window_t w, int x_root, int y_root, unsigned long direction)
0203 {
0204     X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w);
0205     if (c) {
0206         kwinApp()->updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp
0207         c->NETMoveResize(Xcb::fromXNative(x_root), Xcb::fromXNative(y_root), (Direction)direction);
0208     }
0209 }
0210 
0211 void RootInfo::moveResizeWindow(xcb_window_t w, int flags, int x, int y, int width, int height)
0212 {
0213     X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w);
0214     if (c) {
0215         c->NETMoveResizeWindow(flags, Xcb::fromXNative(x), Xcb::fromXNative(y), Xcb::fromXNative(width), Xcb::fromXNative(height));
0216     }
0217 }
0218 
0219 void RootInfo::showWindowMenu(xcb_window_t w, int device_id, int x_root, int y_root)
0220 {
0221     if (X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w)) {
0222         c->GTKShowWindowMenu(Xcb::fromXNative(x_root), Xcb::fromXNative(y_root));
0223     }
0224 }
0225 
0226 void RootInfo::gotPing(xcb_window_t w, xcb_timestamp_t timestamp)
0227 {
0228     if (X11Window *c = Workspace::self()->findClient(Predicate::WindowMatch, w)) {
0229         c->gotPing(timestamp);
0230     }
0231 }
0232 
0233 void RootInfo::changeShowingDesktop(bool showing)
0234 {
0235     Workspace::self()->setShowingDesktop(showing);
0236 }
0237 
0238 void RootInfo::setActiveClient(Window *client)
0239 {
0240     const xcb_window_t w = client ? client->window() : xcb_window_t{XCB_WINDOW_NONE};
0241     if (m_activeWindow == w) {
0242         return;
0243     }
0244     m_activeWindow = w;
0245     setActiveWindow(m_activeWindow);
0246 }
0247 
0248 // ****************************************
0249 // WinInfo
0250 // ****************************************
0251 
0252 WinInfo::WinInfo(X11Window *c, xcb_window_t window,
0253                  xcb_window_t rwin, NET::Properties properties, NET::Properties2 properties2)
0254     : NETWinInfo(kwinApp()->x11Connection(), window, rwin, properties, properties2, NET::WindowManager)
0255     , m_client(c)
0256 {
0257 }
0258 
0259 void WinInfo::changeDesktop(int desktop)
0260 {
0261     Workspace::self()->sendWindowToDesktop(m_client, desktop, true);
0262 }
0263 
0264 void WinInfo::changeFullscreenMonitors(NETFullscreenMonitors topology)
0265 {
0266     m_client->updateFullscreenMonitors(topology);
0267 }
0268 
0269 void WinInfo::changeState(NET::States state, NET::States mask)
0270 {
0271     mask &= ~NET::Sticky; // KWin doesn't support large desktops, ignore
0272     mask &= ~NET::Hidden; // clients are not allowed to change this directly
0273     state &= mask; // for safety, clear all other bits
0274 
0275     if ((mask & NET::FullScreen) != 0 && (state & NET::FullScreen) == 0) {
0276         m_client->setFullScreen(false, false);
0277     }
0278     if ((mask & NET::Max) == NET::Max) {
0279         m_client->setMaximize(state & NET::MaxVert, state & NET::MaxHoriz);
0280     } else if (mask & NET::MaxVert) {
0281         m_client->setMaximize(state & NET::MaxVert, m_client->maximizeMode() & MaximizeHorizontal);
0282     } else if (mask & NET::MaxHoriz) {
0283         m_client->setMaximize(m_client->maximizeMode() & MaximizeVertical, state & NET::MaxHoriz);
0284     }
0285 
0286     if (mask & NET::Shaded) {
0287         m_client->setShade(state & NET::Shaded ? ShadeNormal : ShadeNone);
0288     }
0289     if (mask & NET::KeepAbove) {
0290         m_client->setKeepAbove((state & NET::KeepAbove) != 0);
0291     }
0292     if (mask & NET::KeepBelow) {
0293         m_client->setKeepBelow((state & NET::KeepBelow) != 0);
0294     }
0295     if (mask & NET::SkipTaskbar) {
0296         m_client->setOriginalSkipTaskbar((state & NET::SkipTaskbar) != 0);
0297     }
0298     if (mask & NET::SkipPager) {
0299         m_client->setSkipPager((state & NET::SkipPager) != 0);
0300     }
0301     if (mask & NET::SkipSwitcher) {
0302         m_client->setSkipSwitcher((state & NET::SkipSwitcher) != 0);
0303     }
0304     if (mask & NET::DemandsAttention) {
0305         m_client->demandAttention((state & NET::DemandsAttention) != 0);
0306     }
0307     if (mask & NET::Modal) {
0308         m_client->setModal((state & NET::Modal) != 0);
0309     }
0310     // unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() )
0311     if ((mask & NET::FullScreen) != 0 && (state & NET::FullScreen) != 0) {
0312         m_client->setFullScreen(true, false);
0313     }
0314 }
0315 
0316 void WinInfo::disable()
0317 {
0318     m_client = nullptr; // only used when the object is passed to Deleted
0319 }
0320 
0321 } // namespace