File indexing completed on 2024-04-28 05:35:36
0001 /* 0002 SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include <QAbstractNativeEventFilter> 0010 #include <QObject> 0011 0012 #include "kworkspace_export.h" 0013 #include <config-outputorder.h> 0014 0015 #if HAVE_X11 0016 #include <xcb/xcb.h> 0017 #endif 0018 0019 class QScreen; 0020 class QTimer; 0021 0022 /** 0023 * This class watches for output ordering changes from 0024 * the relevant backend 0025 */ 0026 class KWORKSPACE_EXPORT OutputOrderWatcher : public QObject 0027 { 0028 Q_OBJECT 0029 public: 0030 /** 0031 * Create the correct OutputOrderWatcher 0032 */ 0033 static OutputOrderWatcher *instance(QObject *parent); 0034 0035 /** 0036 * Returns the list of outputs in order 0037 * 0038 * At the time of change signalling all Screens are 0039 * guaranteed to exist in QGuiApplication. 0040 * 0041 * After screen removal this can temporarily contain 0042 * dead entries. 0043 */ 0044 QStringList outputOrder() const; 0045 0046 /** 0047 * @internal 0048 * For X11 we know libkscreen takes a server grab whilst changing properties. 0049 * This means we know at the time of any runtime screen addition and removal the priorities will 0050 * be up-to-date when we poll them. 0051 * 0052 * For dynamic ordering changes without screen changes we will get the change property multiple times. 0053 * A timer is used to batch them. 0054 * 0055 * A caveat on X11 is the initial startup where plasmashell may query screen information before 0056 * kscreen has set properties. 0057 * This should resolve itself as a dynamic re-ordering when kscreen does start. 0058 * 0059 * For wayland we know kwin sends the priority order whenever screen changes are made. 0060 * As creating screens requires an extra async call to kwin (to bind to the output) 0061 * we always get the new priority ordering before and screen additions. 0062 * We should always have correct values on startup. 0063 */ 0064 virtual void refresh(); 0065 Q_SIGNALS: 0066 void outputOrderChanged(const QStringList &outputOrder); 0067 0068 protected: 0069 OutputOrderWatcher(QObject *parent); 0070 /** 0071 * Backend failed, use QScreen based implementaion 0072 */ 0073 void useFallback(bool fallback); 0074 0075 QStringList m_outputOrder; 0076 bool m_orderProtocolPresent = false; 0077 0078 private: 0079 }; 0080 0081 #if HAVE_X11 0082 class X11OutputOrderWatcher : public OutputOrderWatcher, public QAbstractNativeEventFilter 0083 { 0084 Q_OBJECT 0085 public: 0086 X11OutputOrderWatcher(QObject *parent); 0087 void refresh() override; 0088 0089 protected: 0090 bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override; 0091 0092 private: 0093 QTimer *m_delayTimer = nullptr; // This is just to simulate the protocol that will be guaranteed to always arrive after screens additions and removals 0094 // Xrandr 0095 int m_xrandrExtensionOffset; 0096 xcb_atom_t m_kdeScreenAtom = XCB_ATOM_NONE; 0097 }; 0098 #endif 0099 0100 class WaylandOutputOrderWatcher : public OutputOrderWatcher 0101 { 0102 Q_OBJECT 0103 public: 0104 WaylandOutputOrderWatcher(QObject *parent); 0105 void refresh() override; 0106 0107 private: 0108 bool hasAllScreens() const; 0109 QStringList m_pendingOutputOrder; 0110 };