- implemented resize using xcb - use xcb to move sizeGrip on resize because Qt move seems broken after widget is reparented - use xcb to get sizegrip' root coordinate, because Qt MapTo methods are broken after widget is reparented - protect all XCB calls behind typedef and runtime check - disable sizeGrip if not in X11wilder-pre-rebase
parent
453ad537cb
commit
efadfc24d4
8 changed files with 625 additions and 5 deletions
@ -0,0 +1,41 @@ |
||||
|
||||
/*
|
||||
* Copyright 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr> |
||||
* |
||||
* 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) version 3 or any later version |
||||
* accepted by the membership of KDE e.V. (or its successor approved |
||||
* by the membership of KDE e.V.), which shall act as a proxy |
||||
* defined in Section 14 of version 3 of the license. |
||||
* |
||||
* 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/>.
|
||||
*/ |
||||
|
||||
#include "breezehelper.h" |
||||
#include "config-breeze.h" |
||||
|
||||
#include <QApplication> |
||||
|
||||
namespace Breeze |
||||
{ |
||||
|
||||
//______________________________________________________________________________
|
||||
bool Helper::isX11( void ) |
||||
{ |
||||
#if BREEZE_HAVE_X11 |
||||
static bool isX11 = QApplication::platformName() == QStringLiteral("xcb"); |
||||
return isX11; |
||||
#else |
||||
return false; |
||||
#endif |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,38 @@ |
||||
#ifndef breezehelper_h |
||||
#define breezehelper_h |
||||
|
||||
/*
|
||||
* Copyright 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr> |
||||
* |
||||
* 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) version 3 or any later version |
||||
* accepted by the membership of KDE e.V. (or its successor approved |
||||
* by the membership of KDE e.V.), which shall act as a proxy |
||||
* defined in Section 14 of version 3 of the license. |
||||
* |
||||
* 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/>.
|
||||
*/ |
||||
|
||||
namespace Breeze |
||||
{ |
||||
class Helper |
||||
{ |
||||
|
||||
public: |
||||
|
||||
//* true if style was compiled for and is running on X11
|
||||
static bool isX11( void ); |
||||
|
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif |
||||
@ -0,0 +1,317 @@ |
||||
/*************************************************************************
|
||||
* Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr> * |
||||
* * |
||||
* 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, write to the * |
||||
* Free Software Foundation, Inc., * |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * |
||||
*************************************************************************/ |
||||
|
||||
|
||||
#include "breezesizegrip.h" |
||||
#include "breezesizegrip.moc" |
||||
|
||||
#include "breezehelper.h" |
||||
|
||||
#include <KDecoration2/DecoratedClient> |
||||
|
||||
#include <QPainter> |
||||
#include <QPolygon> |
||||
#include <QTimer> |
||||
|
||||
#if BREEZE_HAVE_X11 |
||||
#include <QX11Info> |
||||
#endif |
||||
|
||||
namespace Breeze |
||||
{ |
||||
|
||||
//* scoped pointer convenience typedef
|
||||
template <typename T> using ScopedPointer = QScopedPointer<T, QScopedPointerPodDeleter>; |
||||
|
||||
//_____________________________________________
|
||||
SizeGrip::SizeGrip( Decoration* decoration ):QWidget(nullptr) |
||||
,m_decoration( decoration ) |
||||
|
||||
#if BREEZE_HAVE_X11 |
||||
,m_moveResizeAtom( 0 ) |
||||
#endif |
||||
|
||||
{ |
||||
|
||||
setAttribute(Qt::WA_NoSystemBackground ); |
||||
setAutoFillBackground( false ); |
||||
|
||||
// cursor
|
||||
setCursor( Qt::SizeFDiagCursor ); |
||||
|
||||
// size
|
||||
setFixedSize( QSize( GripSize, GripSize ) ); |
||||
|
||||
// mask
|
||||
QPolygon p; |
||||
p << QPoint( 0, GripSize ) |
||||
<< QPoint( GripSize, 0 ) |
||||
<< QPoint( GripSize, GripSize ) |
||||
<< QPoint( 0, GripSize ); |
||||
|
||||
setMask( QRegion( p ) ); |
||||
|
||||
// embed
|
||||
embed(); |
||||
updatePosition(); |
||||
|
||||
// connections
|
||||
KDecoration2::DecoratedClient *c = decoration->client().data(); |
||||
connect( c, &KDecoration2::DecoratedClient::widthChanged, this, &SizeGrip::updatePosition ); |
||||
connect( c, &KDecoration2::DecoratedClient::heightChanged, this, &SizeGrip::updatePosition ); |
||||
connect( c, &KDecoration2::DecoratedClient::activeChanged, this, &SizeGrip::updateActiveState ); |
||||
|
||||
// show
|
||||
show(); |
||||
|
||||
} |
||||
|
||||
//_____________________________________________
|
||||
SizeGrip::~SizeGrip( void ) |
||||
{} |
||||
|
||||
//_____________________________________________
|
||||
void SizeGrip::updateActiveState( void ) |
||||
{ |
||||
#if BREEZE_HAVE_X11 |
||||
if( Helper::isX11() ) |
||||
{ |
||||
const quint32 value = XCB_STACK_MODE_ABOVE; |
||||
xcb_configure_window( QX11Info::connection(), winId(), XCB_CONFIG_WINDOW_STACK_MODE, &value ); |
||||
xcb_map_window( QX11Info::connection(), winId() ); |
||||
} |
||||
#endif |
||||
|
||||
update(); |
||||
|
||||
} |
||||
|
||||
//_____________________________________________
|
||||
void SizeGrip::embed( void ) |
||||
{ |
||||
|
||||
#if BREEZE_HAVE_X11 |
||||
|
||||
if( !Helper::isX11() ) return; |
||||
KDecoration2::DecoratedClient *c = m_decoration.data()->client().data(); |
||||
|
||||
xcb_window_t windowId = c->windowId(); |
||||
if( windowId ) |
||||
{ |
||||
|
||||
/*
|
||||
find client's parent |
||||
we want the size grip to be at the same level as the client in the stack |
||||
*/ |
||||
xcb_window_t current = windowId; |
||||
xcb_connection_t* connection = QX11Info::connection(); |
||||
xcb_query_tree_cookie_t cookie = xcb_query_tree_unchecked( connection, current ); |
||||
ScopedPointer<xcb_query_tree_reply_t> tree(xcb_query_tree_reply( connection, cookie, nullptr ) ); |
||||
if( !tree.isNull() && tree->parent ) current = tree->parent; |
||||
|
||||
// reparent
|
||||
xcb_reparent_window( connection, winId(), current, 0, 0 ); |
||||
setWindowTitle( "Breeze::SizeGrip" ); |
||||
|
||||
} else { |
||||
|
||||
hide(); |
||||
|
||||
} |
||||
|
||||
#endif |
||||
} |
||||
|
||||
//_____________________________________________
|
||||
void SizeGrip::paintEvent( QPaintEvent* ) |
||||
{ |
||||
|
||||
if( !m_decoration ) return; |
||||
KDecoration2::DecoratedClient *c = m_decoration.data()->client().data(); |
||||
|
||||
// get relevant colors
|
||||
const QColor backgroundColor( m_decoration.data()->colorSettings().titleBar( c->isActive() ) ); |
||||
|
||||
// create and configure painter
|
||||
QPainter painter(this); |
||||
painter.setRenderHints(QPainter::Antialiasing ); |
||||
|
||||
painter.setPen( Qt::NoPen ); |
||||
painter.setBrush( backgroundColor ); |
||||
|
||||
// polygon
|
||||
QPolygon p; |
||||
p << QPoint( 0, GripSize ) |
||||
<< QPoint( GripSize, 0 ) |
||||
<< QPoint( GripSize, GripSize ) |
||||
<< QPoint( 0, GripSize ); |
||||
painter.drawPolygon( p ); |
||||
|
||||
} |
||||
|
||||
//_____________________________________________
|
||||
void SizeGrip::mousePressEvent( QMouseEvent* event ) |
||||
{ |
||||
|
||||
switch (event->button()) |
||||
{ |
||||
|
||||
case Qt::RightButton: |
||||
{ |
||||
hide(); |
||||
QTimer::singleShot(5000, this, SLOT(show())); |
||||
break; |
||||
} |
||||
|
||||
case Qt::MidButton: |
||||
{ |
||||
hide(); |
||||
break; |
||||
} |
||||
|
||||
case Qt::LeftButton: |
||||
if( rect().contains( event->pos() ) ) |
||||
{ sendMoveResizeEvent( event->pos() ); } |
||||
break; |
||||
|
||||
default: break; |
||||
|
||||
} |
||||
|
||||
return; |
||||
|
||||
} |
||||
|
||||
//_______________________________________________________________________________
|
||||
void SizeGrip::updatePosition( void ) |
||||
{ |
||||
|
||||
#if BREEZE_HAVE_X11 |
||||
if( !Helper::isX11() ) return; |
||||
|
||||
KDecoration2::DecoratedClient *c = m_decoration.data()->client().data(); |
||||
QPoint position( |
||||
c->width() - GripSize - Offset, |
||||
c->height() - GripSize - Offset ); |
||||
|
||||
quint32 values[2] = { quint32(position.x()), quint32(position.y()) }; |
||||
xcb_configure_window( QX11Info::connection(), winId(), XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values ); |
||||
#endif |
||||
|
||||
} |
||||
|
||||
//_____________________________________________
|
||||
void SizeGrip::sendMoveResizeEvent( QPoint position ) |
||||
{ |
||||
|
||||
#if BREEZE_HAVE_X11 |
||||
if( !Helper::isX11() ) return; |
||||
|
||||
// pointer to connection
|
||||
xcb_connection_t* connection( QX11Info::connection() ); |
||||
|
||||
// client
|
||||
KDecoration2::DecoratedClient *c = m_decoration.data()->client().data(); |
||||
|
||||
/*
|
||||
get root position matching position |
||||
need to use xcb because the embedding of the widget |
||||
breaks QT's mapToGlobal and other methods |
||||
*/ |
||||
QPoint rootPosition( position ); |
||||
xcb_get_geometry_cookie_t cookie( xcb_get_geometry( connection, winId() ) ); |
||||
ScopedPointer<xcb_get_geometry_reply_t> reply( xcb_get_geometry_reply( connection, cookie, 0x0 ) ); |
||||
if( reply ) |
||||
{ |
||||
|
||||
// translate coordinates
|
||||
xcb_translate_coordinates_cookie_t coordCookie( xcb_translate_coordinates( |
||||
connection, winId(), reply.data()->root, |
||||
-reply.data()->border_width, |
||||
-reply.data()->border_width ) ); |
||||
|
||||
ScopedPointer< xcb_translate_coordinates_reply_t> coordReply( xcb_translate_coordinates_reply( connection, coordCookie, 0x0 ) ); |
||||
|
||||
if( coordReply ) |
||||
{ |
||||
rootPosition.rx() += coordReply.data()->dst_x; |
||||
rootPosition.ry() += coordReply.data()->dst_y; |
||||
} |
||||
|
||||
} |
||||
|
||||
// move/resize atom
|
||||
if( !m_moveResizeAtom ) |
||||
{ |
||||
|
||||
// create atom if not found
|
||||
const QString atomName( "_NET_WM_MOVERESIZE" ); |
||||
xcb_intern_atom_cookie_t cookie( xcb_intern_atom( connection, false, atomName.size(), qPrintable( atomName ) ) ); |
||||
ScopedPointer<xcb_intern_atom_reply_t> reply( xcb_intern_atom_reply( connection, cookie, 0x0 ) ); |
||||
m_moveResizeAtom = reply ? reply->atom:0; |
||||
|
||||
} |
||||
|
||||
if( !m_moveResizeAtom ) return; |
||||
|
||||
// button release event
|
||||
xcb_button_release_event_t releaseEvent; |
||||
memset(&releaseEvent, 0, sizeof(releaseEvent)); |
||||
|
||||
releaseEvent.response_type = XCB_BUTTON_RELEASE; |
||||
releaseEvent.event = winId(); |
||||
releaseEvent.child = XCB_WINDOW_NONE; |
||||
releaseEvent.root = QX11Info::appRootWindow(); |
||||
releaseEvent.event_x = position.x(); |
||||
releaseEvent.event_y = position.y(); |
||||
releaseEvent.root_x = rootPosition.x(); |
||||
releaseEvent.root_y = rootPosition.y(); |
||||
releaseEvent.detail = XCB_BUTTON_INDEX_1; |
||||
releaseEvent.state = XCB_BUTTON_MASK_1; |
||||
releaseEvent.time = XCB_CURRENT_TIME; |
||||
releaseEvent.same_screen = true; |
||||
xcb_send_event( connection, false, winId(), XCB_EVENT_MASK_BUTTON_RELEASE, reinterpret_cast<const char*>(&releaseEvent)); |
||||
|
||||
xcb_ungrab_pointer( connection, XCB_TIME_CURRENT_TIME ); |
||||
|
||||
// move resize event
|
||||
xcb_client_message_event_t clientMessageEvent; |
||||
memset(&clientMessageEvent, 0, sizeof(clientMessageEvent)); |
||||
|
||||
clientMessageEvent.response_type = XCB_CLIENT_MESSAGE; |
||||
clientMessageEvent.type = m_moveResizeAtom; |
||||
clientMessageEvent.format = 32; |
||||
clientMessageEvent.window = c->windowId(); |
||||
clientMessageEvent.data.data32[0] = rootPosition.x(); |
||||
clientMessageEvent.data.data32[1] = rootPosition.y(); |
||||
clientMessageEvent.data.data32[2] = 4; // bottom right
|
||||
clientMessageEvent.data.data32[3] = Qt::LeftButton; |
||||
clientMessageEvent.data.data32[4] = 0; |
||||
|
||||
xcb_send_event( connection, false, QX11Info::appRootWindow(), |
||||
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | |
||||
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, |
||||
reinterpret_cast<const char*>(&clientMessageEvent) ); |
||||
|
||||
xcb_flush( connection ); |
||||
#endif |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,100 @@ |
||||
#ifndef breezesizegrip_h |
||||
#define breezesizegrip_h |
||||
|
||||
/*************************************************************************
|
||||
* Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr> * |
||||
* * |
||||
* 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, write to the * |
||||
* Free Software Foundation, Inc., * |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * |
||||
*************************************************************************/ |
||||
|
||||
#include "breezedecoration.h" |
||||
#include "config-breeze.h" |
||||
|
||||
#include <QMouseEvent> |
||||
#include <QPaintEvent> |
||||
#include <QWidget> |
||||
#include <QPointer> |
||||
|
||||
#if BREEZE_HAVE_X11 |
||||
#include <xcb/xcb.h> |
||||
#endif |
||||
|
||||
namespace Breeze |
||||
{ |
||||
|
||||
//* implements size grip for all widgets
|
||||
class SizeGrip: public QWidget |
||||
{ |
||||
|
||||
Q_OBJECT |
||||
|
||||
public: |
||||
|
||||
//* constructor
|
||||
explicit SizeGrip( Decoration* ); |
||||
|
||||
//* constructor
|
||||
virtual ~SizeGrip( void ); |
||||
|
||||
protected Q_SLOTS: |
||||
|
||||
//* update background color
|
||||
void updateActiveState( void ); |
||||
|
||||
//* update position
|
||||
void updatePosition( void ); |
||||
|
||||
//* embed into parent widget
|
||||
void embed( void ); |
||||
|
||||
protected: |
||||
|
||||
//*@name event handlers
|
||||
//@{
|
||||
|
||||
//* paint
|
||||
virtual void paintEvent( QPaintEvent* ) override; |
||||
|
||||
//* mouse press
|
||||
virtual void mousePressEvent( QMouseEvent* ) override; |
||||
|
||||
//@}
|
||||
|
||||
private: |
||||
|
||||
//* send resize event
|
||||
void sendMoveResizeEvent( QPoint ); |
||||
|
||||
//* grip size
|
||||
enum { |
||||
Offset = 0, |
||||
GripSize = 14 |
||||
}; |
||||
|
||||
//* decoration
|
||||
QPointer<Decoration> m_decoration; |
||||
|
||||
//* move/resize atom
|
||||
#if BREEZE_HAVE_X11 |
||||
xcb_atom_t m_moveResizeAtom; |
||||
#endif |
||||
|
||||
}; |
||||
|
||||
|
||||
} |
||||
|
||||
#endif |
||||
@ -0,0 +1,28 @@ |
||||
/* config-breeze.h. Generated by cmake from config-breeze.h.cmake */ |
||||
|
||||
/************************************************************************* |
||||
* Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr> * |
||||
* * |
||||
* 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, write to the * |
||||
* Free Software Foundation, Inc., * |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * |
||||
*************************************************************************/ |
||||
|
||||
#ifndef config_breeze_h |
||||
#define config_breeze_h |
||||
|
||||
/* Define to 1 if XCB libraries are found */ |
||||
#cmakedefine01 BREEZE_HAVE_X11 |
||||
|
||||
#endif |
||||
Loading…
Reference in new issue