2017-01-02 17:05:30 -05:00
/*
* Copyright 2016 Smith AR < audoban @ openmailbox . org >
* Michail Vourlakos < mvourlakos @ gmail . com >
*
* This file is part of Latte - Dock
*
* Latte - Dock 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 .
*
* Latte - Dock 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/>.
*/
2016-12-25 09:25:27 +02:00
# include "xwindowinterface.h"
2016-12-29 00:37:53 -05:00
# include "../liblattedock/extras.h"
2016-12-25 09:25:27 +02:00
2016-12-29 00:37:53 -05:00
# include <QDebug>
2017-02-11 02:54:03 -05:00
# include <QTimer>
2016-12-28 02:57:31 -05:00
# include <QtX11Extras/QX11Info>
2016-12-25 09:25:27 +02:00
# include <KWindowSystem>
2016-12-30 02:11:42 -05:00
# include <KWindowInfo>
2016-12-28 02:57:31 -05:00
# include <NETWM>
2016-12-25 09:25:27 +02:00
2016-12-28 02:57:31 -05:00
namespace Latte {
2016-12-25 09:25:27 +02:00
2017-02-24 21:40:47 -05:00
XWindowInterface : : XWindowInterface ( QObject * parent )
: AbstractWindowInterface ( parent )
2016-12-25 09:25:27 +02:00
{
2017-02-24 21:40:47 -05:00
m_activities = new KActivities : : Consumer ( this ) ;
connect ( KWindowSystem : : self ( ) , & KWindowSystem : : activeWindowChanged
2017-03-01 15:26:46 +02:00
, this , & AbstractWindowInterface : : activeWindowChanged ) ;
2017-02-24 21:40:47 -05:00
connect ( KWindowSystem : : self ( )
2017-03-01 15:26:46 +02:00
, static_cast < void ( KWindowSystem : : * ) ( WId , NET : : Properties , NET : : Properties2 ) >
( & KWindowSystem : : windowChanged )
, this , & XWindowInterface : : windowChangedProxy ) ;
2017-02-24 21:40:47 -05:00
2017-01-02 01:04:10 -05:00
auto addWindow = [ & ] ( WId wid ) {
if ( std : : find ( m_windows . cbegin ( ) , m_windows . cend ( ) , wid ) = = m_windows . cend ( ) ) {
if ( isValidWindow ( KWindowInfo ( wid , NET : : WMWindowType ) ) ) {
m_windows . push_back ( wid ) ;
emit windowAdded ( wid ) ;
}
2016-12-28 02:57:31 -05:00
}
2017-01-02 01:04:10 -05:00
} ;
2017-02-24 21:40:47 -05:00
connect ( KWindowSystem : : self ( ) , & KWindowSystem : : windowAdded , this , addWindow ) ;
connect ( KWindowSystem : : self ( ) , & KWindowSystem : : windowRemoved , [ this ] ( WId wid ) {
2017-01-02 01:04:10 -05:00
if ( std : : find ( m_windows . cbegin ( ) , m_windows . cend ( ) , wid ) ! = m_windows . end ( ) ) {
m_windows . remove ( wid ) ;
emit windowRemoved ( wid ) ;
}
2016-12-28 02:57:31 -05:00
} ) ;
2017-02-24 21:40:47 -05:00
connect ( KWindowSystem : : self ( ) , & KWindowSystem : : currentDesktopChanged
2017-03-01 15:26:46 +02:00
, this , & XWindowInterface : : currentDesktopChanged ) ;
2017-02-24 21:40:47 -05:00
connect ( m_activities . data ( ) , & KActivities : : Consumer : : currentActivityChanged
2017-03-01 15:26:46 +02:00
, this , & XWindowInterface : : currentActivityChanged ) ;
2017-02-12 03:01:12 -05:00
2017-01-02 01:04:10 -05:00
// fill windows list
foreach ( const auto & wid , KWindowSystem : : self ( ) - > windows ( ) ) {
addWindow ( wid ) ;
}
2016-12-25 09:25:27 +02:00
}
XWindowInterface : : ~ XWindowInterface ( )
{
}
2017-02-24 21:40:47 -05:00
void XWindowInterface : : setDockExtraFlags ( QQuickWindow & view )
2016-12-25 09:25:27 +02:00
{
2016-12-28 02:57:31 -05:00
NETWinInfo winfo ( QX11Info : : connection ( )
2017-02-24 21:40:47 -05:00
, static_cast < xcb_window_t > ( view . winId ( ) )
, static_cast < xcb_window_t > ( view . winId ( ) )
2016-12-28 02:57:31 -05:00
, 0 , 0 ) ;
2016-12-25 09:25:27 +02:00
2017-02-24 21:40:47 -05:00
winfo . setAllowedActions ( NET : : ActionChangeDesktop ) ;
KWindowSystem : : setType ( view . winId ( ) , NET : : Dock ) ;
KWindowSystem : : setState ( view . winId ( ) , NET : : SkipTaskbar | NET : : SkipPager ) ;
KWindowSystem : : setOnAllDesktops ( view . winId ( ) , true ) ;
KWindowSystem : : setOnActivities ( view . winId ( ) , { " 0 " } ) ;
2016-12-25 09:25:27 +02:00
}
2017-03-23 00:03:45 -05:00
void XWindowInterface : : setDockStruts ( WId dockId , const QRect & dockRect
, const QScreen & screen , Plasma : : Types : : Location location ) const
2016-12-29 00:37:53 -05:00
{
NETExtendedStrut strut ;
2017-01-16 14:07:49 -05:00
2017-03-23 00:03:45 -05:00
const QRect currentScreen { screen . geometry ( ) } ;
const QRect wholeScreen { { 0 , 0 } , screen . virtualSize ( ) } ;
2016-12-29 00:37:53 -05:00
switch ( location ) {
2017-03-23 00:03:45 -05:00
case Plasma : : Types : : TopEdge : {
const int topOffset { screen . geometry ( ) . top ( ) } ;
strut . top_width = dockRect . height ( ) + topOffset ;
2016-12-29 00:37:53 -05:00
strut . top_start = dockRect . x ( ) ;
strut . top_end = dockRect . x ( ) + dockRect . width ( ) - 1 ;
break ;
2017-03-23 00:03:45 -05:00
}
2017-01-16 14:07:49 -05:00
2017-03-23 00:03:45 -05:00
case Plasma : : Types : : BottomEdge : {
const int bottomOffset { wholeScreen . bottom ( ) - currentScreen . bottom ( ) } ;
strut . bottom_width = dockRect . height ( ) + bottomOffset ;
2016-12-29 00:37:53 -05:00
strut . bottom_start = dockRect . x ( ) ;
strut . bottom_end = dockRect . x ( ) + dockRect . width ( ) - 1 ;
break ;
2017-03-23 00:03:45 -05:00
}
case Plasma : : Types : : LeftEdge : {
const int leftOffset = { screen . geometry ( ) . left ( ) } ;
strut . left_width = dockRect . width ( ) + leftOffset ;
2016-12-29 00:37:53 -05:00
strut . left_start = dockRect . y ( ) ;
strut . left_end = dockRect . y ( ) + dockRect . height ( ) - 1 ;
break ;
2017-03-23 00:03:45 -05:00
}
case Plasma : : Types : : RightEdge : {
const int rightOffset = { wholeScreen . right ( ) - currentScreen . right ( ) } ;
strut . right_width = dockRect . width ( ) + rightOffset ;
2016-12-29 00:37:53 -05:00
strut . right_start = dockRect . y ( ) ;
strut . right_end = dockRect . y ( ) + dockRect . height ( ) - 1 ;
break ;
2017-03-23 00:03:45 -05:00
}
2016-12-29 00:37:53 -05:00
default :
qWarning ( ) < < " wrong location: " < < qEnumToStr ( location ) ;
return ;
}
2017-01-16 14:07:49 -05:00
2017-02-24 21:40:47 -05:00
KWindowSystem : : setExtendedStrut ( dockId ,
2016-12-29 00:37:53 -05:00
strut . left_width , strut . left_start , strut . left_end ,
strut . right_width , strut . right_start , strut . right_end ,
strut . top_width , strut . top_start , strut . top_end ,
strut . bottom_width , strut . bottom_start , strut . bottom_end
) ;
}
2017-02-24 21:40:47 -05:00
void XWindowInterface : : removeDockStruts ( WId dockId ) const
{
KWindowSystem : : setStrut ( dockId , 0 , 0 , 0 , 0 ) ;
}
WId XWindowInterface : : activeWindow ( ) const
{
return KWindowSystem : : self ( ) - > activeWindow ( ) ;
}
const std : : list < WId > & XWindowInterface : : windows ( ) const
{
return m_windows ;
}
void XWindowInterface : : skipTaskBar ( const QDialog & dialog ) const
{
KWindowSystem : : setState ( dialog . winId ( ) , NET : : SkipTaskbar ) ;
}
void XWindowInterface : : slideWindow ( QQuickWindow & view , AbstractWindowInterface : : Slide location ) const
{
auto slideLocation = KWindowEffects : : NoEdge ;
switch ( location ) {
case Slide : : Top :
slideLocation = KWindowEffects : : TopEdge ;
break ;
case Slide : : Bottom :
slideLocation = KWindowEffects : : BottomEdge ;
break ;
case Slide : : Left :
slideLocation = KWindowEffects : : LeftEdge ;
break ;
case Slide : : Right :
slideLocation = KWindowEffects : : RightEdge ;
break ;
default :
2017-03-01 15:26:46 +02:00
break ;
2017-02-24 21:40:47 -05:00
}
KWindowEffects : : slideWindow ( view . winId ( ) , slideLocation , - 1 ) ;
}
void XWindowInterface : : enableBlurBehind ( QQuickWindow & view ) const
2016-12-29 00:37:53 -05:00
{
2017-02-24 21:40:47 -05:00
KWindowEffects : : enableBlurBehind ( view . winId ( ) ) ;
2016-12-29 00:37:53 -05:00
}
2017-02-24 21:40:47 -05:00
2017-01-02 01:04:10 -05:00
WindowInfoWrap XWindowInterface : : requestInfoActive ( ) const
2016-12-25 09:25:27 +02:00
{
2016-12-28 02:57:31 -05:00
return requestInfo ( KWindowSystem : : activeWindow ( ) ) ;
2016-12-25 09:25:27 +02:00
}
2017-01-02 01:04:10 -05:00
bool XWindowInterface : : isOnCurrentDesktop ( WId wid ) const
{
KWindowInfo winfo ( wid , NET : : WMDesktop ) ;
2017-02-13 17:52:41 -05:00
return winfo . valid ( ) & & winfo . isOnCurrentDesktop ( ) ;
2017-01-02 01:04:10 -05:00
}
WindowInfoWrap XWindowInterface : : requestInfo ( WId wid ) const
2016-12-25 09:25:27 +02:00
{
2017-03-15 02:57:42 -05:00
const KWindowInfo winfo { wid , NET : : WMFrameExtents
| NET : : WMWindowType
| NET : : WMGeometry
| NET : : WMState } ;
2016-12-28 02:57:31 -05:00
WindowInfoWrap winfoWrap ;
2017-01-16 14:07:49 -05:00
2017-03-15 02:57:42 -05:00
if ( isValidWindow ( winfo ) ) {
2017-01-02 01:04:10 -05:00
winfoWrap . setIsValid ( true ) ;
winfoWrap . setWid ( wid ) ;
winfoWrap . setIsActive ( KWindowSystem : : activeWindow ( ) = = wid ) ;
winfoWrap . setIsMinimized ( winfo . hasState ( NET : : Hidden ) ) ;
2017-03-12 04:01:27 -05:00
winfoWrap . setIsMaxVert ( winfo . hasState ( NET : : MaxVert ) ) ;
winfoWrap . setIsMaxHoriz ( winfo . hasState ( NET : : MaxHoriz ) ) ;
2017-01-02 01:04:10 -05:00
winfoWrap . setIsFullscreen ( winfo . hasState ( NET : : FullScreen ) ) ;
2017-03-23 22:06:59 -05:00
winfoWrap . setIsShaded ( winfo . hasState ( NET : : Shaded ) ) ;
2017-02-11 01:58:25 -05:00
winfoWrap . setGeometry ( winfo . frameGeometry ( ) ) ;
2017-01-02 01:04:10 -05:00
} else if ( m_desktopId = = wid ) {
winfoWrap . setIsValid ( true ) ;
winfoWrap . setIsPlasmaDesktop ( true ) ;
winfoWrap . setWid ( wid ) ;
}
2017-01-16 14:07:49 -05:00
2016-12-28 02:57:31 -05:00
return winfoWrap ;
}
2017-01-02 01:04:10 -05:00
bool XWindowInterface : : isValidWindow ( const KWindowInfo & winfo ) const
2016-12-28 02:57:31 -05:00
{
2017-03-15 02:57:42 -05:00
constexpr auto types = NET : : DockMask | NET : : MenuMask | NET : : SplashMask | NET : : NormalMask ;
auto winType = winfo . windowType ( types ) ;
2017-01-16 14:07:49 -05:00
2017-01-24 14:27:57 -05:00
if ( winType = = - 1 ) {
2017-03-15 02:57:42 -05:00
// Trying to get more types for verify if the window have any other type
winType = winfo . windowType ( ~ types & NET : : AllTypesMask ) ;
2017-01-16 14:07:49 -05:00
2017-03-15 02:57:42 -05:00
if ( winType = = - 1 ) {
qWarning ( ) < < KWindowInfo ( winfo . win ( ) , 0 , NET : : WM2WindowClass ) . windowClassName ( )
< < " doesn't have any WindowType, assuming as NET::Normal " ;
2017-01-24 14:27:57 -05:00
return true ;
2017-03-15 02:57:42 -05:00
}
2017-01-24 14:27:57 -05:00
}
return ! ( ( winType & NET : : Menu ) | | ( winType & NET : : Dock ) | | ( winType & NET : : Splash ) ) ;
2016-12-25 09:25:27 +02:00
}
2016-12-28 02:57:31 -05:00
void XWindowInterface : : windowChangedProxy ( WId wid , NET : : Properties prop1 , NET : : Properties2 prop2 )
2016-12-25 09:25:27 +02:00
{
2016-12-28 02:57:31 -05:00
//! if the dock changed is ignored
2017-02-24 21:40:47 -05:00
if ( std : : find ( m_docks . cbegin ( ) , m_docks . cend ( ) , wid ) ! = m_docks . cend ( ) )
2016-12-28 02:57:31 -05:00
return ;
2017-01-16 14:07:49 -05:00
2017-01-02 01:04:10 -05:00
const auto winType = KWindowInfo ( wid , NET : : WMWindowType ) . windowType ( NET : : DesktopMask ) ;
2017-01-16 14:07:49 -05:00
2017-01-02 01:04:10 -05:00
if ( winType ! = - 1 & & ( winType & NET : : Desktop ) ) {
m_desktopId = wid ;
emit windowChanged ( wid ) ;
2016-12-28 02:57:31 -05:00
return ;
2017-01-02 01:04:10 -05:00
}
2017-01-16 14:07:49 -05:00
2017-02-24 21:40:47 -05:00
//! ignore when, eg: the user presses a key
2017-01-02 01:04:10 -05:00
if ( prop1 = = 0 & & prop2 = = NET : : WM2UserTime ) {
return ;
}
2017-01-16 14:07:49 -05:00
2016-12-28 02:57:31 -05:00
if ( prop1 & & ! ( prop1 & NET : : WMState | | prop1 & NET : : WMGeometry | | prop1 & NET : : ActiveWindow ) )
return ;
2017-01-16 14:07:49 -05:00
2016-12-30 02:11:42 -05:00
emit windowChanged ( wid ) ;
2016-12-25 09:25:27 +02:00
}
}