diff options
author | Robin Burchell <robin.burchell@viroteck.net> | 2014-08-20 16:31:05 +0200 |
---|---|---|
committer | Robin Burchell <robin.burchell@viroteck.net> | 2014-09-23 12:35:31 +0200 |
commit | 8655435f86b45a343d7a36c35968fa2c7c83f9c3 (patch) | |
tree | 9ead216ddc460db68615f140afaea03b29716bb4 | |
parent | 59d691d6c54932a92933ee69876b8f0bc8cf954e (diff) | |
download | qtwayland-8655435f86b45a343d7a36c35968fa2c7c83f9c3.tar.gz |
QtWaylandClient: Pluginize window decorations.
Convert to a D-pointer, split between abstract base class and an implementation.
Also move implementation of the current built-in decoration to the "bradient"
plugin, named in glorious memory of the programmer-designed blue gradient that
will forever sear our eyeballs.
The decoration plugin may be specified using the environment variable
QT_WAYLAND_DECORATION.
Change-Id: Idc99ab06ae138ad299bad2b62b9595379bd007ab
Reviewed-by: Robin Burchell <robin.burchell@viroteck.net>
-rw-r--r-- | src/client/client.pro | 6 | ||||
-rw-r--r-- | src/client/qwaylandabstractdecoration.cpp | 408 | ||||
-rw-r--r-- | src/client/qwaylandabstractdecoration_p.h | 71 | ||||
-rw-r--r-- | src/client/qwaylanddecorationfactory.cpp | 97 | ||||
-rw-r--r-- | src/client/qwaylanddecorationfactory_p.h | 61 | ||||
-rw-r--r-- | src/client/qwaylanddecorationplugin.cpp | 54 | ||||
-rw-r--r-- | src/client/qwaylanddecorationplugin_p.h | 69 | ||||
-rw-r--r-- | src/client/qwaylandwindow.cpp | 37 | ||||
-rw-r--r-- | src/plugins/decorations/bradient/bradient.json | 3 | ||||
-rw-r--r-- | src/plugins/decorations/bradient/bradient.pro | 17 | ||||
-rw-r--r-- | src/plugins/decorations/bradient/main.cpp | 452 | ||||
-rw-r--r-- | src/plugins/decorations/decorations.pro | 3 | ||||
-rw-r--r-- | src/plugins/plugins.pro | 5 |
13 files changed, 880 insertions, 403 deletions
diff --git a/src/client/client.pro b/src/client/client.pro index ed14a460..a8a1136e 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -3,7 +3,7 @@ QT += core-private gui-private QT_FOR_PRIVATE += platformsupport-private MODULE=waylandclient -MODULE_PLUGIN_TYPES = wayland-graphics-integration-client +MODULE_PLUGIN_TYPES = wayland-graphics-integration-client wayland-decoration-client load(qt_module) @@ -70,6 +70,8 @@ SOURCES += qwaylandintegration.cpp \ qwaylandqtkey.cpp \ ../shared/qwaylandmimehelper.cpp \ qwaylandabstractdecoration.cpp \ + qwaylanddecorationfactory.cpp \ + qwaylanddecorationplugin.cpp \ qwaylandeventthread.cpp\ qwaylandwindowmanagerintegration.cpp \ qwaylandinputcontext.cpp \ @@ -101,6 +103,8 @@ HEADERS += qwaylandintegration_p.h \ qwaylandqtkey_p.h \ ../shared/qwaylandmimehelper.h \ qwaylandabstractdecoration_p.h \ + qwaylanddecorationfactory_p.h \ + qwaylanddecorationplugin_p.h \ qwaylandeventthread_p.h \ qwaylandwindowmanagerintegration_p.h \ qwaylandinputcontext_p.h \ diff --git a/src/client/qwaylandabstractdecoration.cpp b/src/client/qwaylandabstractdecoration.cpp index 2781b426..e247dbba 100644 --- a/src/client/qwaylandabstractdecoration.cpp +++ b/src/client/qwaylandabstractdecoration.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net> ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** @@ -41,431 +42,148 @@ #include "qwaylandabstractdecoration_p.h" +#include <private/qobject_p.h> #include "qwaylandwindow_p.h" #include "qwaylandshellsurface_p.h" #include "qwaylandinputdevice_p.h" #include "qwaylandscreen_p.h" -#include <QtGui/QGuiApplication> #include <QtGui/QImage> -#include <QtGui/QCursor> -#include <QtGui/QPainter> -#include <QtGui/QPalette> -#include <QtGui/QLinearGradient> QT_BEGIN_NAMESPACE -#define BUTTON_SPACING 5 - -#ifndef QT_NO_IMAGEFORMAT_XPM -# define BUTTON_WIDTH 10 +class QWaylandAbstractDecorationPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QWaylandAbstractDecoration) -static const char * const qt_close_xpm[] = { -"10 10 2 1", -"# c #000000", -". c None", -"..........", -".##....##.", -"..##..##..", -"...####...", -"....##....", -"...####...", -"..##..##..", -".##....##.", -"..........", -".........."}; +public: + QWaylandAbstractDecorationPrivate(); + ~QWaylandAbstractDecorationPrivate(); -static const char * const qt_maximize_xpm[]={ -"10 10 2 1", -"# c #000000", -". c None", -"#########.", -"#########.", -"#.......#.", -"#.......#.", -"#.......#.", -"#.......#.", -"#.......#.", -"#.......#.", -"#########.", -".........."}; + QWindow *m_window; + QWaylandWindow *m_wayland_window; -static const char * const qt_minimize_xpm[] = { -"10 10 2 1", -"# c #000000", -". c None", -"..........", -"..........", -"..........", -"..........", -"..........", -"..........", -"..........", -".#######..", -".#######..", -".........."}; + bool m_isDirty; + QImage m_decorationContentImage; -static const char * const qt_normalizeup_xpm[] = { -"10 10 2 1", -"# c #000000", -". c None", -"...######.", -"...######.", -"...#....#.", -".######.#.", -".######.#.", -".#....###.", -".#....#...", -".#....#...", -".######...", -".........."}; -#else -# define BUTTON_WIDTH 22 -#endif + Qt::MouseButtons m_mouseButtons; +}; -QWaylandAbstractDecoration::QWaylandAbstractDecoration(QWaylandWindow *window) - : m_window(window->window()) - , m_wayland_window(window) +QWaylandAbstractDecorationPrivate::QWaylandAbstractDecorationPrivate() + : m_window(0) + , m_wayland_window(0) , m_isDirty(true) , m_decorationContentImage(0) - , m_margins(3,30,3,3) , m_mouseButtons(Qt::NoButton) { - m_wayland_window->setDecoration(this); - - QPalette palette; - m_foregroundColor = palette.color(QPalette::Active, QPalette::HighlightedText); - m_backgroundColor = palette.color(QPalette::Active, QPalette::Highlight); - - QTextOption option(Qt::AlignHCenter | Qt::AlignVCenter); - option.setWrapMode(QTextOption::NoWrap); - m_windowTitle.setTextOption(option); } -QWaylandAbstractDecoration::~QWaylandAbstractDecoration() +QWaylandAbstractDecorationPrivate::~QWaylandAbstractDecorationPrivate() { m_wayland_window->setDecoration(0); } -const QImage &QWaylandAbstractDecoration::contentImage() +QWaylandAbstractDecoration::QWaylandAbstractDecoration() + : QObject(*new QWaylandAbstractDecorationPrivate) { - if (m_isDirty) { - //Update the decoration backingstore - - m_decorationContentImage = QImage(window()->frameGeometry().size(), QImage::Format_ARGB32_Premultiplied); - m_decorationContentImage.fill(Qt::transparent); - this->paint(&m_decorationContentImage); - - m_isDirty = false; - } - - return m_decorationContentImage; } -void QWaylandAbstractDecoration::update() +QWaylandAbstractDecoration::~QWaylandAbstractDecoration() { - m_isDirty = true; } -void QWaylandAbstractDecoration::paint(QPaintDevice *device) +// we do this as a setter to get around plugin factory creates not really +// being a great way to pass arguments +void QWaylandAbstractDecoration::setWaylandWindow(QWaylandWindow *window) { - QRect surfaceRect(QPoint(), window()->frameGeometry().size()); - QRect clips[] = - { - QRect(0, 0, surfaceRect.width(), margins().top()), - QRect(0, surfaceRect.height() - margins().bottom(), surfaceRect.width(), margins().bottom()), - QRect(0, margins().top(), margins().left(), surfaceRect.height() - margins().top() - margins().bottom()), - QRect(surfaceRect.width() - margins().right(), margins().top(), margins().left(), surfaceRect.height() - margins().top() - margins().bottom()) - }; - - QRect top = clips[0]; - - QPainter p(device); - p.setRenderHint(QPainter::Antialiasing); - - // Title bar - QPoint gradCenter(top.center()+ QPoint(30, 60)); - QLinearGradient grad(top.topLeft(), top.bottomLeft()); - QColor base(m_backgroundColor); - grad.setColorAt(0, base.lighter(100)); - grad.setColorAt(1, base.darker(180)); - QPainterPath roundedRect; - roundedRect.addRoundedRect(surfaceRect, 6, 6); - for (int i = 0; i < 4; ++i) { - p.save(); - p.setClipRect(clips[i]); - p.fillPath(roundedRect, grad); - p.restore(); - } - - // Window icon - QIcon icon = m_wayland_window->windowIcon(); - if (!icon.isNull()) { - QPixmap pixmap = icon.pixmap(QSize(128, 128)); - QPixmap scaled = pixmap.scaled(22, 22, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - - QRectF iconRect(0, 0, 22, 22); - p.drawPixmap(iconRect.adjusted(margins().left() + BUTTON_SPACING, 4, - margins().left() + BUTTON_SPACING, 4), - scaled, iconRect); - } - - // Window title - QString windowTitleText = window()->title(); - if (!windowTitleText.isEmpty()) { - if (m_windowTitle.text() != windowTitleText) { - m_windowTitle.setText(windowTitleText); - m_windowTitle.prepare(); - } - - QRect titleBar = top; - titleBar.setLeft(m_margins.left() + BUTTON_SPACING + - (icon.isNull() ? 0 : 22 + BUTTON_SPACING)); - titleBar.setRight(minimizeButtonRect().left() - BUTTON_SPACING); - - p.save(); - p.setClipRect(titleBar); - p.setPen(m_foregroundColor); - QSizeF size = m_windowTitle.size(); - int dx = (top.width() - size.width()) /2; - int dy = (top.height()- size.height()) /2; - QFont font = p.font(); - font.setBold(true); - p.setFont(font); - QPoint windowTitlePoint(top.topLeft().x() + dx, - top.topLeft().y() + dy); - p.drawStaticText(windowTitlePoint,m_windowTitle); - p.restore(); - } - -#ifndef QT_NO_IMAGEFORMAT_XPM - p.save(); - - // Close button - QPixmap closePixmap(qt_close_xpm); - p.drawPixmap(closeButtonRect(), closePixmap, closePixmap.rect()); - - // Maximize button - QPixmap maximizePixmap(m_wayland_window->isMaximized() - ? qt_normalizeup_xpm : qt_maximize_xpm); - p.drawPixmap(maximizeButtonRect(), maximizePixmap, maximizePixmap.rect()); - - // Minimize button - QPixmap minimizePixmap(qt_minimize_xpm); - p.drawPixmap(minimizeButtonRect(), minimizePixmap, minimizePixmap.rect()); + Q_D(QWaylandAbstractDecoration); - p.restore(); -#else - // We don't need antialiasing from now on - p.setRenderHint(QPainter::Antialiasing, false); + // double initialization is probably not great + Q_ASSERT(!d->m_window && !d->m_wayland_window); - QRectF rect; - - // Default pen - QPen pen(m_foregroundColor); - p.setPen(pen); - - // Close button - p.save(); - rect = closeButtonRect(); - p.drawRect(rect); - qreal crossSize = rect.height() / 2; - QPointF crossCenter(rect.center()); - QRectF crossRect(crossCenter.x() - crossSize / 2, crossCenter.y() - crossSize / 2, crossSize, crossSize); - pen.setWidth(2); - p.setPen(pen); - p.drawLine(crossRect.topLeft(), crossRect.bottomRight()); - p.drawLine(crossRect.bottomLeft(), crossRect.topRight()); - p.restore(); - - // Maximize button - p.save(); - p.drawRect(maximizeButtonRect()); - rect = maximizeButtonRect().adjusted(5, 5, -5, -5); - if (m_wayland_window->isMaximized()) { - QRectF rect1 = rect.adjusted(rect.width() / 3, 0, 0, -rect.height() / 3); - QRectF rect2 = rect.adjusted(0, rect.height() / 4, -rect.width() / 4, 0); - p.drawRect(rect1); - p.drawRect(rect2); - } else { - p.setPen(m_foregroundColor); - p.drawRect(rect); - p.drawLine(rect.left(), rect.top() + 1, rect.right(), rect.top() + 1); - } - p.restore(); - - // Minimize button - p.save(); - p.drawRect(minimizeButtonRect()); - rect = minimizeButtonRect().adjusted(5, 5, -5, -5); - pen.setWidth(2); - p.setPen(pen); - p.drawLine(rect.bottomLeft(), rect.bottomRight()); - p.restore(); -#endif + d->m_window = window->window(); + d->m_wayland_window = window; + d->m_wayland_window->setDecoration(this); } -bool QWaylandAbstractDecoration::handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods) - +const QImage &QWaylandAbstractDecoration::contentImage() { - Q_UNUSED(global); + Q_D(QWaylandAbstractDecoration); + if (d->m_isDirty) { + //Update the decoration backingstore + + d->m_decorationContentImage = QImage(window()->frameGeometry().size(), QImage::Format_ARGB32_Premultiplied); + d->m_decorationContentImage.fill(Qt::transparent); + this->paint(&d->m_decorationContentImage); - // Figure out what area mouse is in - if (closeButtonRect().contains(local) && isLeftClicked(b)) { - QWindowSystemInterface::handleCloseEvent(m_window); - } else if (maximizeButtonRect().contains(local) && isLeftClicked(b)) { - m_window->setWindowState(m_wayland_window->isMaximized() ? Qt::WindowNoState : Qt::WindowMaximized); - } else if (minimizeButtonRect().contains(local) && isLeftClicked(b)) { - m_window->setWindowState(Qt::WindowMinimized); - } else if (local.y() <= m_margins.top()) { - processMouseTop(inputDevice,local,b,mods); - } else if (local.y() > m_window->height() - m_margins.bottom() + m_margins.top()) { - processMouseBottom(inputDevice,local,b,mods); - } else if (local.x() <= m_margins.left()) { - processMouseLeft(inputDevice,local,b,mods); - } else if (local.x() > m_window->width() - m_margins.right() + m_margins.left()) { - processMouseRight(inputDevice,local,b,mods); - } else { - m_wayland_window->restoreMouseCursor(inputDevice); - m_mouseButtons = b; - return false; + d->m_isDirty = false; } - m_mouseButtons = b; - return true; + return d->m_decorationContentImage; } -bool QWaylandAbstractDecoration::handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods) +void QWaylandAbstractDecoration::update() { - Q_UNUSED(inputDevice); - Q_UNUSED(global); - Q_UNUSED(mods); - bool handled = state == Qt::TouchPointPressed; - if (handled) { - if (closeButtonRect().contains(local)) - QWindowSystemInterface::handleCloseEvent(m_window); - else if (maximizeButtonRect().contains(local)) - m_window->setWindowState(m_wayland_window->isMaximized() ? Qt::WindowNoState : Qt::WindowMaximized); - else if (minimizeButtonRect().contains(local)) - m_window->setWindowState(Qt::WindowMinimized); - else if (local.y() <= m_margins.top()) - m_wayland_window->shellSurface()->move(inputDevice); - else - handled = false; - } - - return handled; + Q_D(QWaylandAbstractDecoration); + d->m_isDirty = true; } -bool QWaylandAbstractDecoration::inMouseButtonPressedState() const +void QWaylandAbstractDecoration::setMouseButtons(Qt::MouseButtons mb) { - return m_mouseButtons & Qt::NoButton; + Q_D(QWaylandAbstractDecoration); + d->m_mouseButtons = mb; } void QWaylandAbstractDecoration::startResize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize resize, Qt::MouseButtons buttons) { + Q_D(QWaylandAbstractDecoration); if (isLeftClicked(buttons)) { - m_wayland_window->shellSurface()->resize(inputDevice, resize); + d->m_wayland_window->shellSurface()->resize(inputDevice, resize); inputDevice->removeMouseButtonFromState(Qt::LeftButton); } } void QWaylandAbstractDecoration::startMove(QWaylandInputDevice *inputDevice, Qt::MouseButtons buttons) { + Q_D(QWaylandAbstractDecoration); if (isLeftClicked(buttons)) { - m_wayland_window->shellSurface()->move(inputDevice); + d->m_wayland_window->shellSurface()->move(inputDevice); inputDevice->removeMouseButtonFromState(Qt::LeftButton); } } -void QWaylandAbstractDecoration::processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) -{ - Q_UNUSED(mods); - if (local.y() <= m_margins.bottom()) { - if (local.x() <= margins().left()) { - //top left bit - m_wayland_window->setMouseCursor(inputDevice, Qt::SizeFDiagCursor); - startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP_LEFT,b); - } else if (local.x() > m_window->width() - margins().right()) { - //top right bit - m_wayland_window->setMouseCursor(inputDevice, Qt::SizeBDiagCursor); - startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP_RIGHT,b); - } else { - //top reszie bit - m_wayland_window->setMouseCursor(inputDevice, Qt::SplitVCursor); - startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP,b); - } - } else { - m_wayland_window->restoreMouseCursor(inputDevice); - startMove(inputDevice,b); - } - -} - -void QWaylandAbstractDecoration::processMouseBottom(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) -{ - Q_UNUSED(mods); - if (local.x() <= margins().left()) { - //bottom left bit - m_wayland_window->setMouseCursor(inputDevice, Qt::SizeBDiagCursor); - startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT,b); - } else if (local.x() > m_window->width() - margins().right()) { - //bottom right bit - m_wayland_window->setMouseCursor(inputDevice, Qt::SizeFDiagCursor); - startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT,b); - } else { - //bottom bit - m_wayland_window->setMouseCursor(inputDevice, Qt::SplitVCursor); - startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_BOTTOM,b); - } -} - -void QWaylandAbstractDecoration::processMouseLeft(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) -{ - Q_UNUSED(local); - Q_UNUSED(mods); - m_wayland_window->setMouseCursor(inputDevice, Qt::SplitHCursor); - startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_LEFT,b); -} - -void QWaylandAbstractDecoration::processMouseRight(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) -{ - Q_UNUSED(local); - Q_UNUSED(mods); - m_wayland_window->setMouseCursor(inputDevice, Qt::SplitHCursor); - startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_RIGHT,b); -} - bool QWaylandAbstractDecoration::isLeftClicked(Qt::MouseButtons newMouseButtonState) { - if ((!m_mouseButtons & Qt::LeftButton) && (newMouseButtonState & Qt::LeftButton)) + Q_D(QWaylandAbstractDecoration); + if ((!d->m_mouseButtons & Qt::LeftButton) && (newMouseButtonState & Qt::LeftButton)) return true; return false; } bool QWaylandAbstractDecoration::isLeftReleased(Qt::MouseButtons newMouseButtonState) { - if ((m_mouseButtons & Qt::LeftButton) && !(newMouseButtonState & Qt::LeftButton)) + Q_D(QWaylandAbstractDecoration); + if ((d->m_mouseButtons & Qt::LeftButton) && !(newMouseButtonState & Qt::LeftButton)) return true; return false; } -QRectF QWaylandAbstractDecoration::closeButtonRect() const +bool QWaylandAbstractDecoration::isDirty() const { - return QRectF(window()->frameGeometry().width() - BUTTON_WIDTH - BUTTON_SPACING * 2, - (m_margins.top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); + Q_D(const QWaylandAbstractDecoration); + return d->m_isDirty; } -QRectF QWaylandAbstractDecoration::maximizeButtonRect() const +QWindow *QWaylandAbstractDecoration::window() const { - return QRectF(window()->frameGeometry().width() - BUTTON_WIDTH * 2 - BUTTON_SPACING * 3, - (m_margins.top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); + Q_D(const QWaylandAbstractDecoration); + return d->m_window; } -QRectF QWaylandAbstractDecoration::minimizeButtonRect() const +QWaylandWindow *QWaylandAbstractDecoration::waylandWindow() const { - return QRectF(window()->frameGeometry().width() - BUTTON_WIDTH * 3 - BUTTON_SPACING * 4, - (m_margins.top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); + Q_D(const QWaylandAbstractDecoration); + return d->m_wayland_window; } QT_END_NAMESPACE diff --git a/src/client/qwaylandabstractdecoration_p.h b/src/client/qwaylandabstractdecoration_p.h index c94c9951..6171cab1 100644 --- a/src/client/qwaylandabstractdecoration_p.h +++ b/src/client/qwaylandabstractdecoration_p.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net> ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** @@ -64,77 +65,41 @@ class QEvent; class QWaylandScreen; class QWaylandWindow; class QWaylandInputDevice; +class QWaylandAbstractDecorationPrivate; -class Q_WAYLAND_CLIENT_EXPORT QWaylandAbstractDecoration +class Q_WAYLAND_CLIENT_EXPORT QWaylandAbstractDecoration : public QObject { + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandAbstractDecoration) public: - QWaylandAbstractDecoration(QWaylandWindow *window); + QWaylandAbstractDecoration(); virtual ~QWaylandAbstractDecoration(); + void setWaylandWindow(QWaylandWindow *window); + QWaylandWindow *waylandWindow() const; + void update(); bool isDirty() const; - bool handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,Qt::MouseButtons b,Qt::KeyboardModifiers mods); - bool handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods); - bool inMouseButtonPressedState() const; - - void startResize(QWaylandInputDevice *inputDevice,enum wl_shell_surface_resize resize, Qt::MouseButtons buttons); - void startMove(QWaylandInputDevice *inputDevice, Qt::MouseButtons buttons); - QMargins margins() const; + virtual QMargins margins() const = 0; QWindow *window() const; - QWaylandWindow *waylandWindow() const; const QImage &contentImage(); + virtual bool handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,Qt::MouseButtons b,Qt::KeyboardModifiers mods) = 0; + virtual bool handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods) = 0; + protected: - void paint(QPaintDevice *device); + virtual void paint(QPaintDevice *device) = 0; + + void setMouseButtons(Qt::MouseButtons mb); -private: - void processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); - void processMouseBottom(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); - void processMouseLeft(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); - void processMouseRight(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); + void startResize(QWaylandInputDevice *inputDevice,enum wl_shell_surface_resize resize, Qt::MouseButtons buttons); + void startMove(QWaylandInputDevice *inputDevice, Qt::MouseButtons buttons); bool isLeftClicked(Qt::MouseButtons newMouseButtonState); bool isLeftReleased(Qt::MouseButtons newMouseButtonState); - - QRectF closeButtonRect() const; - QRectF maximizeButtonRect() const; - QRectF minimizeButtonRect() const; - - QWindow *m_window; - QWaylandWindow *m_wayland_window; - - bool m_isDirty; - QImage m_decorationContentImage; - - QMargins m_margins; - Qt::MouseButtons m_mouseButtons; - - QColor m_foregroundColor; - QColor m_backgroundColor; - QStaticText m_windowTitle; }; -inline bool QWaylandAbstractDecoration::isDirty() const -{ - return m_isDirty; -} - -inline QMargins QWaylandAbstractDecoration::margins() const -{ - return m_margins; -} - -inline QWindow *QWaylandAbstractDecoration::window() const -{ - return m_window; -} - -inline QWaylandWindow *QWaylandAbstractDecoration::waylandWindow() const -{ - return m_wayland_window; -} - QT_END_NAMESPACE #endif // QWAYLANDABSTRACTDECORATION_H diff --git a/src/client/qwaylanddecorationfactory.cpp b/src/client/qwaylanddecorationfactory.cpp new file mode 100644 index 00000000..6f1f7469 --- /dev/null +++ b/src/client/qwaylanddecorationfactory.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylanddecorationfactory_p.h" +#include "qwaylanddecorationplugin_p.h" + +#include <QtCore/private/qfactoryloader_p.h> +#include <QtCore/QCoreApplication> +#include <QtCore/QDir> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_LIBRARY +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, + (QWaylandDecorationFactoryInterface_iid, QLatin1String("/wayland-decoration-client"), Qt::CaseInsensitive)) +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, directLoader, + (QWaylandDecorationFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive)) +#endif + +QStringList QWaylandDecorationFactory::keys(const QString &pluginPath) +{ +#ifndef QT_NO_LIBRARY + QStringList list; + if (!pluginPath.isEmpty()) { + QCoreApplication::addLibraryPath(pluginPath); + list = directLoader()->keyMap().values(); + if (!list.isEmpty()) { + const QString postFix = QStringLiteral(" (from ") + + QDir::toNativeSeparators(pluginPath) + + QLatin1Char(')'); + const QStringList::iterator end = list.end(); + for (QStringList::iterator it = list.begin(); it != end; ++it) + (*it).append(postFix); + } + } + list.append(loader()->keyMap().values()); + return list; +#else + return QStringList(); +#endif +} + +QWaylandAbstractDecoration *QWaylandDecorationFactory::create(const QString &name, const QStringList &args, const QString &pluginPath) +{ +#ifndef QT_NO_LIBRARY + // Try loading the plugin from platformPluginPath first: + if (!pluginPath.isEmpty()) { + QCoreApplication::addLibraryPath(pluginPath); + if (QWaylandAbstractDecoration *ret = qLoadPlugin1<QWaylandAbstractDecoration, QWaylandDecorationPlugin>(directLoader(), name, args)) + return ret; + } + if (QWaylandAbstractDecoration *ret = qLoadPlugin1<QWaylandAbstractDecoration, QWaylandDecorationPlugin>(loader(), name, args)) + return ret; +#endif + + return 0; +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylanddecorationfactory_p.h b/src/client/qwaylanddecorationfactory_p.h new file mode 100644 index 00000000..a7729bca --- /dev/null +++ b/src/client/qwaylanddecorationfactory_p.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDDECORATIONFACTORY_H +#define QWAYLANDDECORATIONFACTORY_H + +#include <QtWaylandClient/private/qwaylandclientexport_p.h> +#include <QtCore/QStringList> + +QT_BEGIN_NAMESPACE + +class QWaylandAbstractDecoration; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandDecorationFactory +{ +public: + static QStringList keys(const QString &pluginPath = QString()); + static QWaylandAbstractDecoration *create(const QString &name, const QStringList &args, const QString &pluginPath = QString()); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDDECORATIONFACTORY_H diff --git a/src/client/qwaylanddecorationplugin.cpp b/src/client/qwaylanddecorationplugin.cpp new file mode 100644 index 00000000..edad5f5f --- /dev/null +++ b/src/client/qwaylanddecorationplugin.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylanddecorationplugin_p.h" + +QT_BEGIN_NAMESPACE + +QWaylandDecorationPlugin::QWaylandDecorationPlugin(QObject *parent) + : QObject(parent) +{ +} +QWaylandDecorationPlugin::~QWaylandDecorationPlugin() +{ +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylanddecorationplugin_p.h b/src/client/qwaylanddecorationplugin_p.h new file mode 100644 index 00000000..6ed8935d --- /dev/null +++ b/src/client/qwaylanddecorationplugin_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDDECORATIONPLUGIN_H +#define QWAYLANDDECORATIONPLUGIN_H + +#include <QtWaylandClient/private/qwaylandclientexport_p.h> + +#include <QtCore/qplugin.h> +#include <QtCore/qfactoryinterface.h> +#include <QtCore/QObject> + +QT_BEGIN_NAMESPACE + +class QWaylandAbstractDecoration; + +#define QWaylandDecorationFactoryInterface_iid "org.qt-project.Qt.WaylandClient.QWaylandDecorationFactoryInterface.5.4" + +class Q_WAYLAND_CLIENT_EXPORT QWaylandDecorationPlugin : public QObject +{ + Q_OBJECT +public: + explicit QWaylandDecorationPlugin(QObject *parent = 0); + ~QWaylandDecorationPlugin(); + + virtual QWaylandAbstractDecoration *create(const QString &key, const QStringList ¶mList) = 0; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDDECORATIONPLUGIN_H diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index c900b98d..2fc904aa 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -53,6 +53,7 @@ #include "qwaylandabstractdecoration_p.h" #include "qwaylandwindowmanagerintegration_p.h" #include "qwaylandnativeinterface_p.h" +#include "qwaylanddecorationfactory_p.h" #include <QtCore/QFileInfo> #include <QtCore/QPointer> @@ -486,6 +487,7 @@ bool QWaylandWindow::createDecoration() if (!mDisplay->supportsWindowDecoration()) return false; + static bool decorationPluginFailed = false; bool decoration = false; switch (window()->type()) { case Qt::Window: @@ -503,9 +505,37 @@ bool QWaylandWindow::createDecoration() if (window()->flags() & Qt::BypassWindowManagerHint) decoration = false; - if (decoration) { - if (!mWindowDecoration) - mWindowDecoration = new QWaylandAbstractDecoration(this); + if (decoration && !decorationPluginFailed) { + if (!mWindowDecoration) { + QStringList decorations = QWaylandDecorationFactory::keys(); + if (decorations.empty()) { + qWarning() << "No decoration plugins available. Running with no decorations."; + decorationPluginFailed = true; + return false; + } + + QString targetKey; + QByteArray decorationPluginName = qgetenv("QT_WAYLAND_DECORATION"); + if (!decorationPluginName.isEmpty()) { + targetKey = QString::fromLocal8Bit(decorationPluginName); + if (!decorations.contains(targetKey)) { + qWarning() << "Requested decoration " << targetKey << " not found, falling back to default"; + targetKey = QString(); // fallthrough + } + } + + if (targetKey.isEmpty()) + targetKey = decorations.first(); // first come, first served. + + + mWindowDecoration = QWaylandDecorationFactory::create(targetKey, QStringList()); + if (!mWindowDecoration) { + qWarning() << "Could not create decoration from factory! Running with no decorations."; + decorationPluginFailed = true; + return false; + } + mWindowDecoration->setWaylandWindow(this); + } } else { delete mWindowDecoration; mWindowDecoration = 0; @@ -519,6 +549,7 @@ QWaylandAbstractDecoration *QWaylandWindow::decoration() const return mWindowDecoration; } +// ### can't this go away? we directly set up our decorations, after all void QWaylandWindow::setDecoration(QWaylandAbstractDecoration *decoration) { mWindowDecoration = decoration; diff --git a/src/plugins/decorations/bradient/bradient.json b/src/plugins/decorations/bradient/bradient.json new file mode 100644 index 00000000..e1a5ef24 --- /dev/null +++ b/src/plugins/decorations/bradient/bradient.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "bradient" ] +} diff --git a/src/plugins/decorations/bradient/bradient.pro b/src/plugins/decorations/bradient/bradient.pro new file mode 100644 index 00000000..fd376f4a --- /dev/null +++ b/src/plugins/decorations/bradient/bradient.pro @@ -0,0 +1,17 @@ +PLUGIN_TYPE = wayland-decoration-client +load(qt_plugin) + +QT += waylandclient-private + +OTHER_FILES += \ + bradient.json + +SOURCES += main.cpp + +contains(QT_CONFIG, no-pkg-config) { + LIBS += -lwayland-client +} else { + CONFIG += link_pkgconfig + PKGCONFIG += wayland-client +} + diff --git a/src/plugins/decorations/bradient/main.cpp b/src/plugins/decorations/bradient/main.cpp new file mode 100644 index 00000000..c249248c --- /dev/null +++ b/src/plugins/decorations/bradient/main.cpp @@ -0,0 +1,452 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Robin Burchell <robin.burchell@viroteck.net> +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/QCursor> +#include <QtGui/QPainter> +#include <QtGui/QPalette> +#include <QtGui/QLinearGradient> + +#include <qpa/qwindowsysteminterface.h> + +#include <QtWaylandClient/private/qwaylanddecorationplugin_p.h> +#include <QtWaylandClient/private/qwaylandabstractdecoration_p.h> +#include <QtWaylandClient/private/qwaylandwindow_p.h> +#include <QtWaylandClient/private/qwaylandshellsurface_p.h> + +QT_BEGIN_NAMESPACE + +#define BUTTON_SPACING 5 + +#ifndef QT_NO_IMAGEFORMAT_XPM +# define BUTTON_WIDTH 10 + +static const char * const qt_close_xpm[] = { +"10 10 2 1", +"# c #000000", +". c None", +"..........", +".##....##.", +"..##..##..", +"...####...", +"....##....", +"...####...", +"..##..##..", +".##....##.", +"..........", +".........."}; + +static const char * const qt_maximize_xpm[]={ +"10 10 2 1", +"# c #000000", +". c None", +"#########.", +"#########.", +"#.......#.", +"#.......#.", +"#.......#.", +"#.......#.", +"#.......#.", +"#.......#.", +"#########.", +".........."}; + +static const char * const qt_minimize_xpm[] = { +"10 10 2 1", +"# c #000000", +". c None", +"..........", +"..........", +"..........", +"..........", +"..........", +"..........", +"..........", +".#######..", +".#######..", +".........."}; + +static const char * const qt_normalizeup_xpm[] = { +"10 10 2 1", +"# c #000000", +". c None", +"...######.", +"...######.", +"...#....#.", +".######.#.", +".######.#.", +".#....###.", +".#....#...", +".#....#...", +".######...", +".........."}; +#else +# define BUTTON_WIDTH 22 +#endif + +class Q_WAYLAND_CLIENT_EXPORT QWaylandBradientDecoration : public QWaylandAbstractDecoration +{ +public: + QWaylandBradientDecoration(); +protected: + QMargins margins() const Q_DECL_OVERRIDE; + void paint(QPaintDevice *device) Q_DECL_OVERRIDE; + bool handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,Qt::MouseButtons b,Qt::KeyboardModifiers mods) Q_DECL_OVERRIDE; + bool handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods) Q_DECL_OVERRIDE; +private: + void processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); + void processMouseBottom(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); + void processMouseLeft(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); + void processMouseRight(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); + + QRectF closeButtonRect() const; + QRectF maximizeButtonRect() const; + QRectF minimizeButtonRect() const; + + QColor m_foregroundColor; + QColor m_backgroundColor; + QStaticText m_windowTitle; +}; + + + +QWaylandBradientDecoration::QWaylandBradientDecoration() + : QWaylandAbstractDecoration() +{ + QPalette palette; + m_foregroundColor = palette.color(QPalette::Active, QPalette::HighlightedText); + m_backgroundColor = palette.color(QPalette::Active, QPalette::Highlight); + + QTextOption option(Qt::AlignHCenter | Qt::AlignVCenter); + option.setWrapMode(QTextOption::NoWrap); + m_windowTitle.setTextOption(option); +} + +QRectF QWaylandBradientDecoration::closeButtonRect() const +{ + return QRectF(window()->frameGeometry().width() - BUTTON_WIDTH - BUTTON_SPACING * 2, + (margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); +} + +QRectF QWaylandBradientDecoration::maximizeButtonRect() const +{ + return QRectF(window()->frameGeometry().width() - BUTTON_WIDTH * 2 - BUTTON_SPACING * 3, + (margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); +} + +QRectF QWaylandBradientDecoration::minimizeButtonRect() const +{ + return QRectF(window()->frameGeometry().width() - BUTTON_WIDTH * 3 - BUTTON_SPACING * 4, + (margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); +} + +QMargins QWaylandBradientDecoration::margins() const +{ + return QMargins(3, 30, 3, 3); +} + +void QWaylandBradientDecoration::paint(QPaintDevice *device) +{ + QRect surfaceRect(QPoint(), window()->frameGeometry().size()); + QRect clips[] = + { + QRect(0, 0, surfaceRect.width(), margins().top()), + QRect(0, surfaceRect.height() - margins().bottom(), surfaceRect.width(), margins().bottom()), + QRect(0, margins().top(), margins().left(), surfaceRect.height() - margins().top() - margins().bottom()), + QRect(surfaceRect.width() - margins().right(), margins().top(), margins().left(), surfaceRect.height() - margins().top() - margins().bottom()) + }; + + QRect top = clips[0]; + + QPainter p(device); + p.setRenderHint(QPainter::Antialiasing); + + // Title bar + QPoint gradCenter(top.center()+ QPoint(30, 60)); + QLinearGradient grad(top.topLeft(), top.bottomLeft()); + QColor base(m_backgroundColor); + grad.setColorAt(0, base.lighter(100)); + grad.setColorAt(1, base.darker(180)); + QPainterPath roundedRect; + roundedRect.addRoundedRect(surfaceRect, 6, 6); + for (int i = 0; i < 4; ++i) { + p.save(); + p.setClipRect(clips[i]); + p.fillPath(roundedRect, grad); + p.restore(); + } + + // Window icon + QIcon icon = waylandWindow()->windowIcon(); + if (!icon.isNull()) { + QPixmap pixmap = icon.pixmap(QSize(128, 128)); + QPixmap scaled = pixmap.scaled(22, 22, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + + QRectF iconRect(0, 0, 22, 22); + p.drawPixmap(iconRect.adjusted(margins().left() + BUTTON_SPACING, 4, + margins().left() + BUTTON_SPACING, 4), + scaled, iconRect); + } + + // Window title + QString windowTitleText = window()->title(); + if (!windowTitleText.isEmpty()) { + if (m_windowTitle.text() != windowTitleText) { + m_windowTitle.setText(windowTitleText); + m_windowTitle.prepare(); + } + + QRect titleBar = top; + titleBar.setLeft(margins().left() + BUTTON_SPACING + + (icon.isNull() ? 0 : 22 + BUTTON_SPACING)); + titleBar.setRight(minimizeButtonRect().left() - BUTTON_SPACING); + + p.save(); + p.setClipRect(titleBar); + p.setPen(m_foregroundColor); + QSizeF size = m_windowTitle.size(); + int dx = (top.width() - size.width()) /2; + int dy = (top.height()- size.height()) /2; + QFont font = p.font(); + font.setBold(true); + p.setFont(font); + QPoint windowTitlePoint(top.topLeft().x() + dx, + top.topLeft().y() + dy); + p.drawStaticText(windowTitlePoint, m_windowTitle); + p.restore(); + } + +#ifndef QT_NO_IMAGEFORMAT_XPM + p.save(); + + // Close button + QPixmap closePixmap(qt_close_xpm); + p.drawPixmap(closeButtonRect(), closePixmap, closePixmap.rect()); + + // Maximize button + QPixmap maximizePixmap(waylandWindow()->isMaximized() + ? qt_normalizeup_xpm : qt_maximize_xpm); + p.drawPixmap(maximizeButtonRect(), maximizePixmap, maximizePixmap.rect()); + + // Minimize button + QPixmap minimizePixmap(qt_minimize_xpm); + p.drawPixmap(minimizeButtonRect(), minimizePixmap, minimizePixmap.rect()); + + p.restore(); +#else + // We don't need antialiasing from now on + p.setRenderHint(QPainter::Antialiasing, false); + + QRectF rect; + + // Default pen + QPen pen(m_foregroundColor); + p.setPen(pen); + + // Close button + p.save(); + rect = closeButtonRect(); + p.drawRect(rect); + qreal crossSize = rect.height() / 2; + QPointF crossCenter(rect.center()); + QRectF crossRect(crossCenter.x() - crossSize / 2, crossCenter.y() - crossSize / 2, crossSize, crossSize); + pen.setWidth(2); + p.setPen(pen); + p.drawLine(crossRect.topLeft(), crossRect.bottomRight()); + p.drawLine(crossRect.bottomLeft(), crossRect.topRight()); + p.restore(); + + // Maximize button + p.save(); + p.drawRect(maximizeButtonRect()); + rect = maximizeButtonRect().adjusted(5, 5, -5, -5); + if (waylandWindow()->isMaximized()) { + QRectF rect1 = rect.adjusted(rect.width() / 3, 0, 0, -rect.height() / 3); + QRectF rect2 = rect.adjusted(0, rect.height() / 4, -rect.width() / 4, 0); + p.drawRect(rect1); + p.drawRect(rect2); + } else { + p.setPen(m_foregroundColor); + p.drawRect(rect); + p.drawLine(rect.left(), rect.top() + 1, rect.right(), rect.top() + 1); + } + p.restore(); + + // Minimize button + p.save(); + p.drawRect(minimizeButtonRect()); + rect = minimizeButtonRect().adjusted(5, 5, -5, -5); + pen.setWidth(2); + p.setPen(pen); + p.drawLine(rect.bottomLeft(), rect.bottomRight()); + p.restore(); +#endif +} + +bool QWaylandBradientDecoration::handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods) + +{ + Q_UNUSED(global); + + // Figure out what area mouse is in + if (closeButtonRect().contains(local) && isLeftClicked(b)) { + QWindowSystemInterface::handleCloseEvent(window()); + } else if (maximizeButtonRect().contains(local) && isLeftClicked(b)) { + window()->setWindowState(waylandWindow()->isMaximized() ? Qt::WindowNoState : Qt::WindowMaximized); + } else if (minimizeButtonRect().contains(local) && isLeftClicked(b)) { + window()->setWindowState(Qt::WindowMinimized); + } else if (local.y() <= margins().top()) { + processMouseTop(inputDevice,local,b,mods); + } else if (local.y() > window()->height() - margins().bottom() + margins().top()) { + processMouseBottom(inputDevice,local,b,mods); + } else if (local.x() <= margins().left()) { + processMouseLeft(inputDevice,local,b,mods); + } else if (local.x() > window()->width() - margins().right() + margins().left()) { + processMouseRight(inputDevice,local,b,mods); + } else { + waylandWindow()->restoreMouseCursor(inputDevice); + setMouseButtons(b); + return false; + } + + setMouseButtons(b); + return true; +} + +bool QWaylandBradientDecoration::handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods) +{ + Q_UNUSED(inputDevice); + Q_UNUSED(global); + Q_UNUSED(mods); + bool handled = state == Qt::TouchPointPressed; + if (handled) { + if (closeButtonRect().contains(local)) + QWindowSystemInterface::handleCloseEvent(window()); + else if (maximizeButtonRect().contains(local)) + window()->setWindowState(waylandWindow()->isMaximized() ? Qt::WindowNoState : Qt::WindowMaximized); + else if (minimizeButtonRect().contains(local)) + window()->setWindowState(Qt::WindowMinimized); + else if (local.y() <= margins().top()) + waylandWindow()->shellSurface()->move(inputDevice); + else + handled = false; + } + + return handled; +} + +void QWaylandBradientDecoration::processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +{ + Q_UNUSED(mods); + if (local.y() <= margins().bottom()) { + if (local.x() <= margins().left()) { + //top left bit + waylandWindow()->setMouseCursor(inputDevice, Qt::SizeFDiagCursor); + startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP_LEFT,b); + } else if (local.x() > window()->width() - margins().right()) { + //top right bit + waylandWindow()->setMouseCursor(inputDevice, Qt::SizeBDiagCursor); + startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP_RIGHT,b); + } else { + //top reszie bit + waylandWindow()->setMouseCursor(inputDevice, Qt::SplitVCursor); + startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP,b); + } + } else { + waylandWindow()->restoreMouseCursor(inputDevice); + startMove(inputDevice,b); + } + +} + +void QWaylandBradientDecoration::processMouseBottom(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +{ + Q_UNUSED(mods); + if (local.x() <= margins().left()) { + //bottom left bit + waylandWindow()->setMouseCursor(inputDevice, Qt::SizeBDiagCursor); + startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT,b); + } else if (local.x() > window()->width() - margins().right()) { + //bottom right bit + waylandWindow()->setMouseCursor(inputDevice, Qt::SizeFDiagCursor); + startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT,b); + } else { + //bottom bit + waylandWindow()->setMouseCursor(inputDevice, Qt::SplitVCursor); + startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_BOTTOM,b); + } +} + +void QWaylandBradientDecoration::processMouseLeft(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +{ + Q_UNUSED(local); + Q_UNUSED(mods); + waylandWindow()->setMouseCursor(inputDevice, Qt::SplitHCursor); + startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_LEFT,b); +} + +void QWaylandBradientDecoration::processMouseRight(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +{ + Q_UNUSED(local); + Q_UNUSED(mods); + waylandWindow()->setMouseCursor(inputDevice, Qt::SplitHCursor); + startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_RIGHT,b); +} + +class QWaylandBradientDecorationPlugin : public QWaylandDecorationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QWaylandDecorationFactoryInterface_iid FILE "bradient.json") +public: + QWaylandAbstractDecoration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; +}; + +QWaylandAbstractDecoration *QWaylandBradientDecorationPlugin::create(const QString& system, const QStringList& paramList) +{ + Q_UNUSED(paramList); + Q_UNUSED(system); + return new QWaylandBradientDecoration(); +} + + +QT_END_NAMESPACE + +#include "main.moc" diff --git a/src/plugins/decorations/decorations.pro b/src/plugins/decorations/decorations.pro new file mode 100644 index 00000000..6d51a450 --- /dev/null +++ b/src/plugins/decorations/decorations.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS += \ + bradient diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 554dd40c..a1a8a5b7 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -1,2 +1,5 @@ TEMPLATE=subdirs -SUBDIRS += platforms hardwareintegration +SUBDIRS += \ + platforms \ + hardwareintegration \ + decorations |