diff --git a/kstyle/CMakeLists.txt b/kstyle/CMakeLists.txt
index 27a81fe4..b269cd18 100644
--- a/kstyle/CMakeLists.txt
+++ b/kstyle/CMakeLists.txt
@@ -1,133 +1,108 @@
################# Qt/KDE #################
find_package(Qt5 REQUIRED CONFIG COMPONENTS Widgets DBus)
find_package(KF5 REQUIRED COMPONENTS
I18n
Config
GuiAddons
IconThemes
ConfigWidgets
WindowSystem)
-find_package(Qt5 COMPONENTS Quick)
+find_package(Qt5 COMPONENTS Quick X11Extras)
set(BREEZE_HAVE_QTQUICK ${Qt5Quick_FOUND})
+set(BREEZE_HAVE_QTX11EXTRAS ${Qt5X11Extras_FOUND})
find_package( KF5FrameworkIntegration CONFIG )
set_package_properties(KF5FrameworkIntegration PROPERTIES
DESCRIPTION "KF5 Framework Integration"
URL "https://projects.kde.org/projects/frameworks/frameworkintegration"
TYPE OPTIONAL
PURPOSE "Required to use KStyle convenience functionalities in style")
set(BREEZE_HAVE_KSTYLE ${KF5FrameworkIntegration_FOUND})
-find_package(XCB COMPONENTS XCB)
-set_package_properties(XCB PROPERTIES
- DESCRIPTION "X protocol C-language Binding"
- URL "https://xcb.freedesktop.org"
- TYPE OPTIONAL
- PURPOSE "Required to pass style properties to native Windows on X11 Platform"
-)
-
-find_package(KF5Wayland CONFIG)
-set(BREEZE_HAVE_KWAYLAND ${KF5Wayland_FOUND})
-
-if(UNIX AND NOT APPLE)
- set(BREEZE_HAVE_X11 ${XCB_XCB_FOUND})
- if (XCB_XCB_FOUND)
- find_package(Qt5 REQUIRED CONFIG COMPONENTS X11Extras)
- endif()
-else()
- set(BREEZE_HAVE_X11 FALSE)
-endif()
-
################# includes #################
include_directories(
animations
debug
)
include_directories(${CMAKE_SOURCE_DIR}/libbreezecommon)
include_directories(${CMAKE_BINARY_DIR}/libbreezecommon)
################# configuration #################
configure_file(config-breeze.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-breeze.h )
########### next target ###############
set(breeze_PART_SRCS
animations/breezeanimation.cpp
animations/breezeanimations.cpp
animations/breezeanimationdata.cpp
animations/breezebaseengine.cpp
animations/breezebusyindicatordata.cpp
animations/breezebusyindicatorengine.cpp
animations/breezedialdata.cpp
animations/breezedialengine.cpp
animations/breezeenabledata.cpp
animations/breezegenericdata.cpp
animations/breezeheaderviewdata.cpp
animations/breezeheaderviewengine.cpp
animations/breezescrollbardata.cpp
animations/breezescrollbarengine.cpp
animations/breezespinboxengine.cpp
animations/breezespinboxdata.cpp
animations/breezestackedwidgetdata.cpp
animations/breezestackedwidgetengine.cpp
animations/breezetabbarengine.cpp
animations/breezetabbardata.cpp
animations/breezetoolboxengine.cpp
animations/breezetransitiondata.cpp
animations/breezetransitionwidget.cpp
animations/breezewidgetstateengine.cpp
animations/breezewidgetstatedata.cpp
debug/breezewidgetexplorer.cpp
breezeaddeventfilter.cpp
breezeblurhelper.cpp
breezeframeshadow.cpp
breezehelper.cpp
breezemdiwindowshadow.cpp
breezemnemonics.cpp
breezepropertynames.cpp
breezeshadowhelper.cpp
breezesplitterproxy.cpp
breezestyle.cpp
breezestyleplugin.cpp
breezetileset.cpp
breezewindowmanager.cpp
)
kconfig_add_kcfg_files(breeze_PART_SRCS breezestyleconfigdata.kcfgc)
add_library(breeze MODULE ${breeze_PART_SRCS})
target_link_libraries(breeze Qt5::Core Qt5::Gui Qt5::Widgets Qt5::DBus)
if( BREEZE_HAVE_QTQUICK )
target_link_libraries(breeze Qt5::Quick)
endif()
+if (BREEZE_HAVE_QTX11EXTRAS)
+ target_link_libraries(breeze Qt5::X11Extras)
+endif()
target_link_libraries(breeze KF5::ConfigCore KF5::ConfigWidgets KF5::GuiAddons KF5::IconThemes KF5::WindowSystem)
target_link_libraries(breeze breezecommon5)
if(KF5FrameworkIntegration_FOUND)
target_link_libraries(breeze KF5::Style)
endif()
if (WIN32)
# As stated in https://docs.microsoft.com/en-us/cpp/c-runtime-library/math-constants M_PI only gets defined
# when if _USE_MATH_DEFINES is defined
target_compile_definitions(breeze PRIVATE _USE_MATH_DEFINES _BSD_SOURCE)
endif()
-if(BREEZE_HAVE_X11)
- target_link_libraries(breeze ${XCB_LIBRARIES})
- target_link_libraries(breeze Qt5::X11Extras)
-endif()
-
-if(BREEZE_HAVE_KWAYLAND)
- target_link_libraries(breeze KF5::WaylandClient)
-endif()
-
########### install files ###############
install(TARGETS breeze DESTINATION ${QT_PLUGIN_INSTALL_DIR}/styles/)
install(FILES breeze.themerc DESTINATION ${DATA_INSTALL_DIR}/kstyle/themes)
########### subdirectories ###############
add_subdirectory(config)
diff --git a/kstyle/breeze.kcfg b/kstyle/breeze.kcfg
index ad96ad2f..846da2b8 100644
--- a/kstyle/breeze.kcfg
+++ b/kstyle/breeze.kcfg
@@ -1,195 +1,190 @@
255
25
255
ShadowLarge
0, 0, 0
true
true
10
100
false
true
800
0
0
MN_AUTO
true
true
true
true
false
false
false
false
false
true
WD_FULL
-
-
- true
-
-
true
12
false
false
100
diff --git a/kstyle/breezehelper.cpp b/kstyle/breezehelper.cpp
index aaf3369a..5823cd44 100644
--- a/kstyle/breezehelper.cpp
+++ b/kstyle/breezehelper.cpp
@@ -1,1616 +1,1616 @@
/*************************************************************************
* Copyright (C) 2014 by Hugo Pereira Da Costa *
* *
* 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 "breezehelper.h"
#include "breeze.h"
#include "breezestyleconfigdata.h"
#include
#include
#include
#include
#include
-#if BREEZE_HAVE_X11
+#if BREEZE_HAVE_QTX11EXTRAS
#include
#endif
#include
namespace Breeze
{
//* contrast for arrow and treeline rendering
static const qreal arrowShade = 0.15;
//____________________________________________________________________
Helper::Helper( KSharedConfig::Ptr config ):
_config( std::move( config ) )
{}
//____________________________________________________________________
KSharedConfig::Ptr Helper::config() const
{ return _config; }
//____________________________________________________________________
void Helper::loadConfig()
{
_viewFocusBrush = KStatefulBrush( KColorScheme::View, KColorScheme::FocusColor );
_viewHoverBrush = KStatefulBrush( KColorScheme::View, KColorScheme::HoverColor );
_viewNegativeTextBrush = KStatefulBrush( KColorScheme::View, KColorScheme::NegativeText );
const QPalette palette( QApplication::palette() );
const KConfigGroup group( _config->group( "WM" ) );
_activeTitleBarColor = group.readEntry( "activeBackground", palette.color( QPalette::Active, QPalette::Highlight ) );
_activeTitleBarTextColor = group.readEntry( "activeForeground", palette.color( QPalette::Active, QPalette::HighlightedText ) );
_inactiveTitleBarColor = group.readEntry( "inactiveBackground", palette.color( QPalette::Disabled, QPalette::Highlight ) );
_inactiveTitleBarTextColor = group.readEntry( "inactiveForeground", palette.color( QPalette::Disabled, QPalette::HighlightedText ) );
}
//____________________________________________________________________
QColor Helper::frameOutlineColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const
{
QColor outline( KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.25 ) );
// focus takes precedence over hover
if( mode == AnimationFocus )
{
const QColor focus( focusColor( palette ) );
const QColor hover( hoverColor( palette ) );
if( mouseOver ) outline = KColorUtils::mix( hover, focus, opacity );
else outline = KColorUtils::mix( outline, focus, opacity );
} else if( hasFocus ) {
outline = focusColor( palette );
} else if( mode == AnimationHover ) {
const QColor hover( hoverColor( palette ) );
outline = KColorUtils::mix( outline, hover, opacity );
} else if( mouseOver ) {
outline = hoverColor( palette );
}
return outline;
}
//____________________________________________________________________
QColor Helper::focusOutlineColor( const QPalette& palette ) const
{ return KColorUtils::mix( focusColor( palette ), palette.color( QPalette::WindowText ), 0.15 ); }
//____________________________________________________________________
QColor Helper::hoverOutlineColor( const QPalette& palette ) const
{ return KColorUtils::mix( hoverColor( palette ), palette.color( QPalette::WindowText ), 0.15 ); }
//____________________________________________________________________
QColor Helper::buttonFocusOutlineColor( const QPalette& palette ) const
{ return KColorUtils::mix( focusColor( palette ), palette.color( QPalette::ButtonText ), 0.15 ); }
//____________________________________________________________________
QColor Helper::buttonHoverOutlineColor( const QPalette& palette ) const
{ return KColorUtils::mix( hoverColor( palette ), palette.color( QPalette::ButtonText ), 0.15 ); }
//____________________________________________________________________
QColor Helper::sidePanelOutlineColor( const QPalette& palette, bool hasFocus, qreal opacity, AnimationMode mode ) const
{
QColor outline( palette.color( QPalette::Inactive, QPalette::Highlight ) );
const QColor &focus = palette.color( QPalette::Active, QPalette::Highlight );
if( mode == AnimationFocus )
{
outline = KColorUtils::mix( outline, focus, opacity );
} else if( hasFocus ) {
outline = focus;
}
return outline;
}
//____________________________________________________________________
QColor Helper::frameBackgroundColor( const QPalette& palette, QPalette::ColorGroup group ) const
{ return KColorUtils::mix( palette.color( group, QPalette::Window ), palette.color( group, QPalette::Base ), 0.3 ); }
//____________________________________________________________________
QColor Helper::arrowColor( const QPalette& palette, QPalette::ColorGroup group, QPalette::ColorRole role ) const
{
switch( role )
{
case QPalette::Text: return KColorUtils::mix( palette.color( group, QPalette::Text ), palette.color( group, QPalette::Base ), arrowShade );
case QPalette::WindowText: return KColorUtils::mix( palette.color( group, QPalette::WindowText ), palette.color( group, QPalette::Window ), arrowShade );
case QPalette::ButtonText: return KColorUtils::mix( palette.color( group, QPalette::ButtonText ), palette.color( group, QPalette::Button ), arrowShade );
default: return palette.color( group, role );
}
}
//____________________________________________________________________
QColor Helper::arrowColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const
{
QColor outline( arrowColor( palette, QPalette::WindowText ) );
if( mode == AnimationHover )
{
const QColor focus( focusColor( palette ) );
const QColor hover( hoverColor( palette ) );
if( hasFocus ) outline = KColorUtils::mix( focus, hover, opacity );
else outline = KColorUtils::mix( outline, hover, opacity );
} else if( mouseOver ) {
outline = hoverColor( palette );
} else if( mode == AnimationFocus ) {
const QColor focus( focusColor( palette ) );
outline = KColorUtils::mix( outline, focus, opacity );
} else if( hasFocus ) {
outline = focusColor( palette );
}
return outline;
}
//____________________________________________________________________
QColor Helper::buttonOutlineColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const
{
QColor outline( KColorUtils::mix( palette.color( QPalette::Button ), palette.color( QPalette::ButtonText ), 0.3 ) );
if( mode == AnimationHover )
{
if( hasFocus )
{
const QColor focus( buttonFocusOutlineColor( palette ) );
const QColor hover( buttonHoverOutlineColor( palette ) );
outline = KColorUtils::mix( focus, hover, opacity );
} else {
const QColor hover( hoverColor( palette ) );
outline = KColorUtils::mix( outline, hover, opacity );
}
} else if( mouseOver ) {
if( hasFocus ) outline = buttonHoverOutlineColor( palette );
else outline = hoverColor( palette );
} else if( mode == AnimationFocus ) {
const QColor focus( buttonFocusOutlineColor( palette ) );
outline = KColorUtils::mix( outline, focus, opacity );
} else if( hasFocus ) {
outline = buttonFocusOutlineColor( palette );
}
return outline;
}
//____________________________________________________________________
QColor Helper::buttonBackgroundColor( const QPalette& palette, bool mouseOver, bool hasFocus, bool sunken, qreal opacity, AnimationMode mode ) const
{
QColor background( sunken ?
KColorUtils::mix( palette.color( QPalette::Button ), palette.color( QPalette::ButtonText ), 0.2 ):
palette.color( QPalette::Button ) );
if( mode == AnimationHover )
{
const QColor focus( focusColor( palette ) );
const QColor hover( hoverColor( palette ) );
if( hasFocus ) background = KColorUtils::mix( focus, hover, opacity );
} else if( mouseOver && hasFocus ) {
background = hoverColor( palette );
} else if( mode == AnimationFocus ) {
const QColor focus( focusColor( palette ) );
background = KColorUtils::mix( background, focus, opacity );
} else if( hasFocus ) {
background = focusColor( palette );
}
return background;
}
//____________________________________________________________________
QColor Helper::toolButtonColor( const QPalette& palette, bool mouseOver, bool hasFocus, bool sunken, qreal opacity, AnimationMode mode ) const
{
QColor outline;
const QColor hoverColor( this->hoverColor( palette ) );
const QColor focusColor( this->focusColor( palette ) );
const QColor sunkenColor = alphaColor( palette.color( QPalette::WindowText ), 0.2 );
// hover takes precedence over focus
if( mode == AnimationHover )
{
if( hasFocus ) outline = KColorUtils::mix( focusColor, hoverColor, opacity );
else if( sunken ) outline = sunkenColor;
else outline = alphaColor( hoverColor, opacity );
} else if( mouseOver ) {
outline = hoverColor;
} else if( mode == AnimationFocus ) {
if( sunken ) outline = KColorUtils::mix( sunkenColor, focusColor, opacity );
else outline = alphaColor( focusColor, opacity );
} else if( hasFocus ) {
outline = focusColor;
} else if( sunken ) {
outline = sunkenColor;
}
return outline;
}
//____________________________________________________________________
QColor Helper::sliderOutlineColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const
{
QColor outline( KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.4 ) );
// hover takes precedence over focus
if( mode == AnimationHover )
{
const QColor hover( hoverColor( palette ) );
const QColor focus( focusColor( palette ) );
if( hasFocus ) outline = KColorUtils::mix( focus, hover, opacity );
else outline = KColorUtils::mix( outline, hover, opacity );
} else if( mouseOver ) {
outline = hoverColor( palette );
} else if( mode == AnimationFocus ) {
const QColor focus( focusColor( palette ) );
outline = KColorUtils::mix( outline, focus, opacity );
} else if( hasFocus ) {
outline = focusColor( palette );
}
return outline;
}
//____________________________________________________________________
QColor Helper::scrollBarHandleColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const
{
QColor color( alphaColor( palette.color( QPalette::WindowText ), 0.5 ) );
// hover takes precedence over focus
if( mode == AnimationHover )
{
const QColor hover( hoverColor( palette ) );
const QColor focus( focusColor( palette ) );
if( hasFocus ) color = KColorUtils::mix( focus, hover, opacity );
else color = KColorUtils::mix( color, hover, opacity );
} else if( mouseOver ) {
color = hoverColor( palette );
} else if( mode == AnimationFocus ) {
const QColor focus( focusColor( palette ) );
color = KColorUtils::mix( color, focus, opacity );
} else if( hasFocus ) {
color = focusColor( palette );
}
return color;
}
//______________________________________________________________________________
QColor Helper::checkBoxIndicatorColor( const QPalette& palette, bool mouseOver, bool active, qreal opacity, AnimationMode mode ) const
{
QColor color( KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.6 ) );
if( mode == AnimationHover )
{
const QColor focus( focusColor( palette ) );
const QColor hover( hoverColor( palette ) );
if( active ) color = KColorUtils::mix( focus, hover, opacity );
else color = KColorUtils::mix( color, hover, opacity );
} else if( mouseOver ) {
color = hoverColor( palette );
} else if( active ) {
color = focusColor( palette );
}
return color;
}
//______________________________________________________________________________
QColor Helper::separatorColor( const QPalette& palette ) const
{ return KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.25 ); }
//______________________________________________________________________________
QPalette Helper::disabledPalette( const QPalette& source, qreal ratio ) const
{
QPalette copy( source );
const QList roles = { QPalette::Background, QPalette::Highlight, QPalette::WindowText, QPalette::ButtonText, QPalette::Text, QPalette::Button };
foreach( const QPalette::ColorRole& role, roles )
{ copy.setColor( role, KColorUtils::mix( source.color( QPalette::Active, role ), source.color( QPalette::Disabled, role ), 1.0-ratio ) ); }
return copy;
}
//____________________________________________________________________
QColor Helper::alphaColor( QColor color, qreal alpha ) const
{
if( alpha >= 0 && alpha < 1.0 )
{ color.setAlphaF( alpha*color.alphaF() ); }
return color;
}
//______________________________________________________________________________
void Helper::renderDebugFrame( QPainter* painter, const QRect& rect ) const
{
painter->save();
painter->setRenderHints( QPainter::Antialiasing );
painter->setBrush( Qt::NoBrush );
painter->setPen( Qt::red );
painter->drawRect( strokedRect( rect ) );
painter->restore();
}
//______________________________________________________________________________
void Helper::renderFocusRect( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, Sides sides ) const
{
if( !color.isValid() ) return;
painter->save();
painter->setRenderHints( QPainter::Antialiasing );
painter->setBrush( color );
if( !( outline.isValid() && sides ) )
{
painter->setPen( Qt::NoPen );
painter->drawRect( rect );
} else {
painter->setClipRect( rect );
QRectF copy( strokedRect( rect ) );
const qreal radius( frameRadius( PenWidth::Frame, -1 ) );
if( !(sides&SideTop) ) copy.adjust( 0, -radius, 0, 0 );
if( !(sides&SideBottom) ) copy.adjust( 0, 0, 0, radius );
if( !(sides&SideLeft) ) copy.adjust( -radius, 0, 0, 0 );
if( !(sides&SideRight) ) copy.adjust( 0, 0, radius, 0 );
painter->setPen( outline );
// painter->setBrush( Qt::NoBrush );
painter->drawRoundedRect( copy, radius, radius );
}
painter->restore();
}
//______________________________________________________________________________
void Helper::renderFocusLine( QPainter* painter, const QRect& rect, const QColor& color ) const
{
if( !color.isValid() ) return;
painter->save();
painter->setRenderHint( QPainter::Antialiasing, false );
painter->setBrush( Qt::NoBrush );
painter->setPen( color );
painter->translate( 0, 2 );
painter->drawLine( rect.bottomLeft(), rect.bottomRight() );
painter->restore();
}
//______________________________________________________________________________
void Helper::renderFrame(
QPainter* painter, const QRect& rect,
const QColor& color, const QColor& outline ) const
{
painter->setRenderHint( QPainter::Antialiasing );
QRectF frameRect( rect.adjusted( 1, 1, -1, -1 ) );
qreal radius( frameRadius( PenWidth::NoPen, -1 ) );
// set pen
if( outline.isValid() )
{
painter->setPen( outline );
frameRect = strokedRect( frameRect );
radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame );
} else {
painter->setPen( Qt::NoPen );
}
// set brush
if( color.isValid() ) painter->setBrush( color );
else painter->setBrush( Qt::NoBrush );
// render
painter->drawRoundedRect( frameRect, radius, radius );
}
//______________________________________________________________________________
void Helper::renderSidePanelFrame( QPainter* painter, const QRect& rect, const QColor& outline, Side side ) const
{
// check color
if( !outline.isValid() ) return;
// adjust rect
QRectF frameRect( strokedRect( rect ) );
// setup painter
painter->setRenderHint( QPainter::Antialiasing );
painter->setPen( outline );
// render
switch( side )
{
default:
case SideLeft:
painter->drawLine( frameRect.topRight(), frameRect.bottomRight() );
break;
case SideTop:
painter->drawLine( frameRect.topLeft(), frameRect.topRight() );
break;
case SideRight:
painter->drawLine( frameRect.topLeft(), frameRect.bottomLeft() );
break;
case SideBottom:
painter->drawLine( frameRect.bottomLeft(), frameRect.bottomRight() );
break;
case AllSides:
{
const qreal radius( frameRadius( PenWidth::Frame, -1 ) );
painter->drawRoundedRect( frameRect, radius, radius );
break;
}
}
}
//______________________________________________________________________________
void Helper::renderMenuFrame(
QPainter* painter, const QRect& rect,
const QColor& color, const QColor& outline, bool roundCorners ) const
{
// set brush
if( color.isValid() ) painter->setBrush( color );
else painter->setBrush( Qt::NoBrush );
if( roundCorners )
{
painter->setRenderHint( QPainter::Antialiasing );
QRectF frameRect( rect );
qreal radius( frameRadius( PenWidth::NoPen, -1 ) );
// set pen
if( outline.isValid() )
{
painter->setPen( outline );
frameRect = strokedRect( frameRect );
radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame );
} else painter->setPen( Qt::NoPen );
// render
painter->drawRoundedRect( frameRect, radius, radius );
} else {
painter->setRenderHint( QPainter::Antialiasing, false );
QRect frameRect( rect );
if( outline.isValid() )
{
painter->setPen( outline );
frameRect.adjust( 0, 0, -1, -1 );
} else painter->setPen( Qt::NoPen );
painter->drawRect( frameRect );
}
}
//______________________________________________________________________________
void Helper::renderButtonFrame(
QPainter* painter, const QRect& rect,
const QColor& color, const QColor& outline, const QColor& shadow,
bool hasFocus, bool sunken ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
// copy rect
QRectF frameRect( rect );
frameRect.adjust( 1, 1, -1, -1 );
qreal radius( frameRadius( PenWidth::NoPen, -1 ) );
// shadow
if( sunken ) {
frameRect.translate( 1, 1 );
} else {
renderRoundedRectShadow( painter, frameRect, shadow, radius );
}
if( outline.isValid() )
{
QLinearGradient gradient( frameRect.topLeft(), frameRect.bottomLeft() );
gradient.setColorAt( 0, outline.lighter( hasFocus ? 103:101 ) );
gradient.setColorAt( 1, outline.darker( hasFocus ? 110:103 ) );
painter->setPen( QPen( QBrush( gradient ), 1.0 ) );
frameRect = strokedRect( frameRect );
radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame );
} else painter->setPen( Qt::NoPen );
// content
if( color.isValid() )
{
QLinearGradient gradient( frameRect.topLeft(), frameRect.bottomLeft() );
gradient.setColorAt( 0, color.lighter( hasFocus ? 103:101 ) );
gradient.setColorAt( 1, color.darker( hasFocus ? 110:103 ) );
painter->setBrush( gradient );
} else painter->setBrush( Qt::NoBrush );
// render
painter->drawRoundedRect( frameRect, radius, radius );
}
//______________________________________________________________________________
void Helper::renderToolButtonFrame(
QPainter* painter, const QRect& rect,
const QColor& color, bool sunken ) const
{
// do nothing for invalid color
if( !color.isValid() ) return;
// setup painter
painter->setRenderHints( QPainter::Antialiasing );
const QRectF baseRect( rect.adjusted( 1, 1, -1, -1 ) );
if( sunken )
{
const qreal radius( frameRadius( PenWidth::NoPen ) );
painter->setPen( Qt::NoPen );
painter->setBrush( color );
painter->drawRoundedRect( baseRect, radius, radius );
} else {
const qreal radius( frameRadius( PenWidth::Frame ) );
painter->setPen( color );
painter->setBrush( Qt::NoBrush );
const QRectF outlineRect( strokedRect( baseRect ) );
painter->drawRoundedRect( outlineRect, radius, radius );
}
}
//______________________________________________________________________________
void Helper::renderToolBoxFrame(
QPainter* painter, const QRect& rect, int tabWidth,
const QColor& outline ) const
{
if( !outline.isValid() ) return;
// round radius
const qreal radius( frameRadius( PenWidth::Frame ) );
const QSizeF cornerSize( 2*radius, 2*radius );
// if rect - tabwidth is even, need to increase tabWidth by 1 unit
// for anti aliasing
if( !((rect.width() - tabWidth)%2) ) ++tabWidth;
// adjust rect for antialiasing
QRectF baseRect( strokedRect( rect ) );
// create path
QPainterPath path;
path.moveTo( 0, baseRect.height()-1 );
path.lineTo( ( baseRect.width() - tabWidth )/2 - radius, baseRect.height()-1 );
path.arcTo( QRectF( QPointF( ( baseRect.width() - tabWidth )/2 - 2*radius, baseRect.height()-1 - 2*radius ), cornerSize ), 270, 90 );
path.lineTo( ( baseRect.width() - tabWidth )/2, radius );
path.arcTo( QRectF( QPointF( ( baseRect.width() - tabWidth )/2, 0 ), cornerSize ), 180, -90 );
path.lineTo( ( baseRect.width() + tabWidth )/2 -1 - radius, 0 );
path.arcTo( QRectF( QPointF( ( baseRect.width() + tabWidth )/2 - 1 - 2*radius, 0 ), cornerSize ), 90, -90 );
path.lineTo( ( baseRect.width() + tabWidth )/2 -1, baseRect.height()-1 - radius );
path.arcTo( QRectF( QPointF( ( baseRect.width() + tabWidth )/2 -1, baseRect.height()-1 - 2*radius ), cornerSize ), 180, 90 );
path.lineTo( baseRect.width()-1, baseRect.height()-1 );
// render
painter->setRenderHints( QPainter::Antialiasing );
painter->setBrush( Qt::NoBrush );
painter->setPen( outline );
painter->translate( baseRect.topLeft() );
painter->drawPath( path );
}
//______________________________________________________________________________
void Helper::renderTabWidgetFrame(
QPainter* painter, const QRect& rect,
const QColor& color, const QColor& outline, Corners corners ) const
{
painter->setRenderHint( QPainter::Antialiasing );
QRectF frameRect( rect.adjusted( 1, 1, -1, -1 ) );
qreal radius( frameRadius( PenWidth::NoPen, -1 ) );
// set pen
if( outline.isValid() )
{
painter->setPen( outline );
frameRect = strokedRect( frameRect );
radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame );
} else painter->setPen( Qt::NoPen );
// set brush
if( color.isValid() ) painter->setBrush( color );
else painter->setBrush( Qt::NoBrush );
// render
QPainterPath path( roundedPath( frameRect, corners, radius ) );
painter->drawPath( path );
}
//______________________________________________________________________________
void Helper::renderSelection(
QPainter* painter, const QRect& rect,
const QColor& color ) const
{
painter->setRenderHint( QPainter::Antialiasing );
painter->setPen( Qt::NoPen );
painter->setBrush( color );
painter->drawRect( rect );
}
//______________________________________________________________________________
void Helper::renderSeparator(
QPainter* painter, const QRect& rect,
const QColor& color, bool vertical ) const
{
painter->setRenderHint( QPainter::Antialiasing, false );
painter->setBrush( Qt::NoBrush );
painter->setPen( color );
if( vertical )
{
painter->translate( rect.width()/2, 0 );
painter->drawLine( rect.topLeft(), rect.bottomLeft() );
} else {
painter->translate( 0, rect.height()/2 );
painter->drawLine( rect.topLeft(), rect.topRight() );
}
}
//______________________________________________________________________________
void Helper::renderCheckBoxBackground(
QPainter* painter, const QRect& rect,
const QColor& color, bool sunken ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
// copy rect and radius
QRectF frameRect( rect );
frameRect.adjust( 3, 3, -3, -3 );
if( sunken ) frameRect.translate(1, 1);
painter->setPen( Qt::NoPen );
painter->setBrush( color );
painter->drawRect( frameRect );
}
//______________________________________________________________________________
void Helper::renderCheckBox(
QPainter* painter, const QRect& rect,
const QColor& color, const QColor& shadow,
bool sunken, CheckBoxState state, qreal animation ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
// copy rect and radius
QRectF frameRect( rect );
frameRect.adjust( 2, 2, -2, -2 );
qreal radius( frameRadius( PenWidth::NoPen, -1 ) );
// shadow
if( sunken )
{
frameRect.translate(1, 1);
} else {
renderRoundedRectShadow( painter, frameRect, shadow, radius );
}
// content
{
painter->setPen( QPen( color, PenWidth::Frame ) );
painter->setBrush( Qt::NoBrush );
radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame );
const QRectF contentRect( strokedRect( frameRect ) );
painter->drawRoundedRect( contentRect, radius, radius );
}
// mark
if( state == CheckOn )
{
painter->setBrush( color );
painter->setPen( Qt::NoPen );
const QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) );
painter->drawRect( markerRect );
} else if( state == CheckPartial ) {
QPen pen( color, 2 );
pen.setJoinStyle( Qt::MiterJoin );
painter->setPen( pen );
const QRectF markerRect( frameRect.adjusted( 4, 4, -4, -4 ) );
painter->drawRect( markerRect );
painter->setPen( Qt::NoPen );
painter->setBrush( color );
painter->setRenderHint( QPainter::Antialiasing, false );
QPainterPath path;
path.moveTo( markerRect.topLeft() );
path.lineTo( markerRect.right() - 1, markerRect.top() );
path.lineTo( markerRect.left(), markerRect.bottom()-1 );
painter->drawPath( path );
} else if( state == CheckAnimated ) {
const QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) );
QPainterPath path;
path.moveTo( markerRect.topRight() );
path.lineTo( markerRect.center() + animation*( markerRect.topLeft() - markerRect.center() ) );
path.lineTo( markerRect.bottomLeft() );
path.lineTo( markerRect.center() + animation*( markerRect.bottomRight() - markerRect.center() ) );
path.closeSubpath();
painter->setBrush( color );
painter->setPen( Qt::NoPen );
painter->drawPath( path );
}
}
//______________________________________________________________________________
void Helper::renderRadioButtonBackground( QPainter* painter, const QRect& rect, const QColor& color, bool sunken ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
// copy rect
QRectF frameRect( rect );
frameRect.adjust( 3, 3, -3, -3 );
if( sunken ) frameRect.translate(1, 1);
painter->setPen( Qt::NoPen );
painter->setBrush( color );
painter->drawEllipse( frameRect );
}
//______________________________________________________________________________
void Helper::renderRadioButton(
QPainter* painter, const QRect& rect,
const QColor& color, const QColor& shadow,
bool sunken, RadioButtonState state, qreal animation ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
// copy rect
QRectF frameRect( rect );
frameRect.adjust( 2, 2, -2, -2 );
// shadow
if( sunken )
{
frameRect.translate( 1, 1 );
} else {
renderEllipseShadow( painter, frameRect, shadow );
}
// content
{
painter->setPen( QPen( color, PenWidth::Frame ) );
painter->setBrush( Qt::NoBrush );
const QRectF contentRect( strokedRect( frameRect ) );
painter->drawEllipse( contentRect );
}
// mark
if( state == RadioOn )
{
painter->setBrush( color );
painter->setPen( Qt::NoPen );
const QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) );
painter->drawEllipse( markerRect );
} else if( state == RadioAnimated ) {
painter->setBrush( color );
painter->setPen( Qt::NoPen );
QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) );
painter->translate( markerRect.center() );
painter->rotate( 45 );
markerRect.setWidth( markerRect.width()*animation );
markerRect.translate( -markerRect.center() );
painter->drawEllipse( markerRect );
}
}
//______________________________________________________________________________
void Helper::renderSliderGroove(
QPainter* painter, const QRect& rect,
const QColor& color ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
const QRectF baseRect( rect );
const qreal radius( 0.5*Metrics::Slider_GrooveThickness );
// content
if( color.isValid() )
{
painter->setPen( Qt::NoPen );
painter->setBrush( color );
painter->drawRoundedRect( baseRect, radius, radius );
}
}
//______________________________________________________________________________
void Helper::renderDialGroove(
QPainter* painter, const QRect& rect,
const QColor& color,
qreal first, qreal last ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
const QRectF baseRect( rect );
// content
if( color.isValid() )
{
const qreal penWidth( Metrics::Slider_GrooveThickness );
const QRectF grooveRect( rect.adjusted( penWidth/2, penWidth/2, -penWidth/2, -penWidth/2 ) );
// setup angles
const int angleStart( first * 180 * 16 / M_PI );
const int angleSpan( (last - first ) * 180 * 16 / M_PI );
// setup pen
if( angleSpan != 0 )
{
QPen pen( color, penWidth );
pen.setCapStyle( Qt::RoundCap );
painter->setPen( pen );
painter->setBrush( Qt::NoBrush );
painter->drawArc( grooveRect, angleStart, angleSpan );
}
}
}
//______________________________________________________________________________
void Helper::renderDialContents(
QPainter* painter, const QRect& rect,
const QColor& color,
qreal first, qreal second ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
const QRectF baseRect( rect );
// content
if( color.isValid() )
{
// setup groove rect
const qreal penWidth( Metrics::Slider_GrooveThickness );
const QRectF grooveRect( rect.adjusted( penWidth/2, penWidth/2, -penWidth/2, -penWidth/2 ) );
// setup angles
const int angleStart( first * 180 * 16 / M_PI );
const int angleSpan( (second - first ) * 180 * 16 / M_PI );
// setup pen
if( angleSpan != 0 )
{
QPen pen( color, penWidth );
pen.setCapStyle( Qt::RoundCap );
painter->setPen( pen );
painter->setBrush( Qt::NoBrush );
painter->drawArc( grooveRect, angleStart, angleSpan );
}
}
}
//______________________________________________________________________________
void Helper::renderSliderHandle(
QPainter* painter, const QRect& rect,
const QColor& color,
const QColor& outline,
const QColor& shadow,
bool sunken ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
// copy rect
QRectF frameRect( rect );
frameRect.adjust( 1, 1, -1, -1 );
// shadow
if( !sunken )
{
renderEllipseShadow( painter, frameRect, shadow );
}
// set pen
if( outline.isValid() )
{
painter->setPen( outline );
frameRect = strokedRect( frameRect );
} else painter->setPen( Qt::NoPen );
// set brush
if( color.isValid() ) painter->setBrush( color );
else painter->setBrush( Qt::NoBrush );
// render
painter->drawEllipse( frameRect );
}
//______________________________________________________________________________
void Helper::renderProgressBarGroove(
QPainter* painter, const QRect& rect,
const QColor& color ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
const QRectF baseRect( rect );
const qreal radius( 0.5*Metrics::ProgressBar_Thickness );
// content
if( color.isValid() )
{
painter->setPen( Qt::NoPen );
painter->setBrush( color );
painter->drawRoundedRect( baseRect, radius, radius );
}
}
//______________________________________________________________________________
void Helper::renderProgressBarBusyContents(
QPainter* painter, const QRect& rect,
const QColor& first,
const QColor& second,
bool horizontal,
bool reverse,
int progress
) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
const QRectF baseRect( rect );
const qreal radius( 0.5*Metrics::ProgressBar_Thickness );
// setup brush
QPixmap pixmap( horizontal ? 2*Metrics::ProgressBar_BusyIndicatorSize : 1, horizontal ? 1:2*Metrics::ProgressBar_BusyIndicatorSize );
pixmap.fill( second );
if( horizontal )
{
QPainter painter( &pixmap );
painter.setBrush( first );
painter.setPen( Qt::NoPen );
progress %= 2*Metrics::ProgressBar_BusyIndicatorSize;
if( reverse ) progress = 2*Metrics::ProgressBar_BusyIndicatorSize - progress - 1;
painter.drawRect( QRect( 0, 0, Metrics::ProgressBar_BusyIndicatorSize, 1 ).translated( progress, 0 ) );
if( progress > Metrics::ProgressBar_BusyIndicatorSize )
{ painter.drawRect( QRect( 0, 0, Metrics::ProgressBar_BusyIndicatorSize, 1 ).translated( progress - 2*Metrics::ProgressBar_BusyIndicatorSize, 0 ) ); }
} else {
QPainter painter( &pixmap );
painter.setBrush( first );
painter.setPen( Qt::NoPen );
progress %= 2*Metrics::ProgressBar_BusyIndicatorSize;
progress = 2*Metrics::ProgressBar_BusyIndicatorSize - progress - 1;
painter.drawRect( QRect( 0, 0, 1, Metrics::ProgressBar_BusyIndicatorSize ).translated( 0, progress ) );
if( progress > Metrics::ProgressBar_BusyIndicatorSize )
{ painter.drawRect( QRect( 0, 0, 1, Metrics::ProgressBar_BusyIndicatorSize ).translated( 0, progress - 2*Metrics::ProgressBar_BusyIndicatorSize ) ); }
}
painter->setPen( Qt::NoPen );
painter->setBrush( pixmap );
painter->drawRoundedRect( baseRect, radius, radius );
}
//______________________________________________________________________________
void Helper::renderScrollBarHandle(
QPainter* painter, const QRect& rect,
const QColor& color ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
const QRectF baseRect( rect );
const qreal radius( 0.5 * std::min({baseRect.width(), baseRect.height(), (qreal)Metrics::ScrollBar_SliderWidth}) );
// content
if( color.isValid() )
{
painter->setPen( Qt::NoPen );
painter->setBrush( color );
painter->drawRoundedRect( baseRect, radius, radius );
}
}
//______________________________________________________________________________
void Helper::renderScrollBarBorder(
QPainter* painter, const QRect& rect,
const QColor& color ) const
{
// content
if( color.isValid() )
{
painter->setPen( Qt::NoPen );
painter->setBrush( color );
painter->drawRect( rect );
}
}
//______________________________________________________________________________
void Helper::renderTabBarTab( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, Corners corners ) const
{
// setup painter
painter->setRenderHint( QPainter::Antialiasing, true );
QRectF frameRect( rect );
qreal radius( frameRadius( PenWidth::NoPen, -1 ) );
// pen
if( outline.isValid() )
{
painter->setPen( outline );
frameRect = strokedRect( frameRect );
radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame );
} else painter->setPen( Qt::NoPen );
// brush
if( color.isValid() ) painter->setBrush( color );
else painter->setBrush( Qt::NoBrush );
// render
QPainterPath path( roundedPath( frameRect, corners, radius ) );
painter->drawPath( path );
}
//______________________________________________________________________________
void Helper::renderArrow( QPainter* painter, const QRect& rect, const QColor& color, ArrowOrientation orientation ) const
{
// define polygon
QPolygonF arrow;
switch( orientation )
{
/* The inner points of the normal arrows are not on half pixels because
* they need to have an even width (up/down) or height (left/right).
* An even width/height makes them easier to align with other UI elements.
*/
case ArrowUp: arrow = QVector{QPointF( -4.5, 1.5 ), QPointF( 0, -3 ), QPointF( 4.5, 1.5 )}; break;
case ArrowDown: arrow = QVector{QPointF( -4.5, -1.5 ), QPointF( 0, 3 ), QPointF( 4.5, -1.5 )}; break;
case ArrowLeft: arrow = QVector{QPointF( 1.5, -4.5 ), QPointF( -3, 0 ), QPointF( 1.5, 4.5 )}; break;
case ArrowRight: arrow = QVector{QPointF( -1.5, -4.5 ), QPointF( 3, 0 ), QPointF( -1.5, 4.5 )}; break;
case ArrowDown_Small: arrow = QVector{QPointF( 1.5, 3.5 ), QPointF( 3.5, 5.5 ), QPointF( 5.5, 3.5 )}; break;
default: break;
}
painter->save();
painter->setRenderHints( QPainter::Antialiasing );
painter->translate( QRectF( rect ).center() );
painter->setBrush( Qt::NoBrush );
QPen pen( color, PenWidth::Symbol );
pen.setCapStyle(Qt::SquareCap);
pen.setJoinStyle(Qt::MiterJoin);
painter->setPen( pen );
painter->drawPolyline( arrow );
painter->restore();
}
//______________________________________________________________________________
void Helper::renderDecorationButton( QPainter* painter, const QRect& rect, const QColor& color, ButtonType buttonType, bool inverted ) const
{
painter->save();
painter->setViewport( rect );
painter->setWindow( 0, 0, 18, 18 );
painter->setRenderHints( QPainter::Antialiasing );
// initialize pen
QPen pen;
pen.setCapStyle( Qt::RoundCap );
pen.setJoinStyle( Qt::MiterJoin );
if( inverted )
{
// render circle
painter->setPen( Qt::NoPen );
painter->setBrush( color );
painter->drawEllipse( QRectF( 0, 0, 18, 18 ) );
// take out the inner part
painter->setCompositionMode( QPainter::CompositionMode_DestinationOut );
painter->setBrush( Qt::NoBrush );
pen.setColor( Qt::black );
} else {
painter->setBrush( Qt::NoBrush );
pen.setColor( color );
}
pen.setCapStyle( Qt::RoundCap );
pen.setJoinStyle( Qt::MiterJoin );
pen.setWidthF( PenWidth::Symbol*qMax(1.0, 18.0/rect.width() ) );
painter->setPen( pen );
switch( buttonType )
{
case ButtonClose:
{
painter->drawLine( QPointF( 5, 5 ), QPointF( 13, 13 ) );
painter->drawLine( 13, 5, 5, 13 );
break;
}
case ButtonMaximize:
{
painter->drawPolyline( QVector{
QPointF( 4, 11 ),
QPointF( 9, 6 ),
QPointF( 14, 11 )});
break;
}
case ButtonMinimize:
{
painter->drawPolyline(QVector{
QPointF( 4, 7 ),
QPointF( 9, 12 ),
QPointF( 14, 7 )} );
break;
}
case ButtonRestore:
{
pen.setJoinStyle( Qt::RoundJoin );
painter->setPen( pen );
painter->drawPolygon( QVector{
QPointF( 4.5, 9 ),
QPointF( 9, 4.5 ),
QPointF( 13.5, 9 ),
QPointF( 9, 13.5 )});
break;
}
default: break;
}
painter->restore();
}
//______________________________________________________________________________
void Helper::renderRoundedRectShadow( QPainter* painter, const QRectF& rect, const QColor& color, qreal radius ) const
{
if( !color.isValid() ) return;
painter->save();
qreal translation = 0.5 * PenWidth::Shadow; // Translate for the pen
/* Clipping prevents shadows from being visible inside checkboxes.
* Clipping away unneeded parts here also improves performance by 40-60%
* versus using just an outline of a rectangle.
* Tested by looking at the paint analyser in GammaRay.
*/
// Right side
QRegion clip( rect.right() - std::ceil( radius ), rect.top(),
std::ceil( radius ) + PenWidth::Shadow, rect.height() );
// Bottom side
clip = clip.united( QRegion( rect.left(), rect.bottom() - std::ceil( radius ),
rect.width(), std::ceil( radius ) + PenWidth::Shadow ) );
painter->setClipRegion( clip );
painter->setPen( color );
painter->setBrush( Qt::NoBrush );
painter->drawRoundedRect( rect.translated( translation, translation ), radius, radius );
painter->restore();
}
//______________________________________________________________________________
void Helper::renderEllipseShadow( QPainter* painter, const QRectF& rect, const QColor& color ) const
{
if( !color.isValid() ) return;
painter->save();
// Clipping does not improve performance here
qreal adjustment = 0.5 * PenWidth::Shadow; // Adjust for the pen
qreal radius = rect.width() / 2 - adjustment;
/* The right side is offset by +0.5 for the visible part of the shadow.
* The other sides are offset by +0.5 or -0.5 because of the pen.
*/
QRectF shadowRect = rect.adjusted( adjustment, adjustment, adjustment, -adjustment );
painter->translate( rect.center() );
painter->rotate( 45 );
painter->translate( -rect.center() );
painter->setPen( color );
painter->setBrush( Qt::NoBrush );
painter->drawRoundedRect( shadowRect, radius, radius );
painter->restore();
}
//______________________________________________________________________________
bool Helper::isX11()
{
#if BREEZE_HAVE_X11
static const bool s_isX11 = KWindowSystem::isPlatformX11();
return s_isX11;
#endif
return false;
}
//______________________________________________________________________________
bool Helper::isWayland()
{
static const bool s_isWayland = KWindowSystem::isPlatformWayland();
return s_isWayland;
}
//______________________________________________________________________________
QRectF Helper::strokedRect( const QRectF &rect, const int penWidth ) const
{
/* With a pen stroke width of 1, the rectangle should have each of its
* sides moved inwards by half a pixel. This allows the stroke to be
* pixel perfect instead of blurry from sitting between pixels and
* prevents the rectangle with a stroke from becoming larger than the
* original size of the rectangle.
*/
qreal adjustment = 0.5 * penWidth;
return QRectF( rect ).adjusted( adjustment, adjustment, -adjustment, -adjustment );
}
QRectF Helper::strokedRect( const QRect &rect, const int penWidth ) const
{
return strokedRect(QRectF(rect), penWidth);
}
//______________________________________________________________________________
QPainterPath Helper::roundedPath( const QRectF& rect, Corners corners, qreal radius ) const
{
QPainterPath path;
// simple cases
if( corners == 0 )
{
path.addRect( rect );
return path;
}
if( corners == AllCorners ) {
path.addRoundedRect( rect, radius, radius );
return path;
}
const QSizeF cornerSize( 2*radius, 2*radius );
// rotate counterclockwise
// top left corner
if( corners & CornerTopLeft )
{
path.moveTo( rect.topLeft() + QPointF( radius, 0 ) );
path.arcTo( QRectF( rect.topLeft(), cornerSize ), 90, 90 );
} else path.moveTo( rect.topLeft() );
// bottom left corner
if( corners & CornerBottomLeft )
{
path.lineTo( rect.bottomLeft() - QPointF( 0, radius ) );
path.arcTo( QRectF( rect.bottomLeft() - QPointF( 0, 2*radius ), cornerSize ), 180, 90 );
} else path.lineTo( rect.bottomLeft() );
// bottom right corner
if( corners & CornerBottomRight )
{
path.lineTo( rect.bottomRight() - QPointF( radius, 0 ) );
path.arcTo( QRectF( rect.bottomRight() - QPointF( 2*radius, 2*radius ), cornerSize ), 270, 90 );
} else path.lineTo( rect.bottomRight() );
// top right corner
if( corners & CornerTopRight )
{
path.lineTo( rect.topRight() + QPointF( 0, radius ) );
path.arcTo( QRectF( rect.topRight() - QPointF( 2*radius, 0 ), cornerSize ), 0, 90 );
} else path.lineTo( rect.topRight() );
path.closeSubpath();
return path;
}
//________________________________________________________________________________________________________
bool Helper::compositingActive() const
{
- #if BREEZE_HAVE_X11
+ #if BREEZE_HAVE_QTX11EXTRAS
if( isX11() )
{ return QX11Info::isCompositingManagerRunning( QX11Info::appScreen() ); }
#endif
// use KWindowSystem
return KWindowSystem::compositingActive();
}
//____________________________________________________________________
bool Helper::hasAlphaChannel( const QWidget* widget ) const
{ return compositingActive() && widget && widget->testAttribute( Qt::WA_TranslucentBackground ); }
//______________________________________________________________________________________
qreal Helper::devicePixelRatio( const QPixmap& pixmap ) const
{
return pixmap.devicePixelRatio();
}
QPixmap Helper::coloredIcon(const QIcon& icon, const QPalette& palette, const QSize &size, QIcon::Mode mode, QIcon::State state)
{
const QPalette activePalette = KIconLoader::global()->customPalette();
const bool changePalette = activePalette != palette;
if (changePalette) {
KIconLoader::global()->setCustomPalette(palette);
}
const QPixmap pixmap = icon.pixmap(size, mode, state);
if (changePalette) {
if (activePalette == QPalette()) {
KIconLoader::global()->resetPalette();
} else {
KIconLoader::global()->setCustomPalette(activePalette);
}
}
return pixmap;
}
}
diff --git a/kstyle/breezewindowmanager.cpp b/kstyle/breezewindowmanager.cpp
index f74d5953..87ba0b65 100644
--- a/kstyle/breezewindowmanager.cpp
+++ b/kstyle/breezewindowmanager.cpp
@@ -1,922 +1,758 @@
/*************************************************************************
* Copyright (C) 2014 by Hugo Pereira Da Costa *
* *
* 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 . *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////////
// breezewindowmanager.cpp
// pass some window mouse press/release/move event actions to window manager
// -------------------
//
// Copyright (c) 2014 Hugo Pereira Da Costa
//
// Largely inspired from BeSpin style
// Copyright (C) 2007 Thomas Luebking
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//////////////////////////////////////////////////////////////////////////////
#include "breezewindowmanager.h"
#include "breezepropertynames.h"
#include "breezehelper.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// needed to deal with device pixel ratio
#include
#if BREEZE_HAVE_QTQUICK
// needed to enable dragging from QQuickWindows
#include
#include
#endif
-#if BREEZE_HAVE_X11
-#include
-#include
-
-#include
-
-#endif
-
-#if BREEZE_HAVE_KWAYLAND
-#include
-#include
-#include
-#include
-#include
-#endif
-
namespace Util
{
template
inline T makeT( std::initializer_list&& reference )
{
return T( std::move( reference ) );
}
}
namespace Breeze
{
//* provide application-wise event filter
/**
it us used to unlock dragging and make sure event look is properly restored
after a drag has occurred
*/
class AppEventFilter: public QObject
{
public:
//* constructor
explicit AppEventFilter( WindowManager* parent ):
QObject( parent ),
_parent( parent )
{}
//* event filter
bool eventFilter( QObject* object, QEvent* event ) override
{
if( event->type() == QEvent::MouseButtonRelease )
{
// stop drag timer
if( _parent->_dragTimer.isActive() )
{ _parent->resetDrag(); }
// unlock
if( _parent->isLocked() )
{ _parent->setLocked( false ); }
}
if( !_parent->enabled() ) return false;
/*
if a drag is in progress, the widget will not receive any event
we trigger on the first MouseMove or MousePress events that are received
by any widget in the application to detect that the drag is finished
*/
- if( _parent->useWMMoveResize() && _parent->_dragInProgress && _parent->_target && ( event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonPress ) )
+ if( _parent->_dragInProgress && _parent->_target && ( event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonPress ) )
{ return appMouseEvent( object, event ); }
return false;
}
protected:
//* application-wise event.
/** needed to catch end of XMoveResize events */
bool appMouseEvent( QObject*, QEvent* event )
{
Q_UNUSED( event );
/*
post some mouseRelease event to the target, in order to counter balance
the mouse press that triggered the drag. Note that it triggers a resetDrag
*/
QMouseEvent mouseEvent( QEvent::MouseButtonRelease, _parent->_dragPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier );
qApp->sendEvent( _parent->_target.data(), &mouseEvent );
return false;
}
private:
//* parent
WindowManager* _parent = nullptr;
};
//_____________________________________________________________
WindowManager::WindowManager( QObject* parent ):
QObject( parent )
{
// install application wise event filter
_appEventFilter = new AppEventFilter( this );
qApp->installEventFilter( _appEventFilter );
}
//_____________________________________________________________
void WindowManager::initialize()
{
setEnabled( StyleConfigData::windowDragMode() != StyleConfigData::WD_NONE );
setDragMode( StyleConfigData::windowDragMode() );
- setUseWMMoveResize( StyleConfigData::useWMMoveResize() );
-
setDragDistance( QApplication::startDragDistance() );
setDragDelay( QApplication::startDragTime() );
initializeWhiteList();
initializeBlackList();
- initializeWayland();
-
- }
- //_______________________________________________________
- void WindowManager::initializeWayland()
- {
- #if BREEZE_HAVE_KWAYLAND
- if( !Helper::isWayland() ) return;
- if( _seat ) return;
-
- using namespace KWayland::Client;
- auto connection = ConnectionThread::fromApplication( this );
- if( !connection ) return;
-
- auto 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;
- }
- #else
- Q_UNUSED( hasPointer );
- #endif
}
//_____________________________________________________________
void WindowManager::registerWidget( QWidget* widget )
{
if( isBlackListed( widget ) || isDragable( widget ) )
{
/*
install filter for dragable widgets.
also install filter for blacklisted widgets
to be able to catch the relevant events and prevent
the drag to happen
*/
widget->removeEventFilter( this );
widget->installEventFilter( this );
}
}
#if BREEZE_HAVE_QTQUICK
//_____________________________________________________________
void WindowManager::registerQuickItem( QQuickItem* item )
{
if ( !item ) return;
if( auto window = item->window() )
{
auto contentItem = window->contentItem();
contentItem->setAcceptedMouseButtons( Qt::LeftButton );
contentItem->removeEventFilter( this );
contentItem->installEventFilter( this );
}
}
#endif
//_____________________________________________________________
void WindowManager::unregisterWidget( QWidget* widget )
{ if( widget ) widget->removeEventFilter( this ); }
//_____________________________________________________________
void WindowManager::initializeWhiteList()
{
_whiteList = Util::makeT({
ExceptionId( QStringLiteral( "MplayerWindow" ) ),
ExceptionId( QStringLiteral( "ViewSliders@kmix" ) ),
ExceptionId( QStringLiteral( "Sidebar_Widget@konqueror" ) )
});
foreach( const QString& exception, StyleConfigData::windowDragWhiteList() )
{
ExceptionId id( exception );
if( !id.className().isEmpty() )
{ _whiteList.insert( ExceptionId( exception ) ); }
}
}
//_____________________________________________________________
void WindowManager::initializeBlackList()
{
_blackList = Util::makeT({
ExceptionId( QStringLiteral( "CustomTrackView@kdenlive" ) ),
ExceptionId( QStringLiteral( "MuseScore" ) ),
ExceptionId( QStringLiteral( "KGameCanvasWidget" ) )
});
foreach( const QString& exception, StyleConfigData::windowDragBlackList() )
{
ExceptionId id( exception );
if( !id.className().isEmpty() )
{ _blackList.insert( ExceptionId( exception ) ); }
}
}
//_____________________________________________________________
bool WindowManager::eventFilter( QObject* object, QEvent* event )
{
if( !enabled() ) return false;
switch ( event->type() )
{
case QEvent::MouseButtonPress:
return mousePressEvent( object, event );
break;
case QEvent::MouseMove:
if ( object == _target.data()
#if BREEZE_HAVE_QTQUICK
|| object == _quickTarget.data()
#endif
) return mouseMoveEvent( object, event );
break;
case QEvent::MouseButtonRelease:
if ( _target
#if BREEZE_HAVE_QTQUICK
|| _quickTarget
#endif
) return mouseReleaseEvent( object, event );
break;
default:
break;
}
return false;
}
//_____________________________________________________________
void WindowManager::timerEvent( QTimerEvent* event )
{
if( event->timerId() == _dragTimer.timerId() )
{
_dragTimer.stop();
- if( _target ) startDrag( _target.data()->window()->windowHandle(), _globalDragPoint );
+ if( _target ) startDrag( _target.data()->window()->windowHandle() );
#if BREEZE_HAVE_QTQUICK
- else if( _quickTarget ) startDrag( _quickTarget.data()->window(), _globalDragPoint );
+ else if( _quickTarget ) startDrag( _quickTarget.data()->window() );
#endif
} else {
return QObject::timerEvent( event );
}
}
//_____________________________________________________________
bool WindowManager::mousePressEvent( QObject* object, QEvent* event )
{
// cast event and check buttons/modifiers
auto mouseEvent = static_cast( event );
if (mouseEvent->source() != Qt::MouseEventNotSynthesized)
{ return false; }
if( !( mouseEvent->modifiers() == Qt::NoModifier && mouseEvent->button() == Qt::LeftButton ) )
{ return false; }
// check lock
if( isLocked() ) return false;
else setLocked( true );
#if BREEZE_HAVE_QTQUICK
// check QQuickItem - we can immediately start drag, because QQuickWindow's contentItem
// only receives mouse events that weren't handled by children
if( auto item = qobject_cast( object ) )
{
_quickTarget = item;
_dragPoint = mouseEvent->pos();
_globalDragPoint = mouseEvent->globalPos();
if( _dragTimer.isActive() ) _dragTimer.stop();
_dragTimer.start( _dragDelay, this );
return true;
}
#endif
// cast to widget
auto widget = static_cast( object );
// check if widget can be dragged from current position
if( isBlackListed( widget ) || !canDrag( widget ) ) return false;
// retrieve widget's child at event position
auto position( mouseEvent->pos() );
auto child = widget->childAt( position );
if( !canDrag( widget, child, position ) ) return false;
// save target and drag point
_target = widget;
_dragPoint = position;
_globalDragPoint = mouseEvent->globalPos();
_dragAboutToStart = true;
// send a move event to the current child with same position
// if received, it is caught to actually start the drag
auto localPoint( _dragPoint );
if( child ) localPoint = child->mapFrom( widget, localPoint );
else child = widget;
QMouseEvent localMouseEvent( QEvent::MouseMove, localPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier );
qApp->sendEvent( child, &localMouseEvent );
// never eat event
return false;
}
//_____________________________________________________________
bool WindowManager::mouseMoveEvent( QObject* object, QEvent* event )
{
Q_UNUSED( object );
// stop timer
if( _dragTimer.isActive() ) _dragTimer.stop();
// cast event and check drag distance
auto mouseEvent = static_cast( event );
if (mouseEvent->source() != Qt::MouseEventNotSynthesized)
{ return false; }
if( !_dragInProgress )
{
if( _dragAboutToStart )
{
if( mouseEvent->pos() == _dragPoint )
{
// start timer,
_dragAboutToStart = false;
if( _dragTimer.isActive() ) _dragTimer.stop();
_dragTimer.start( _dragDelay, this );
} else resetDrag();
} else if( QPoint( mouseEvent->globalPos() - _globalDragPoint ).manhattanLength() >= _dragDistance ) {
_dragTimer.start( 0, this );
}
return true;
- } else if( !useWMMoveResize() && _target ) {
-
- // use QWidget::move for the grabbing
- /* this works only if the sending object and the target are identical */
- auto window( _target.data()->window() );
- window->move( window->pos() + mouseEvent->pos() - _dragPoint );
- return true;
-
} else return false;
}
//_____________________________________________________________
bool WindowManager::mouseReleaseEvent( QObject* object, QEvent* event )
{
Q_UNUSED( object );
Q_UNUSED( event );
resetDrag();
return false;
}
//_____________________________________________________________
bool WindowManager::isDragable( QWidget* widget )
{
// check widget
if( !widget ) return false;
// accepted default types
if(
( qobject_cast( widget ) && widget->isWindow() ) ||
( qobject_cast( widget ) && widget->isWindow() ) ||
qobject_cast( widget ) )
{ return true; }
// more accepted types, provided they are not dock widget titles
if( ( qobject_cast( widget ) ||
qobject_cast( widget ) ||
qobject_cast( widget ) ||
qobject_cast( widget ) ) &&
!isDockWidgetTitle( widget ) )
{ return true; }
if( widget->inherits( "KScreenSaver" ) && widget->inherits( "KCModule" ) )
{ return true; }
if( isWhiteListed( widget ) )
{ return true; }
// flat toolbuttons
if( auto toolButton = qobject_cast( widget ) )
{ if( toolButton->autoRaise() ) return true; }
// viewports
/*
one needs to check that
1/ the widget parent is a scrollarea
2/ it matches its parent viewport
3/ the parent is not blacklisted
*/
if( auto listView = qobject_cast( widget->parentWidget() ) )
{ if( listView->viewport() == widget && !isBlackListed( listView ) ) return true; }
if( auto treeView = qobject_cast( widget->parentWidget() ) )
{ if( treeView->viewport() == widget && !isBlackListed( treeView ) ) return true; }
/*
catch labels in status bars.
this is because of kstatusbar
who captures buttonPress/release events
*/
if( auto label = qobject_cast( widget ) )
{
if( label->textInteractionFlags().testFlag( Qt::TextSelectableByMouse ) ) return false;
QWidget* parent = label->parentWidget();
while( parent )
{
if( qobject_cast( parent ) ) return true;
parent = parent->parentWidget();
}
}
return false;
}
//_____________________________________________________________
bool WindowManager::isBlackListed( QWidget* widget )
{
// check against noAnimations property
const auto propertyValue( widget->property( PropertyNames::noWindowGrab ) );
if( propertyValue.isValid() && propertyValue.toBool() ) return true;
// list-based blacklisted widgets
const auto appName( qApp->applicationName() );
foreach( const ExceptionId& id, _blackList )
{
if( !id.appName().isEmpty() && id.appName() != appName ) continue;
if( id.className() == QStringLiteral( "*" ) && !id.appName().isEmpty() )
{
// if application name matches and all classes are selected
// disable the grabbing entirely
setEnabled( false );
return true;
}
if( widget->inherits( id.className().toLatin1().data() ) ) return true;
}
return false;
}
//_____________________________________________________________
bool WindowManager::isWhiteListed( QWidget* widget ) const
{
const auto appName( qApp->applicationName() );
foreach( const ExceptionId& id, _whiteList )
{
if( !(id.appName().isEmpty() || id.appName() == appName ) ) continue;
if( widget->inherits( id.className().toLatin1().data() ) ) return true;
}
return false;
}
//_____________________________________________________________
bool WindowManager::canDrag( QWidget* widget )
{
// check if enabled
if( !enabled() ) return false;
// assume isDragable widget is already passed
// check some special cases where drag should not be effective
// check mouse grabber
if( QWidget::mouseGrabber() ) return false;
/*
check cursor shape.
Assume that a changed cursor means that some action is in progress
and should prevent the drag
*/
if( widget->cursor().shape() != Qt::ArrowCursor ) return false;
// accept
return true;
}
//_____________________________________________________________
bool WindowManager::canDrag( QWidget* widget, QWidget* child, const QPoint& position )
{
// retrieve child at given position and check cursor again
if( child && child->cursor().shape() != Qt::ArrowCursor ) return false;
/*
check against children from which drag should never be enabled,
even if mousePress/Move has been passed to the parent
*/
if( child && (
qobject_cast(child ) ||
qobject_cast( child ) ||
qobject_cast( child ) ) )
{ return false; }
// tool buttons
if( auto toolButton = qobject_cast( widget ) )
{
if( dragMode() == StyleConfigData::WD_MINIMAL && !qobject_cast(widget->parentWidget() ) ) return false;
return toolButton->autoRaise() && !toolButton->isEnabled();
}
// check menubar
if( auto menuBar = qobject_cast( widget ) )
{
// do not drag from menubars embedded in Mdi windows
if( findParent( widget ) ) return false;
// check if there is an active action
if( menuBar->activeAction() && menuBar->activeAction()->isEnabled() ) return false;
// check if action at position exists and is enabled
if( auto action = menuBar->actionAt( position ) )
{
if( action->isSeparator() ) return true;
if( action->isEnabled() ) return false;
}
// return true in all other cases
return true;
}
/*
in MINIMAL mode, anything that has not been already accepted
and does not come from a toolbar is rejected
*/
if( dragMode() == StyleConfigData::WD_MINIMAL )
{
if( qobject_cast( widget ) ) return true;
else return false;
}
/* following checks are relevant only for WD_FULL mode */
// tabbar. Make sure no tab is under the cursor
if( auto tabBar = qobject_cast( widget ) )
{ return tabBar->tabAt( position ) == -1; }
/*
check groupboxes
prevent drag if unchecking grouboxes
*/
if( auto groupBox = qobject_cast( widget ) )
{
// non checkable group boxes are always ok
if( !groupBox->isCheckable() ) return true;
// gather options to retrieve checkbox subcontrol rect
QStyleOptionGroupBox opt;
opt.initFrom( groupBox );
if( groupBox->isFlat() ) opt.features |= QStyleOptionFrame::Flat;
opt.lineWidth = 1;
opt.midLineWidth = 0;
opt.text = groupBox->title();
opt.textAlignment = groupBox->alignment();
opt.subControls = (QStyle::SC_GroupBoxFrame | QStyle::SC_GroupBoxCheckBox);
if (!groupBox->title().isEmpty()) opt.subControls |= QStyle::SC_GroupBoxLabel;
opt.state |= (groupBox->isChecked() ? QStyle::State_On : QStyle::State_Off);
// check against groupbox checkbox
if( groupBox->style()->subControlRect(QStyle::CC_GroupBox, &opt, QStyle::SC_GroupBoxCheckBox, groupBox ).contains( position ) )
{ return false; }
// check against groupbox label
if( !groupBox->title().isEmpty() && groupBox->style()->subControlRect(QStyle::CC_GroupBox, &opt, QStyle::SC_GroupBoxLabel, groupBox ).contains( position ) )
{ return false; }
return true;
}
// labels
if( auto label = qobject_cast( widget ) )
{ if( label->textInteractionFlags().testFlag( Qt::TextSelectableByMouse ) ) return false; }
// abstract item views
QAbstractItemView* itemView( nullptr );
if(
( itemView = qobject_cast( widget->parentWidget() ) ) ||
( itemView = qobject_cast( widget->parentWidget() ) ) )
{
if( widget == itemView->viewport() )
{
// QListView
if( itemView->frameShape() != QFrame::NoFrame ) return false;
else if(
itemView->selectionMode() != QAbstractItemView::NoSelection &&
itemView->selectionMode() != QAbstractItemView::SingleSelection &&
itemView->model() && itemView->model()->rowCount() ) return false;
else if( itemView->model() && itemView->indexAt( position ).isValid() ) return false;
}
} else if( ( itemView = qobject_cast( widget->parentWidget() ) ) ) {
if( widget == itemView->viewport() )
{
// QAbstractItemView
if( itemView->frameShape() != QFrame::NoFrame ) return false;
else if( itemView->indexAt( position ).isValid() ) return false;
}
} else if( auto graphicsView = qobject_cast( widget->parentWidget() ) ) {
if( widget == graphicsView->viewport() )
{
// QGraphicsView
if( graphicsView->frameShape() != QFrame::NoFrame ) return false;
else if( graphicsView->dragMode() != QGraphicsView::NoDrag ) return false;
else if( graphicsView->itemAt( position ) ) return false;
}
}
return true;
}
//____________________________________________________________
void WindowManager::resetDrag()
{
- if( (!useWMMoveResize() ) && _target && _cursorOverride ) {
-
- qApp->restoreOverrideCursor();
- _cursorOverride = false;
-
- }
-
_target.clear();
#if BREEZE_HAVE_QTQUICK
_quickTarget.clear();
#endif
if( _dragTimer.isActive() ) _dragTimer.stop();
_dragPoint = QPoint();
_globalDragPoint = QPoint();
_dragAboutToStart = false;
_dragInProgress = false;
}
//____________________________________________________________
- void WindowManager::startDrag( QWindow* window, const QPoint& position )
+ void WindowManager::startDrag( QWindow* window )
{
if( !( enabled() && window ) ) return;
if( QWidget::mouseGrabber() ) return;
- // ungrab pointer
- if( useWMMoveResize() )
- {
-
- if( Helper::isX11() ) startDragX11( window, position );
- else if( Helper::isWayland() ) startDragWayland( window, position );
-
- } else if( !_cursorOverride ) {
-
- qApp->setOverrideCursor( Qt::SizeAllCursor );
- _cursorOverride = true;
-
- }
-
- _dragInProgress = true;
-
- }
-
- //_______________________________________________________
- void WindowManager::startDragX11( QWindow* window, const QPoint& position )
- {
- #if BREEZE_HAVE_X11
- // connection
- auto connection( QX11Info::connection() );
-
- auto net_connection = connection;
- const qreal dpiRatio = window->devicePixelRatio();
- const QPoint origin = window->screen()->geometry().topLeft();
- const QPoint native = (position - origin) * dpiRatio + origin;
-
- xcb_ungrab_pointer( connection, XCB_TIME_CURRENT_TIME );
- NETRootInfo( net_connection, NET::WMMoveResize ).moveResizeRequest(
- window->winId(), native.x(), native.y(), NET::Move );
-
- #else
-
- Q_UNUSED( window );
- Q_UNUSED( position );
-
- #endif
- }
-
- //_______________________________________________________
- void WindowManager::startDragWayland( QWindow* window, const QPoint& )
- {
- #if BREEZE_HAVE_KWAYLAND
- if( !_seat ) {
- return;
- }
-
- auto shellSurface = KWayland::Client::ShellSurface::fromWindow(window);
- if( !shellSurface )
- {
- // TODO: also check for xdg-shell in future
- return;
- }
-
- shellSurface->requestMove( _seat, _waylandSerial );
- #else
- Q_UNUSED( window );
- #endif
- }
-
- //____________________________________________________________
- bool WindowManager::supportWMMoveResize() const
- {
-
- #if BREEZE_HAVE_KWAYLAND
- if( Helper::isWayland() )
- {
- return true;
- }
- #endif
-
- #if BREEZE_HAVE_X11
- return Helper::isX11();
- #else
- return false;
- #endif
+ _dragInProgress = window->startSystemMove();
}
//____________________________________________________________
bool WindowManager::isDockWidgetTitle( const QWidget* widget ) const
{
if( !widget ) return false;
if( auto dockWidget = qobject_cast( widget->parent() ) )
{
return widget == dockWidget->titleBarWidget();
} else return false;
}
}
diff --git a/kstyle/breezewindowmanager.h b/kstyle/breezewindowmanager.h
index 27fd9c25..7f365828 100644
--- a/kstyle/breezewindowmanager.h
+++ b/kstyle/breezewindowmanager.h
@@ -1,334 +1,280 @@
#ifndef breezewindowmanager_h
#define breezewindowmanager_h
/*************************************************************************
* Copyright (C) 2014 by Hugo Pereira Da Costa *
* *
* 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 "breeze.h"
#include "breezestyleconfigdata.h"
#include "config-breeze.h"
#include
#include
#include
#include
#include
#include
#include
#if BREEZE_HAVE_QTQUICK
#include
#endif
-#if BREEZE_HAVE_KWAYLAND
-namespace KWayland
-{
- namespace Client
- {
- class Pointer;
- class Seat;
- }
-}
-#endif
-
namespace Breeze
{
class WindowManager: public QObject
{
Q_OBJECT
public:
//* constructor
explicit WindowManager( QObject* );
//* initialize
/** read relevant options from config */
void initialize();
//* register widget
void registerWidget( QWidget* );
#if BREEZE_HAVE_QTQUICK
//* register quick item
void registerQuickItem( QQuickItem* );
#endif
//* unregister widget
void unregisterWidget( QWidget* );
//* event filter [reimplemented]
bool eventFilter( QObject*, QEvent* ) override;
protected:
//* timer event,
/** used to start drag if button is pressed for a long enough time */
void timerEvent( QTimerEvent* ) override;
//* mouse press event
bool mousePressEvent( QObject*, QEvent* );
//* mouse move event
bool mouseMoveEvent( QObject*, QEvent* );
//* mouse release event
bool mouseReleaseEvent( QObject*, QEvent* );
//*@name configuration
//@{
//* enable state
bool enabled() const
{ return _enabled; }
//* enable state
void setEnabled( bool value )
{ _enabled = value; }
- //* returns true if window manager is used for moving
- bool useWMMoveResize() const
- { return supportWMMoveResize() && _useWMMoveResize; }
-
- //* use window manager for moving, when available
- void setUseWMMoveResize( bool value )
- { _useWMMoveResize = value; }
-
//* drag mode
int dragMode() const
{ return _dragMode; }
//* drag mode
void setDragMode( int value )
{ _dragMode = value; }
//* drag distance (pixels)
void setDragDistance( int value )
{ _dragDistance = value; }
//* drag delay (msec)
void setDragDelay( int value )
{ _dragDelay = value; }
//* set list of whiteListed widgets
/**
white list is read from options and is used to adjust
per-app window dragging issues
*/
void initializeWhiteList();
//* set list of blackListed widgets
/**
black list is read from options and is used to adjust
per-app window dragging issues
*/
void initializeBlackList();
- //* initializes the Wayland specific parts
- void initializeWayland();
-
- //* The Wayland Seat's hasPointer property changed
- void waylandHasPointerChanged(bool hasPointer);
-
//@}
//* returns true if widget is dragable
bool isDragable( QWidget* );
//* returns true if widget is dragable
bool isBlackListed( QWidget* );
//* returns true if widget is dragable
bool isWhiteListed( QWidget* ) const;
//* returns true if drag can be started from current widget
bool canDrag( QWidget* );
//* returns true if drag can be started from current widget and position
/** child at given position is passed as second argument */
bool canDrag( QWidget*, QWidget*, const QPoint& );
//* reset drag
void resetDrag();
//* start drag
- void startDrag( QWindow*, const QPoint& );
-
- //* X11 specific implementation for startDrag
- void startDragX11( QWindow*, const QPoint& );
-
- //* Wayland specific implementation for startDrag
- void startDragWayland( QWindow*, const QPoint& );
-
- //* returns true if window manager is used for moving
- /** right now this is true only for X11 */
- bool supportWMMoveResize() const;
+ void startDrag( QWindow* );
//* utility function
bool isDockWidgetTitle( const QWidget* ) const;
//*@name lock
//@{
void setLocked( bool value )
{ _locked = value; }
//* lock
bool isLocked() const
{ return _locked; }
//@}
//* returns first widget matching given class, or nullptr if none
template T findParent( const QWidget* ) const;
private:
//* enability
bool _enabled = true;
- //* use WM moveResize
- bool _useWMMoveResize = true;
-
//* drag mode
int _dragMode = StyleConfigData::WD_FULL;
//* drag distance
/** this is copied from kwin::geometry */
int _dragDistance = QApplication::startDragDistance();
//* drag delay
/** this is copied from kwin::geometry */
int _dragDelay = QApplication::startDragTime();
//* wrapper for exception id
class ExceptionId
{
public:
//* constructor
explicit ExceptionId( const QString& value )
{
const QStringList args( value.split( QChar::fromLatin1( '@' ) ) );
if( args.isEmpty() ) return;
_exception.second = args[0].trimmed();
if( args.size()>1 ) _exception.first = args[1].trimmed();
}
const QString& appName() const
{ return _exception.first; }
const QString& className() const
{ return _exception.second; }
private:
QPair _exception;
friend uint qHash( const ExceptionId& value )
{ return qHash(value._exception); }
friend bool operator == ( const ExceptionId& lhs, const ExceptionId& rhs )
{ return lhs._exception == rhs._exception; }
};
//* exception set
using ExceptionSet = QSet;
//* list of white listed special widgets
/**
it is read from options and is used to adjust
per-app window dragging issues
*/
ExceptionSet _whiteList;
//* list of black listed special widgets
/**
it is read from options and is used to adjust
per-app window dragging issues
*/
ExceptionSet _blackList;
//* drag point
QPoint _dragPoint;
QPoint _globalDragPoint;
//* drag timer
QBasicTimer _dragTimer;
//* target being dragged
/** Weak pointer is used in case the target gets deleted while drag is in progress */
WeakPointer _target;
#if BREEZE_HAVE_QTQUICK
WeakPointer _quickTarget;
#endif
//* true if drag is about to start
bool _dragAboutToStart = false;
//* true if drag is in progress
bool _dragInProgress = false;
//* true if drag is locked
bool _locked = false;
- //* cursor override
- /** used to keep track of application cursor being overridden when dragging in non-WM mode */
- bool _cursorOverride = false;
-
//* application event filter
QObject* _appEventFilter = nullptr;
- #if BREEZE_HAVE_KWAYLAND
-
- //* The Wayland seat object which needs to be passed to move requests.
- KWayland::Client::Seat* _seat = nullptr;
-
- //* The Wayland pointer object where we get pointer events on.
- KWayland::Client::Pointer* _pointer = nullptr;
-
- //* latest serial which needs to be passed to the move requests.
- quint32 _waylandSerial = 0;
- #endif
-
//* allow access of all private members to the app event filter
friend class AppEventFilter;
};
//____________________________________________________________________
template
T WindowManager::findParent( const QWidget* widget ) const
{
if( !widget ) return nullptr;
for( QWidget* parent = widget->parentWidget(); parent; parent = parent->parentWidget() )
{ if( T cast = qobject_cast(parent) ) return cast; }
return nullptr;
}
}
#endif
diff --git a/kstyle/config-breeze.h.cmake b/kstyle/config-breeze.h.cmake
index dff55d6d..c9dabac5 100644
--- a/kstyle/config-breeze.h.cmake
+++ b/kstyle/config-breeze.h.cmake
@@ -1,36 +1,34 @@
/* config-breeze.h. Generated by cmake from config-breeze.h.cmake */
/*************************************************************************
* Copyright (C) 2014 by Hugo Pereira Da Costa *
* *
* 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 QtQuick is available */
#cmakedefine01 BREEZE_HAVE_QTQUICK
+/* Define to 1 if QtX11Extras is available */
+#cmakedefine01 BREEZE_HAVE_QTX11EXTRAS
+
/* Define to 1 if FrameworkIntegration/Kstyle libraries are found */
#cmakedefine01 BREEZE_HAVE_KSTYLE
-/* Define to 1 if XCB libraries are found */
-#cmakedefine01 BREEZE_HAVE_X11
-
-#cmakedefine01 BREEZE_HAVE_KWAYLAND
-
#endif