kwin/backends/drm/drm_backend.h
Martin Gräßlin a66eb1a5b9 [backends/drm] Double Tap to enable output
If the output is off a double tap (touch) can re-enable it. The two
taps have to happen in the double click interval (we don't have
something better and it kind of matches) and have to be by only one
touch point. If there are multiple touch points it's not considered
as a double tap. A todo is to restrict the possible distance of the
two taps to one thumb.

Tested-By: Marco Martin
2016-02-15 17:35:36 +01:00

282 lines
7.4 KiB
C++

/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_DRM_BACKEND_H
#define KWIN_DRM_BACKEND_H
#include "abstract_backend.h"
#include "input.h"
#include <QElapsedTimer>
#include <QImage>
#include <QPointer>
#include <QSize>
#include <xf86drmMode.h>
struct gbm_bo;
struct gbm_surface;
namespace KWayland
{
namespace Server
{
class OutputInterface;
}
}
namespace KWin
{
class Udev;
class UdevMonitor;
class DrmBuffer;
class DrmOutput;
class DpmsInputEventFilter;
template <typename Pointer, void (*cleanupFunc)(Pointer*)>
struct DrmCleanup
{
static inline void cleanup(Pointer *ptr)
{
cleanupFunc(ptr);
}
};
template <typename T, void (*cleanupFunc)(T*)> using ScopedDrmPointer = QScopedPointer<T, DrmCleanup<T, cleanupFunc>>;
class KWIN_EXPORT DrmBackend : public AbstractBackend
{
Q_OBJECT
Q_INTERFACES(KWin::AbstractBackend)
Q_PLUGIN_METADATA(IID "org.kde.kwin.AbstractBackend" FILE "drm.json")
public:
explicit DrmBackend(QObject *parent = nullptr);
virtual ~DrmBackend();
Screens *createScreens(QObject *parent = nullptr) override;
QPainterBackend *createQPainterBackend() override;
OpenGLBackend* createOpenGLBackend() override;
void installCursorFromServer() override;
void installCursorImage(Qt::CursorShape shape) override;
void init() override;
DrmBuffer *createBuffer(const QSize &size);
DrmBuffer *createBuffer(gbm_surface *surface);
void present(DrmBuffer *buffer, DrmOutput *output);
QSize size() const;
int fd() const {
return m_fd;
}
QVector<DrmOutput*> outputs() const {
return m_outputs;
}
QVector<DrmBuffer*> buffers() const {
return m_buffers;
}
void bufferDestroyed(DrmBuffer *b);
void outputWentOff();
void checkOutputsAreOn();
public Q_SLOTS:
void turnOutputsOn();
Q_SIGNALS:
void outputRemoved(KWin::DrmOutput *output);
void outputAdded(KWin::DrmOutput *output);
private:
static void pageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data);
void openDrm();
void activate(bool active);
void reactivate();
void deactivate();
void queryResources();
void setCursor();
void updateCursor();
void hideCursor();
void moveCursor();
void initCursor();
quint32 findCrtc(drmModeRes *res, drmModeConnector *connector, bool *ok = nullptr);
bool crtcIsUsed(quint32 crtc);
void outputDpmsChanged();
void readOutputsConfiguration();
QByteArray generateOutputConfigurationUuid() const;
DrmOutput *findOutput(quint32 connector);
QScopedPointer<Udev> m_udev;
QScopedPointer<UdevMonitor> m_udevMonitor;
int m_fd = -1;
int m_drmId = 0;
QVector<DrmOutput*> m_outputs;
DrmBuffer *m_cursor[2];
int m_cursorIndex = 0;
int m_pageFlipsPending = 0;
bool m_active = false;
QVector<DrmBuffer*> m_buffers;
QScopedPointer<DpmsInputEventFilter> m_dpmsFilter;
};
class DrmOutput : public QObject
{
Q_OBJECT
public:
struct Edid {
QByteArray eisaId;
QByteArray monitorName;
QByteArray serialNumber;
QSize physicalSize;
};
virtual ~DrmOutput();
void showCursor(DrmBuffer *buffer);
void hideCursor();
void moveCursor(const QPoint &globalPos);
bool present(DrmBuffer *buffer);
void pageFlipped();
void init(drmModeConnector *connector);
void restoreSaved();
void blank();
QSize size() const;
QRect geometry() const;
QString name() const;
int currentRefreshRate() const;
enum class DpmsMode {
On = DRM_MODE_DPMS_ON,
Standby = DRM_MODE_DPMS_STANDBY,
Suspend = DRM_MODE_DPMS_SUSPEND,
Off = DRM_MODE_DPMS_OFF
};
void setDpms(DpmsMode mode);
bool isDpmsEnabled() const {
return m_dpmsMode == DpmsMode::On;
}
QByteArray uuid() const {
return m_uuid;
}
Q_SIGNALS:
void dpmsChanged();
private:
friend class DrmBackend;
DrmOutput(DrmBackend *backend);
void cleanupBlackBuffer();
bool setMode(DrmBuffer *buffer);
void initEdid(drmModeConnector *connector);
void initDpms(drmModeConnector *connector);
bool isCurrentMode(const drmModeModeInfo *mode) const;
void initUuid();
void setGlobalPos(const QPoint &pos);
DrmBackend *m_backend;
QPoint m_globalPos;
quint32 m_crtcId = 0;
quint32 m_connector = 0;
quint32 m_lastStride = 0;
bool m_lastGbm = false;
drmModeModeInfo m_mode;
DrmBuffer *m_currentBuffer = nullptr;
DrmBuffer *m_blackBuffer = nullptr;
struct CrtcCleanup {
static void inline cleanup(_drmModeCrtc *ptr) {
drmModeFreeCrtc(ptr);
}
};
Edid m_edid;
QScopedPointer<_drmModeCrtc, CrtcCleanup> m_savedCrtc;
QPointer<KWayland::Server::OutputInterface> m_waylandOutput;
ScopedDrmPointer<_drmModeProperty, &drmModeFreeProperty> m_dpms;
DpmsMode m_dpmsMode = DpmsMode::On;
QByteArray m_uuid;
};
class DrmBuffer
{
public:
~DrmBuffer();
bool map(QImage::Format format = QImage::Format_RGB32);
QImage *image() const {
return m_image;
}
quint32 handle() const {
return m_handle;
}
const QSize &size() const {
return m_size;
}
quint32 bufferId() const {
return m_bufferId;
}
quint32 stride() const {
return m_stride;
}
gbm_bo *gbm() const {
return m_bo;
}
bool isGbm() const {
return m_bo != nullptr;
}
void releaseGbm();
private:
friend class DrmBackend;
DrmBuffer(DrmBackend *backend, const QSize &size);
DrmBuffer(DrmBackend *backend, gbm_surface *surface);
DrmBackend *m_backend;
gbm_surface *m_surface = nullptr;
gbm_bo *m_bo = nullptr;
QSize m_size;
quint32 m_handle = 0;
quint32 m_bufferId = 0;
quint32 m_stride = 0;
quint64 m_bufferSize = 0;
void *m_memory = nullptr;
QImage *m_image = nullptr;
};
class DpmsInputEventFilter : public InputEventFilter
{
public:
DpmsInputEventFilter(DrmBackend *backend);
~DpmsInputEventFilter();
bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override;
bool wheelEvent(QWheelEvent *event) override;
bool keyEvent(QKeyEvent *event) override;
bool touchDown(quint32 id, const QPointF &pos, quint32 time) override;
bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override;
bool touchUp(quint32 id, quint32 time) override;
private:
void notify();
DrmBackend *m_backend;
QElapsedTimer m_doubleTapTimer;
QVector<qint32> m_touchPoints;
bool m_secondTap = false;
};
}
Q_DECLARE_METATYPE(KWin::DrmOutput*)
#endif