File indexing completed on 2024-04-28 05:30:23

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 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 #include "main.h"
0011 
0012 #include <config-kwin.h>
0013 
0014 #include "atoms.h"
0015 #include "colors/colormanager.h"
0016 #include "compositor.h"
0017 #include "core/outputbackend.h"
0018 #include "core/rendertarget.h"
0019 #include "core/session.h"
0020 #include "cursor.h"
0021 #include "cursorsource.h"
0022 #include "effect/effecthandler.h"
0023 #include "input.h"
0024 #include "inputmethod.h"
0025 #include "opengl/gltexture.h"
0026 #include "opengl/glutils.h"
0027 #include "options.h"
0028 #include "outline.h"
0029 #include "pluginmanager.h"
0030 #include "pointer_input.h"
0031 #include "scene/cursorscene.h"
0032 #include "screenedge.h"
0033 #include "sm.h"
0034 #include "tabletmodemanager.h"
0035 #include "utils/xcbutils.h"
0036 #include "wayland/surface.h"
0037 #include "workspace.h"
0038 #include "x11eventfilter.h"
0039 
0040 #if KWIN_BUILD_SCREENLOCKER
0041 #include "screenlockerwatcher.h"
0042 #endif
0043 
0044 #include "effect/effecthandler.h"
0045 
0046 // KDE
0047 #include <KAboutData>
0048 #include <KLocalizedString>
0049 // Qt
0050 #include <QCommandLineParser>
0051 #include <QQuickWindow>
0052 #include <private/qtx11extras_p.h>
0053 #include <qplatformdefs.h>
0054 
0055 #include <cerrno>
0056 
0057 #if __has_include(<malloc.h>)
0058 #include <malloc.h>
0059 #endif
0060 #include <unistd.h>
0061 
0062 // xcb
0063 #include <xcb/damage.h>
0064 #ifndef XCB_GE_GENERIC
0065 #define XCB_GE_GENERIC 35
0066 #endif
0067 
0068 Q_DECLARE_METATYPE(KSharedConfigPtr)
0069 
0070 namespace KWin
0071 {
0072 
0073 Options *options;
0074 Atoms *atoms;
0075 int Application::crashes = 0;
0076 
0077 Application::Application(Application::OperationMode mode, int &argc, char **argv)
0078     : QApplication(argc, argv)
0079     , m_eventFilter(new XcbEventFilter())
0080     , m_configLock(false)
0081     , m_config(KSharedConfig::openConfig(QStringLiteral("kwinrc")))
0082     , m_kxkbConfig()
0083     , m_operationMode(mode)
0084 {
0085     qRegisterMetaType<Options::WindowOperation>("Options::WindowOperation");
0086     qRegisterMetaType<KWin::EffectWindow *>();
0087     qRegisterMetaType<KWin::SurfaceInterface *>("KWin::SurfaceInterface *");
0088     qRegisterMetaType<KSharedConfigPtr>();
0089     qRegisterMetaType<std::chrono::nanoseconds>();
0090 }
0091 
0092 void Application::setConfigLock(bool lock)
0093 {
0094     m_configLock = lock;
0095 }
0096 
0097 Application::OperationMode Application::operationMode() const
0098 {
0099     return m_operationMode;
0100 }
0101 
0102 void Application::setOperationMode(OperationMode mode)
0103 {
0104     m_operationMode = mode;
0105 }
0106 
0107 bool Application::shouldUseWaylandForCompositing() const
0108 {
0109     return m_operationMode == OperationModeWaylandOnly || m_operationMode == OperationModeXwayland;
0110 }
0111 
0112 void Application::start()
0113 {
0114     // Prevent KWin from synchronously autostarting kactivitymanagerd
0115     // Indeed, kactivitymanagerd being a QApplication it will depend
0116     // on KWin startup... this is unsatisfactory dependency wise,
0117     // and it turns out that it leads to a deadlock in the Wayland case
0118     setProperty("org.kde.KActivities.core.disableAutostart", true);
0119 
0120     setQuitOnLastWindowClosed(false);
0121     setQuitLockEnabled(false);
0122 
0123     if (!m_config->isImmutable() && m_configLock) {
0124         // TODO: This shouldn't be necessary
0125         // config->setReadOnly( true );
0126         m_config->reparseConfiguration();
0127     }
0128     if (!m_kxkbConfig) {
0129         m_kxkbConfig = KSharedConfig::openConfig(QStringLiteral("kxkbrc"), KConfig::NoGlobals);
0130     }
0131     if (!m_inputConfig) {
0132         m_inputConfig = KSharedConfig::openConfig(QStringLiteral("kcminputrc"), KConfig::NoGlobals);
0133     }
0134 
0135     performStartup();
0136 }
0137 
0138 Application::~Application()
0139 {
0140     delete options;
0141     destroyAtoms();
0142     destroyPlatform();
0143     m_session.reset();
0144 }
0145 
0146 void Application::notifyStarted()
0147 {
0148     Q_EMIT started();
0149 }
0150 
0151 void Application::destroyAtoms()
0152 {
0153     delete atoms;
0154     atoms = nullptr;
0155 }
0156 
0157 void Application::destroyPlatform()
0158 {
0159     m_outputBackend.reset();
0160 }
0161 
0162 void Application::resetCrashesCount()
0163 {
0164     crashes = 0;
0165 }
0166 
0167 void Application::setCrashCount(int count)
0168 {
0169     crashes = count;
0170 }
0171 
0172 bool Application::wasCrash()
0173 {
0174     return crashes > 0;
0175 }
0176 
0177 void Application::createAboutData()
0178 {
0179     KAboutData aboutData(QStringLiteral("kwin"), // The program name used internally
0180                          i18n("KWin"), // A displayable program name string
0181                          KWIN_VERSION_STRING, // The program version string
0182                          i18n("KDE window manager"), // Short description of what the app does
0183                          KAboutLicense::GPL, // The license this code is released under
0184                          i18n("(c) 1999-2019, The KDE Developers")); // Copyright Statement
0185 
0186     aboutData.addAuthor(i18n("Matthias Ettrich"), QString(), QStringLiteral("ettrich@kde.org"));
0187     aboutData.addAuthor(i18n("Cristian Tibirna"), QString(), QStringLiteral("tibirna@kde.org"));
0188     aboutData.addAuthor(i18n("Daniel M. Duley"), QString(), QStringLiteral("mosfet@kde.org"));
0189     aboutData.addAuthor(i18n("Luboš Luňák"), QString(), QStringLiteral("l.lunak@kde.org"));
0190     aboutData.addAuthor(i18n("Martin Flöser"), QString(), QStringLiteral("mgraesslin@kde.org"));
0191     aboutData.addAuthor(i18n("David Edmundson"), QStringLiteral("Maintainer"), QStringLiteral("davidedmundson@kde.org"));
0192     aboutData.addAuthor(i18n("Roman Gilg"), QStringLiteral("Maintainer"), QStringLiteral("subdiff@gmail.com"));
0193     aboutData.addAuthor(i18n("Vlad Zahorodnii"), QStringLiteral("Maintainer"), QStringLiteral("vlad.zahorodnii@kde.org"));
0194     aboutData.addAuthor(i18n("Xaver Hugl"), QStringLiteral("Maintainer"), QStringLiteral("xaver.hugl@gmail.com"));
0195     KAboutData::setApplicationData(aboutData);
0196 }
0197 
0198 static const QString s_lockOption = QStringLiteral("lock");
0199 static const QString s_crashesOption = QStringLiteral("crashes");
0200 
0201 void Application::setupCommandLine(QCommandLineParser *parser)
0202 {
0203     QCommandLineOption lockOption(s_lockOption, i18n("Disable configuration options"));
0204     QCommandLineOption crashesOption(s_crashesOption, i18n("Indicate that KWin has recently crashed n times"), QStringLiteral("n"));
0205 
0206     parser->setApplicationDescription(i18n("KDE window manager"));
0207     parser->addOption(lockOption);
0208     parser->addOption(crashesOption);
0209     KAboutData::applicationData().setupCommandLine(parser);
0210 }
0211 
0212 void Application::processCommandLine(QCommandLineParser *parser)
0213 {
0214     KAboutData aboutData = KAboutData::applicationData();
0215     aboutData.processCommandLine(parser);
0216     setConfigLock(parser->isSet(s_lockOption));
0217     Application::setCrashCount(parser->value(s_crashesOption).toInt());
0218 }
0219 
0220 void Application::setupMalloc()
0221 {
0222 #ifdef M_TRIM_THRESHOLD
0223     // Prevent fragmentation of the heap by malloc (glibc).
0224     //
0225     // The default threshold is 128*1024, which can result in a large memory usage
0226     // due to fragmentation especially if we use the raster graphicssystem. On the
0227     // otherside if the threshold is too low, free() starts to permanently ask the kernel
0228     // about shrinking the heap.
0229     const int pagesize = sysconf(_SC_PAGESIZE);
0230     mallopt(M_TRIM_THRESHOLD, 5 * pagesize);
0231 #endif // M_TRIM_THRESHOLD
0232 }
0233 
0234 void Application::setupLocalizedString()
0235 {
0236     KLocalizedString::setApplicationDomain(QByteArrayLiteral("kwin"));
0237 }
0238 
0239 void Application::createWorkspace()
0240 {
0241     // we want all QQuickWindows with an alpha buffer, do here as Workspace might create QQuickWindows
0242     QQuickWindow::setDefaultAlphaBuffer(true);
0243 
0244     // This tries to detect compositing options and can use GLX. GLX problems
0245     // (X errors) shouldn't cause kwin to abort, so this is out of the
0246     // critical startup section where x errors cause kwin to abort.
0247 
0248     // create workspace.
0249     (void)new Workspace();
0250     Q_EMIT workspaceCreated();
0251 }
0252 
0253 void Application::createInput()
0254 {
0255 #if KWIN_BUILD_SCREENLOCKER
0256     m_screenLockerWatcher = std::make_unique<ScreenLockerWatcher>();
0257 #endif
0258     auto input = InputRedirection::create(this);
0259     input->init();
0260     m_platformCursor = createPlatformCursor();
0261 }
0262 
0263 void Application::createAtoms()
0264 {
0265     atoms = new Atoms;
0266 }
0267 
0268 void Application::createOptions()
0269 {
0270     options = new Options;
0271 }
0272 
0273 void Application::createPlugins()
0274 {
0275     m_pluginManager = std::make_unique<PluginManager>();
0276 }
0277 
0278 void Application::createColorManager()
0279 {
0280     m_colorManager = std::make_unique<ColorManager>();
0281 }
0282 
0283 void Application::createInputMethod()
0284 {
0285     m_inputMethod = std::make_unique<InputMethod>();
0286 }
0287 
0288 void Application::createTabletModeManager()
0289 {
0290     m_tabletModeManager = std::make_unique<TabletModeManager>();
0291 }
0292 
0293 TabletModeManager *Application::tabletModeManager() const
0294 {
0295     return m_tabletModeManager.get();
0296 }
0297 
0298 void Application::installNativeX11EventFilter()
0299 {
0300     installNativeEventFilter(m_eventFilter.get());
0301 }
0302 
0303 void Application::removeNativeX11EventFilter()
0304 {
0305     removeNativeEventFilter(m_eventFilter.get());
0306 }
0307 
0308 void Application::destroyInput()
0309 {
0310     delete InputRedirection::self();
0311 }
0312 
0313 void Application::destroyWorkspace()
0314 {
0315     delete Workspace::self();
0316 }
0317 
0318 void Application::destroyCompositor()
0319 {
0320     delete Compositor::self();
0321 }
0322 
0323 void Application::destroyPlugins()
0324 {
0325     m_pluginManager.reset();
0326 }
0327 
0328 void Application::destroyColorManager()
0329 {
0330     m_colorManager.reset();
0331 }
0332 
0333 void Application::destroyInputMethod()
0334 {
0335     m_inputMethod.reset();
0336 }
0337 
0338 std::unique_ptr<Edge> Application::createScreenEdge(ScreenEdges *edges)
0339 {
0340     return std::make_unique<Edge>(edges);
0341 }
0342 
0343 std::unique_ptr<Cursor> Application::createPlatformCursor()
0344 {
0345     return std::make_unique<InputRedirectionCursor>();
0346 }
0347 
0348 std::unique_ptr<OutlineVisual> Application::createOutline(Outline *outline)
0349 {
0350     if (Compositor::compositing()) {
0351         return std::make_unique<CompositedOutlineVisual>(outline);
0352     }
0353     return nullptr;
0354 }
0355 
0356 void Application::createEffectsHandler(Compositor *compositor, WorkspaceScene *scene)
0357 {
0358     new EffectsHandler(compositor, scene);
0359 }
0360 
0361 void Application::registerEventFilter(X11EventFilter *filter)
0362 {
0363     if (filter->isGenericEvent()) {
0364         m_genericEventFilters.append(new X11EventFilterContainer(filter));
0365     } else {
0366         m_eventFilters.append(new X11EventFilterContainer(filter));
0367     }
0368 }
0369 
0370 static X11EventFilterContainer *takeEventFilter(X11EventFilter *eventFilter,
0371                                                 QList<QPointer<X11EventFilterContainer>> &list)
0372 {
0373     for (int i = 0; i < list.count(); ++i) {
0374         X11EventFilterContainer *container = list.at(i);
0375         if (container->filter() == eventFilter) {
0376             return list.takeAt(i);
0377         }
0378     }
0379     return nullptr;
0380 }
0381 
0382 void Application::setXwaylandScale(qreal scale)
0383 {
0384     Q_ASSERT(scale != 0);
0385     if (scale != m_xwaylandScale) {
0386         m_xwaylandScale = scale;
0387         applyXwaylandScale();
0388         Q_EMIT xwaylandScaleChanged();
0389     }
0390 }
0391 
0392 void Application::applyXwaylandScale()
0393 {
0394     const bool xwaylandClientsScale = KConfig(QStringLiteral("kdeglobals"))
0395                                           .group(QStringLiteral("KScreen"))
0396                                           .readEntry("XwaylandClientsScale", true);
0397 
0398     KConfigGroup xwaylandGroup = kwinApp()->config()->group(QStringLiteral("Xwayland"));
0399     if (xwaylandClientsScale) {
0400         xwaylandGroup.writeEntry("Scale", m_xwaylandScale, KConfig::Notify);
0401     } else {
0402         xwaylandGroup.deleteEntry("Scale", KConfig::Notify);
0403     }
0404     xwaylandGroup.sync();
0405 
0406     if (x11Connection()) {
0407         // rerun the fonts kcm init that does the appropriate xrdb call with the new settings
0408         QProcess::startDetached("kcminit", {"kcm_fonts_init", "kcm_style_init"});
0409     }
0410 }
0411 
0412 void Application::unregisterEventFilter(X11EventFilter *filter)
0413 {
0414     X11EventFilterContainer *container = nullptr;
0415     if (filter->isGenericEvent()) {
0416         container = takeEventFilter(filter, m_genericEventFilters);
0417     } else {
0418         container = takeEventFilter(filter, m_eventFilters);
0419     }
0420     delete container;
0421 }
0422 
0423 bool Application::dispatchEvent(xcb_generic_event_t *event)
0424 {
0425     static const QList<QByteArray> s_xcbEerrors({QByteArrayLiteral("Success"),
0426                                                  QByteArrayLiteral("BadRequest"),
0427                                                  QByteArrayLiteral("BadValue"),
0428                                                  QByteArrayLiteral("BadWindow"),
0429                                                  QByteArrayLiteral("BadPixmap"),
0430                                                  QByteArrayLiteral("BadAtom"),
0431                                                  QByteArrayLiteral("BadCursor"),
0432                                                  QByteArrayLiteral("BadFont"),
0433                                                  QByteArrayLiteral("BadMatch"),
0434                                                  QByteArrayLiteral("BadDrawable"),
0435                                                  QByteArrayLiteral("BadAccess"),
0436                                                  QByteArrayLiteral("BadAlloc"),
0437                                                  QByteArrayLiteral("BadColor"),
0438                                                  QByteArrayLiteral("BadGC"),
0439                                                  QByteArrayLiteral("BadIDChoice"),
0440                                                  QByteArrayLiteral("BadName"),
0441                                                  QByteArrayLiteral("BadLength"),
0442                                                  QByteArrayLiteral("BadImplementation"),
0443                                                  QByteArrayLiteral("Unknown")});
0444 
0445     kwinApp()->updateX11Time(event);
0446 
0447     const uint8_t x11EventType = event->response_type & ~0x80;
0448     if (!x11EventType) {
0449         // let's check whether it's an error from one of the extensions KWin uses
0450         xcb_generic_error_t *error = reinterpret_cast<xcb_generic_error_t *>(event);
0451         const QList<Xcb::ExtensionData> extensions = Xcb::Extensions::self()->extensions();
0452         for (const auto &extension : extensions) {
0453             if (error->major_code == extension.majorOpcode) {
0454                 QByteArray errorName;
0455                 if (error->error_code < s_xcbEerrors.size()) {
0456                     errorName = s_xcbEerrors.at(error->error_code);
0457                 } else if (error->error_code >= extension.errorBase) {
0458                     const int index = error->error_code - extension.errorBase;
0459                     if (index >= 0 && index < extension.errorCodes.size()) {
0460                         errorName = extension.errorCodes.at(index);
0461                     }
0462                 }
0463                 if (errorName.isEmpty()) {
0464                     errorName = QByteArrayLiteral("Unknown");
0465                 }
0466                 qCWarning(KWIN_CORE, "XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d (%s)",
0467                           int(error->error_code), errorName.constData(),
0468                           int(error->sequence), int(error->resource_id),
0469                           int(error->major_code), extension.name.constData(),
0470                           int(error->minor_code),
0471                           extension.opCodes.size() > error->minor_code ? extension.opCodes.at(error->minor_code).constData() : "Unknown");
0472                 return true;
0473             }
0474         }
0475         return false;
0476     }
0477 
0478     if (x11EventType == XCB_GE_GENERIC) {
0479         xcb_ge_generic_event_t *ge = reinterpret_cast<xcb_ge_generic_event_t *>(event);
0480 
0481         // We need to make a shadow copy of the event filter list because an activated event
0482         // filter may mutate it by removing or installing another event filter.
0483         const auto eventFilters = m_genericEventFilters;
0484 
0485         for (X11EventFilterContainer *container : eventFilters) {
0486             if (!container) {
0487                 continue;
0488             }
0489             X11EventFilter *filter = container->filter();
0490             if (filter->extension() == ge->extension && filter->genericEventTypes().contains(ge->event_type) && filter->event(event)) {
0491                 return true;
0492             }
0493         }
0494     } else {
0495         // We need to make a shadow copy of the event filter list because an activated event
0496         // filter may mutate it by removing or installing another event filter.
0497         const auto eventFilters = m_eventFilters;
0498 
0499         for (X11EventFilterContainer *container : eventFilters) {
0500             if (!container) {
0501                 continue;
0502             }
0503             X11EventFilter *filter = container->filter();
0504             if (filter->eventTypes().contains(x11EventType) && filter->event(event)) {
0505                 return true;
0506             }
0507         }
0508     }
0509 
0510     if (workspace()) {
0511         return workspace()->workspaceEvent(event);
0512     }
0513 
0514     return false;
0515 }
0516 
0517 static quint32 monotonicTime()
0518 {
0519     timespec ts;
0520 
0521     const int result = clock_gettime(CLOCK_MONOTONIC, &ts);
0522     if (result) {
0523         qCWarning(KWIN_CORE, "Failed to query monotonic time: %s", strerror(errno));
0524     }
0525 
0526     return ts.tv_sec * 1000 + ts.tv_nsec / 1000000L;
0527 }
0528 
0529 void Application::updateXTime()
0530 {
0531     switch (operationMode()) {
0532     case Application::OperationModeX11:
0533         setX11Time(QX11Info::getTimestamp(), TimestampUpdate::Always);
0534         break;
0535 
0536     case Application::OperationModeXwayland:
0537         setX11Time(monotonicTime(), TimestampUpdate::Always);
0538         break;
0539 
0540     default:
0541         // Do not update the current X11 time stamp if it's the Wayland only session.
0542         break;
0543     }
0544 }
0545 
0546 void Application::updateX11Time(xcb_generic_event_t *event)
0547 {
0548     xcb_timestamp_t time = XCB_TIME_CURRENT_TIME;
0549     const uint8_t eventType = event->response_type & ~0x80;
0550     switch (eventType) {
0551     case XCB_KEY_PRESS:
0552     case XCB_KEY_RELEASE:
0553         time = reinterpret_cast<xcb_key_press_event_t *>(event)->time;
0554         break;
0555     case XCB_BUTTON_PRESS:
0556     case XCB_BUTTON_RELEASE:
0557         time = reinterpret_cast<xcb_button_press_event_t *>(event)->time;
0558         break;
0559     case XCB_MOTION_NOTIFY:
0560         time = reinterpret_cast<xcb_motion_notify_event_t *>(event)->time;
0561         break;
0562     case XCB_ENTER_NOTIFY:
0563     case XCB_LEAVE_NOTIFY:
0564         time = reinterpret_cast<xcb_enter_notify_event_t *>(event)->time;
0565         break;
0566     case XCB_FOCUS_IN:
0567     case XCB_FOCUS_OUT:
0568     case XCB_KEYMAP_NOTIFY:
0569     case XCB_EXPOSE:
0570     case XCB_GRAPHICS_EXPOSURE:
0571     case XCB_NO_EXPOSURE:
0572     case XCB_VISIBILITY_NOTIFY:
0573     case XCB_CREATE_NOTIFY:
0574     case XCB_DESTROY_NOTIFY:
0575     case XCB_UNMAP_NOTIFY:
0576     case XCB_MAP_NOTIFY:
0577     case XCB_MAP_REQUEST:
0578     case XCB_REPARENT_NOTIFY:
0579     case XCB_CONFIGURE_NOTIFY:
0580     case XCB_CONFIGURE_REQUEST:
0581     case XCB_GRAVITY_NOTIFY:
0582     case XCB_RESIZE_REQUEST:
0583     case XCB_CIRCULATE_NOTIFY:
0584     case XCB_CIRCULATE_REQUEST:
0585         // no timestamp
0586         return;
0587     case XCB_PROPERTY_NOTIFY:
0588         time = reinterpret_cast<xcb_property_notify_event_t *>(event)->time;
0589         break;
0590     case XCB_SELECTION_CLEAR:
0591         time = reinterpret_cast<xcb_selection_clear_event_t *>(event)->time;
0592         break;
0593     case XCB_SELECTION_REQUEST:
0594         time = reinterpret_cast<xcb_selection_request_event_t *>(event)->time;
0595         break;
0596     case XCB_SELECTION_NOTIFY:
0597         time = reinterpret_cast<xcb_selection_notify_event_t *>(event)->time;
0598         break;
0599     case XCB_COLORMAP_NOTIFY:
0600     case XCB_CLIENT_MESSAGE:
0601     case XCB_MAPPING_NOTIFY:
0602     case XCB_GE_GENERIC:
0603         // no timestamp
0604         return;
0605     default:
0606         // extension handling
0607         if (Xcb::Extensions::self()) {
0608             if (eventType == Xcb::Extensions::self()->shapeNotifyEvent()) {
0609                 time = reinterpret_cast<xcb_shape_notify_event_t *>(event)->server_time;
0610             }
0611             if (eventType == Xcb::Extensions::self()->damageNotifyEvent()) {
0612                 time = reinterpret_cast<xcb_damage_notify_event_t *>(event)->timestamp;
0613             }
0614         }
0615         break;
0616     }
0617     setX11Time(time);
0618 }
0619 
0620 bool XcbEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result)
0621 {
0622     if (eventType == "xcb_generic_event_t") {
0623         return kwinApp()->dispatchEvent(static_cast<xcb_generic_event_t *>(message));
0624     }
0625     return false;
0626 }
0627 
0628 QProcessEnvironment Application::processStartupEnvironment() const
0629 {
0630     return m_processEnvironment;
0631 }
0632 
0633 void Application::setProcessStartupEnvironment(const QProcessEnvironment &environment)
0634 {
0635     m_processEnvironment = environment;
0636 }
0637 
0638 void Application::setOutputBackend(std::unique_ptr<OutputBackend> &&backend)
0639 {
0640     Q_ASSERT(!m_outputBackend);
0641     m_outputBackend = std::move(backend);
0642 }
0643 
0644 void Application::setSession(std::unique_ptr<Session> &&session)
0645 {
0646     Q_ASSERT(!m_session);
0647     m_session = std::move(session);
0648 }
0649 
0650 PluginManager *Application::pluginManager() const
0651 {
0652     return m_pluginManager.get();
0653 }
0654 
0655 InputMethod *Application::inputMethod() const
0656 {
0657     return m_inputMethod.get();
0658 }
0659 
0660 ColorManager *Application::colorManager() const
0661 {
0662     return m_colorManager.get();
0663 }
0664 
0665 XwaylandInterface *Application::xwayland() const
0666 {
0667     return nullptr;
0668 }
0669 
0670 #if KWIN_BUILD_SCREENLOCKER
0671 ScreenLockerWatcher *Application::screenLockerWatcher() const
0672 {
0673     return m_screenLockerWatcher.get();
0674 }
0675 #endif
0676 
0677 static PlatformCursorImage grabCursorOpenGL()
0678 {
0679     CursorScene *scene = Compositor::self()->cursorScene();
0680     if (!scene) {
0681         return PlatformCursorImage();
0682     }
0683 
0684     Cursor *cursor = Cursors::self()->currentCursor();
0685     Output *output = workspace()->outputAt(cursor->pos());
0686 
0687     const auto texture = GLTexture::allocate(GL_RGBA8, (cursor->geometry().size() * output->scale()).toSize());
0688     if (!texture) {
0689         return PlatformCursorImage{};
0690     }
0691     texture->setContentTransform(OutputTransform::FlipY);
0692     GLFramebuffer framebuffer(texture.get());
0693     RenderTarget renderTarget(&framebuffer);
0694 
0695     SceneDelegate delegate(scene, output);
0696     scene->prePaint(&delegate);
0697     scene->paint(renderTarget, infiniteRegion());
0698     scene->postPaint();
0699 
0700     QImage image = texture->toImage();
0701     image.setDevicePixelRatio(output->scale());
0702 
0703     return PlatformCursorImage(image, cursor->hotspot());
0704 }
0705 
0706 static PlatformCursorImage grabCursorSoftware()
0707 {
0708     CursorScene *scene = Compositor::self()->cursorScene();
0709     if (!scene) {
0710         return PlatformCursorImage();
0711     }
0712 
0713     Cursor *cursor = Cursors::self()->currentCursor();
0714     Output *output = workspace()->outputAt(cursor->pos());
0715 
0716     QImage image((cursor->geometry().size() * output->scale()).toSize(), QImage::Format_ARGB32_Premultiplied);
0717     RenderTarget renderTarget(&image);
0718 
0719     SceneDelegate delegate(scene, output);
0720     scene->prePaint(&delegate);
0721     scene->paint(renderTarget, infiniteRegion());
0722     scene->postPaint();
0723 
0724     image.setDevicePixelRatio(output->scale());
0725     return PlatformCursorImage(image, cursor->hotspot());
0726 }
0727 
0728 PlatformCursorImage Application::cursorImage() const
0729 {
0730     Cursor *cursor = Cursors::self()->currentCursor();
0731     if (cursor->geometry().isEmpty()) {
0732         return PlatformCursorImage();
0733     }
0734 
0735     if (auto shapeSource = qobject_cast<ShapeCursorSource *>(cursor->source())) {
0736         return PlatformCursorImage(shapeSource->image(), shapeSource->hotspot());
0737     }
0738 
0739     // The cursor content is provided by a client, grab the contents of the cursor scene.
0740     switch (effects->compositingType()) {
0741     case OpenGLCompositing:
0742         return grabCursorOpenGL();
0743     case QPainterCompositing:
0744         return grabCursorSoftware();
0745     default:
0746         Q_UNREACHABLE();
0747     }
0748 }
0749 
0750 void Application::startInteractiveWindowSelection(std::function<void(KWin::Window *)> callback, const QByteArray &cursorName)
0751 {
0752     if (!input()) {
0753         callback(nullptr);
0754         return;
0755     }
0756     input()->startInteractiveWindowSelection(callback, cursorName);
0757 }
0758 
0759 void Application::startInteractivePositionSelection(std::function<void(const QPointF &)> callback)
0760 {
0761     if (!input()) {
0762         callback(QPointF(-1, -1));
0763         return;
0764     }
0765     input()->startInteractivePositionSelection(callback);
0766 }
0767 
0768 } // namespace
0769 
0770 #include "moc_main.cpp"