1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 #ifndef KWIN_PLATFORM_H
10 #define KWIN_PLATFORM_H
11 #include <kwin_export.h>
12 #include <kwinglobals.h>
13 #include <epoxy/egl.h>
14 #include "input.h"
15 
16 #include <QImage>
17 #include <QObject>
18 
19 #include <functional>
20 
21 class QAction;
22 
23 namespace KWaylandServer {
24 class OutputConfigurationV2Interface;
25 }
26 
27 namespace KWin
28 {
29 
30 class AbstractOutput;
31 class Edge;
32 class Compositor;
33 class DmaBufTexture;
34 class OverlayWindow;
35 class OpenGLBackend;
36 class Outline;
37 class OutlineVisual;
38 class QPainterBackend;
39 class RenderLoop;
40 class Scene;
41 class ScreenEdges;
42 class Session;
43 class Toplevel;
44 
45 class KWIN_EXPORT Outputs : public QVector<AbstractOutput*>
46 {
47 public:
Outputs()48     Outputs(){};
49     template <typename T>
Outputs(const QVector<T> & other)50     Outputs(const QVector<T> &other) {
51         resize(other.size());
52         std::copy(other.constBegin(), other.constEnd(), begin());
53     }
54 };
55 
56 class KWIN_EXPORT Platform : public QObject
57 {
58     Q_OBJECT
59 public:
60     ~Platform() override;
61 
62     virtual Session *session() const = 0;
63     virtual bool initialize() = 0;
64     virtual OpenGLBackend *createOpenGLBackend();
65     virtual QPainterBackend *createQPainterBackend();
createDmaBufTexture(const QSize & size)66     virtual DmaBufTexture *createDmaBufTexture(const QSize &size) {
67         Q_UNUSED(size);
68         return nullptr;
69     }
70 
71     /**
72      * Allows the platform to create a platform specific screen edge.
73      * The default implementation creates a Edge.
74      */
75     virtual Edge *createScreenEdge(ScreenEdges *parent);
76     /**
77      * Allows the platform to create a platform specific Cursor.
78      * The default implementation creates an InputRedirectionCursor.
79      */
80     virtual void createPlatformCursor(QObject *parent = nullptr);
81     virtual void warpPointer(const QPointF &globalPos);
82     /**
83      * Whether our Compositing EGL display supports creating native EGL fences.
84      */
85     bool supportsNativeFence() const;
86     /**
87      * The EGLDisplay used by the compositing scene.
88      */
89     EGLDisplay sceneEglDisplay() const;
90     void setSceneEglDisplay(EGLDisplay display);
91     /**
92      * Returns the compositor-wide shared EGL context. This function may return EGL_NO_CONTEXT
93      * if the underlying rendering backend does not use EGL.
94      *
95      * Note that the returned context should never be made current. Instead, create a context
96      * that shares with this one and make the new context current.
97      */
98     EGLContext sceneEglGlobalShareContext() const;
99     /**
100      * Sets the global share context to @a context. This function is intended to be called only
101      * by rendering backends.
102      */
103     void setSceneEglGlobalShareContext(EGLContext context);
104 
105     /**
106      * Implementing subclasses should provide a size in case the backend represents
107      * a basic screen and uses the BasicScreens.
108      *
109      * Base implementation returns an invalid size.
110      */
111     virtual QSize screenSize() const;
112     /**
113      * Implement this method to receive configuration change requests through KWayland's
114      * OutputManagement interface.
115      *
116      * Base implementation warns that the current backend does not implement this
117      * functionality.
118      */
119     void requestOutputsChange(KWaylandServer::OutputConfigurationV2Interface *config);
120 
121     /**
122      * Whether the Platform requires compositing for rendering.
123      * Default implementation returns @c true. If the implementing Platform allows to be used
124      * without compositing (e.g. rendering is done by the windowing system), re-implement this method.
125      */
126     virtual bool requiresCompositing() const;
127     /**
128      * Whether Compositing is possible in the Platform.
129      * Returning @c false in this method makes only sense if requiresCompositing returns @c false.
130      *
131      * The default implementation returns @c true.
132      * @see requiresCompositing
133      */
134     virtual bool compositingPossible() const;
135     /**
136      * Returns a user facing text explaining why compositing is not possible in case
137      * compositingPossible returns @c false.
138      *
139      * The default implementation returns an empty string.
140      * @see compositingPossible
141      */
142     virtual QString compositingNotPossibleReason() const;
143     /**
144      * Whether OpenGL compositing is broken.
145      * The Platform can implement this method if it is able to detect whether OpenGL compositing
146      * broke (e.g. triggered a crash in a previous run).
147      *
148      * Default implementation returns @c false.
149      * @see createOpenGLSafePoint
150      */
151     virtual bool openGLCompositingIsBroken() const;
152     enum class OpenGLSafePoint {
153         PreInit,
154         PostInit,
155         PreFrame,
156         PostFrame,
157         PostLastGuardedFrame
158     };
159     /**
160      * This method is invoked before and after creating the OpenGL rendering Scene.
161      * An implementing Platform can use it to detect crashes triggered by the OpenGL implementation.
162      * This can be used for openGLCompositingIsBroken.
163      *
164      * The default implementation does nothing.
165      * @see openGLCompositingIsBroken.
166      */
167     virtual void createOpenGLSafePoint(OpenGLSafePoint safePoint);
168 
169     /**
170      * Starts an interactive window selection process.
171      *
172      * Once the user selected a window the @p callback is invoked with the selected Toplevel as
173      * argument. In case the user cancels the interactive window selection or selecting a window is currently
174      * not possible (e.g. screen locked) the @p callback is invoked with a @c nullptr argument.
175      *
176      * During the interactive window selection the cursor is turned into a crosshair cursor unless
177      * @p cursorName is provided. The argument @p cursorName is a QByteArray instead of Qt::CursorShape
178      * to support the "pirate" cursor for kill window which is not wrapped by Qt::CursorShape.
179      *
180      * The default implementation forwards to InputRedirection.
181      *
182      * @param callback The function to invoke once the interactive window selection ends
183      * @param cursorName The optional name of the cursor shape to use, default is crosshair
184      */
185     virtual void startInteractiveWindowSelection(std::function<void(KWin::Toplevel*)> callback, const QByteArray &cursorName = QByteArray());
186 
187     /**
188      * Starts an interactive position selection process.
189      *
190      * Once the user selected a position on the screen the @p callback is invoked with
191      * the selected point as argument. In case the user cancels the interactive position selection
192      * or selecting a position is currently not possible (e.g. screen locked) the @p callback
193      * is invoked with a point at @c -1 as x and y argument.
194      *
195      * During the interactive window selection the cursor is turned into a crosshair cursor.
196      *
197      * The default implementation forwards to InputRedirection.
198      *
199      * @param callback The function to invoke once the interactive position selection ends
200      */
201     virtual void startInteractivePositionSelection(std::function<void(const QPoint &)> callback);
202 
203     /**
204      * Platform specific preparation for an @p action which is used for KGlobalAccel.
205      *
206      * A platform might need to do preparation for an @p action before
207      * it can be used with KGlobalAccel.
208      *
209      * Code using KGlobalAccel should invoke this method for the @p action
210      * prior to setting up any shortcuts and connections.
211      *
212      * The default implementation does nothing.
213      *
214      * @param action The action which will be used with KGlobalAccel.
215      * @since 5.10
216      */
217     virtual void setupActionForGlobalAccel(QAction *action);
218 
219     /**
220      * Returns @c true if the software cursor is being used; otherwise returns @c false.
221      */
222     bool usesSoftwareCursor() const;
223 
224     /**
225      * Returns @c true if the software cursor is being forced; otherwise returns @c false.
226      *
227      * Note that the value returned by this function not always matches usesSoftwareCursor().
228      * If this function returns @c true, then it is guaranteed that the compositor will
229      * use the software cursor. However, this doesn't apply vice versa.
230      *
231      * If the compositor uses a software cursor, this function may return @c false. This
232      * is typically the case if the current cursor image can't be displayed using hardware
233      * cursors, for example due to buffer size limitations, etc.
234      *
235      * @see usesSoftwareCursor()
236      */
237     bool isSoftwareCursorForced() const;
238 
239     /**
240      * Returns a PlatformCursorImage. By default this is created by softwareCursor and
241      * softwareCursorHotspot. An implementing subclass can use this to provide a better
242      * suited PlatformCursorImage.
243      *
244      * @see softwareCursor
245      * @see softwareCursorHotspot
246      * @since 5.9
247      */
248     virtual PlatformCursorImage cursorImage() const;
249 
250     /**
251      * The Platform cursor image should be hidden.
252      * @see showCursor
253      * @see doHideCursor
254      * @see isCursorHidden
255      * @since 5.9
256      */
257     void hideCursor();
258 
259     /**
260      * The Platform cursor image should be shown again.
261      * @see hideCursor
262      * @see doShowCursor
263      * @see isCursorHidden
264      * @since 5.9
265      */
266     void showCursor();
267 
268     /**
269      * Whether the cursor is currently hidden.
270      * @see showCursor
271      * @see hideCursor
272      * @since 5.9
273      */
isCursorHidden()274     bool isCursorHidden() const {
275         return m_hideCursorCounter > 0;
276     }
isReady()277     bool isReady() const {
278         return m_ready;
279     }
setInitialWindowSize(const QSize & size)280     void setInitialWindowSize(const QSize &size) {
281         m_initialWindowSize = size;
282     }
setDeviceIdentifier(const QByteArray & identifier)283     void setDeviceIdentifier(const QByteArray &identifier) {
284         m_deviceIdentifier = identifier;
285     }
supportsPointerWarping()286     bool supportsPointerWarping() const {
287         return m_pointerWarping;
288     }
initialOutputCount()289     int initialOutputCount() const {
290         return m_initialOutputCount;
291     }
setInitialOutputCount(int count)292     void setInitialOutputCount(int count) {
293         m_initialOutputCount = count;
294     }
initialOutputScale()295     qreal initialOutputScale() const {
296         return m_initialOutputScale;
297     }
setInitialOutputScale(qreal scale)298     void setInitialOutputScale(qreal scale) {
299         m_initialOutputScale = scale;
300     }
301 
302     /**
303      * Creates the OverlayWindow required for X11 based compositors.
304      * Default implementation returns @c nullptr.
305      */
306     virtual OverlayWindow *createOverlayWindow();
307 
308     /**
309      * Queries the current X11 time stamp of the X server.
310      */
311     void updateXTime();
312 
313     /**
314      * Creates the OutlineVisual for the given @p outline.
315      * Default implementation creates an OutlineVisual suited for composited usage.
316      */
317     virtual OutlineVisual *createOutline(Outline *outline);
318 
319     /**
320      * Platform specific way to invert the screen.
321      * Default implementation invokes the invert effect
322      */
323     virtual void invertScreen();
324 
325     /**
326      * Default implementation creates an EffectsHandlerImp;
327      */
328     virtual void createEffectsHandler(Compositor *compositor, Scene *scene);
329 
330     /**
331      * The CompositingTypes supported by the Platform.
332      * The first item should be the most preferred one.
333      * @since 5.11
334      */
335     virtual QVector<CompositingType> supportedCompositors() const = 0;
336 
337     /**
338      * Whether gamma control is supported by the backend.
339      * @since 5.12
340      */
supportsGammaControl()341     bool supportsGammaControl() const {
342         return m_supportsGammaControl;
343     }
344 
345     // outputs with connections (org_kde_kwin_outputdevice)
outputs()346     virtual Outputs outputs() const {
347         return Outputs();
348     }
349     // actively compositing outputs (wl_output)
enabledOutputs()350     virtual Outputs enabledOutputs() const {
351         return Outputs();
352     }
353     AbstractOutput *findOutput(int screenId) const;
354     AbstractOutput *findOutput(const QUuid &uuid) const;
355     AbstractOutput *outputAt(const QPoint &pos) const;
356 
357     /**
358      * A string of information to include in kwin debug output
359      * It should not be translated.
360      *
361      * The base implementation prints the name.
362      * @since 5.12
363      */
364     virtual QString supportInformation() const;
365 
366     /**
367      * The compositor plugin which got selected from @ref supportedCompositors.
368      * Prior to selecting a compositor this returns @c NoCompositing.
369      *
370      * This method allows the platforms to limit the offerings in @ref supportedCompositors
371      * in case they do not support runtime compositor switching
372      */
selectedCompositor()373     CompositingType selectedCompositor() const
374     {
375         return m_selectedCompositor;
376     }
377     /**
378      * Used by Compositor to set the used compositor.
379      */
setSelectedCompositor(CompositingType type)380     void setSelectedCompositor(CompositingType type)
381     {
382         m_selectedCompositor = type;
383     }
384 
385     /**
386      * Returns @c true if rendering is split per screen; otherwise returns @c false.
387      */
388     bool isPerScreenRenderingEnabled() const;
389 
390     /**
391      * If the Platform doesn't support per screen rendering, this function returns the
392      * RenderLoop that drives compositing.
393      */
394     virtual RenderLoop *renderLoop() const;
395 
396 public Q_SLOTS:
397     void pointerMotion(const QPointF &position, quint32 time);
398     void pointerButtonPressed(quint32 button, quint32 time);
399     void pointerButtonReleased(quint32 button, quint32 time);
400     void pointerAxisHorizontal(qreal delta, quint32 time, qint32 discreteDelta = 0,
401         InputRedirection::PointerAxisSource source = InputRedirection::PointerAxisSourceUnknown);
402     void pointerAxisVertical(qreal delta, quint32 time, qint32 discreteDelta = 0,
403         InputRedirection::PointerAxisSource source = InputRedirection::PointerAxisSourceUnknown);
404     void keyboardKeyPressed(quint32 key, quint32 time);
405     void keyboardKeyReleased(quint32 key, quint32 time);
406     void keyboardModifiers(uint32_t modsDepressed, uint32_t modsLatched, uint32_t modsLocked, uint32_t group);
407     void keymapChange(int fd, uint32_t size);
408     void touchDown(qint32 id, const QPointF &pos, quint32 time);
409     void touchUp(qint32 id, quint32 time);
410     void touchMotion(qint32 id, const QPointF &pos, quint32 time);
411     void cancelTouchSequence();
412     void touchCancel();
413     void touchFrame();
414     int touchPointCount();
415 
416     void processSwipeGestureBegin(int fingerCount, quint32 time);
417     void processSwipeGestureUpdate(const QSizeF &delta, quint32 time);
418     void processSwipeGestureEnd(quint32 time);
419     void processSwipeGestureCancelled(quint32 time);
420     void processPinchGestureBegin(int fingerCount, quint32 time);
421     void processPinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time);
422     void processPinchGestureEnd(quint32 time);
423     void processPinchGestureCancelled(quint32 time);
424 
425     void cursorRendered(const QRect &geometry);
sceneInitialized()426     virtual void sceneInitialized() {};
427 
428 Q_SIGNALS:
429     void screensQueried();
430     void readyChanged(bool);
431     /**
432      * This signal is emitted when an output has been connected. The @a output is not ready
433      * for compositing yet.
434      */
435     void outputAdded(AbstractOutput *output);
436     /**
437      * This signal is emitted when an output has been disconnected.
438      */
439     void outputRemoved(AbstractOutput *output);
440     /**
441      * This signal is emitted when the @a output has become activated and it is ready for
442      * compositing.
443      */
444     void outputEnabled(AbstractOutput *output);
445     /**
446      * This signal is emitted when the @a output has been deactivated and it is no longer
447      * being composited. The outputDisabled() signal is guaranteed to be emitted before the
448      * output is removed.
449      *
450      * @see outputEnabled, outputRemoved
451      */
452     void outputDisabled(AbstractOutput *output);
453 
454 protected:
455     explicit Platform(QObject *parent = nullptr);
456     void setSoftwareCursor(bool set);
457     void setSoftwareCursorForced(bool forced);
458     void repaint(const QRect &rect);
459     void setReady(bool ready);
460     void setPerScreenRenderingEnabled(bool enabled);
initialWindowSize()461     QSize initialWindowSize() const {
462         return m_initialWindowSize;
463     }
deviceIdentifier()464     QByteArray deviceIdentifier() const {
465         return m_deviceIdentifier;
466     }
setSupportsPointerWarping(bool set)467     void setSupportsPointerWarping(bool set) {
468         m_pointerWarping = set;
469     }
setSupportsGammaControl(bool set)470     void setSupportsGammaControl(bool set) {
471         m_supportsGammaControl = set;
472     }
473 
474     /**
475      * Whether the backend is supposed to change the configuration of outputs.
476      */
supportsOutputChanges()477     void supportsOutputChanges() {
478         m_supportsOutputChanges = true;
479     }
480 
481     /**
482      * Actual platform specific way to hide the cursor.
483      * Sub-classes need to implement if they support hiding the cursor.
484      *
485      * This method is invoked by hideCursor if the cursor needs to be hidden.
486      * The default implementation does nothing.
487      *
488      * @see doShowCursor
489      * @see hideCursor
490      * @see showCursor
491      */
492     virtual void doHideCursor();
493     /**
494      * Actual platform specific way to show the cursor.
495      * Sub-classes need to implement if they support showing the cursor.
496      *
497      * This method is invoked by showCursor if the cursor needs to be shown again.
498      *
499      * @see doShowCursor
500      * @see hideCursor
501      * @see showCursor
502      */
503     virtual void doShowCursor();
504     virtual void doSetSoftwareCursor();
505 
506 private:
507     void triggerCursorRepaint();
508     bool m_softwareCursor = false;
509     bool m_softwareCursorForced = false;
510     struct {
511         QRect lastRenderedGeometry;
512     } m_cursor;
513     bool m_ready = false;
514     QSize m_initialWindowSize;
515     QByteArray m_deviceIdentifier;
516     bool m_pointerWarping = false;
517     int m_initialOutputCount = 1;
518     qreal m_initialOutputScale = 1;
519     EGLDisplay m_eglDisplay;
520     EGLContext m_globalShareContext = EGL_NO_CONTEXT;
521     int m_hideCursorCounter = 0;
522     bool m_supportsGammaControl = false;
523     bool m_supportsOutputChanges = false;
524     bool m_isPerScreenRenderingEnabled = false;
525     CompositingType m_selectedCompositor = NoCompositing;
526 };
527 
528 }
529 
530 Q_DECLARE_INTERFACE(KWin::Platform, "org.kde.kwin.Platform")
531 
532 #endif
533