2020-08-02 22:22:19 +00:00
|
|
|
/*
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
2015-03-20 13:41:03 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
2015-03-20 13:41:03 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2016-04-07 07:24:17 +00:00
|
|
|
#include "platform.h"
|
2019-08-28 18:54:37 +00:00
|
|
|
|
|
|
|
#include "abstract_output.h"
|
2015-04-02 12:37:23 +00:00
|
|
|
#include <config-kwin.h>
|
2015-04-01 13:36:40 +00:00
|
|
|
#include "composite.h"
|
|
|
|
#include "cursor.h"
|
2017-08-21 06:53:56 +00:00
|
|
|
#include "effects.h"
|
2017-09-21 12:52:46 +00:00
|
|
|
#include <KCoreAddons>
|
2017-08-07 15:54:56 +00:00
|
|
|
#include "overlaywindow.h"
|
2017-08-21 09:59:52 +00:00
|
|
|
#include "outline.h"
|
2016-02-23 11:29:05 +00:00
|
|
|
#include "pointer_input.h"
|
2017-09-08 13:49:52 +00:00
|
|
|
#include "scene.h"
|
2019-08-28 18:54:37 +00:00
|
|
|
#include "screens.h"
|
2016-04-15 11:47:56 +00:00
|
|
|
#include "screenedge.h"
|
2015-03-20 13:41:03 +00:00
|
|
|
#include "wayland_server.h"
|
[colorcorrection] Night Color - blue light filter at nighttime
With Wayland KWin needs to provide certain services, which were provided
before that by the Xserver. One of these is gamma correction, which includes
the - by many people beloved - functionality to reduce the blue light at
nighttime. This patch provides the KWin part of that. It is self contained,
but in the end will work in tandem with a lib in Plasma Workspace and a KCM
in Plasma Desktop, which can be used to configure Night Color.
* Three modi:
** Automatic: The location and sun timings are determined automatically
(location data updates will be provided by the workspace)
** Location: The sun timings are determined by fixed location data
** Timings: The sun timings are set manually by the user
* Color temperature value changes are smoothly applied:
** Configuration changes, which lead to other current values are changed
in a quick way over a few seconds
** Changes on sunrise and sunset are applied slowly over the course of few
minutes till several hours depending on the configuration
* The current color value is set immediately at startup or after suspend
phases and VT switches. There is no flickering.
* All configuration is done via a DBus interface, changed values are tested
on correctness and applied atomically
* Self contained mechanism, speaks directly to the hardware by setting the
gamma ramps on the CRTC
* Currently working on DRM backend, extensible to other platform backends in
the future
* The code is written in a way to make the classes later easily extendable to
also provide normal color correction, as it's currently done by KGamma on X
Test Plan:
Manually with the workspace parts and added integration tests in KWin using
the virtual backend.
BUG:371494
Reviewers: #kwin, graesslin
Subscribers: kwin, plasma-devel, #kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D5928
2017-12-11 09:43:12 +00:00
|
|
|
|
2020-04-29 15:18:41 +00:00
|
|
|
#include <KWaylandServer/outputconfiguration_interface.h>
|
|
|
|
#include <KWaylandServer/outputchangeset.h>
|
2015-03-20 13:41:03 +00:00
|
|
|
|
2020-04-27 10:49:36 +00:00
|
|
|
#include <QX11Info>
|
|
|
|
|
2020-04-29 13:54:06 +00:00
|
|
|
#include <cerrno>
|
|
|
|
|
2015-03-20 13:41:03 +00:00
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
Platform::Platform(QObject *parent)
|
2015-03-20 13:41:03 +00:00
|
|
|
: QObject(parent)
|
2016-07-18 08:27:56 +00:00
|
|
|
, m_eglDisplay(EGL_NO_DISPLAY)
|
2015-03-20 13:41:03 +00:00
|
|
|
{
|
2020-10-28 07:03:09 +00:00
|
|
|
setSoftwareCursorForced(false);
|
2020-04-02 16:18:01 +00:00
|
|
|
connect(Cursors::self(), &Cursors::currentCursorRendered, this, &Platform::cursorRendered);
|
2015-03-20 13:41:03 +00:00
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
Platform::~Platform()
|
2015-03-20 13:41:03 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-10-17 14:12:21 +00:00
|
|
|
PlatformCursorImage Platform::cursorImage() const
|
|
|
|
{
|
2020-04-02 16:18:01 +00:00
|
|
|
Cursor* cursor = Cursors::self()->currentCursor();
|
|
|
|
return PlatformCursorImage(cursor->image(), cursor->hotspot());
|
2016-10-17 14:12:21 +00:00
|
|
|
}
|
|
|
|
|
2016-10-20 08:21:54 +00:00
|
|
|
void Platform::hideCursor()
|
|
|
|
{
|
|
|
|
m_hideCursorCounter++;
|
|
|
|
if (m_hideCursorCounter == 1) {
|
|
|
|
doHideCursor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::doHideCursor()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::showCursor()
|
|
|
|
{
|
|
|
|
m_hideCursorCounter--;
|
|
|
|
if (m_hideCursorCounter == 0) {
|
|
|
|
doShowCursor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::doShowCursor()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
OpenGLBackend *Platform::createOpenGLBackend()
|
2015-03-27 07:51:56 +00:00
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
QPainterBackend *Platform::createQPainterBackend()
|
2015-03-27 08:05:03 +00:00
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-12-08 09:17:56 +00:00
|
|
|
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
|
2020-12-05 15:54:19 +00:00
|
|
|
XRenderBackend *Platform::createXRenderBackend()
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2020-12-08 09:17:56 +00:00
|
|
|
#endif
|
2020-12-05 15:54:19 +00:00
|
|
|
|
2019-09-05 14:59:53 +00:00
|
|
|
void Platform::prepareShutdown()
|
|
|
|
{
|
|
|
|
setOutputsEnabled(false);
|
|
|
|
}
|
|
|
|
|
2016-04-15 11:47:56 +00:00
|
|
|
Edge *Platform::createScreenEdge(ScreenEdges *edges)
|
|
|
|
{
|
|
|
|
return new Edge(edges);
|
|
|
|
}
|
|
|
|
|
2016-08-15 10:00:03 +00:00
|
|
|
void Platform::createPlatformCursor(QObject *parent)
|
|
|
|
{
|
|
|
|
new InputRedirectionCursor(parent);
|
|
|
|
}
|
|
|
|
|
2020-04-29 15:18:41 +00:00
|
|
|
void Platform::requestOutputsChange(KWaylandServer::OutputConfigurationInterface *config)
|
2016-03-10 18:57:07 +00:00
|
|
|
{
|
2019-08-28 18:54:37 +00:00
|
|
|
if (!m_supportsOutputChanges) {
|
|
|
|
qCWarning(KWIN_CORE) << "This backend does not support configuration changes.";
|
|
|
|
config->setFailed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-29 15:18:41 +00:00
|
|
|
using Enablement = KWaylandServer::OutputDeviceInterface::Enablement;
|
2019-08-28 18:54:37 +00:00
|
|
|
|
|
|
|
const auto changes = config->changes();
|
|
|
|
|
|
|
|
//process all non-disabling changes
|
|
|
|
for (auto it = changes.begin(); it != changes.end(); it++) {
|
2020-04-29 15:18:41 +00:00
|
|
|
const KWaylandServer::OutputChangeSet *changeset = it.value();
|
2019-08-28 18:54:37 +00:00
|
|
|
|
2021-01-14 08:21:59 +00:00
|
|
|
AbstractOutput* output = findOutput(it.key()->uuid());
|
2019-08-28 18:54:37 +00:00
|
|
|
if (!output) {
|
|
|
|
qCWarning(KWIN_CORE) << "Could NOT find output matching " << it.key()->uuid();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-01-14 08:21:59 +00:00
|
|
|
qDebug(KWIN_CORE) << "Platform::requestOutputsChange enabling" << changeset << it.key()->uuid() << changeset->enabledChanged() << (changeset->enabled() == Enablement::Enabled);
|
|
|
|
|
2019-08-28 18:54:37 +00:00
|
|
|
if (changeset->enabledChanged() &&
|
|
|
|
changeset->enabled() == Enablement::Enabled) {
|
|
|
|
output->setEnabled(true);
|
|
|
|
}
|
2021-01-14 08:21:59 +00:00
|
|
|
|
2019-08-28 18:54:37 +00:00
|
|
|
output->applyChanges(changeset);
|
|
|
|
}
|
|
|
|
|
|
|
|
//process any disable requests
|
|
|
|
for (auto it = changes.begin(); it != changes.end(); it++) {
|
2020-04-29 15:18:41 +00:00
|
|
|
const KWaylandServer::OutputChangeSet *changeset = it.value();
|
2019-08-28 18:54:37 +00:00
|
|
|
|
|
|
|
if (changeset->enabledChanged() &&
|
|
|
|
changeset->enabled() == Enablement::Disabled) {
|
|
|
|
if (enabledOutputs().count() == 1) {
|
|
|
|
// TODO: check beforehand this condition and set failed otherwise
|
|
|
|
// TODO: instead create a dummy output?
|
|
|
|
qCWarning(KWIN_CORE) << "Not disabling final screen" << it.key()->uuid();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto output = findOutput(it.key()->uuid());
|
|
|
|
if (!output) {
|
|
|
|
qCWarning(KWIN_CORE) << "Could NOT find output matching " << it.key()->uuid();
|
|
|
|
continue;
|
|
|
|
}
|
2021-01-14 08:21:59 +00:00
|
|
|
qDebug(KWIN_CORE) << "Platform::requestOutputsChange disabling false" << it.key()->uuid();
|
2019-08-28 18:54:37 +00:00
|
|
|
output->setEnabled(false);
|
|
|
|
}
|
|
|
|
}
|
2021-01-14 08:21:59 +00:00
|
|
|
|
2019-08-31 08:27:04 +00:00
|
|
|
emit screens()->changed();
|
2019-08-28 18:54:37 +00:00
|
|
|
config->setApplied();
|
|
|
|
}
|
|
|
|
|
2020-08-18 18:42:45 +00:00
|
|
|
AbstractOutput *Platform::findOutput(int screenId)
|
|
|
|
{
|
|
|
|
return enabledOutputs().value(screenId);
|
|
|
|
}
|
|
|
|
|
2019-08-28 18:54:37 +00:00
|
|
|
AbstractOutput *Platform::findOutput(const QByteArray &uuid)
|
|
|
|
{
|
|
|
|
const auto outs = outputs();
|
|
|
|
auto it = std::find_if(outs.constBegin(), outs.constEnd(),
|
|
|
|
[uuid](AbstractOutput *output) {
|
|
|
|
return output->uuid() == uuid; }
|
|
|
|
);
|
|
|
|
if (it != outs.constEnd()) {
|
|
|
|
return *it;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-10-28 06:40:06 +00:00
|
|
|
bool Platform::usesSoftwareCursor() const
|
|
|
|
{
|
|
|
|
return m_softwareCursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::setSoftwareCursor(bool set)
|
2015-04-01 13:36:40 +00:00
|
|
|
{
|
2020-10-28 06:40:06 +00:00
|
|
|
if (m_softwareCursor == set) {
|
2015-04-01 13:36:40 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-10-28 06:40:06 +00:00
|
|
|
m_softwareCursor = set;
|
2020-10-28 07:03:09 +00:00
|
|
|
doSetSoftwareCursor();
|
2020-10-28 06:40:06 +00:00
|
|
|
if (m_softwareCursor) {
|
2020-04-02 16:18:01 +00:00
|
|
|
connect(Cursors::self(), &Cursors::positionChanged, this, &Platform::triggerCursorRepaint);
|
|
|
|
connect(Cursors::self(), &Cursors::currentCursorChanged, this, &Platform::triggerCursorRepaint);
|
2015-04-01 13:36:40 +00:00
|
|
|
} else {
|
2020-04-02 16:18:01 +00:00
|
|
|
disconnect(Cursors::self(), &Cursors::positionChanged, this, &Platform::triggerCursorRepaint);
|
|
|
|
disconnect(Cursors::self(), &Cursors::currentCursorChanged, this, &Platform::triggerCursorRepaint);
|
2015-04-01 13:36:40 +00:00
|
|
|
}
|
2020-10-26 07:39:55 +00:00
|
|
|
triggerCursorRepaint();
|
2015-04-01 13:36:40 +00:00
|
|
|
}
|
|
|
|
|
2020-10-28 07:03:09 +00:00
|
|
|
void Platform::doSetSoftwareCursor()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Platform::isSoftwareCursorForced() const
|
|
|
|
{
|
|
|
|
return m_softwareCursorForced;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::setSoftwareCursorForced(bool forced)
|
|
|
|
{
|
|
|
|
if (qEnvironmentVariableIsSet("KWIN_FORCE_SW_CURSOR")) {
|
|
|
|
forced = true;
|
|
|
|
}
|
|
|
|
if (m_softwareCursorForced == forced) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_softwareCursorForced = forced;
|
|
|
|
if (m_softwareCursorForced) {
|
|
|
|
setSoftwareCursor(true);
|
|
|
|
} else {
|
|
|
|
// Do not unset the software cursor yet, the platform will choose the right
|
|
|
|
// moment when it can be done. There is still a chance that we must continue
|
|
|
|
// using the software cursor.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::triggerCursorRepaint()
|
2015-04-01 13:36:40 +00:00
|
|
|
{
|
2016-02-23 11:29:05 +00:00
|
|
|
if (!Compositor::self()) {
|
2015-04-01 13:36:40 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-06-28 06:33:47 +00:00
|
|
|
Compositor::self()->addRepaint(m_cursor.lastRenderedGeometry);
|
2020-04-02 16:18:01 +00:00
|
|
|
Compositor::self()->addRepaint(Cursors::self()->currentCursor()->geometry());
|
2015-04-01 13:36:40 +00:00
|
|
|
}
|
|
|
|
|
2020-04-02 16:18:01 +00:00
|
|
|
void Platform::cursorRendered(const QRect &geometry)
|
2015-04-01 13:36:40 +00:00
|
|
|
{
|
2020-10-28 06:40:06 +00:00
|
|
|
if (m_softwareCursor) {
|
2020-04-02 16:18:01 +00:00
|
|
|
m_cursor.lastRenderedGeometry = geometry;
|
2016-02-23 11:29:05 +00:00
|
|
|
}
|
2015-04-01 13:36:40 +00:00
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::keyboardKeyPressed(quint32 key, quint32 time)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->processKeyboardKey(key, InputRedirection::KeyboardKeyPressed, time);
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::keyboardKeyReleased(quint32 key, quint32 time)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->processKeyboardKey(key, InputRedirection::KeyboardKeyReleased, time);
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::keyboardModifiers(uint32_t modsDepressed, uint32_t modsLatched, uint32_t modsLocked, uint32_t group)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->processKeyboardModifiers(modsDepressed, modsLatched, modsLocked, group);
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::keymapChange(int fd, uint32_t size)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->processKeymapChange(fd, size);
|
|
|
|
}
|
|
|
|
|
Send axis_source, axis_discrete, and axis_stop
Summary:
So far KWin didn't send axis_source, axis_discrete, and axis_stop. Even
though most of those events are optional, clients need them to work as
expected. For example, one needs axis_source and axis_stop to implement
kinetic scrolling; Xwayland needs axis_discrete to prevent multiple
scroll events when the compositor sends axis deltas greater than 10, etc.
BUG: 404152
FIXED-IN: 5.17.0
Test Plan:
* Content of a webpage in Firefox is moved by one line per each mouse
wheel "click";
* Scrolled gedit using 2 fingers on GNOME Shell, sway, and KDE Plasma;
in all three cases wayland debug looked the same (except diagonal scroll
motions).
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19000
2019-02-12 09:14:51 +00:00
|
|
|
void Platform::pointerAxisHorizontal(qreal delta, quint32 time, qint32 discreteDelta, InputRedirection::PointerAxisSource source)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
Send axis_source, axis_discrete, and axis_stop
Summary:
So far KWin didn't send axis_source, axis_discrete, and axis_stop. Even
though most of those events are optional, clients need them to work as
expected. For example, one needs axis_source and axis_stop to implement
kinetic scrolling; Xwayland needs axis_discrete to prevent multiple
scroll events when the compositor sends axis deltas greater than 10, etc.
BUG: 404152
FIXED-IN: 5.17.0
Test Plan:
* Content of a webpage in Firefox is moved by one line per each mouse
wheel "click";
* Scrolled gedit using 2 fingers on GNOME Shell, sway, and KDE Plasma;
in all three cases wayland debug looked the same (except diagonal scroll
motions).
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19000
2019-02-12 09:14:51 +00:00
|
|
|
input()->processPointerAxis(InputRedirection::PointerAxisHorizontal, delta, discreteDelta, source, time);
|
2015-05-05 08:44:46 +00:00
|
|
|
}
|
|
|
|
|
Send axis_source, axis_discrete, and axis_stop
Summary:
So far KWin didn't send axis_source, axis_discrete, and axis_stop. Even
though most of those events are optional, clients need them to work as
expected. For example, one needs axis_source and axis_stop to implement
kinetic scrolling; Xwayland needs axis_discrete to prevent multiple
scroll events when the compositor sends axis deltas greater than 10, etc.
BUG: 404152
FIXED-IN: 5.17.0
Test Plan:
* Content of a webpage in Firefox is moved by one line per each mouse
wheel "click";
* Scrolled gedit using 2 fingers on GNOME Shell, sway, and KDE Plasma;
in all three cases wayland debug looked the same (except diagonal scroll
motions).
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19000
2019-02-12 09:14:51 +00:00
|
|
|
void Platform::pointerAxisVertical(qreal delta, quint32 time, qint32 discreteDelta, InputRedirection::PointerAxisSource source)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
Send axis_source, axis_discrete, and axis_stop
Summary:
So far KWin didn't send axis_source, axis_discrete, and axis_stop. Even
though most of those events are optional, clients need them to work as
expected. For example, one needs axis_source and axis_stop to implement
kinetic scrolling; Xwayland needs axis_discrete to prevent multiple
scroll events when the compositor sends axis deltas greater than 10, etc.
BUG: 404152
FIXED-IN: 5.17.0
Test Plan:
* Content of a webpage in Firefox is moved by one line per each mouse
wheel "click";
* Scrolled gedit using 2 fingers on GNOME Shell, sway, and KDE Plasma;
in all three cases wayland debug looked the same (except diagonal scroll
motions).
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19000
2019-02-12 09:14:51 +00:00
|
|
|
input()->processPointerAxis(InputRedirection::PointerAxisVertical, delta, discreteDelta, source, time);
|
2015-05-05 08:44:46 +00:00
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::pointerButtonPressed(quint32 button, quint32 time)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->processPointerButton(button, InputRedirection::PointerButtonPressed, time);
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::pointerButtonReleased(quint32 button, quint32 time)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->processPointerButton(button, InputRedirection::PointerButtonReleased, time);
|
|
|
|
}
|
|
|
|
|
2021-01-17 22:18:08 +00:00
|
|
|
int Platform::touchPointCount()
|
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return input()->touchPointCount();
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::pointerMotion(const QPointF &position, quint32 time)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->processPointerMotion(position, time);
|
|
|
|
}
|
|
|
|
|
2021-01-17 22:18:08 +00:00
|
|
|
void Platform::cancelTouchSequence()
|
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->cancelTouchSequence();
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::touchCancel()
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->cancelTouch();
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::touchDown(qint32 id, const QPointF &pos, quint32 time)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->processTouchDown(id, pos, time);
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::touchFrame()
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->touchFrame();
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::touchMotion(qint32 id, const QPointF &pos, quint32 time)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->processTouchMotion(id, pos, time);
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::touchUp(qint32 id, quint32 time)
|
2015-05-05 08:44:46 +00:00
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->processTouchUp(id, time);
|
|
|
|
}
|
|
|
|
|
2017-03-15 16:56:08 +00:00
|
|
|
void Platform::processSwipeGestureBegin(int fingerCount, quint32 time)
|
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->pointer()->processSwipeGestureBegin(fingerCount, time);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::processSwipeGestureUpdate(const QSizeF &delta, quint32 time)
|
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->pointer()->processSwipeGestureUpdate(delta, time);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::processSwipeGestureEnd(quint32 time)
|
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->pointer()->processSwipeGestureEnd(time);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::processSwipeGestureCancelled(quint32 time)
|
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->pointer()->processSwipeGestureCancelled(time);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::processPinchGestureBegin(int fingerCount, quint32 time)
|
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->pointer()->processPinchGestureBegin(fingerCount, time);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::processPinchGestureUpdate(qreal scale, qreal angleDelta, const QSizeF &delta, quint32 time)
|
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->pointer()->processPinchGestureUpdate(scale, angleDelta, delta, time);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::processPinchGestureEnd(quint32 time)
|
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->pointer()->processPinchGestureEnd(time);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::processPinchGestureCancelled(quint32 time)
|
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->pointer()->processPinchGestureCancelled(time);
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::repaint(const QRect &rect)
|
2015-05-05 08:54:13 +00:00
|
|
|
{
|
|
|
|
if (!Compositor::self()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Compositor::self()->addRepaint(rect);
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::setReady(bool ready)
|
2015-05-05 17:02:52 +00:00
|
|
|
{
|
|
|
|
if (m_ready == ready) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_ready = ready;
|
|
|
|
emit readyChanged(m_ready);
|
|
|
|
}
|
|
|
|
|
2020-11-09 12:19:15 +00:00
|
|
|
bool Platform::isPerScreenRenderingEnabled() const
|
|
|
|
{
|
|
|
|
return m_isPerScreenRenderingEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::setPerScreenRenderingEnabled(bool enabled)
|
|
|
|
{
|
|
|
|
m_isPerScreenRenderingEnabled = enabled;
|
|
|
|
}
|
|
|
|
|
Introduce RenderLoop
At the moment, our frame scheduling infrastructure is still heavily
based on Xinerama-style rendering. Specifically, we assume that painting
is driven by a single timer, etc.
This change introduces a new type - RenderLoop. Its main purpose is to
drive compositing on a specific output, or in case of X11, on the
overlay window.
With RenderLoop, compositing is synchronized to vblank events. It
exposes the last and the next estimated presentation timestamp. The
expected presentation timestamp can be used by effects to ensure that
animations are synchronized with the upcoming vblank event.
On Wayland, every outputs has its own render loop. On X11, per screen
rendering is not possible, therefore the platform exposes the render
loop for the overlay window. Ideally, the Scene has to expose the
RenderLoop, but as the first step towards better compositing scheduling
it's good as is for the time being.
The RenderLoop tries to minimize the latency by delaying compositing as
close as possible to the next vblank event. One tricky thing about it is
that if compositing is too close to the next vblank event, animations
may become a little bit choppy. However, increasing the latency reduces
the choppiness.
Given that, there is no any "silver bullet" solution for the choppiness
issue, a new option has been added in the Compositing KCM to specify the
amount of latency. By default, it's "Medium," but if a user is not
satisfied with the upstream default, they can tweak it.
2020-11-19 08:52:29 +00:00
|
|
|
RenderLoop *Platform::renderLoop() const
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
void Platform::warpPointer(const QPointF &globalPos)
|
2015-06-05 17:34:03 +00:00
|
|
|
{
|
|
|
|
Q_UNUSED(globalPos)
|
|
|
|
}
|
|
|
|
|
2020-10-12 06:50:55 +00:00
|
|
|
bool Platform::supportsSurfacelessContext() const
|
2015-08-18 06:40:35 +00:00
|
|
|
{
|
2020-10-16 16:30:37 +00:00
|
|
|
Compositor *compositor = Compositor::self();
|
|
|
|
if (Q_UNLIKELY(!compositor)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (Scene *scene = compositor->scene()) {
|
|
|
|
return scene->supportsSurfacelessContext();
|
2016-11-17 06:51:04 +00:00
|
|
|
}
|
|
|
|
return false;
|
2015-08-18 06:40:35 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 09:27:00 +00:00
|
|
|
bool Platform::supportsNativeFence() const
|
|
|
|
{
|
|
|
|
if (Compositor *compositor = Compositor::self()) {
|
|
|
|
return compositor->scene()->supportsNativeFence();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-07-18 08:27:56 +00:00
|
|
|
EGLDisplay KWin::Platform::sceneEglDisplay() const
|
2015-08-18 06:35:34 +00:00
|
|
|
{
|
2016-07-18 08:27:56 +00:00
|
|
|
return m_eglDisplay;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::setSceneEglDisplay(EGLDisplay display)
|
|
|
|
{
|
|
|
|
m_eglDisplay = display;
|
2015-08-18 06:35:34 +00:00
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
QSize Platform::screenSize() const
|
2015-11-17 09:32:06 +00:00
|
|
|
{
|
|
|
|
return QSize();
|
|
|
|
}
|
|
|
|
|
2016-04-07 07:18:10 +00:00
|
|
|
QVector<QRect> Platform::screenGeometries() const
|
2015-11-20 15:11:35 +00:00
|
|
|
{
|
|
|
|
return QVector<QRect>({QRect(QPoint(0, 0), screenSize())});
|
|
|
|
}
|
|
|
|
|
2016-10-25 23:36:02 +00:00
|
|
|
QVector<qreal> Platform::screenScales() const
|
|
|
|
{
|
|
|
|
return QVector<qreal>({1});
|
|
|
|
}
|
|
|
|
|
2016-05-09 14:41:37 +00:00
|
|
|
bool Platform::requiresCompositing() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-05-09 15:32:43 +00:00
|
|
|
bool Platform::compositingPossible() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Platform::compositingNotPossibleReason() const
|
|
|
|
{
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Platform::openGLCompositingIsBroken() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-10 08:34:09 +00:00
|
|
|
void Platform::createOpenGLSafePoint(OpenGLSafePoint safePoint)
|
|
|
|
{
|
|
|
|
Q_UNUSED(safePoint)
|
|
|
|
}
|
|
|
|
|
2016-11-15 09:22:56 +00:00
|
|
|
void Platform::startInteractiveWindowSelection(std::function<void(KWin::Toplevel*)> callback, const QByteArray &cursorName)
|
|
|
|
{
|
2016-11-15 13:23:51 +00:00
|
|
|
if (!input()) {
|
|
|
|
callback(nullptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->startInteractiveWindowSelection(callback, cursorName);
|
2016-11-15 09:22:56 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 14:53:17 +00:00
|
|
|
void Platform::startInteractivePositionSelection(std::function<void(const QPoint &)> callback)
|
|
|
|
{
|
|
|
|
if (!input()) {
|
|
|
|
callback(QPoint(-1, -1));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input()->startInteractivePositionSelection(callback);
|
|
|
|
}
|
|
|
|
|
2017-01-17 06:12:44 +00:00
|
|
|
void Platform::setupActionForGlobalAccel(QAction *action)
|
|
|
|
{
|
|
|
|
Q_UNUSED(action)
|
|
|
|
}
|
|
|
|
|
2017-08-07 15:54:56 +00:00
|
|
|
OverlayWindow *Platform::createOverlayWindow()
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-04-27 10:49:36 +00:00
|
|
|
static quint32 monotonicTime()
|
|
|
|
{
|
|
|
|
timespec ts;
|
|
|
|
|
|
|
|
const int result = clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
|
|
if (result)
|
|
|
|
qCWarning(KWIN_CORE, "Failed to query monotonic time: %s", strerror(errno));
|
|
|
|
|
|
|
|
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000L;
|
|
|
|
}
|
|
|
|
|
2017-08-24 14:53:40 +00:00
|
|
|
void Platform::updateXTime()
|
|
|
|
{
|
2020-04-27 10:49:36 +00:00
|
|
|
switch (kwinApp()->operationMode()) {
|
|
|
|
case Application::OperationModeX11:
|
|
|
|
kwinApp()->setX11Time(QX11Info::getTimestamp(), Application::TimestampUpdate::Always);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Application::OperationModeXwayland:
|
|
|
|
kwinApp()->setX11Time(monotonicTime(), Application::TimestampUpdate::Always);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// Do not update the current X11 time stamp if it's the Wayland only session.
|
|
|
|
break;
|
|
|
|
}
|
2017-08-24 14:53:40 +00:00
|
|
|
}
|
|
|
|
|
2017-08-21 09:59:52 +00:00
|
|
|
OutlineVisual *Platform::createOutline(Outline *outline)
|
|
|
|
{
|
|
|
|
if (Compositor::compositing()) {
|
|
|
|
return new CompositedOutlineVisual(outline);
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-08-20 20:15:21 +00:00
|
|
|
Decoration::Renderer *Platform::createDecorationRenderer(Decoration::DecoratedClientImpl *client)
|
|
|
|
{
|
2019-09-05 16:06:03 +00:00
|
|
|
if (Compositor::self()->scene()) {
|
2017-09-01 18:58:30 +00:00
|
|
|
return Compositor::self()->scene()->createDecorationRenderer(client);
|
2017-08-20 20:15:21 +00:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-08-21 06:53:56 +00:00
|
|
|
void Platform::invertScreen()
|
|
|
|
{
|
|
|
|
if (effects) {
|
|
|
|
if (Effect *inverter = static_cast<EffectsHandlerImpl*>(effects)->provides(Effect::ScreenInversion)) {
|
|
|
|
qCDebug(KWIN_CORE) << "inverting screen using Effect plugin";
|
|
|
|
QMetaObject::invokeMethod(inverter, "toggleScreenInversion", Qt::DirectConnection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-23 18:21:26 +00:00
|
|
|
void Platform::createEffectsHandler(Compositor *compositor, Scene *scene)
|
|
|
|
{
|
|
|
|
new EffectsHandlerImpl(compositor, scene);
|
|
|
|
}
|
|
|
|
|
2017-11-07 19:12:51 +00:00
|
|
|
QString Platform::supportInformation() const
|
|
|
|
{
|
|
|
|
return QStringLiteral("Name: %1\n").arg(metaObject()->className());
|
|
|
|
}
|
|
|
|
|
2020-10-16 14:57:35 +00:00
|
|
|
EGLContext Platform::sceneEglGlobalShareContext() const
|
|
|
|
{
|
|
|
|
return m_globalShareContext;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Platform::setSceneEglGlobalShareContext(EGLContext context)
|
|
|
|
{
|
|
|
|
m_globalShareContext = context;
|
|
|
|
}
|
|
|
|
|
2015-03-20 13:41:03 +00:00
|
|
|
}
|