1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 2019 Roman Gilg <subdiff@gmail.com>
6     SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
7 
8     SPDX-License-Identifier: GPL-2.0-or-later
9 */
10 #ifndef KWIN_XWL_XWAYLAND
11 #define KWIN_XWL_XWAYLAND
12 
13 #include "xwayland_interface.h"
14 
15 #include <QProcess>
16 #include <QSocketNotifier>
17 #include <QTemporaryFile>
18 
19 class KSelectionOwner;
20 
21 namespace KWin
22 {
23 class ApplicationWaylandAbstract;
24 class XwaylandSocket;
25 
26 namespace Xwl
27 {
28 
29 class Xwayland : public XwaylandInterface
30 {
31     Q_OBJECT
32 
33 public:
34     Xwayland(ApplicationWaylandAbstract *app, QObject *parent = nullptr);
35     ~Xwayland() override;
36 
37     /**
38      * Returns the associated Xwayland process or @c null if the Xwayland server is inactive.
39      */
40     QProcess *process() const override;
41 
42     /**
43      * Set file descriptors that xwayland should use for listening
44      * This is to be used in conjuction with kwin_wayland_wrapper which creates a socket externally
45      * That external process is responsible for setting up the DISPLAY env with a valid value.
46      * Ownership of the file descriptor is not transferrred.
47      */
48     void setListenFDs(const QVector<int> &listenFds);
49 
50     /**
51      * Sets the display name used by XWayland (i.e ':0')
52      * This is to be used in conjuction with kwin_wayland_wrapper to provide the name of the socket
53      * created externally
54      */
55     void setDisplayName(const QString &displayName);
56 
57     /**
58      * Sets the xauthority file to be used by XWayland
59      * This is to be used in conjuction with kwin_wayland_wrapper
60      */
61     void setXauthority(const QString &xauthority);
62 
63 public Q_SLOTS:
64     /**
65      * Starts the Xwayland server.
66      *
67      * This method will spawn an Xwayland process and will establish a new XCB connection to it.
68      * If an error has occurred during the startup, the errorOccurred() signal is going to
69      * be emitted. If the Xwayland server has started successfully, the started() signal will be
70      * emitted.
71      *
72      * @see started(), stop()
73      */
74     void start();
75     /**
76      * Stops the Xwayland server.
77      *
78      * This method will destroy the existing XCB connection as well all connected X11 clients.
79      *
80      * A SIGTERM signal will be sent to the Xwayland process. If Xwayland doesn't shut down
81      * within a reasonable amount of time (5 seconds), a SIGKILL signal will be sent and thus
82      * the process will be killed for good.
83      *
84      * If the Xwayland process crashes, the server will be stopped automatically.
85      *
86      * @see start()
87      */
88     void stop();
89 
90 Q_SIGNALS:
91     /**
92      * This signal is emitted when the Xwayland server has been started successfully and it is
93      * ready to accept and manage X11 clients.
94      */
95     void started();
96     /**
97      * This signal is emitted when an error occurs with the Xwayland server.
98      */
99     void errorOccurred();
100 
101 private Q_SLOTS:
102     void dispatchEvents();
103     void resetCrashCount();
104 
105     void handleXwaylandFinished(int exitCode, QProcess::ExitStatus exitStatus);
106     void handleXwaylandCrashed();
107     void handleXwaylandError(QProcess::ProcessError error);
108     void handleXwaylandReady();
109 
110     void handleSelectionLostOwnership();
111     void handleSelectionFailedToClaimOwnership();
112     void handleSelectionClaimedOwnership();
113 
114 private:
115     void installSocketNotifier();
116     void uninstallSocketNotifier();
117     void maybeDestroyReadyNotifier();
118 
119     bool startInternal();
120     void stopInternal();
121     void restartInternal();
122 
123     bool createX11Connection();
124     void destroyX11Connection();
125 
126     DragEventReply dragMoveFilter(Toplevel *target, const QPoint &pos) override;
127     KWaylandServer::AbstractDropHandler *xwlDropHandler() override;
128 
129     int m_xcbConnectionFd = -1;
130     QProcess *m_xwaylandProcess = nullptr;
131     QSocketNotifier *m_socketNotifier = nullptr;
132     QSocketNotifier *m_readyNotifier = nullptr;
133     QTimer *m_resetCrashCountTimer = nullptr;
134     ApplicationWaylandAbstract *m_app;
135     QScopedPointer<KSelectionOwner> m_selectionOwner;
136     // this is only used when kwin is run without kwin_wayland_wrapper
137     QScopedPointer<XwaylandSocket> m_socket;
138 
139     QVector<int> m_listenFds;
140     QString m_displayName;
141     QString m_xAuthority;
142 
143     int m_crashCount = 0;
144 
145     Q_DISABLE_COPY(Xwayland)
146 };
147 
148 } // namespace Xwl
149 } // namespace KWin
150 
151 #endif
152