File indexing completed on 2024-11-10 04:57:50
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"