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 };