File indexing completed on 2024-11-03 13:42:34
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "unmanaged.h" 0011 0012 #include "deleted.h" 0013 #include "effects.h" 0014 #include "scene/surfaceitem_x11.h" 0015 #include "scene/windowitem.h" 0016 #include "utils/common.h" 0017 #include "wayland/surface_interface.h" 0018 #include "workspace.h" 0019 0020 #include <QDebug> 0021 #include <QTimer> 0022 #include <QWidget> 0023 #include <QWindow> 0024 0025 #include <xcb/shape.h> 0026 0027 using namespace KWaylandServer; 0028 0029 namespace KWin 0030 { 0031 0032 // window types that are supported as unmanaged (mainly for compositing) 0033 const NET::WindowTypes SUPPORTED_UNMANAGED_WINDOW_TYPES_MASK = NET::NormalMask 0034 | NET::DesktopMask 0035 | NET::DockMask 0036 | NET::ToolbarMask 0037 | NET::MenuMask 0038 | NET::DialogMask 0039 /*| NET::OverrideMask*/ 0040 | NET::TopMenuMask 0041 | NET::UtilityMask 0042 | NET::SplashMask 0043 | NET::DropdownMenuMask 0044 | NET::PopupMenuMask 0045 | NET::TooltipMask 0046 | NET::NotificationMask 0047 | NET::ComboBoxMask 0048 | NET::DNDIconMask 0049 | NET::OnScreenDisplayMask 0050 | NET::CriticalNotificationMask; 0051 0052 Unmanaged::Unmanaged() 0053 : Window() 0054 { 0055 switch (kwinApp()->operationMode()) { 0056 case Application::OperationModeXwayland: 0057 // The wayland surface is associated with the override-redirect window asynchronously. 0058 connect(this, &Window::surfaceChanged, this, &Unmanaged::associate); 0059 break; 0060 case Application::OperationModeX11: 0061 // We have no way knowing whether the override-redirect window can be painted. Mark it 0062 // as ready for painting after synthetic 50ms delay. 0063 QTimer::singleShot(50, this, &Unmanaged::initialize); 0064 break; 0065 case Application::OperationModeWaylandOnly: 0066 Q_UNREACHABLE(); 0067 } 0068 } 0069 0070 Unmanaged::~Unmanaged() 0071 { 0072 } 0073 0074 std::unique_ptr<WindowItem> Unmanaged::createItem(Scene *scene) 0075 { 0076 return std::make_unique<WindowItemX11>(this, scene); 0077 } 0078 0079 void Unmanaged::associate() 0080 { 0081 if (surface()->isMapped()) { 0082 initialize(); 0083 } else { 0084 // Queued connection because we want to mark the window ready for painting after 0085 // the associated surface item has processed the new surface state. 0086 connect(surface(), &SurfaceInterface::mapped, this, &Unmanaged::initialize, Qt::QueuedConnection); 0087 } 0088 } 0089 0090 void Unmanaged::initialize() 0091 { 0092 setReadyForPainting(); 0093 } 0094 0095 bool Unmanaged::track(xcb_window_t w) 0096 { 0097 XServerGrabber xserverGrabber; 0098 Xcb::WindowAttributes attr(w); 0099 Xcb::WindowGeometry geo(w); 0100 if (attr.isNull() || attr->map_state != XCB_MAP_STATE_VIEWABLE) { 0101 return false; 0102 } 0103 if (attr->_class == XCB_WINDOW_CLASS_INPUT_ONLY) { 0104 return false; 0105 } 0106 if (geo.isNull()) { 0107 return false; 0108 } 0109 0110 setWindowHandles(w); // the window is also the frame 0111 Xcb::selectInput(w, attr->your_event_mask | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE); 0112 m_bufferGeometry = geo.rect(); 0113 m_frameGeometry = geo.rect(); 0114 m_clientGeometry = geo.rect(); 0115 checkOutput(); 0116 m_visual = attr->visual; 0117 bit_depth = geo->depth; 0118 info = new NETWinInfo(kwinApp()->x11Connection(), w, kwinApp()->x11RootWindow(), 0119 NET::WMWindowType | NET::WMPid, 0120 NET::WM2Opacity | NET::WM2WindowRole | NET::WM2WindowClass | NET::WM2OpaqueRegion); 0121 setOpacity(info->opacityF()); 0122 getResourceClass(); 0123 getWmClientLeader(); 0124 getWmClientMachine(); 0125 if (Xcb::Extensions::self()->isShapeAvailable()) { 0126 xcb_shape_select_input(kwinApp()->x11Connection(), w, true); 0127 } 0128 detectShape(w); 0129 getWmOpaqueRegion(); 0130 getSkipCloseAnimation(); 0131 setupCompositing(); 0132 if (QWindow *internalWindow = findInternalWindow()) { 0133 m_outline = internalWindow->property("__kwin_outline").toBool(); 0134 } 0135 if (effects) { 0136 static_cast<EffectsHandlerImpl *>(effects)->checkInputWindowStacking(); 0137 } 0138 return true; 0139 } 0140 0141 void Unmanaged::release(ReleaseReason releaseReason) 0142 { 0143 Deleted *del = nullptr; 0144 if (releaseReason != ReleaseReason::KWinShutsDown) { 0145 del = Deleted::create(this); 0146 } 0147 Q_EMIT windowClosed(this, del); 0148 finishCompositing(releaseReason); 0149 if (!QWidget::find(window()) && releaseReason != ReleaseReason::Destroyed) { // don't affect our own windows 0150 if (Xcb::Extensions::self()->isShapeAvailable()) { 0151 xcb_shape_select_input(kwinApp()->x11Connection(), window(), false); 0152 } 0153 Xcb::selectInput(window(), XCB_EVENT_MASK_NO_EVENT); 0154 } 0155 workspace()->removeUnmanaged(this); 0156 if (releaseReason != ReleaseReason::KWinShutsDown) { 0157 disownDataPassedToDeleted(); 0158 del->unrefWindow(); 0159 } 0160 deleteUnmanaged(this); 0161 } 0162 0163 void Unmanaged::deleteUnmanaged(Unmanaged *c) 0164 { 0165 delete c; 0166 } 0167 0168 bool Unmanaged::hasScheduledRelease() const 0169 { 0170 return m_scheduledRelease; 0171 } 0172 0173 int Unmanaged::desktop() const 0174 { 0175 return NET::OnAllDesktops; // TODO for some window types should be the current desktop? 0176 } 0177 0178 QStringList Unmanaged::activities() const 0179 { 0180 return QStringList(); 0181 } 0182 0183 QVector<VirtualDesktop *> Unmanaged::desktops() const 0184 { 0185 return QVector<VirtualDesktop *>(); 0186 } 0187 0188 QPointF Unmanaged::clientPos() const 0189 { 0190 return QPoint(0, 0); // unmanaged windows don't have decorations 0191 } 0192 0193 NET::WindowType Unmanaged::windowType(bool direct, int supportedTypes) const 0194 { 0195 // for unmanaged windows the direct does not make any difference 0196 // as there are no rules to check and no hacks to apply 0197 if (supportedTypes == 0) { 0198 supportedTypes = SUPPORTED_UNMANAGED_WINDOW_TYPES_MASK; 0199 } 0200 return info->windowType(NET::WindowTypes(supportedTypes)); 0201 } 0202 0203 bool Unmanaged::isOutline() const 0204 { 0205 return m_outline; 0206 } 0207 0208 bool Unmanaged::isUnmanaged() const 0209 { 0210 return true; 0211 } 0212 0213 QWindow *Unmanaged::findInternalWindow() const 0214 { 0215 const QWindowList windows = kwinApp()->topLevelWindows(); 0216 for (QWindow *w : windows) { 0217 if (w->handle() && w->winId() == window()) { 0218 return w; 0219 } 0220 } 0221 return nullptr; 0222 } 0223 0224 void Unmanaged::checkOutput() 0225 { 0226 setOutput(workspace()->outputAt(frameGeometry().center())); 0227 } 0228 0229 void Unmanaged::damageNotifyEvent() 0230 { 0231 Q_ASSERT(kwinApp()->operationMode() == Application::OperationModeX11); 0232 SurfaceItemX11 *item = static_cast<SurfaceItemX11 *>(surfaceItem()); 0233 if (item) { 0234 item->processDamage(); 0235 } 0236 } 0237 0238 } // namespace