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