kwin/autotests/integration/kwin_wayland_test.h

863 lines
26 KiB
C
Raw Normal View History

2020-08-02 22:22:19 +00:00
/*
KWin - the KDE window manager
This file is part of the KDE project.
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
2020-08-02 22:22:19 +00:00
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
2020-08-02 22:22:19 +00:00
SPDX-License-Identifier: GPL-2.0-or-later
*/
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
#ifndef KWIN_WAYLAND_TEST_H
#define KWIN_WAYLAND_TEST_H
#include "core/inputdevice.h"
#include "main.h"
2022-04-22 17:39:12 +00:00
#include "window.h"
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
// Qt
#include <QSignalSpy>
#include <QTest>
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
#include <KWayland/Client/surface.h>
#include <optional>
#include "qwayland-cursor-shape-v1.h"
#include "qwayland-fractional-scale-v1.h"
#include "qwayland-idle-inhibit-unstable-v1.h"
#include "qwayland-input-method-unstable-v1.h"
#include "qwayland-kde-output-device-v2.h"
#include "qwayland-kde-output-management-v2.h"
#include "qwayland-kde-screen-edge-v1.h"
#include "qwayland-text-input-unstable-v3.h"
#include "qwayland-wlr-layer-shell-unstable-v1.h"
#include "qwayland-xdg-decoration-unstable-v1.h"
#include "qwayland-xdg-shell.h"
#include "qwayland-zkde-screencast-unstable-v1.h"
namespace KWayland
{
namespace Client
{
class AppMenuManager;
class ConnectionThread;
class Compositor;
class Output;
class PlasmaShell;
class PlasmaWindowManagement;
class Pointer;
Implement support for pointer constraints Summary: There are two types of constraints supported: 1. Pointer confinement 2. Pointer locking In the case of confinement the pointer is confined to a given region of the surface. This is comparable to general operation where the pointer is confined to the screen region. In the second case the pointer gets locked. That means it cannot move at all. No further position updates are provided, only relative motion events can go to the application. There is a hint about cursor position update on unlock which is not yet implemented in KWayland::Server, thus also not in this change. The implementation in KWin grants the requests for pointer constraints when the pointer enters the constrained region, either by pointer movement or by e.g. stacking order changes. There is no confirmation from user required to enter that mode. But we want to show an OSD when the pointer gets constrained, this is not yet implemented, though. Breaking an active constraint is relatively easy. E.g. changing the stacking order will break the constraint if another surface is under the cursor. Also (in case of confinement) moving the pointer to an overlapping window breaks the confinement. But as soon as one moves the pointer back to the window a constraint might get honoured again. To properly break there is a dedicated event filter. It listens for a long press of the Escape key. If hold for 3sec the pointer constraint is broken and not activated again till the pointer got moved out of the window. Afterward when moving in the pointer might activate again. The escape filter ensures that the key press is forwarded to the application if it's a short press or if another key gets pressed during the three seconds. If the three seconds way fires, the later escape release is not sent to the application. This basic interaction is also ensured through an added auto test. This change implements T4605. Test Plan: Added auto test and nested KWin Wayland with D3488 Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D3506
2016-11-25 06:17:43 +00:00
class PointerConstraints;
class Seat;
class ServerSideDecorationManager;
class ShadowManager;
class ShmPool;
class SubCompositor;
class SubSurface;
class Surface;
class TextInputManager;
}
}
namespace QtWayland
{
class zwp_input_panel_surface_v1;
class zwp_text_input_v3;
class zwp_text_input_manager_v3;
}
class ScreencastingV1;
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
namespace KWin
{
namespace Xwl
{
class Xwayland;
}
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
namespace Test
{
class VirtualInputDevice;
}
class WaylandTestApplication : public Application
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
{
Q_OBJECT
public:
WaylandTestApplication(OperationMode mode, int &argc, char **argv);
Run clang-tidy with modernize-use-override check Summary: Currently code base of kwin can be viewed as two pieces. One is very ancient, and the other one is more modern, which uses new C++ features. The main problem with the ancient code is that it was written before C++11 era. So, no override or final keywords, lambdas, etc. Quite recently, KDE compiler settings were changed to show a warning if a virtual method has missing override keyword. As you might have already guessed, this fired back at us because of that ancient code. We had about 500 new compiler warnings. A "solution" was proposed to that problem - disable -Wno-suggest-override and the other similar warning for clang. It's hard to call a solution because those warnings are disabled not only for the old code, but also for new. This is not what we want! The main argument for not actually fixing the problem was that git history will be screwed as well because of human factor. While good git history is a very important thing, we should not go crazy about it and block every change that somehow alters git history. git blame allows to specify starting revision for a reason. The other argument (human factor) can be easily solved by using tools such as clang-tidy. clang-tidy is a clang-based linter for C++. It can be used for various things, e.g. fixing coding style(e.g. add missing braces to if statements, readability-braces-around-statements check), or in our case add missing override keywords. Test Plan: Compiles. Reviewers: #kwin, davidedmundson Reviewed By: #kwin, davidedmundson Subscribers: davidedmundson, apol, romangg, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D22371
2019-07-22 16:52:26 +00:00
~WaylandTestApplication() override;
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
void setInputMethodServerToStart(const QString &inputMethodServer)
{
m_inputMethodServerToStart = inputMethodServer;
}
Test::VirtualInputDevice *virtualPointer() const;
Test::VirtualInputDevice *virtualKeyboard() const;
Test::VirtualInputDevice *virtualTouch() const;
XwaylandInterface *xwayland() const override;
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
protected:
void performStartup() override;
private:
void continueStartupWithScene();
void finalizeStartup();
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
void createVirtualInputDevices();
void destroyVirtualInputDevices();
std::unique_ptr<Xwl::Xwayland> m_xwayland;
QString m_inputMethodServerToStart;
std::unique_ptr<Test::VirtualInputDevice> m_virtualPointer;
std::unique_ptr<Test::VirtualInputDevice> m_virtualKeyboard;
std::unique_ptr<Test::VirtualInputDevice> m_virtualTouch;
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
};
namespace Test
{
class ScreencastingV1;
class MockInputMethod;
class TextInputManagerV3 : public QtWayland::zwp_text_input_manager_v3
{
public:
~TextInputManagerV3() override
{
destroy();
}
};
class TextInputV3 : public QObject, public QtWayland::zwp_text_input_v3
{
Q_OBJECT
public:
~TextInputV3() override
{
destroy();
}
Q_SIGNALS:
void preeditString(const QString &text, int cursor_begin, int cursor_end);
protected:
void zwp_text_input_v3_preedit_string(const QString &text, int32_t cursor_begin, int32_t cursor_end) override
{
Q_EMIT preeditString(text, cursor_begin, cursor_end);
}
};
class LayerShellV1 : public QtWayland::zwlr_layer_shell_v1
{
public:
~LayerShellV1() override;
};
class LayerSurfaceV1 : public QObject, public QtWayland::zwlr_layer_surface_v1
{
Q_OBJECT
public:
~LayerSurfaceV1() override;
protected:
void zwlr_layer_surface_v1_configure(uint32_t serial, uint32_t width, uint32_t height) override;
void zwlr_layer_surface_v1_closed() override;
Q_SIGNALS:
void closeRequested();
void configureRequested(quint32 serial, const QSize &size);
};
/**
* The XdgShell class represents the @c xdg_wm_base global.
*/
class XdgShell : public QtWayland::xdg_wm_base
{
public:
~XdgShell() override;
void xdg_wm_base_ping(uint32_t serial) override
{
pong(serial);
}
};
/**
* The XdgSurface class represents an xdg_surface object.
*/
class XdgSurface : public QObject, public QtWayland::xdg_surface
{
Q_OBJECT
public:
explicit XdgSurface(XdgShell *shell, KWayland::Client::Surface *surface, QObject *parent = nullptr);
~XdgSurface() override;
KWayland::Client::Surface *surface() const;
Q_SIGNALS:
void configureRequested(quint32 serial);
protected:
void xdg_surface_configure(uint32_t serial) override;
private:
KWayland::Client::Surface *m_surface;
};
/**
* The XdgToplevel class represents an xdg_toplevel surface. Note that the XdgToplevel surface
* takes the ownership of the underlying XdgSurface object.
*/
class XdgToplevel : public QObject, public QtWayland::xdg_toplevel
{
Q_OBJECT
public:
enum class State {
Maximized = 1 << 0,
Fullscreen = 1 << 1,
Resizing = 1 << 2,
Activated = 1 << 3
};
Q_DECLARE_FLAGS(States, State)
explicit XdgToplevel(XdgSurface *surface, QObject *parent = nullptr);
~XdgToplevel() override;
XdgSurface *xdgSurface() const;
Q_SIGNALS:
void configureRequested(const QSize &size, KWin::Test::XdgToplevel::States states);
void closeRequested();
protected:
void xdg_toplevel_configure(int32_t width, int32_t height, wl_array *states) override;
void xdg_toplevel_close() override;
private:
std::unique_ptr<XdgSurface> m_xdgSurface;
};
/**
* The XdgPositioner class represents an xdg_positioner object.
*/
class XdgPositioner : public QtWayland::xdg_positioner
{
public:
explicit XdgPositioner(XdgShell *shell);
~XdgPositioner() override;
};
/**
* The XdgPopup class represents an xdg_popup surface. Note that the XdgPopup surface takes
* the ownership of the underlying XdgSurface object.
*/
class XdgPopup : public QObject, public QtWayland::xdg_popup
{
Q_OBJECT
public:
XdgPopup(XdgSurface *surface, XdgSurface *parentSurface, XdgPositioner *positioner, QObject *parent = nullptr);
~XdgPopup() override;
XdgSurface *xdgSurface() const;
Q_SIGNALS:
void configureRequested(const QRect &rect);
void doneReceived();
protected:
void xdg_popup_configure(int32_t x, int32_t y, int32_t width, int32_t height) override;
void xdg_popup_popup_done() override;
private:
std::unique_ptr<XdgSurface> m_xdgSurface;
};
class XdgDecorationManagerV1 : public QtWayland::zxdg_decoration_manager_v1
{
public:
~XdgDecorationManagerV1() override;
};
class XdgToplevelDecorationV1 : public QObject, public QtWayland::zxdg_toplevel_decoration_v1
{
Q_OBJECT
public:
XdgToplevelDecorationV1(XdgDecorationManagerV1 *manager, XdgToplevel *toplevel, QObject *parent = nullptr);
~XdgToplevelDecorationV1() override;
Q_SIGNALS:
void configureRequested(QtWayland::zxdg_toplevel_decoration_v1::mode mode);
protected:
void zxdg_toplevel_decoration_v1_configure(uint32_t mode) override;
};
class IdleInhibitManagerV1 : public QtWayland::zwp_idle_inhibit_manager_v1
{
public:
~IdleInhibitManagerV1() override;
};
class IdleInhibitorV1 : public QtWayland::zwp_idle_inhibitor_v1
{
public:
IdleInhibitorV1(IdleInhibitManagerV1 *manager, KWayland::Client::Surface *surface);
~IdleInhibitorV1() override;
};
class WaylandOutputConfigurationV2 : public QObject, public QtWayland::kde_output_configuration_v2
{
Q_OBJECT
public:
WaylandOutputConfigurationV2(struct ::kde_output_configuration_v2 *object);
Q_SIGNALS:
void applied();
void failed();
protected:
void kde_output_configuration_v2_applied() override;
void kde_output_configuration_v2_failed() override;
};
class WaylandOutputManagementV2 : public QObject, public QtWayland::kde_output_management_v2
{
Q_OBJECT
public:
WaylandOutputManagementV2(struct ::wl_registry *registry, int id, int version);
WaylandOutputConfigurationV2 *createConfiguration();
};
class WaylandOutputDeviceV2Mode : public QObject, public QtWayland::kde_output_device_mode_v2
{
Q_OBJECT
public:
WaylandOutputDeviceV2Mode(struct ::kde_output_device_mode_v2 *object);
~WaylandOutputDeviceV2Mode() override;
int refreshRate() const;
QSize size() const;
bool preferred() const;
bool operator==(const WaylandOutputDeviceV2Mode &other) const;
static WaylandOutputDeviceV2Mode *get(struct ::kde_output_device_mode_v2 *object);
Q_SIGNALS:
void removed();
protected:
void kde_output_device_mode_v2_size(int32_t width, int32_t height) override;
void kde_output_device_mode_v2_refresh(int32_t refresh) override;
void kde_output_device_mode_v2_preferred() override;
void kde_output_device_mode_v2_removed() override;
private:
int m_refreshRate = 60000;
QSize m_size;
bool m_preferred = false;
};
class WaylandOutputDeviceV2 : public QObject, public QtWayland::kde_output_device_v2
{
Q_OBJECT
public:
WaylandOutputDeviceV2(int id);
~WaylandOutputDeviceV2() override;
QByteArray edid() const;
bool enabled() const;
int id() const;
QString name() const;
QString model() const;
QString manufacturer() const;
qreal scale() const;
QPoint globalPosition() const;
QSize pixelSize() const;
int refreshRate() const;
uint32_t vrrPolicy() const;
uint32_t overscan() const;
uint32_t capabilities() const;
uint32_t rgbRange() const;
QString modeId() const;
Q_SIGNALS:
void enabledChanged();
void done();
protected:
void kde_output_device_v2_geometry(int32_t x,
int32_t y,
int32_t physical_width,
int32_t physical_height,
int32_t subpixel,
const QString &make,
const QString &model,
int32_t transform) override;
void kde_output_device_v2_current_mode(struct ::kde_output_device_mode_v2 *mode) override;
void kde_output_device_v2_mode(struct ::kde_output_device_mode_v2 *mode) override;
void kde_output_device_v2_done() override;
void kde_output_device_v2_scale(wl_fixed_t factor) override;
void kde_output_device_v2_edid(const QString &raw) override;
void kde_output_device_v2_enabled(int32_t enabled) override;
void kde_output_device_v2_uuid(const QString &uuid) override;
void kde_output_device_v2_serial_number(const QString &serialNumber) override;
void kde_output_device_v2_eisa_id(const QString &eisaId) override;
void kde_output_device_v2_capabilities(uint32_t flags) override;
void kde_output_device_v2_overscan(uint32_t overscan) override;
void kde_output_device_v2_vrr_policy(uint32_t vrr_policy) override;
void kde_output_device_v2_rgb_range(uint32_t rgb_range) override;
private:
QString modeName(const WaylandOutputDeviceV2Mode *m) const;
WaylandOutputDeviceV2Mode *deviceModeFromId(const int modeId) const;
WaylandOutputDeviceV2Mode *m_mode;
QList<WaylandOutputDeviceV2Mode *> m_modes;
int m_id;
QPoint m_pos;
QSize m_physicalSize;
int32_t m_subpixel;
QString m_manufacturer;
QString m_model;
int32_t m_transform;
qreal m_factor;
QByteArray m_edid;
int32_t m_enabled;
QString m_uuid;
QString m_serialNumber;
QString m_eisaId;
uint32_t m_flags;
uint32_t m_overscan;
uint32_t m_vrr_policy;
uint32_t m_rgbRange;
};
class MockInputMethod : public QObject, QtWayland::zwp_input_method_v1
{
Q_OBJECT
public:
MockInputMethod(struct wl_registry *registry, int id, int version);
~MockInputMethod();
KWayland::Client::Surface *inputPanelSurface() const
{
return m_inputSurface.get();
}
auto *context() const
{
return m_context;
}
Q_SIGNALS:
void activate();
protected:
void zwp_input_method_v1_activate(struct ::zwp_input_method_context_v1 *context) override;
void zwp_input_method_v1_deactivate(struct ::zwp_input_method_context_v1 *context) override;
private:
std::unique_ptr<KWayland::Client::Surface> m_inputSurface;
QtWayland::zwp_input_panel_surface_v1 *m_inputMethodSurface = nullptr;
struct ::zwp_input_method_context_v1 *m_context = nullptr;
};
class FractionalScaleManagerV1 : public QObject, public QtWayland::wp_fractional_scale_manager_v1
{
Q_OBJECT
public:
~FractionalScaleManagerV1() override;
};
class FractionalScaleV1 : public QObject, public QtWayland::wp_fractional_scale_v1
{
Q_OBJECT
public:
~FractionalScaleV1() override;
int preferredScale();
protected:
void wp_fractional_scale_v1_preferred_scale(uint32_t scale) override;
private:
int m_preferredScale = 120;
};
class ScreenEdgeManagerV1 : public QObject, public QtWayland::kde_screen_edge_manager_v1
{
Q_OBJECT
public:
~ScreenEdgeManagerV1() override;
};
class AutoHideScreenEdgeV1 : public QObject, public QtWayland::kde_auto_hide_screen_edge_v1
{
Q_OBJECT
public:
AutoHideScreenEdgeV1(ScreenEdgeManagerV1 *manager, KWayland::Client::Surface *surface, uint32_t border);
~AutoHideScreenEdgeV1() override;
};
class CursorShapeManagerV1 : public QObject, public QtWayland::wp_cursor_shape_manager_v1
{
Q_OBJECT
public:
~CursorShapeManagerV1() override;
};
class CursorShapeDeviceV1 : public QObject, public QtWayland::wp_cursor_shape_device_v1
{
Q_OBJECT
public:
CursorShapeDeviceV1(CursorShapeManagerV1 *manager, KWayland::Client::Pointer *pointer);
~CursorShapeDeviceV1() override;
};
enum class AdditionalWaylandInterface {
Seat = 1 << 0,
Decoration = 1 << 1,
PlasmaShell = 1 << 2,
Implement support for pointer constraints Summary: There are two types of constraints supported: 1. Pointer confinement 2. Pointer locking In the case of confinement the pointer is confined to a given region of the surface. This is comparable to general operation where the pointer is confined to the screen region. In the second case the pointer gets locked. That means it cannot move at all. No further position updates are provided, only relative motion events can go to the application. There is a hint about cursor position update on unlock which is not yet implemented in KWayland::Server, thus also not in this change. The implementation in KWin grants the requests for pointer constraints when the pointer enters the constrained region, either by pointer movement or by e.g. stacking order changes. There is no confirmation from user required to enter that mode. But we want to show an OSD when the pointer gets constrained, this is not yet implemented, though. Breaking an active constraint is relatively easy. E.g. changing the stacking order will break the constraint if another surface is under the cursor. Also (in case of confinement) moving the pointer to an overlapping window breaks the confinement. But as soon as one moves the pointer back to the window a constraint might get honoured again. To properly break there is a dedicated event filter. It listens for a long press of the Escape key. If hold for 3sec the pointer constraint is broken and not activated again till the pointer got moved out of the window. Afterward when moving in the pointer might activate again. The escape filter ensures that the key press is forwarded to the application if it's a short press or if another key gets pressed during the three seconds. If the three seconds way fires, the later escape release is not sent to the application. This basic interaction is also ensured through an added auto test. This change implements T4605. Test Plan: Added auto test and nested KWin Wayland with D3488 Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D3506
2016-11-25 06:17:43 +00:00
WindowManagement = 1 << 3,
PointerConstraints = 1 << 4,
IdleInhibitV1 = 1 << 5,
AppMenu = 1 << 6,
ShadowManager = 1 << 7,
XdgDecorationV1 = 1 << 8,
OutputManagementV2 = 1 << 9,
TextInputManagerV2 = 1 << 10,
InputMethodV1 = 1 << 11,
LayerShellV1 = 1 << 12,
TextInputManagerV3 = 1 << 13,
OutputDeviceV2 = 1 << 14,
FractionalScaleManagerV1 = 1 << 15,
ScreencastingV1 = 1 << 16,
ScreenEdgeV1 = 1 << 17,
CursorShapeV1 = 1 << 18,
};
Q_DECLARE_FLAGS(AdditionalWaylandInterfaces, AdditionalWaylandInterface)
class VirtualInputDevice : public InputDevice
{
Q_OBJECT
public:
explicit VirtualInputDevice(QObject *parent = nullptr);
void setPointer(bool set);
void setKeyboard(bool set);
void setTouch(bool set);
void setLidSwitch(bool set);
void setName(const QString &name);
QString sysName() const override;
QString name() const override;
bool isEnabled() const override;
void setEnabled(bool enabled) override;
LEDs leds() const override;
void setLeds(LEDs leds) override;
bool isKeyboard() const override;
bool isAlphaNumericKeyboard() const override;
bool isPointer() const override;
bool isTouchpad() const override;
bool isTouch() const override;
bool isTabletTool() const override;
bool isTabletPad() const override;
bool isTabletModeSwitch() const override;
bool isLidSwitch() const override;
private:
QString m_name;
bool m_pointer = false;
bool m_keyboard = false;
bool m_touch = false;
bool m_lidSwitch = false;
};
void keyboardKeyPressed(quint32 key, quint32 time);
void keyboardKeyReleased(quint32 key, quint32 time);
void pointerAxisHorizontal(qreal delta,
quint32 time,
qint32 discreteDelta = 0,
InputRedirection::PointerAxisSource source = InputRedirection::PointerAxisSourceUnknown);
void pointerAxisVertical(qreal delta,
quint32 time,
qint32 discreteDelta = 0,
InputRedirection::PointerAxisSource source = InputRedirection::PointerAxisSourceUnknown);
void pointerButtonPressed(quint32 button, quint32 time);
void pointerButtonReleased(quint32 button, quint32 time);
void pointerMotion(const QPointF &position, quint32 time);
void pointerMotionRelative(const QPointF &delta, quint32 time);
void touchCancel();
void touchDown(qint32 id, const QPointF &pos, quint32 time);
void touchMotion(qint32 id, const QPointF &pos, quint32 time);
void touchUp(qint32 id, quint32 time);
/**
* Creates a Wayland Connection in a dedicated thread and creates various
* client side objects which can be used to create windows.
* @returns @c true if created successfully, @c false if there was an error
* @see destroyWaylandConnection
*/
bool setupWaylandConnection(AdditionalWaylandInterfaces flags = AdditionalWaylandInterfaces());
/**
* Destroys the Wayland Connection created with @link{setupWaylandConnection}.
* This can be called from cleanup in order to ensure that no Wayland Connection
* leaks into the next test method.
* @see setupWaylandConnection
*/
void destroyWaylandConnection();
KWayland::Client::ConnectionThread *waylandConnection();
KWayland::Client::Compositor *waylandCompositor();
KWayland::Client::SubCompositor *waylandSubCompositor();
KWayland::Client::ShadowManager *waylandShadowManager();
KWayland::Client::ShmPool *waylandShmPool();
KWayland::Client::Seat *waylandSeat();
KWayland::Client::ServerSideDecorationManager *waylandServerSideDecoration();
KWayland::Client::PlasmaShell *waylandPlasmaShell();
KWayland::Client::PlasmaWindowManagement *waylandWindowManagement();
Implement support for pointer constraints Summary: There are two types of constraints supported: 1. Pointer confinement 2. Pointer locking In the case of confinement the pointer is confined to a given region of the surface. This is comparable to general operation where the pointer is confined to the screen region. In the second case the pointer gets locked. That means it cannot move at all. No further position updates are provided, only relative motion events can go to the application. There is a hint about cursor position update on unlock which is not yet implemented in KWayland::Server, thus also not in this change. The implementation in KWin grants the requests for pointer constraints when the pointer enters the constrained region, either by pointer movement or by e.g. stacking order changes. There is no confirmation from user required to enter that mode. But we want to show an OSD when the pointer gets constrained, this is not yet implemented, though. Breaking an active constraint is relatively easy. E.g. changing the stacking order will break the constraint if another surface is under the cursor. Also (in case of confinement) moving the pointer to an overlapping window breaks the confinement. But as soon as one moves the pointer back to the window a constraint might get honoured again. To properly break there is a dedicated event filter. It listens for a long press of the Escape key. If hold for 3sec the pointer constraint is broken and not activated again till the pointer got moved out of the window. Afterward when moving in the pointer might activate again. The escape filter ensures that the key press is forwarded to the application if it's a short press or if another key gets pressed during the three seconds. If the three seconds way fires, the later escape release is not sent to the application. This basic interaction is also ensured through an added auto test. This change implements T4605. Test Plan: Added auto test and nested KWin Wayland with D3488 Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D3506
2016-11-25 06:17:43 +00:00
KWayland::Client::PointerConstraints *waylandPointerConstraints();
KWayland::Client::AppMenuManager *waylandAppMenuManager();
WaylandOutputManagementV2 *waylandOutputManagementV2();
KWayland::Client::TextInputManager *waylandTextInputManager();
QVector<KWayland::Client::Output *> waylandOutputs();
KWayland::Client::Output *waylandOutput(const QString &name);
ScreencastingV1 *screencasting();
QVector<WaylandOutputDeviceV2 *> waylandOutputDevicesV2();
2022-04-23 19:51:16 +00:00
bool waitForWaylandSurface(Window *window);
bool waitForWaylandPointer();
bool waitForWaylandTouch();
bool waitForWaylandKeyboard();
void flushWaylandConnection();
/**
* Ensures that all client requests are processed by the compositor and all events
* sent by the compositor are seen by the client.
*/
bool waylandSync();
std::unique_ptr<KWayland::Client::Surface> createSurface();
KWayland::Client::SubSurface *createSubSurface(KWayland::Client::Surface *surface,
KWayland::Client::Surface *parentSurface, QObject *parent = nullptr);
LayerSurfaceV1 *createLayerSurfaceV1(KWayland::Client::Surface *surface,
const QString &scope,
KWayland::Client::Output *output = nullptr,
LayerShellV1::layer layer = LayerShellV1::layer_top);
TextInputManagerV3 *waylandTextInputManagerV3();
enum class CreationSetup {
CreateOnly,
CreateAndConfigure, /// commit and wait for the configure event, making this surface ready to commit buffers
};
QtWayland::zwp_input_panel_surface_v1 *createInputPanelSurfaceV1(KWayland::Client::Surface *surface,
KWayland::Client::Output *output);
FractionalScaleV1 *createFractionalScaleV1(KWayland::Client::Surface *surface);
XdgToplevel *createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent = nullptr);
XdgToplevel *createXdgToplevelSurface(KWayland::Client::Surface *surface,
CreationSetup configureMode,
QObject *parent = nullptr);
XdgPositioner *createXdgPositioner();
XdgPopup *createXdgPopupSurface(KWayland::Client::Surface *surface, XdgSurface *parentSurface,
XdgPositioner *positioner,
CreationSetup configureMode = CreationSetup::CreateAndConfigure,
QObject *parent = nullptr);
XdgToplevelDecorationV1 *createXdgToplevelDecorationV1(XdgToplevel *toplevel, QObject *parent = nullptr);
IdleInhibitorV1 *createIdleInhibitorV1(KWayland::Client::Surface *surface);
AutoHideScreenEdgeV1 *createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border);
CursorShapeDeviceV1 *createCursorShapeDeviceV1(KWayland::Client::Pointer *pointer);
/**
* Creates a shared memory buffer of @p size in @p color and attaches it to the @p surface.
* The @p surface gets damaged and committed, thus it's rendered.
*/
void render(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format = QImage::Format_ARGB32_Premultiplied);
/**
* Creates a shared memory buffer using the supplied image @p img and attaches it to the @p surface
*/
void render(KWayland::Client::Surface *surface, const QImage &img);
/**
2022-04-22 17:39:12 +00:00
* Waits till a new Window is shown and returns the created Window.
* If no Window gets shown during @p timeout @c null is returned.
*/
2022-04-22 17:39:12 +00:00
Window *waitForWaylandWindowShown(int timeout = 5000);
/**
* Combination of @link{render} and @link{waitForWaylandWindowShown}.
*/
2022-04-22 17:39:12 +00:00
Window *renderAndWaitForShown(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format = QImage::Format_ARGB32, int timeout = 5000);
Window *renderAndWaitForShown(KWayland::Client::Surface *surface, const QImage &img, int timeout = 5000);
/**
2022-04-23 19:51:16 +00:00
* Waits for the @p window to be destroyed.
*/
bool waitForWindowClosed(Window *window);
/**
* Locks the screen and waits till the screen is locked.
* @returns @c true if the screen could be locked, @c false otherwise
*/
bool lockScreen();
/**
* Unlocks the screen and waits till the screen is unlocked.
* @returns @c true if the screen could be unlocked, @c false otherwise
*/
bool unlockScreen();
/**
* Returns @c true if the system has at least one render node; otherwise returns @c false.
*
* This can be used to test whether the system is capable of allocating and sharing prime buffers, etc.
*/
bool renderNodeAvailable();
/**
* Creates an X11 connection
* Internally a nested event loop is spawned whilst we connect to avoid a deadlock
* with X on demand
*/
struct XcbConnectionDeleter
{
void operator()(xcb_connection_t *pointer);
};
typedef std::unique_ptr<xcb_connection_t, XcbConnectionDeleter> XcbConnectionPtr;
XcbConnectionPtr createX11Connection();
MockInputMethod *inputMethod();
KWayland::Client::Surface *inputPanelSurface();
class ScreencastingStreamV1 : public QObject, public QtWayland::zkde_screencast_stream_unstable_v1
{
Q_OBJECT
friend class ScreencastingV1;
public:
ScreencastingStreamV1(QObject *parent)
: QObject(parent)
{
}
~ScreencastingStreamV1() override
{
if (isInitialized()) {
close();
}
}
quint32 nodeId() const
{
Q_ASSERT(m_nodeId.has_value());
return *m_nodeId;
}
void zkde_screencast_stream_unstable_v1_created(uint32_t node) override
{
m_nodeId = node;
Q_EMIT created(node);
}
void zkde_screencast_stream_unstable_v1_closed() override
{
Q_EMIT closed();
}
void zkde_screencast_stream_unstable_v1_failed(const QString &error) override
{
Q_EMIT failed(error);
}
Q_SIGNALS:
void created(quint32 nodeid);
void failed(const QString &error);
void closed();
private:
std::optional<uint> m_nodeId;
};
class ScreencastingV1 : public QObject, public QtWayland::zkde_screencast_unstable_v1
{
Q_OBJECT
public:
explicit ScreencastingV1(QObject *parent = nullptr)
: QObject(parent)
{
}
ScreencastingStreamV1 *createOutputStream(wl_output *output, pointer mode)
{
auto stream = new ScreencastingStreamV1(this);
stream->init(stream_output(output, mode));
return stream;
}
ScreencastingStreamV1 *createWindowStream(const QString &uuid, pointer mode)
{
auto stream = new ScreencastingStreamV1(this);
stream->init(stream_window(uuid, mode));
return stream;
}
};
struct OutputInfo
{
QRect geometry;
double scale = 1;
bool internal = false;
};
void setOutputConfig(const QVector<QRect> &geometries);
void setOutputConfig(const QVector<OutputInfo> &infos);
}
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
}
Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::Test::AdditionalWaylandInterfaces)
Q_DECLARE_METATYPE(KWin::Test::XdgToplevel::States)
Q_DECLARE_METATYPE(QtWayland::zxdg_toplevel_decoration_v1::mode)
#define WAYLANDTEST_MAIN(TestObject) \
int main(int argc, char *argv[]) \
{ \
setenv("QT_QPA_PLATFORM", "wayland-org.kde.kwin.qpa", true); \
setenv("QT_QPA_PLATFORM_PLUGIN_PATH", QFileInfo(QString::fromLocal8Bit(argv[0])).absolutePath().toLocal8Bit().constData(), true); \
setenv("KWIN_FORCE_OWN_QPA", "1", true); \
qunsetenv("KDE_FULL_SESSION"); \
qunsetenv("KDE_SESSION_VERSION"); \
qunsetenv("XDG_SESSION_DESKTOP"); \
qunsetenv("XDG_CURRENT_DESKTOP"); \
KWin::WaylandTestApplication app(KWin::Application::OperationModeXwayland, argc, argv); \
app.setAttribute(Qt::AA_Use96Dpi, true); \
TestObject tc; \
return QTest::qExec(&tc, argc, argv); \
}
[autotest] Welcome to integration testing KWin This is the beginning of a new testing era for KWin: finally we are able to test against a running KWin. This works by making use of the new virtual framebuffer backend for Wayland. It starts a specific Application subclass which is mostly a fork of ApplicationWayland. The individual tests are able to influence the socket name and the size of the virtual screen. This is supposed to be done in initTestCase. To know when KWin is fully started one can use the workspaceCreated signal of KWin::Application. KWin is not started in another process, but the kwin library is used, so the test has pretty much full introspection to everything going on inside KWin. It can access the Workspace, WaylandServer, fake input events through InputRedirection and so on. Once the test KWin is running it's possible to connect to it using KWayland::Client library. This allows to introspect the Workspace to see whether all worked as expected (e.g. correct stacking order, active window and so on). This first autotest is mostly meant to illustrate how to setup a test and how one can use KWayland::Client to interact with the mock KWin. For more tests it is suggested to move the connections to the Wayland server in the init() and cleanup() methods. The change also affects the qpa plugin: the specific check to only run in binaries called kwin_wayland doesn't hold any more. This can now be overwritten by an env variable. Please note that this first test will probably fail in the CI system as it might not have XWayland which is needed by KWin.
2015-10-02 13:04:57 +00:00
#endif