From 85f0e93ee82c23d32c019db157060d52cbc82c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Tue, 11 Oct 2016 11:40:48 +0200 Subject: [PATCH] [kstyle] Implement window moving on Wayland Summary: So far breeze hard disabled the window moving on Wayland. With this change the required functionality gets added. For that Breeze creates an additional Seat and a Pointer on it to track all pointer button events on the window. That way the kstyle gets the latest serial which needs to be passed to the move requests. This is not available through QtWayland's native interface, thus Breeze needs to interact with Wayland directly. When the move is triggered Breeze gets the ShellSurface for the window and triggers the move on the own Seat object with the tracked serial. Test Plan: Tested with KWin and Weston, move triggered in both. Reviewers: #plasma_on_wayland Subscribers: plasma-devel Tags: #plasma_on_wayland Differential Revision: https://phabricator.kde.org/D3019 --- kstyle/breezewindowmanager.cpp | 176 +++++++++++++++++++++++++-------- kstyle/breezewindowmanager.h | 32 ++++++ 2 files changed, 169 insertions(+), 39 deletions(-) diff --git a/kstyle/breezewindowmanager.cpp b/kstyle/breezewindowmanager.cpp index ff91ddbe..eed26fc8 100644 --- a/kstyle/breezewindowmanager.cpp +++ b/kstyle/breezewindowmanager.cpp @@ -93,6 +93,14 @@ #endif +#if BREEZE_HAVE_KWAYLAND +#include +#include +#include +#include +#include +#endif + namespace Breeze { @@ -203,6 +211,11 @@ namespace Breeze _dragInProgress( false ), _locked( false ), _cursorOverride( false ) + #if BREEZE_HAVE_KWAYLAND + , _seat( Q_NULLPTR ) + , _pointer( Q_NULLPTR ) + , _waylandSerial( 0 ) + #endif { // install application wise event filter @@ -224,7 +237,62 @@ namespace Breeze initializeWhiteList(); initializeBlackList(); + initializeWayland(); + + } + + //_______________________________________________________ + void WindowManager::initializeWayland() + { + #if BREEZE_HAVE_KWAYLAND + if( !Helper::isWayland() ) return; + + if( _seat ) { + // already initialized + return; + } + + using namespace KWayland::Client; + auto connection = ConnectionThread::fromApplication( this ); + if( !connection ) { + return; + } + Registry *registry = new Registry( this ); + registry->create( connection ); + connect(registry, &Registry::interfacesAnnounced, this, + [registry, this] { + const auto interface = registry->interface( Registry::Interface::Seat ); + if( interface.name != 0 ) { + _seat = registry->createSeat( interface.name, interface.version, this ); + connect(_seat, &Seat::hasPointerChanged, this, &WindowManager::waylandHasPointerChanged); + } + } + ); + registry->setup(); + connection->roundtrip(); + #endif + } + + //_______________________________________________________ + void WindowManager::waylandHasPointerChanged(bool hasPointer) + { + #if BREEZE_HAVE_KWAYLAND + Q_ASSERT( _seat ); + if( hasPointer ) { + if( !_pointer ) { + _pointer = _seat->createPointer(this); + connect(_pointer, &KWayland::Client::Pointer::buttonStateChanged, this, + [this] (quint32 serial) { + _waylandSerial = serial; + } + ); + } + } else { + delete _pointer; + _pointer = nullptr; + } + #endif } //_____________________________________________________________ @@ -570,12 +638,6 @@ namespace Breeze bool WindowManager::canDrag( QWidget* widget, QWidget* child, const QPoint& position ) { - // do not start drag on Wayland, this is not yet supported - // To implement integration with KWayland is required - // and QtWayland must support getting the wl_seat. - // Other option would be adding support to Qt for starting a move - if( Helper::isWayland() ) return false; - // retrieve child at given position and check cursor again if( child && child->cursor().shape() != Qt::ArrowCursor ) return false; @@ -746,58 +808,94 @@ namespace Breeze if( useWMMoveResize() ) { - #if BREEZE_HAVE_X11 - // connection - xcb_connection_t* connection( Helper::connection() ); + if( Helper::isX11() ) { + startDragX11( widget, position ); + } else if( Helper::isWayland() ) { + startDragWayland( widget, position ); + } - // window - const WId window( widget->window()->winId() ); + } else if( !_cursorOverride ) { - #if QT_VERSION >= 0x050300 - qreal dpiRatio = 1; - QWindow* windowHandle = widget->window()->windowHandle(); - if( windowHandle ) dpiRatio = windowHandle->devicePixelRatio(); - else dpiRatio = qApp->devicePixelRatio(); - dpiRatio = qApp->devicePixelRatio(); - #else - const qreal dpiRatio = 1; - #endif + qApp->setOverrideCursor( Qt::SizeAllCursor ); + _cursorOverride = true; - #if BREEZE_USE_KDE4 - Display* net_connection = QX11Info::display(); - #else - xcb_connection_t* net_connection = connection; - #endif + } - xcb_ungrab_pointer( connection, XCB_TIME_CURRENT_TIME ); - NETRootInfo( net_connection, NET::WMMoveResize ).moveResizeRequest( - window, position.x() * dpiRatio, - position.y() * dpiRatio, - NET::Move ); + _dragInProgress = true; - #else + return; - Q_UNUSED( position ); + } - #endif + //_______________________________________________________ + void WindowManager::startDragX11( QWidget* widget, const QPoint& position ) + { + #if BREEZE_HAVE_X11 + // connection + xcb_connection_t* connection( Helper::connection() ); + + // window + const WId window( widget->window()->winId() ); + + #if QT_VERSION >= 0x050300 + qreal dpiRatio = 1; + QWindow* windowHandle = widget->window()->windowHandle(); + if( windowHandle ) dpiRatio = windowHandle->devicePixelRatio(); + else dpiRatio = qApp->devicePixelRatio(); + dpiRatio = qApp->devicePixelRatio(); + #else + const qreal dpiRatio = 1; + #endif - } else if( !_cursorOverride ) { + #if BREEZE_USE_KDE4 + Display* net_connection = QX11Info::display(); + #else + xcb_connection_t* net_connection = connection; + #endif - qApp->setOverrideCursor( Qt::SizeAllCursor ); - _cursorOverride = true; + xcb_ungrab_pointer( connection, XCB_TIME_CURRENT_TIME ); + NETRootInfo( net_connection, NET::WMMoveResize ).moveResizeRequest( + window, position.x() * dpiRatio, + position.y() * dpiRatio, + NET::Move ); - } + #else - _dragInProgress = true; + Q_UNUSED( widget ); + Q_UNUSED( position ); - return; + #endif + } + + //_______________________________________________________ + void WindowManager::startDragWayland( QWidget* widget, const QPoint& position ) + { + #if BREEZE_HAVE_KWAYLAND + if( !_seat ) { + return; + } + QWindow* windowHandle = widget->window()->windowHandle(); + auto shellSurface = KWayland::Client::ShellSurface::fromWindow(windowHandle); + if( !shellSurface ) { + // TODO: also check for xdg-shell in future + return; + } + + shellSurface->requestMove( _seat, _waylandSerial ); + #endif } //____________________________________________________________ bool WindowManager::supportWMMoveResize( void ) const { + #if BREEZE_HAVE_KWAYLAND + if( Helper::isWayland() ) { + return true; + } + #endif + #if BREEZE_HAVE_X11 return Helper::isX11(); #else diff --git a/kstyle/breezewindowmanager.h b/kstyle/breezewindowmanager.h index ba45a500..a26bb51a 100644 --- a/kstyle/breezewindowmanager.h +++ b/kstyle/breezewindowmanager.h @@ -31,6 +31,17 @@ #include #include +#if BREEZE_HAVE_KWAYLAND +namespace KWayland +{ +namespace Client +{ + class Pointer; + class Seat; +} +} +#endif + namespace Breeze { @@ -125,6 +136,12 @@ namespace Breeze */ void initializeBlackList( void ); + //* initializes the Wayland specific parts + void initializeWayland(); + + //* The Wayland Seat's hasPointer property changed + void waylandHasPointerChanged(bool hasPointer); + //@} //* returns true if widget is dragable @@ -149,6 +166,12 @@ namespace Breeze //* start drag void startDrag( QWidget*, const QPoint& ); + //* X11 specific implementation for startDrag + void startDragX11( QWidget*, const QPoint& ); + + //* Wayland specific implementation for startDrag + void startDragWayland( QWidget*, const QPoint& ); + //* returns true if window manager is used for moving /** right now this is true only for X11 */ bool supportWMMoveResize( void ) const; @@ -256,6 +279,15 @@ namespace Breeze //* application event filter QObject* _appEventFilter; + #if BREEZE_HAVE_KWAYLAND + //* The Wayland seat object which needs to be passed to move requests. + KWayland::Client::Seat* _seat; + //* The Wayland pointer object where we get pointer events on. + KWayland::Client::Pointer* _pointer; + //* latest searial which needs to be passed to the move requests. + quint32 _waylandSerial; + #endif + //* allow access of all private members to the app event filter friend class AppEventFilter;