Split Compositor class in Wayland and X11 child classes

Summary:
This patch is a first take at splitting up of the Compositor class into
Wayland and X11 child classes.

In this first patch we mostly deal with setup and teardown procedures.
A future goal is to further differentiate the compositing part itself too.

Test Plan: Manually X from VT and Wayland nested. Autotests pass.

Reviewers: #kwin

Subscribers: sbergeron, anthonyfieroni, zzag, kwin

Tags: #kwin

Maniphest Tasks: T11071

Differential Revision: https://phabricator.kde.org/D22195
icc-effect-5.17.5
Roman Gilg 2019-08-07 19:33:20 +02:00
parent 4e078b9eaf
commit 1db84a2ba7
20 changed files with 429 additions and 268 deletions

View File

@ -126,7 +126,7 @@ void WaylandTestApplication::continueStartupWithScreens()
{
disconnect(kwinApp()->platform(), &Platform::screensQueried, this, &WaylandTestApplication::continueStartupWithScreens);
createScreens();
createCompositor();
WaylandCompositor::create();
connect(Compositor::self(), &Compositor::sceneCreated, this, &WaylandTestApplication::continueStartupWithScene);
}

View File

@ -62,7 +62,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <cstdio>
Q_DECLARE_METATYPE(KWin::Compositor::SuspendReason)
Q_DECLARE_METATYPE(KWin::X11Compositor::SuspendReason)
namespace KWin
{
@ -71,6 +71,27 @@ extern int screen_number; // main.cpp
extern bool is_multihead;
extern int currentRefreshRate();
Compositor *Compositor::s_compositor = nullptr;
Compositor *Compositor::self()
{
return s_compositor;
}
WaylandCompositor *WaylandCompositor::create(QObject *parent)
{
Q_ASSERT(!s_compositor);
auto *compositor = new WaylandCompositor(parent);
s_compositor = compositor;
return compositor;
}
X11Compositor *X11Compositor::create(QObject *parent)
{
Q_ASSERT(!s_compositor);
auto *compositor = new X11Compositor(parent);
s_compositor = compositor;
return compositor;
}
class CompositorSelectionOwner : public KSelectionOwner
{
Q_OBJECT
@ -92,26 +113,21 @@ private:
bool m_owning;
};
KWIN_SINGLETON_FACTORY_VARIABLE(Compositor, s_compositor)
static inline qint64 milliToNano(int milli) { return qint64(milli) * 1000 * 1000; }
static inline qint64 nanoToMilli(int nano) { return nano / (1000*1000); }
Compositor::Compositor(QObject* workspace)
: QObject(workspace)
, m_state(State::Off)
, m_suspended(options->isUseCompositing() ? NoReasonSuspend : UserSuspend)
, m_selectionOwner(NULL)
, vBlankInterval(0)
, fpsInterval(0)
, m_xrrRefreshRate(0)
, m_timeSinceLastVBlank(0)
, m_scene(NULL)
, m_bufferSwapPending(false)
, m_composeAtSwapCompletion(false)
{
qRegisterMetaType<Compositor::SuspendReason>("Compositor::SuspendReason");
connect(options, &Options::configChanged, this, &Compositor::slotConfigChanged);
connect(options, &Options::configChanged, this, &Compositor::configChanged);
m_monotonicClock.start();
@ -131,7 +147,7 @@ Compositor::Compositor(QObject* workspace)
// Workspace is completely constructed, so calling Workspace::self() would result
// in undefined behavior. This is fixed by using a delayed invocation.
if (kwinApp()->platform()->isReady()) {
QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection);
QTimer::singleShot(0, this, &Compositor::start);
}
connect(kwinApp()->platform(), &Platform::readyChanged, this,
[this] (bool ready) {
@ -142,12 +158,6 @@ Compositor::Compositor(QObject* workspace)
}
}, Qt::QueuedConnection
);
connect(kwinApp(), &Application::x11ConnectionAboutToBeDestroyed, this,
[this] {
delete m_selectionOwner;
m_selectionOwner = nullptr;
}
);
if (qEnvironmentVariableIsSet("KWIN_MAX_FRAMES_TESTED"))
m_framesToTestForSafety = qEnvironmentVariableIntValue("KWIN_MAX_FRAMES_TESTED");
@ -161,35 +171,18 @@ Compositor::~Compositor()
emit aboutToDestroy();
stop();
deleteUnusedSupportProperties();
delete m_selectionOwner;
destroyCompositorSelection();
s_compositor = NULL;
}
void Compositor::start()
bool Compositor::setupStart()
{
if (kwinApp()->isTerminating()) {
// Don't start while KWin is terminating. An event to restart might be lingering in the event queue due to graphics reset.
return;
return false;
}
if (m_state != State::Off) {
return;
}
if (m_suspended) {
QStringList reasons;
if (m_suspended & UserSuspend) {
reasons << QStringLiteral("Disabled by User");
}
if (m_suspended & BlockRuleSuspend) {
reasons << QStringLiteral("Disabled by Window");
}
if (m_suspended & ScriptSuspend) {
reasons << QStringLiteral("Disabled by Script");
}
qCDebug(KWIN_CORE) << "Compositing is suspended, reason:" << reasons;
return;
} else if (!kwinApp()->platform()->compositingPossible()) {
qCCritical(KWIN_CORE) << "Compositing is not possible";
return;
return false;
}
m_state = State::Starting;
@ -262,7 +255,7 @@ void Compositor::start()
qCCritical(KWIN_CORE) << "We are going to quit KWin now as it is broken";
qApp->quit();
}
return;
return false;
}
kwinApp()->platform()->setSelectedCompositor(m_scene->compositingType() & OpenGLCompositing ? OpenGLCompositing : m_scene->compositingType());
@ -275,11 +268,7 @@ void Compositor::start()
connect(m_scene, &Scene::resetCompositing, this, &Compositor::reinitialize);
emit sceneCreated();
if (Workspace::self()) {
startupWithWorkspace();
} else {
connect(kwinApp(), &Application::workspaceCreated, this, &Compositor::startupWithWorkspace);
}
return true;
}
void Compositor::claimCompositorSelection()
@ -319,10 +308,9 @@ void Compositor::startupWithWorkspace()
Q_ASSERT(m_scene);
connect(workspace(), &Workspace::destroyed, this, [this] { compositeTimer.stop(); });
setupX11Support();
m_xrrRefreshRate = KWin::currentRefreshRate();
fpsInterval = options->maxFpsInterval();
if (m_scene->syncsToVBlank()) { // if we do vsync, set the fps to the next multiple of the vblank rate
vBlankInterval = milliToNano(1000) / m_xrrRefreshRate;
vBlankInterval = milliToNano(1000) / currentRefreshRate();
fpsInterval = qMax((fpsInterval / vBlankInterval) * vBlankInterval, vBlankInterval);
} else
vBlankInterval = milliToNano(1); // no sync - DO NOT set "0", would cause div-by-zero segfaults.
@ -431,6 +419,12 @@ void Compositor::stop()
emit compositingToggled(false);
}
void Compositor::destroyCompositorSelection()
{
delete m_selectionOwner;
m_selectionOwner = nullptr;
}
void Compositor::releaseCompositorSelection()
{
switch (m_state) {
@ -479,16 +473,14 @@ void Compositor::deleteUnusedSupportProperties()
}
}
void Compositor::slotConfigChanged()
void Compositor::configChanged()
{
if (!m_suspended) {
start();
if (effects) // setupCompositing() may fail
effects->reconfigure();
addRepaintFull();
} else {
stop();
reinitialize();
if (effects) {
// setupCompositing() might fail.
effects->reconfigure();
}
addRepaintFull();
}
void Compositor::reinitialize()
@ -498,8 +490,6 @@ void Compositor::reinitialize()
// Restart compositing
stop();
// resume compositing if suspended
m_suspended = NoReasonSuspend;
start();
if (effects) { // start() may fail
@ -507,77 +497,6 @@ void Compositor::reinitialize()
}
}
// for the shortcut
void Compositor::toggleCompositing()
{
if (kwinApp()->platform()->requiresCompositing()) {
// we are not allowed to turn on/off compositing
return;
}
if (m_suspended) { // direct user call; clear all bits
resume(AllReasonSuspend);
} else { // but only set the user one (sufficient to suspend)
suspend(UserSuspend);
}
}
void Compositor::updateCompositeBlocking()
{
updateClientCompositeBlocking(NULL);
}
void Compositor::updateClientCompositeBlocking(Client *c)
{
if (kwinApp()->platform()->requiresCompositing()) {
return;
}
if (c) { // if c == 0 we just check if we can resume
if (c->isBlockingCompositing()) {
if (!(m_suspended & BlockRuleSuspend)) // do NOT attempt to call suspend(true); from within the eventchain!
QMetaObject::invokeMethod(this, "suspend", Qt::QueuedConnection, Q_ARG(Compositor::SuspendReason, BlockRuleSuspend));
}
}
else if (m_suspended & BlockRuleSuspend) { // lost a client and we're blocked - can we resume?
bool resume = true;
for (ClientList::ConstIterator it = Workspace::self()->clientList().constBegin(); it != Workspace::self()->clientList().constEnd(); ++it) {
if ((*it)->isBlockingCompositing()) {
resume = false;
break;
}
}
if (resume) { // do NOT attempt to call suspend(false); from within the eventchain!
QMetaObject::invokeMethod(this, "resume", Qt::QueuedConnection, Q_ARG(Compositor::SuspendReason, BlockRuleSuspend));
}
}
}
void Compositor::suspend(Compositor::SuspendReason reason)
{
if (kwinApp()->platform()->requiresCompositing()) {
return;
}
Q_ASSERT(reason != NoReasonSuspend);
m_suspended |= reason;
if (reason & KWin::Compositor::ScriptSuspend) {
// when disabled show a shortcut how the user can get back compositing
const auto shortcuts = KGlobalAccel::self()->shortcut(workspace()->findChild<QAction*>(QStringLiteral("Suspend Compositing")));
if (!shortcuts.isEmpty()) {
// display notification only if there is the shortcut
const QString message = i18n("Desktop effects have been suspended by another application.<br/>"
"You can resume using the '%1' shortcut.", shortcuts.first().toString(QKeySequence::NativeText));
KNotification::event(QStringLiteral("compositingsuspendeddbus"), message);
}
}
stop();
}
void Compositor::resume(Compositor::SuspendReason reason)
{
Q_ASSERT(reason != NoReasonSuspend);
m_suspended &= ~reason;
start();
}
void Compositor::addRepaint(int x, int y, int w, int h)
{
if (!hasScene())
@ -641,9 +560,6 @@ void Compositor::bufferSwapComplete()
void Compositor::performCompositing()
{
if (m_scene->usesOverlayWindow() && !isOverlayWindowVisible())
return; // nothing is visible anyway
// If a buffer swap is still pending, we return to the event loop and
// continue processing events until the swap has completed.
if (m_bufferSwapPending) {
@ -875,29 +791,212 @@ bool Compositor::isActive()
return m_state == State::On;
}
bool Compositor::checkForOverlayWindow(WId w) const
WaylandCompositor::WaylandCompositor(QObject *parent)
: Compositor(parent)
{
connect(kwinApp(), &Application::x11ConnectionAboutToBeDestroyed,
this, &WaylandCompositor::destroyCompositorSelection);
}
// for the shortcut
void WaylandCompositor::toggleCompositing()
{
// Not possible on Wayland because we always composite.
}
void WaylandCompositor::start()
{
if (!Compositor::setupStart()) {
// Internal setup failed, abort.
return;
}
if (Workspace::self()) {
startupWithWorkspace();
} else {
connect(kwinApp(), &Application::workspaceCreated, this, &WaylandCompositor::startupWithWorkspace);
}
}
bool WaylandCompositor::checkForOverlayWindow(WId w) const
{
Q_UNUSED(w)
// There is no overlay window in Wayland/XWayland.
return false;
}
int WaylandCompositor::refreshRate() const
{
// TODO: This makes no sense on Wayland. First step would be to atleast
// set the refresh rate to the highest available one. Second step
// would be to not use a uniform value at all but per screen.
return KWin::currentRefreshRate();
}
void WaylandCompositor::updateCompositeBlocking()
{
// Composite blocking not possible on Wayland.
}
void WaylandCompositor::updateClientCompositeBlocking(Client *c)
{
Q_UNUSED(c)
// Composite blocking not possible on Wayland.
}
X11Compositor::X11Compositor(QObject *parent)
: Compositor(parent)
, m_suspended(options->isUseCompositing() ? NoReasonSuspend : UserSuspend)
, m_xrrRefreshRate(0)
{
qRegisterMetaType<X11Compositor::SuspendReason>("X11Compositor::SuspendReason");
}
// for the shortcut
void X11Compositor::toggleCompositing()
{
if (kwinApp()->platform()->requiresCompositing()) {
// we are not allowed to turn on/off compositing
return;
}
if (m_suspended) { // direct user call; clear all bits
resume(AllReasonSuspend);
} else { // but only set the user one (sufficient to suspend)
suspend(UserSuspend);
}
}
void X11Compositor::reinitialize()
{
// resume compositing if suspended
m_suspended = NoReasonSuspend;
Compositor::reinitialize();
}
void X11Compositor::configChanged()
{
if (m_suspended) {
stop();
return;
}
Compositor::configChanged();
}
void X11Compositor::suspend(X11Compositor::SuspendReason reason)
{
Q_ASSERT(reason != NoReasonSuspend);
m_suspended |= reason;
if (reason & ScriptSuspend) {
// when disabled show a shortcut how the user can get back compositing
const auto shortcuts = KGlobalAccel::self()->shortcut(workspace()->findChild<QAction*>(QStringLiteral("Suspend Compositing")));
if (!shortcuts.isEmpty()) {
// display notification only if there is the shortcut
const QString message = i18n("Desktop effects have been suspended by another application.<br/>"
"You can resume using the '%1' shortcut.", shortcuts.first().toString(QKeySequence::NativeText));
KNotification::event(QStringLiteral("compositingsuspendeddbus"), message);
}
}
stop();
}
void X11Compositor::resume(X11Compositor::SuspendReason reason)
{
Q_ASSERT(reason != NoReasonSuspend);
m_suspended &= ~reason;
start();
}
void X11Compositor::start()
{
if (m_suspended) {
QStringList reasons;
if (m_suspended & UserSuspend) {
reasons << QStringLiteral("Disabled by User");
}
if (m_suspended & BlockRuleSuspend) {
reasons << QStringLiteral("Disabled by Window");
}
if (m_suspended & ScriptSuspend) {
reasons << QStringLiteral("Disabled by Script");
}
qCDebug(KWIN_CORE) << "Compositing is suspended, reason:" << reasons;
return;
} else if (!kwinApp()->platform()->compositingPossible()) {
qCCritical(KWIN_CORE) << "Compositing is not possible";
return;
}
if (!Compositor::setupStart()) {
// Internal setup failed, abort.
return;
}
m_xrrRefreshRate = KWin::currentRefreshRate();
startupWithWorkspace();
}
void X11Compositor::performCompositing()
{
if (scene()->usesOverlayWindow() && !isOverlayWindowVisible()) {
return; // nothing is visible anyway
}
Compositor::performCompositing();
}
bool X11Compositor::checkForOverlayWindow(WId w) const
{
if (!hasScene()) {
// no scene, so it cannot be the overlay window
return false;
}
if (!m_scene->overlayWindow()) {
if (!scene()->overlayWindow()) {
// no overlay window, it cannot be the overlay
return false;
}
// and compare the window ID's
return w == m_scene->overlayWindow()->window();
return w == scene()->overlayWindow()->window();
}
bool Compositor::isOverlayWindowVisible() const
bool X11Compositor::isOverlayWindowVisible() const
{
if (!hasScene()) {
return false;
}
if (!m_scene->overlayWindow()) {
if (!scene()->overlayWindow()) {
return false;
}
return m_scene->overlayWindow()->isVisible();
return scene()->overlayWindow()->isVisible();
}
int X11Compositor::refreshRate() const
{
return m_xrrRefreshRate;
}
void X11Compositor::updateCompositeBlocking()
{
updateClientCompositeBlocking(NULL);
}
void X11Compositor::updateClientCompositeBlocking(Client *c)
{
if (kwinApp()->platform()->requiresCompositing()) {
return;
}
if (c) { // if c == 0 we just check if we can resume
if (c->isBlockingCompositing()) {
if (!(m_suspended & BlockRuleSuspend)) // do NOT attempt to call suspend(true); from within the eventchain!
QMetaObject::invokeMethod(this, "suspend", Qt::QueuedConnection, Q_ARG(SuspendReason, BlockRuleSuspend));
}
}
else if (m_suspended & BlockRuleSuspend) { // lost a client and we're blocked - can we resume?
bool resume = true;
for (ClientList::ConstIterator it = Workspace::self()->clientList().constBegin(); it != Workspace::self()->clientList().constEnd(); ++it) {
if ((*it)->isBlockingCompositing()) {
resume = false;
break;
}
}
if (resume) { // do NOT attempt to call suspend(false); from within the eventchain!
QMetaObject::invokeMethod(this, "resume", Qt::QueuedConnection, Q_ARG(SuspendReason, BlockRuleSuspend));
}
}
}
} // namespace

View File

@ -38,15 +38,6 @@ class KWIN_EXPORT Compositor : public QObject
{
Q_OBJECT
public:
enum SuspendReason {
NoReasonSuspend = 0,
UserSuspend = 1 << 0,
BlockRuleSuspend = 1 << 1,
ScriptSuspend = 1 << 2,
AllReasonSuspend = 0xff
};
Q_DECLARE_FLAGS(SuspendReasons, SuspendReason)
enum class State {
On = 0,
Off,
@ -55,6 +46,7 @@ public:
};
~Compositor() override;
static Compositor *self();
// when adding repaints caused by a window, you probably want to use
// either Toplevel::addRepaint() or Toplevel::addWorkspaceRepaint()
@ -80,6 +72,157 @@ public:
*/
void bufferSwapComplete();
/**
* Toggles compositing, that is if the Compositor is suspended it will be resumed
* and if the Compositor is active it will be suspended.
* Invoked by keybinding (shortcut default: Shift + Alt + F12).
*/
virtual void toggleCompositing() = 0;
/**
* Re-initializes the Compositor completely.
* Connected to the D-Bus signal org.kde.KWin /KWin reinitCompositing
*/
virtual void reinitialize();
/**
* Whether the Compositor is active. That is a Scene is present and the Compositor is
* not shutting down itself.
*/
bool isActive();
virtual int refreshRate() const = 0;
bool hasScene() const {
return m_scene != NULL;
}
Scene *scene() const {
return m_scene;
}
/**
* Checks whether @p w is the Scene's overlay window.
*/
virtual bool checkForOverlayWindow(WId w) const = 0;
/**
* @brief Static check to test whether the Compositor is available and active.
*
* @return bool @c true if there is a Compositor and it is active, @c false otherwise
*/
static bool compositing() {
return s_compositor != NULL && s_compositor->isActive();
}
virtual void updateCompositeBlocking() = 0;
virtual void updateClientCompositeBlocking(KWin::Client *c) = 0;
// for delayed supportproperty management of effects
void keepSupportProperty(xcb_atom_t atom);
void removeSupportProperty(xcb_atom_t atom);
Q_SIGNALS:
void compositingToggled(bool active);
void aboutToDestroy();
void aboutToToggleCompositing();
void sceneCreated();
void bufferSwapCompleted();
protected:
explicit Compositor(QObject *parent = nullptr);
void timerEvent(QTimerEvent *te) override;
virtual void start() = 0;
void stop();
/**
* @brief Prepares start.
* @return bool @c true if start should be continued and @c if not.
*/
bool setupStart();
/**
* Continues the startup after Scene And Workspace are created
*/
void startupWithWorkspace();
virtual void performCompositing();
virtual void configChanged();
void destroyCompositorSelection();
static Compositor *s_compositor;
private:
void claimCompositorSelection();
void setupX11Support();
void setCompositeTimer();
bool windowRepaintsPending() const;
void releaseCompositorSelection();
void deleteUnusedSupportProperties();
State m_state;
QBasicTimer compositeTimer;
CompositorSelectionOwner *m_selectionOwner;
QTimer m_releaseSelectionTimer;
QList<xcb_atom_t> m_unusedSupportProperties;
QTimer m_unusedSupportPropertyTimer;
qint64 vBlankInterval, fpsInterval;
QRegion repaints_region;
qint64 m_timeSinceLastVBlank;
Scene *m_scene;
bool m_bufferSwapPending;
bool m_composeAtSwapCompletion;
int m_framesToTestForSafety = 3;
QElapsedTimer m_monotonicClock;
};
class KWIN_EXPORT WaylandCompositor : public Compositor
{
Q_OBJECT
public:
static WaylandCompositor *create(QObject *parent = nullptr);
~WaylandCompositor() override = default;
int refreshRate() const override;
void toggleCompositing() override;
bool checkForOverlayWindow(WId w) const override;
void updateCompositeBlocking() override;
void updateClientCompositeBlocking(KWin::Client* c) override;
protected:
void start() override;
private:
explicit WaylandCompositor(QObject *parent);
};
class KWIN_EXPORT X11Compositor : public Compositor
{
Q_OBJECT
public:
enum SuspendReason {
NoReasonSuspend = 0,
UserSuspend = 1 << 0,
BlockRuleSuspend = 1 << 1,
ScriptSuspend = 1 << 2,
AllReasonSuspend = 0xff
};
Q_DECLARE_FLAGS(SuspendReasons, SuspendReason)
static X11Compositor *create(QObject *parent = nullptr);
~X11Compositor() override = default;
/**
* @brief Suspends the Compositor if it is currently active.
*
@ -89,8 +232,8 @@ public:
* @return void
* @see resume
* @see isActive
*/
Q_INVOKABLE void suspend(Compositor::SuspendReason reason);
**/
Q_INVOKABLE void suspend(SuspendReason reason);
/**
* @brief Resumes the Compositor if it is currently suspended.
@ -108,121 +251,37 @@ public:
* @see isActive
* @see isCompositingPossible
* @see isOpenGLBroken
*/
Q_INVOKABLE void resume(Compositor::SuspendReason reason);
**/
Q_INVOKABLE void resume(SuspendReason reason);
/**
* Toggles compositing, that is if the Compositor is suspended it will be resumed
* and if the Compositor is active it will be suspended.
* Invoked by keybinding (shortcut default: Shift + Alt + F12).
*/
void toggleCompositing();
void toggleCompositing() override;
void reinitialize() override;
/**
* Re-initializes the Compositor completely.
* Connected to the D-Bus signal org.kde.KWin /KWin reinitCompositing
*/
void reinitialize();
void configChanged() override;
/**
* Whether the Compositor is active. That is a Scene is present and the Compositor is
* not shutting down itself.
*/
bool isActive();
int xrrRefreshRate() const {
return m_xrrRefreshRate;
}
bool hasScene() const {
return m_scene != NULL;
}
/**
* Checks whether @p w is the Scene's overlay window.
*/
bool checkForOverlayWindow(WId w) const;
bool checkForOverlayWindow(WId w) const override;
/**
* @returns Whether the Scene's Overlay X Window is visible.
*/
**/
bool isOverlayWindowVisible() const;
Scene *scene() {
return m_scene;
}
int refreshRate() const override;
/**
* @brief Static check to test whether the Compositor is available and active.
*
* @return bool @c true if there is a Compositor and it is active, @c false otherwise
*/
static bool compositing() {
return s_compositor != NULL && s_compositor->isActive();
}
void updateCompositeBlocking();
void updateClientCompositeBlocking(KWin::Client* c);
// for delayed supportproperty management of effects
void keepSupportProperty(xcb_atom_t atom);
void removeSupportProperty(xcb_atom_t atom);
Q_SIGNALS:
void compositingToggled(bool active);
void aboutToDestroy();
void aboutToToggleCompositing();
void sceneCreated();
void bufferSwapCompleted();
void updateCompositeBlocking() override;
void updateClientCompositeBlocking(KWin::Client* c) override;
protected:
void timerEvent(QTimerEvent *te) override;
void start() override;
void performCompositing() override;
private:
Q_INVOKABLE void start();
void stop();
void claimCompositorSelection();
/**
* Continues the startup after Scene And Workspace are created
*/
void startupWithWorkspace();
void setupX11Support();
void setCompositeTimer();
void performCompositing();
bool windowRepaintsPending() const;
void releaseCompositorSelection();
void deleteUnusedSupportProperties();
void slotConfigChanged();
State m_state;
explicit X11Compositor(QObject *parent);
/**
* Whether the Compositor is currently suspended, 8 bits encoding the reason
*/
**/
SuspendReasons m_suspended;
QBasicTimer compositeTimer;
CompositorSelectionOwner *m_selectionOwner;
QTimer m_releaseSelectionTimer;
QList<xcb_atom_t> m_unusedSupportProperties;
QTimer m_unusedSupportPropertyTimer;
qint64 vBlankInterval, fpsInterval;
int m_xrrRefreshRate;
QRegion repaints_region;
qint64 m_timeSinceLastVBlank;
Scene *m_scene;
bool m_bufferSwapPending;
bool m_composeAtSwapCompletion;
int m_framesToTestForSafety = 3;
QElapsedTimer m_monotonicClock;
KWIN_SINGLETON_VARIABLE(Compositor, s_compositor)
};
}

View File

@ -309,12 +309,16 @@ bool CompositorDBusInterface::platformRequiresCompositing() const
void CompositorDBusInterface::resume()
{
m_compositor->resume(Compositor::ScriptSuspend);
if (kwinApp()->operationMode() == Application::OperationModeX11) {
static_cast<X11Compositor*>(m_compositor)->resume(X11Compositor::ScriptSuspend);
}
}
void CompositorDBusInterface::suspend()
{
m_compositor->suspend(Compositor::ScriptSuspend);
if (kwinApp()->operationMode() == Application::OperationModeX11) {
static_cast<X11Compositor*>(m_compositor)->suspend(X11Compositor::ScriptSuspend);
}
}
void CompositorDBusInterface::reinitialize()

View File

@ -310,11 +310,6 @@ void Application::createOptions()
options = new Options;
}
void Application::createCompositor()
{
Compositor::create(this);
}
void Application::setupEventFilters()
{
installNativeEventFilter(m_eventFilter.data());

1
main.h
View File

@ -212,7 +212,6 @@ protected:
void createWorkspace();
void createAtoms();
void createOptions();
void createCompositor();
void setupEventFilters();
void destroyWorkspace();
void destroyCompositor();

View File

@ -180,7 +180,7 @@ void ApplicationWayland::continueStartupWithScreens()
{
disconnect(kwinApp()->platform(), &Platform::screensQueried, this, &ApplicationWayland::continueStartupWithScreens);
createScreens();
createCompositor();
WaylandCompositor::create();
connect(Compositor::self(), &Compositor::sceneCreated, this, &ApplicationWayland::continueStartupWithScene);
}

View File

@ -80,7 +80,7 @@ QRegion OpenGLBackend::accumulatedDamageHistory(int bufferAge) const
return region;
}
OverlayWindow* OpenGLBackend::overlayWindow()
OverlayWindow* OpenGLBackend::overlayWindow() const
{
return NULL;
}

View File

@ -112,7 +112,7 @@ public:
*
* @return :OverlayWindow*
*/
virtual OverlayWindow *overlayWindow();
virtual OverlayWindow *overlayWindow() const;
/**
* @brief Whether the creation of the Backend failed.
*

View File

@ -463,7 +463,7 @@ bool EglOnXBackend::usesOverlayWindow() const
return m_usesOverlayWindow;
}
OverlayWindow* EglOnXBackend::overlayWindow()
OverlayWindow* EglOnXBackend::overlayWindow() const
{
return m_overlayWindow;
}

View File

@ -40,7 +40,7 @@ public:
SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override;
QRegion prepareRenderingFrame() override;
void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion) override;
OverlayWindow* overlayWindow() override;
OverlayWindow* overlayWindow() const override;
bool usesOverlayWindow() const override;
void init() override;

View File

@ -849,7 +849,7 @@ void GlxBackend::doneCurrent()
glXMakeCurrent(display(), None, nullptr);
}
OverlayWindow* GlxBackend::overlayWindow()
OverlayWindow* GlxBackend::overlayWindow() const
{
return m_overlayWindow;
}

View File

@ -76,7 +76,7 @@ public:
void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion) override;
bool makeCurrent() override;
void doneCurrent() override;
OverlayWindow* overlayWindow() override;
OverlayWindow* overlayWindow() const override;
bool usesOverlayWindow() const override;
void init() override;

View File

@ -53,7 +53,7 @@ void XRandRScreens::init()
if (!workspace()->compositing()) {
return;
}
if (Compositor::self()->xrrRefreshRate() == Options::currentRefreshRate()) {
if (Compositor::self()->refreshRate() == Options::currentRefreshRate()) {
return;
}
// desktopResized() should take care of when the size or

View File

@ -519,7 +519,7 @@ SceneOpenGL *SceneOpenGL::createScene(QObject *parent)
return scene;
}
OverlayWindow *SceneOpenGL::overlayWindow()
OverlayWindow *SceneOpenGL::overlayWindow() const
{
return m_backend->overlayWindow();
}
@ -823,11 +823,15 @@ SceneOpenGLTexture *SceneOpenGL::createTexture()
}
bool SceneOpenGL::viewportLimitsMatched(const QSize &size) const {
if (kwinApp()->operationMode() != Application::OperationModeX11) {
// TODO: On Wayland we can't suspend. Find a solution that works here as well!
return true;
}
GLint limit[2];
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, limit);
if (limit[0] < size.width() || limit[1] < size.height()) {
QMetaObject::invokeMethod(Compositor::self(), "suspend",
Qt::QueuedConnection, Q_ARG(Compositor::SuspendReason, Compositor::AllReasonSuspend));
QMetaObject::invokeMethod(static_cast<X11Compositor*>(Compositor::self()), "suspend",
Qt::QueuedConnection, Q_ARG(X11Compositor::SuspendReason, X11Compositor::AllReasonSuspend));
return false;
}
return true;

View File

@ -51,7 +51,7 @@ public:
Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame) override;
Shadow *createShadow(Toplevel *toplevel) override;
void screenGeometryChanged(const QSize &size) override;
OverlayWindow *overlayWindow() override;
OverlayWindow *overlayWindow() const override;
bool usesOverlayWindow() const override;
bool blocksForRetrace() const override;
bool syncsToVBlank() const override;

View File

@ -35,7 +35,7 @@ class KWIN_EXPORT SceneQPainter : public Scene
public:
~SceneQPainter() override;
bool usesOverlayWindow() const override;
OverlayWindow* overlayWindow() override;
OverlayWindow* overlayWindow() const override;
qint64 paint(QRegion damage, ToplevelList windows) override;
void paintGenericScreen(int mask, ScreenPaintData data) override;
CompositingType compositingType() const override;
@ -180,7 +180,7 @@ bool SceneQPainter::usesOverlayWindow() const
}
inline
OverlayWindow* SceneQPainter::overlayWindow()
OverlayWindow* SceneQPainter::overlayWindow() const
{
return m_backend->overlayWindow();
}

View File

@ -159,7 +159,7 @@ public:
Shadow *createShadow(Toplevel *toplevel) override;
void screenGeometryChanged(const QSize &size) override;
xcb_render_picture_t xrenderBufferPicture() const override;
OverlayWindow *overlayWindow() override {
OverlayWindow *overlayWindow() const override {
return m_backend->overlayWindow();
}
bool usesOverlayWindow() const override {

View File

@ -147,7 +147,7 @@ public:
virtual void idle();
virtual bool blocksForRetrace() const;
virtual bool syncsToVBlank() const;
virtual OverlayWindow* overlayWindow() = 0;
virtual OverlayWindow* overlayWindow() const = 0;
virtual bool makeOpenGLContextCurrent();
virtual void doneOpenGLContextCurrent();

View File

@ -176,7 +176,8 @@ Workspace::Workspace(const QString &sessionKey)
if (Compositor::self()) {
m_compositor = Compositor::self();
} else {
m_compositor = Compositor::create(this);
Q_ASSERT(kwinApp()->operationMode() == Application::OperationMode::OperationModeX11);
m_compositor = X11Compositor::create(this);
}
connect(this, &Workspace::currentDesktopChanged, m_compositor, &Compositor::addRepaintFull);
connect(m_compositor, &QObject::destroyed, this, [this] { m_compositor = nullptr; });