Changeset View
Standalone View
composite.cpp
Show First 20 Lines • Show All 56 Lines • ▼ Show 20 Line(s) | |||||
57 | #include <QTextStream> | 57 | #include <QTextStream> | ||
58 | #include <QTimerEvent> | 58 | #include <QTimerEvent> | ||
59 | 59 | | |||
60 | #include <xcb/composite.h> | 60 | #include <xcb/composite.h> | ||
61 | #include <xcb/damage.h> | 61 | #include <xcb/damage.h> | ||
62 | 62 | | |||
63 | #include <cstdio> | 63 | #include <cstdio> | ||
64 | 64 | | |||
65 | Q_DECLARE_METATYPE(KWin::Compositor::SuspendReason) | 65 | Q_DECLARE_METATYPE(KWin::X11Compositor::SuspendReason) | ||
66 | 66 | | |||
67 | namespace KWin | 67 | namespace KWin | ||
68 | { | 68 | { | ||
69 | 69 | | |||
70 | extern int screen_number; // main.cpp | 70 | extern int screen_number; // main.cpp | ||
71 | extern bool is_multihead; | 71 | extern bool is_multihead; | ||
72 | extern int currentRefreshRate(); | 72 | extern int currentRefreshRate(); | ||
73 | 73 | | |||
74 | Compositor *Compositor::s_compositor = nullptr; | ||||
75 | Compositor* Compositor::self() | ||||
76 | { | ||||
77 | return s_compositor; | ||||
78 | } | ||||
79 | | ||||
80 | WaylandCompositor* WaylandCompositor::create(QObject *parent) | ||||
81 | { | ||||
82 | Q_ASSERT(!s_compositor); | ||||
83 | auto *compositor = new WaylandCompositor(parent); | ||||
84 | s_compositor = compositor; | ||||
zzag: Is there a reason for not initializing s_compositor in constructor of Compositor class? | |||||
Not in particular. Setting the static variable in the static method seems more readable to me. Also since we assert here. And its the same like the kwinglobals factory methods do it. romangg: Not in particular. Setting the static variable in the static method seems more readable to me. | |||||
85 | return compositor; | ||||
86 | } | ||||
87 | X11Compositor* X11Compositor::create(QObject *parent) | ||||
88 | { | ||||
89 | Q_ASSERT(!s_compositor); | ||||
90 | auto *compositor = new X11Compositor(parent); | ||||
91 | s_compositor = compositor; | ||||
92 | return compositor; | ||||
93 | } | ||||
94 | | ||||
74 | class CompositorSelectionOwner : public KSelectionOwner | 95 | class CompositorSelectionOwner : public KSelectionOwner | ||
75 | { | 96 | { | ||
76 | Q_OBJECT | 97 | Q_OBJECT | ||
77 | public: | 98 | public: | ||
78 | CompositorSelectionOwner(const char *selection) | 99 | CompositorSelectionOwner(const char *selection) | ||
79 | : KSelectionOwner(selection, connection(), rootWindow()) | 100 | : KSelectionOwner(selection, connection(), rootWindow()) | ||
80 | , m_owning(false) | 101 | , m_owning(false) | ||
81 | { | 102 | { | ||
82 | connect (this, &CompositorSelectionOwner::lostOwnership, | 103 | connect (this, &CompositorSelectionOwner::lostOwnership, | ||
83 | this, [this]() { m_owning = false; }); | 104 | this, [this]() { m_owning = false; }); | ||
84 | } | 105 | } | ||
85 | bool owning() const { | 106 | bool owning() const { | ||
86 | return m_owning; | 107 | return m_owning; | ||
87 | } | 108 | } | ||
88 | void setOwning(bool own) { | 109 | void setOwning(bool own) { | ||
89 | m_owning = own; | 110 | m_owning = own; | ||
90 | } | 111 | } | ||
91 | private: | 112 | private: | ||
92 | bool m_owning; | 113 | bool m_owning; | ||
93 | }; | 114 | }; | ||
94 | 115 | | |||
95 | KWIN_SINGLETON_FACTORY_VARIABLE(Compositor, s_compositor) | | |||
96 | | ||||
97 | static inline qint64 milliToNano(int milli) { return qint64(milli) * 1000 * 1000; } | 116 | static inline qint64 milliToNano(int milli) { return qint64(milli) * 1000 * 1000; } | ||
98 | static inline qint64 nanoToMilli(int nano) { return nano / (1000*1000); } | 117 | static inline qint64 nanoToMilli(int nano) { return nano / (1000*1000); } | ||
99 | 118 | | |||
100 | Compositor::Compositor(QObject* workspace) | 119 | Compositor::Compositor(QObject* workspace) | ||
101 | : QObject(workspace) | 120 | : QObject(workspace) | ||
102 | , m_state(State::Off) | 121 | , m_state(State::Off) | ||
103 | , m_suspended(options->isUseCompositing() ? NoReasonSuspend : UserSuspend) | | |||
104 | , m_selectionOwner(NULL) | 122 | , m_selectionOwner(NULL) | ||
105 | , vBlankInterval(0) | 123 | , vBlankInterval(0) | ||
106 | , fpsInterval(0) | 124 | , fpsInterval(0) | ||
107 | , m_xrrRefreshRate(0) | | |||
108 | , m_timeSinceLastVBlank(0) | 125 | , m_timeSinceLastVBlank(0) | ||
109 | , m_scene(NULL) | 126 | , m_scene(NULL) | ||
110 | , m_bufferSwapPending(false) | 127 | , m_bufferSwapPending(false) | ||
111 | , m_composeAtSwapCompletion(false) | 128 | , m_composeAtSwapCompletion(false) | ||
112 | { | 129 | { | ||
113 | qRegisterMetaType<Compositor::SuspendReason>("Compositor::SuspendReason"); | 130 | connect(options, &Options::configChanged, this, &Compositor::configChanged); | ||
114 | connect(options, &Options::configChanged, this, &Compositor::slotConfigChanged); | | |||
115 | 131 | | |||
116 | m_monotonicClock.start(); | 132 | m_monotonicClock.start(); | ||
117 | 133 | | |||
118 | // 2 sec which should be enough to restart the compositor | 134 | // 2 sec which should be enough to restart the compositor | ||
119 | static const int compositorLostMessageDelay = 2000; | 135 | static const int compositorLostMessageDelay = 2000; | ||
120 | 136 | | |||
121 | m_releaseSelectionTimer.setSingleShot(true); | 137 | m_releaseSelectionTimer.setSingleShot(true); | ||
122 | m_releaseSelectionTimer.setInterval(compositorLostMessageDelay); | 138 | m_releaseSelectionTimer.setInterval(compositorLostMessageDelay); | ||
123 | connect(&m_releaseSelectionTimer, &QTimer::timeout, this, &Compositor::releaseCompositorSelection); | 139 | connect(&m_releaseSelectionTimer, &QTimer::timeout, this, &Compositor::releaseCompositorSelection); | ||
124 | 140 | | |||
125 | m_unusedSupportPropertyTimer.setInterval(compositorLostMessageDelay); | 141 | m_unusedSupportPropertyTimer.setInterval(compositorLostMessageDelay); | ||
126 | m_unusedSupportPropertyTimer.setSingleShot(true); | 142 | m_unusedSupportPropertyTimer.setSingleShot(true); | ||
127 | connect(&m_unusedSupportPropertyTimer, &QTimer::timeout, this, &Compositor::deleteUnusedSupportProperties); | 143 | connect(&m_unusedSupportPropertyTimer, &QTimer::timeout, this, &Compositor::deleteUnusedSupportProperties); | ||
128 | 144 | | |||
129 | // Delay the call to start by one event cycle. | 145 | // Delay the call to start by one event cycle. | ||
130 | // The ctor of this class is invoked from the Workspace ctor, that means before | 146 | // The ctor of this class is invoked from the Workspace ctor, that means before | ||
131 | // Workspace is completely constructed, so calling Workspace::self() would result | 147 | // Workspace is completely constructed, so calling Workspace::self() would result | ||
132 | // in undefined behavior. This is fixed by using a delayed invocation. | 148 | // in undefined behavior. This is fixed by using a delayed invocation. | ||
133 | if (kwinApp()->platform()->isReady()) { | 149 | if (kwinApp()->platform()->isReady()) { | ||
134 | QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection); | 150 | QTimer::singleShot(0, this, &Compositor::start); | ||
135 | } | 151 | } | ||
136 | connect(kwinApp()->platform(), &Platform::readyChanged, this, | 152 | connect(kwinApp()->platform(), &Platform::readyChanged, this, | ||
137 | [this] (bool ready) { | 153 | [this] (bool ready) { | ||
138 | if (ready) { | 154 | if (ready) { | ||
139 | start(); | 155 | start(); | ||
140 | } else { | 156 | } else { | ||
141 | stop(); | 157 | stop(); | ||
142 | } | 158 | } | ||
143 | }, Qt::QueuedConnection | 159 | }, Qt::QueuedConnection | ||
144 | ); | 160 | ); | ||
145 | connect(kwinApp(), &Application::x11ConnectionAboutToBeDestroyed, this, | | |||
146 | [this] { | | |||
147 | delete m_selectionOwner; | | |||
148 | m_selectionOwner = nullptr; | | |||
149 | } | | |||
150 | ); | | |||
151 | 161 | | |||
152 | if (qEnvironmentVariableIsSet("KWIN_MAX_FRAMES_TESTED")) | 162 | if (qEnvironmentVariableIsSet("KWIN_MAX_FRAMES_TESTED")) | ||
153 | m_framesToTestForSafety = qEnvironmentVariableIntValue("KWIN_MAX_FRAMES_TESTED"); | 163 | m_framesToTestForSafety = qEnvironmentVariableIntValue("KWIN_MAX_FRAMES_TESTED"); | ||
154 | 164 | | |||
155 | // register DBus | 165 | // register DBus | ||
156 | new CompositorDBusInterface(this); | 166 | new CompositorDBusInterface(this); | ||
157 | } | 167 | } | ||
158 | 168 | | |||
159 | Compositor::~Compositor() | 169 | Compositor::~Compositor() | ||
160 | { | 170 | { | ||
161 | emit aboutToDestroy(); | 171 | emit aboutToDestroy(); | ||
162 | stop(); | 172 | stop(); | ||
163 | deleteUnusedSupportProperties(); | 173 | deleteUnusedSupportProperties(); | ||
164 | delete m_selectionOwner; | 174 | destroyCompositorSelection(); | ||
165 | s_compositor = NULL; | 175 | s_compositor = NULL; | ||
166 | } | 176 | } | ||
167 | 177 | | |||
168 | void Compositor::start() | 178 | bool Compositor::setupStart() | ||
AbstractClient has generic methods that call "platform-specific" methods to do the dirty work, e.g. doResize, doSetKeepAbove, etc. I've been wondering whether we could apply the same pattern here in the Compositor class. zzag: AbstractClient has generic methods that call "platform-specific" methods to do the dirty work… | |||||
Maybe. Is it a blocker or a necessity to this patch here? Otherwise let's tackle one idea after the other, shall we? romangg: Maybe. Is it a blocker or a necessity to this patch here? Otherwise let's tackle one idea after… | |||||
Well, some parts of KWin(as well Qt) follow this pattern, e.g. EffectsHandlerImpl, so it's a good idea to stick with this pattern in Compositor class. Given that the Compositor class still has X11 bits, I guess we can go with this approach for now. zzag: Well, some parts of KWin(as well Qt) follow this pattern, e.g. EffectsHandlerImpl, so it's a… | |||||
169 | { | 179 | { | ||
170 | if (kwinApp()->isTerminating()) { | 180 | if (kwinApp()->isTerminating()) { | ||
171 | // Don't start while KWin is terminating. An event to restart might be lingering in the event queue due to graphics reset. | 181 | // Don't start while KWin is terminating. An event to restart might be lingering in the event queue due to graphics reset. | ||
172 | return; | 182 | return false; | ||
173 | } | 183 | } | ||
174 | if (m_state != State::Off) { | 184 | if (m_state != State::Off) { | ||
175 | return; | 185 | return false; | ||
176 | } | | |||
177 | if (m_suspended) { | | |||
178 | QStringList reasons; | | |||
179 | if (m_suspended & UserSuspend) { | | |||
180 | reasons << QStringLiteral("Disabled by User"); | | |||
181 | } | | |||
182 | if (m_suspended & BlockRuleSuspend) { | | |||
183 | reasons << QStringLiteral("Disabled by Window"); | | |||
184 | } | | |||
185 | if (m_suspended & ScriptSuspend) { | | |||
186 | reasons << QStringLiteral("Disabled by Script"); | | |||
187 | } | | |||
188 | qCDebug(KWIN_CORE) << "Compositing is suspended, reason:" << reasons; | | |||
189 | return; | | |||
190 | } else if (!kwinApp()->platform()->compositingPossible()) { | | |||
191 | qCCritical(KWIN_CORE) << "Compositing is not possible"; | | |||
192 | return; | | |||
193 | } | 186 | } | ||
194 | m_state = State::Starting; | 187 | m_state = State::Starting; | ||
195 | 188 | | |||
196 | options->reloadCompositingSettings(true); | 189 | options->reloadCompositingSettings(true); | ||
197 | 190 | | |||
198 | setupX11Support(); | 191 | setupX11Support(); | ||
199 | 192 | | |||
200 | // There might still be a deleted around, needs to be cleared before creating the scene (BUG 333275) | 193 | // There might still be a deleted around, needs to be cleared before creating the scene (BUG 333275) | ||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Line(s) | 249 | if (m_selectionOwner) { | |||
257 | m_selectionOwner->setOwning(false); | 250 | m_selectionOwner->setOwning(false); | ||
258 | m_selectionOwner->release(); | 251 | m_selectionOwner->release(); | ||
259 | } | 252 | } | ||
260 | if (!supportedCompositors.contains(NoCompositing)) { | 253 | if (!supportedCompositors.contains(NoCompositing)) { | ||
261 | qCCritical(KWIN_CORE) << "The used windowing system requires compositing"; | 254 | qCCritical(KWIN_CORE) << "The used windowing system requires compositing"; | ||
262 | qCCritical(KWIN_CORE) << "We are going to quit KWin now as it is broken"; | 255 | qCCritical(KWIN_CORE) << "We are going to quit KWin now as it is broken"; | ||
263 | qApp->quit(); | 256 | qApp->quit(); | ||
264 | } | 257 | } | ||
265 | return; | 258 | return false; | ||
266 | } | 259 | } | ||
267 | 260 | | |||
268 | kwinApp()->platform()->setSelectedCompositor(m_scene->compositingType() & OpenGLCompositing ? OpenGLCompositing : m_scene->compositingType()); | 261 | kwinApp()->platform()->setSelectedCompositor(m_scene->compositingType() & OpenGLCompositing ? OpenGLCompositing : m_scene->compositingType()); | ||
269 | 262 | | |||
270 | if (!Workspace::self() && m_scene && m_scene->compositingType() == QPainterCompositing) { | 263 | if (!Workspace::self() && m_scene && m_scene->compositingType() == QPainterCompositing) { | ||
271 | // Force Software QtQuick on first startup with QPainter | 264 | // Force Software QtQuick on first startup with QPainter | ||
272 | QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software); | 265 | QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software); | ||
273 | } | 266 | } | ||
274 | 267 | | |||
275 | connect(m_scene, &Scene::resetCompositing, this, &Compositor::reinitialize); | 268 | connect(m_scene, &Scene::resetCompositing, this, &Compositor::reinitialize); | ||
276 | emit sceneCreated(); | 269 | emit sceneCreated(); | ||
277 | 270 | | |||
278 | if (Workspace::self()) { | 271 | return true; | ||
279 | startupWithWorkspace(); | | |||
280 | } else { | | |||
281 | connect(kwinApp(), &Application::workspaceCreated, this, &Compositor::startupWithWorkspace); | | |||
282 | } | | |||
283 | } | 272 | } | ||
284 | 273 | | |||
285 | void Compositor::claimCompositorSelection() | 274 | void Compositor::claimCompositorSelection() | ||
286 | { | 275 | { | ||
287 | if (!m_selectionOwner) { | 276 | if (!m_selectionOwner) { | ||
288 | char selection_name[ 100 ]; | 277 | char selection_name[ 100 ]; | ||
289 | sprintf(selection_name, "_NET_WM_CM_S%d", Application::x11ScreenNumber()); | 278 | sprintf(selection_name, "_NET_WM_CM_S%d", Application::x11ScreenNumber()); | ||
290 | m_selectionOwner = new CompositorSelectionOwner(selection_name); | 279 | m_selectionOwner = new CompositorSelectionOwner(selection_name); | ||
Show All 23 Lines | |||||
314 | 303 | | |||
315 | void Compositor::startupWithWorkspace() | 304 | void Compositor::startupWithWorkspace() | ||
316 | { | 305 | { | ||
317 | connect(kwinApp(), &Application::x11ConnectionChanged, this, &Compositor::setupX11Support, Qt::UniqueConnection); | 306 | connect(kwinApp(), &Application::x11ConnectionChanged, this, &Compositor::setupX11Support, Qt::UniqueConnection); | ||
318 | Workspace::self()->markXStackingOrderAsDirty(); | 307 | Workspace::self()->markXStackingOrderAsDirty(); | ||
319 | Q_ASSERT(m_scene); | 308 | Q_ASSERT(m_scene); | ||
320 | connect(workspace(), &Workspace::destroyed, this, [this] { compositeTimer.stop(); }); | 309 | connect(workspace(), &Workspace::destroyed, this, [this] { compositeTimer.stop(); }); | ||
321 | setupX11Support(); | 310 | setupX11Support(); | ||
322 | m_xrrRefreshRate = KWin::currentRefreshRate(); | | |||
323 | fpsInterval = options->maxFpsInterval(); | 311 | fpsInterval = options->maxFpsInterval(); | ||
324 | if (m_scene->syncsToVBlank()) { // if we do vsync, set the fps to the next multiple of the vblank rate | 312 | if (m_scene->syncsToVBlank()) { // if we do vsync, set the fps to the next multiple of the vblank rate | ||
325 | vBlankInterval = milliToNano(1000) / m_xrrRefreshRate; | 313 | vBlankInterval = milliToNano(1000) / currentRefreshRate(); | ||
326 | fpsInterval = qMax((fpsInterval / vBlankInterval) * vBlankInterval, vBlankInterval); | 314 | fpsInterval = qMax((fpsInterval / vBlankInterval) * vBlankInterval, vBlankInterval); | ||
327 | } else | 315 | } else | ||
328 | vBlankInterval = milliToNano(1); // no sync - DO NOT set "0", would cause div-by-zero segfaults. | 316 | vBlankInterval = milliToNano(1); // no sync - DO NOT set "0", would cause div-by-zero segfaults. | ||
329 | m_timeSinceLastVBlank = fpsInterval - (options->vBlankTime() + 1); // means "start now" - we don't have even a slight idea when the first vsync will occur | 317 | m_timeSinceLastVBlank = fpsInterval - (options->vBlankTime() + 1); // means "start now" - we don't have even a slight idea when the first vsync will occur | ||
330 | scheduleRepaint(); | 318 | scheduleRepaint(); | ||
331 | kwinApp()->platform()->createEffectsHandler(this, m_scene); // sets also the 'effects' pointer | 319 | kwinApp()->platform()->createEffectsHandler(this, m_scene); // sets also the 'effects' pointer | ||
332 | connect(Workspace::self(), &Workspace::deletedRemoved, m_scene, &Scene::removeToplevel); | 320 | connect(Workspace::self(), &Workspace::deletedRemoved, m_scene, &Scene::removeToplevel); | ||
333 | connect(effects, &EffectsHandler::screenGeometryChanged, this, &Compositor::addRepaintFull); | 321 | connect(effects, &EffectsHandler::screenGeometryChanged, this, &Compositor::addRepaintFull); | ||
▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Line(s) | 364 | { | |||
426 | m_scene = NULL; | 414 | m_scene = NULL; | ||
427 | compositeTimer.stop(); | 415 | compositeTimer.stop(); | ||
428 | repaints_region = QRegion(); | 416 | repaints_region = QRegion(); | ||
429 | 417 | | |||
430 | m_state = State::Off; | 418 | m_state = State::Off; | ||
431 | emit compositingToggled(false); | 419 | emit compositingToggled(false); | ||
432 | } | 420 | } | ||
433 | 421 | | |||
422 | void Compositor::destroyCompositorSelection() | ||||
423 | { | ||||
424 | delete m_selectionOwner; | ||||
425 | m_selectionOwner = nullptr; | ||||
426 | } | ||||
427 | | ||||
434 | void Compositor::releaseCompositorSelection() | 428 | void Compositor::releaseCompositorSelection() | ||
435 | { | 429 | { | ||
436 | switch (m_state) { | 430 | switch (m_state) { | ||
437 | case State::On: | 431 | case State::On: | ||
438 | // We are compositing at the moment. Don't release. | 432 | // We are compositing at the moment. Don't release. | ||
439 | break; | 433 | break; | ||
440 | case State::Off: | 434 | case State::Off: | ||
441 | if (m_selectionOwner) { | 435 | if (m_selectionOwner) { | ||
Show All 32 Lines | 462 | { | |||
474 | if (const auto c = kwinApp()->x11Connection()) { | 468 | if (const auto c = kwinApp()->x11Connection()) { | ||
475 | foreach (const xcb_atom_t &atom, m_unusedSupportProperties) { | 469 | foreach (const xcb_atom_t &atom, m_unusedSupportProperties) { | ||
476 | // remove property from root window | 470 | // remove property from root window | ||
477 | xcb_delete_property(c, kwinApp()->x11RootWindow(), atom); | 471 | xcb_delete_property(c, kwinApp()->x11RootWindow(), atom); | ||
478 | } | 472 | } | ||
479 | } | 473 | } | ||
480 | } | 474 | } | ||
481 | 475 | | |||
482 | void Compositor::slotConfigChanged() | 476 | void Compositor::configChanged() | ||
483 | { | 477 | { | ||
484 | if (!m_suspended) { | 478 | reinitialize(); | ||
485 | start(); | 479 | if (effects) { | ||
486 | if (effects) // setupCompositing() may fail | 480 | // setupCompositing() might fail. | ||
487 | effects->reconfigure(); | 481 | effects->reconfigure(); | ||
488 | addRepaintFull(); | | |||
489 | } else { | | |||
490 | stop(); | | |||
491 | } | 482 | } | ||
483 | addRepaintFull(); | ||||
492 | } | 484 | } | ||
493 | 485 | | |||
494 | void Compositor::reinitialize() | 486 | void Compositor::reinitialize() | ||
495 | { | 487 | { | ||
496 | // Reparse config. Config options will be reloaded by start() | 488 | // Reparse config. Config options will be reloaded by start() | ||
497 | kwinApp()->config()->reparseConfiguration(); | 489 | kwinApp()->config()->reparseConfiguration(); | ||
498 | 490 | | |||
499 | // Restart compositing | 491 | // Restart compositing | ||
500 | stop(); | 492 | stop(); | ||
501 | // resume compositing if suspended | | |||
502 | m_suspended = NoReasonSuspend; | | |||
503 | start(); | 493 | start(); | ||
504 | 494 | | |||
505 | if (effects) { // start() may fail | 495 | if (effects) { // start() may fail | ||
506 | effects->reconfigure(); | 496 | effects->reconfigure(); | ||
507 | } | 497 | } | ||
508 | } | 498 | } | ||
509 | 499 | | |||
510 | // for the shortcut | | |||
511 | void Compositor::toggleCompositing() | | |||
512 | { | | |||
513 | if (kwinApp()->platform()->requiresCompositing()) { | | |||
514 | // we are not allowed to turn on/off compositing | | |||
515 | return; | | |||
516 | } | | |||
517 | if (m_suspended) { // direct user call; clear all bits | | |||
518 | resume(AllReasonSuspend); | | |||
519 | } else { // but only set the user one (sufficient to suspend) | | |||
520 | suspend(UserSuspend); | | |||
521 | } | | |||
522 | } | | |||
523 | | ||||
524 | void Compositor::updateCompositeBlocking() | | |||
525 | { | | |||
526 | updateClientCompositeBlocking(NULL); | | |||
527 | } | | |||
528 | | ||||
529 | void Compositor::updateClientCompositeBlocking(Client *c) | | |||
530 | { | | |||
531 | if (kwinApp()->platform()->requiresCompositing()) { | | |||
532 | return; | | |||
533 | } | | |||
534 | if (c) { // if c == 0 we just check if we can resume | | |||
535 | if (c->isBlockingCompositing()) { | | |||
536 | if (!(m_suspended & BlockRuleSuspend)) // do NOT attempt to call suspend(true); from within the eventchain! | | |||
537 | QMetaObject::invokeMethod(this, "suspend", Qt::QueuedConnection, Q_ARG(Compositor::SuspendReason, BlockRuleSuspend)); | | |||
538 | } | | |||
539 | } | | |||
540 | else if (m_suspended & BlockRuleSuspend) { // lost a client and we're blocked - can we resume? | | |||
541 | bool resume = true; | | |||
542 | for (ClientList::ConstIterator it = Workspace::self()->clientList().constBegin(); it != Workspace::self()->clientList().constEnd(); ++it) { | | |||
543 | if ((*it)->isBlockingCompositing()) { | | |||
544 | resume = false; | | |||
545 | break; | | |||
546 | } | | |||
547 | } | | |||
548 | if (resume) { // do NOT attempt to call suspend(false); from within the eventchain! | | |||
549 | QMetaObject::invokeMethod(this, "resume", Qt::QueuedConnection, Q_ARG(Compositor::SuspendReason, BlockRuleSuspend)); | | |||
550 | } | | |||
551 | } | | |||
552 | } | | |||
553 | | ||||
554 | void Compositor::suspend(Compositor::SuspendReason reason) | | |||
555 | { | | |||
556 | if (kwinApp()->platform()->requiresCompositing()) { | | |||
557 | return; | | |||
558 | } | | |||
559 | Q_ASSERT(reason != NoReasonSuspend); | | |||
560 | m_suspended |= reason; | | |||
561 | if (reason & KWin::Compositor::ScriptSuspend) { | | |||
562 | // when disabled show a shortcut how the user can get back compositing | | |||
563 | const auto shortcuts = KGlobalAccel::self()->shortcut(workspace()->findChild<QAction*>(QStringLiteral("Suspend Compositing"))); | | |||
564 | if (!shortcuts.isEmpty()) { | | |||
565 | // display notification only if there is the shortcut | | |||
566 | const QString message = i18n("Desktop effects have been suspended by another application.<br/>" | | |||
567 | "You can resume using the '%1' shortcut.", shortcuts.first().toString(QKeySequence::NativeText)); | | |||
568 | KNotification::event(QStringLiteral("compositingsuspendeddbus"), message); | | |||
569 | } | | |||
570 | } | | |||
571 | stop(); | | |||
572 | } | | |||
573 | | ||||
574 | void Compositor::resume(Compositor::SuspendReason reason) | | |||
575 | { | | |||
576 | Q_ASSERT(reason != NoReasonSuspend); | | |||
577 | m_suspended &= ~reason; | | |||
578 | start(); | | |||
579 | } | | |||
580 | | ||||
581 | void Compositor::addRepaint(int x, int y, int w, int h) | 500 | void Compositor::addRepaint(int x, int y, int w, int h) | ||
582 | { | 501 | { | ||
583 | if (!hasScene()) | 502 | if (!hasScene()) | ||
584 | return; | 503 | return; | ||
585 | repaints_region += QRegion(x, y, w, h); | 504 | repaints_region += QRegion(x, y, w, h); | ||
586 | scheduleRepaint(); | 505 | scheduleRepaint(); | ||
587 | } | 506 | } | ||
588 | 507 | | |||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Line(s) | 549 | { | |||
636 | if (m_composeAtSwapCompletion) { | 555 | if (m_composeAtSwapCompletion) { | ||
637 | m_composeAtSwapCompletion = false; | 556 | m_composeAtSwapCompletion = false; | ||
638 | performCompositing(); | 557 | performCompositing(); | ||
639 | } | 558 | } | ||
640 | } | 559 | } | ||
641 | 560 | | |||
642 | void Compositor::performCompositing() | 561 | void Compositor::performCompositing() | ||
643 | { | 562 | { | ||
644 | if (m_scene->usesOverlayWindow() && !isOverlayWindowVisible()) | | |||
645 | return; // nothing is visible anyway | | |||
646 | | ||||
647 | // If a buffer swap is still pending, we return to the event loop and | 563 | // If a buffer swap is still pending, we return to the event loop and | ||
648 | // continue processing events until the swap has completed. | 564 | // continue processing events until the swap has completed. | ||
649 | if (m_bufferSwapPending) { | 565 | if (m_bufferSwapPending) { | ||
650 | m_composeAtSwapCompletion = true; | 566 | m_composeAtSwapCompletion = true; | ||
651 | compositeTimer.stop(); | 567 | compositeTimer.stop(); | ||
652 | return; | 568 | return; | ||
653 | } | 569 | } | ||
654 | 570 | | |||
▲ Show 20 Lines • Show All 215 Lines • ▼ Show 20 Line(s) | 724 | { | |||
870 | compositeTimer.start(qMin(waitTime, 250u), this); // force 4fps minimum | 786 | compositeTimer.start(qMin(waitTime, 250u), this); // force 4fps minimum | ||
871 | } | 787 | } | ||
872 | 788 | | |||
873 | bool Compositor::isActive() | 789 | bool Compositor::isActive() | ||
874 | { | 790 | { | ||
875 | return m_state == State::On; | 791 | return m_state == State::On; | ||
876 | } | 792 | } | ||
877 | 793 | | |||
878 | bool Compositor::checkForOverlayWindow(WId w) const | 794 | WaylandCompositor::WaylandCompositor(QObject *parent) | ||
795 | : Compositor(parent) | ||||
796 | { | ||||
797 | connect(kwinApp(), &Application::x11ConnectionAboutToBeDestroyed, | ||||
798 | this, &WaylandCompositor::destroyCompositorSelection); | ||||
799 | } | ||||
800 | | ||||
801 | // for the shortcut | ||||
802 | void WaylandCompositor::toggleCompositing() | ||||
803 | { | ||||
804 | // Not possible on Wayland because we always composite. | ||||
805 | } | ||||
806 | | ||||
807 | void WaylandCompositor::start() | ||||
808 | { | ||||
809 | if (!Compositor::setupStart()) { | ||||
810 | // Internal setup failed, abort. | ||||
811 | return; | ||||
812 | } | ||||
813 | if (Workspace::self()) { | ||||
814 | startupWithWorkspace(); | ||||
815 | } else { | ||||
816 | connect(kwinApp(), &Application::workspaceCreated, this, &WaylandCompositor::startupWithWorkspace); | ||||
817 | } | ||||
818 | } | ||||
819 | | ||||
820 | bool WaylandCompositor::checkForOverlayWindow(WId w) const | ||||
821 | { | ||||
822 | Q_UNUSED(w) | ||||
823 | // There is no overlay window in Wayland/XWayland. | ||||
824 | return false; | ||||
825 | } | ||||
826 | | ||||
827 | int WaylandCompositor::refreshRate() const | ||||
828 | { | ||||
829 | // TODO: This makes no sense on Wayland. First step would be to atleast | ||||
830 | // set the refresh rate to the highest available one. Second step | ||||
831 | // would be to not use a uniform value at all but per screen. | ||||
832 | return KWin::currentRefreshRate(); | ||||
833 | } | ||||
834 | | ||||
835 | void WaylandCompositor::updateCompositeBlocking() | ||||
836 | { | ||||
837 | // Composite blocking not possible on Wayland. | ||||
838 | } | ||||
839 | | ||||
840 | void WaylandCompositor::updateClientCompositeBlocking(Client *c) | ||||
841 | { | ||||
842 | Q_UNUSED(c) | ||||
843 | // Composite blocking not possible on Wayland. | ||||
844 | } | ||||
845 | | ||||
846 | X11Compositor::X11Compositor(QObject *parent) | ||||
847 | : Compositor(parent) | ||||
848 | , m_suspended(options->isUseCompositing() ? NoReasonSuspend : UserSuspend) | ||||
849 | , m_xrrRefreshRate(0) | ||||
850 | { | ||||
851 | qRegisterMetaType<X11Compositor::SuspendReason>("X11Compositor::SuspendReason"); | ||||
852 | } | ||||
853 | | ||||
854 | // for the shortcut | ||||
855 | void X11Compositor::toggleCompositing() | ||||
856 | { | ||||
857 | if (kwinApp()->platform()->requiresCompositing()) { | ||||
858 | // we are not allowed to turn on/off compositing | ||||
859 | return; | ||||
860 | } | ||||
861 | if (m_suspended) { // direct user call; clear all bits | ||||
862 | resume(AllReasonSuspend); | ||||
863 | } else { // but only set the user one (sufficient to suspend) | ||||
864 | suspend(UserSuspend); | ||||
anthonyfieroni: It looks incorrect.
```
resume(AllReasonSuspend);
```
? | |||||
True, what I wanted to do there was calling the parent's method Compositor::reinitialize(). Thanks! romangg: True, what I wanted to do there was calling the parent's method `Compositor::reinitialize()`. | |||||
865 | } | ||||
866 | } | ||||
867 | | ||||
868 | void X11Compositor::reinitialize() | ||||
869 | { | ||||
870 | // resume compositing if suspended | ||||
871 | m_suspended = NoReasonSuspend; | ||||
872 | Compositor::reinitialize(); | ||||
873 | } | ||||
874 | | ||||
875 | void X11Compositor::configChanged() | ||||
876 | { | ||||
877 | if (m_suspended) { | ||||
878 | stop(); | ||||
879 | return; | ||||
880 | } | ||||
881 | Compositor::configChanged(); | ||||
882 | } | ||||
883 | | ||||
884 | void X11Compositor::suspend(X11Compositor::SuspendReason reason) | ||||
885 | { | ||||
886 | Q_ASSERT(reason != NoReasonSuspend); | ||||
887 | m_suspended |= reason; | ||||
888 | if (reason & ScriptSuspend) { | ||||
889 | // when disabled show a shortcut how the user can get back compositing | ||||
890 | const auto shortcuts = KGlobalAccel::self()->shortcut(workspace()->findChild<QAction*>(QStringLiteral("Suspend Compositing"))); | ||||
891 | if (!shortcuts.isEmpty()) { | ||||
892 | // display notification only if there is the shortcut | ||||
893 | const QString message = i18n("Desktop effects have been suspended by another application.<br/>" | ||||
894 | "You can resume using the '%1' shortcut.", shortcuts.first().toString(QKeySequence::NativeText)); | ||||
895 | KNotification::event(QStringLiteral("compositingsuspendeddbus"), message); | ||||
896 | } | ||||
897 | } | ||||
898 | stop(); | ||||
899 | } | ||||
900 | | ||||
901 | void X11Compositor::resume(X11Compositor::SuspendReason reason) | ||||
902 | { | ||||
903 | Q_ASSERT(reason != NoReasonSuspend); | ||||
904 | m_suspended &= ~reason; | ||||
905 | start(); | ||||
906 | } | ||||
907 | | ||||
908 | void X11Compositor::start() | ||||
909 | { | ||||
910 | if (m_suspended) { | ||||
911 | QStringList reasons; | ||||
912 | if (m_suspended & UserSuspend) { | ||||
913 | reasons << QStringLiteral("Disabled by User"); | ||||
914 | } | ||||
915 | if (m_suspended & BlockRuleSuspend) { | ||||
916 | reasons << QStringLiteral("Disabled by Window"); | ||||
917 | } | ||||
918 | if (m_suspended & ScriptSuspend) { | ||||
919 | reasons << QStringLiteral("Disabled by Script"); | ||||
920 | } | ||||
921 | qCDebug(KWIN_CORE) << "Compositing is suspended, reason:" << reasons; | ||||
922 | return; | ||||
923 | } else if (!kwinApp()->platform()->compositingPossible()) { | ||||
924 | qCCritical(KWIN_CORE) << "Compositing is not possible"; | ||||
925 | return; | ||||
926 | } | ||||
927 | if (!Compositor::setupStart()) { | ||||
928 | // Internal setup failed, abort. | ||||
929 | return; | ||||
930 | } | ||||
931 | m_xrrRefreshRate = KWin::currentRefreshRate(); | ||||
932 | startupWithWorkspace(); | ||||
933 | } | ||||
934 | void X11Compositor::performCompositing() | ||||
935 | { | ||||
936 | if (scene()->usesOverlayWindow() && !isOverlayWindowVisible()) { | ||||
937 | return; // nothing is visible anyway | ||||
938 | } | ||||
939 | Compositor::performCompositing(); | ||||
940 | } | ||||
941 | | ||||
942 | bool X11Compositor::checkForOverlayWindow(WId w) const | ||||
879 | { | 943 | { | ||
880 | if (!hasScene()) { | 944 | if (!hasScene()) { | ||
881 | // no scene, so it cannot be the overlay window | 945 | // no scene, so it cannot be the overlay window | ||
882 | return false; | 946 | return false; | ||
883 | } | 947 | } | ||
884 | if (!m_scene->overlayWindow()) { | 948 | if (!scene()->overlayWindow()) { | ||
885 | // no overlay window, it cannot be the overlay | 949 | // no overlay window, it cannot be the overlay | ||
886 | return false; | 950 | return false; | ||
887 | } | 951 | } | ||
888 | // and compare the window ID's | 952 | // and compare the window ID's | ||
889 | return w == m_scene->overlayWindow()->window(); | 953 | return w == scene()->overlayWindow()->window(); | ||
890 | } | 954 | } | ||
891 | 955 | | |||
892 | bool Compositor::isOverlayWindowVisible() const | 956 | bool X11Compositor::isOverlayWindowVisible() const | ||
893 | { | 957 | { | ||
894 | if (!hasScene()) { | 958 | if (!hasScene()) { | ||
895 | return false; | 959 | return false; | ||
896 | } | 960 | } | ||
897 | if (!m_scene->overlayWindow()) { | 961 | if (!scene()->overlayWindow()) { | ||
898 | return false; | 962 | return false; | ||
899 | } | 963 | } | ||
900 | return m_scene->overlayWindow()->isVisible(); | 964 | return scene()->overlayWindow()->isVisible(); | ||
965 | } | ||||
966 | | ||||
967 | int X11Compositor::refreshRate() const | ||||
968 | { | ||||
969 | return m_xrrRefreshRate; | ||||
970 | } | ||||
971 | | ||||
972 | void X11Compositor::updateCompositeBlocking() | ||||
973 | { | ||||
974 | updateClientCompositeBlocking(NULL); | ||||
975 | } | ||||
976 | | ||||
977 | void X11Compositor::updateClientCompositeBlocking(Client *c) | ||||
978 | { | ||||
979 | if (kwinApp()->platform()->requiresCompositing()) { | ||||
980 | return; | ||||
981 | } | ||||
982 | if (c) { // if c == 0 we just check if we can resume | ||||
983 | if (c->isBlockingCompositing()) { | ||||
984 | if (!(m_suspended & BlockRuleSuspend)) // do NOT attempt to call suspend(true); from within the eventchain! | ||||
985 | QMetaObject::invokeMethod(this, "suspend", Qt::QueuedConnection, Q_ARG(SuspendReason, BlockRuleSuspend)); | ||||
986 | } | ||||
987 | } | ||||
988 | else if (m_suspended & BlockRuleSuspend) { // lost a client and we're blocked - can we resume? | ||||
989 | bool resume = true; | ||||
990 | for (ClientList::ConstIterator it = Workspace::self()->clientList().constBegin(); it != Workspace::self()->clientList().constEnd(); ++it) { | ||||
991 | if ((*it)->isBlockingCompositing()) { | ||||
992 | resume = false; | ||||
993 | break; | ||||
994 | } | ||||
995 | } | ||||
996 | if (resume) { // do NOT attempt to call suspend(false); from within the eventchain! | ||||
997 | QMetaObject::invokeMethod(this, "resume", Qt::QueuedConnection, Q_ARG(SuspendReason, BlockRuleSuspend)); | ||||
998 | } | ||||
999 | } | ||||
901 | } | 1000 | } | ||
902 | 1001 | | |||
903 | } // namespace | 1002 | } // namespace | ||
904 | 1003 | | |||
905 | // included for CompositorSelectionOwner | 1004 | // included for CompositorSelectionOwner | ||
906 | #include "composite.moc" | 1005 | #include "composite.moc" |
Is there a reason for not initializing s_compositor in constructor of Compositor class?