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