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"
2018-12-02 03:05:52 +03:00
// local
2019-06-01 01:20:54 +03:00
# include "tasktools.h"
2018-12-06 13:15:58 +03:00
# include "view/view.h"
2020-01-22 20:45:13 +03:00
# include "view/helpers/screenedgeghostwindow.h"
2019-12-26 22:10:11 +03:00
# include "../../liblatte2/extras.h"
# include "../../liblatte2/types.h"
2016-12-25 10:25:27 +03:00
2018-12-02 03:05:52 +03:00
// Qt
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
2018-12-02 03:05:52 +03:00
// KDE
2019-06-01 01:20:54 +03:00
# include <KDesktopFile>
2016-12-25 10:25:27 +03:00
# include <KWindowSystem>
2016-12-30 10:11:42 +03:00
# include <KWindowInfo>
2019-05-27 18:56:24 +03:00
# include <KIconThemes/KIconLoader>
2016-12-25 10:25:27 +03:00
2018-12-02 03:05:52 +03:00
// X11
# include <NETWM>
2018-03-28 20:39:52 +03:00
# include <xcb/xcb.h>
2016-12-28 10:57:31 +03:00
namespace Latte {
2019-05-11 15:43:10 +03:00
namespace WindowSystem {
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
{
2019-06-08 00:31:30 +03:00
m_currentDesktop = QString ( KWindowSystem : : self ( ) - > currentDesktop ( ) ) ;
2019-06-01 01:20:54 +03:00
2019-05-12 02:35:28 +03:00
connect ( KWindowSystem : : self ( ) , & KWindowSystem : : activeWindowChanged , this , & AbstractWindowInterface : : activeWindowChanged ) ;
connect ( KWindowSystem : : self ( ) , & KWindowSystem : : windowRemoved , this , & AbstractWindowInterface : : windowRemoved ) ;
2019-06-08 00:31:30 +03:00
2020-03-05 22:20:25 +03:00
connect ( KWindowSystem : : self ( ) , & KWindowSystem : : windowAdded , this , & XWindowInterface : : windowAddedProxy ) ;
2019-06-08 00:31:30 +03:00
connect ( KWindowSystem : : self ( ) , & KWindowSystem : : currentDesktopChanged , this , [ & ] ( int desktop ) {
m_currentDesktop = QString ( desktop ) ;
emit currentDesktopChanged ( ) ;
} ) ;
2019-05-12 02:35:28 +03:00
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 ) ;
2019-11-02 11:45:37 +03:00
for ( auto wid : KWindowSystem : : self ( ) - > windows ( ) ) {
2020-03-05 22:20:25 +03:00
windowAddedProxy ( wid ) ;
2019-11-02 11:45:37 +03:00
}
2016-12-25 10:25:27 +03:00
}
XWindowInterface : : ~ XWindowInterface ( )
{
}
2019-12-26 17:53:37 +03:00
void XWindowInterface : : setViewExtraFlags ( QObject * view , bool isPanelWindow , Latte : : Types : : Visibility mode )
2016-12-25 10:25:27 +03:00
{
2019-12-26 17:53:37 +03:00
WId winId = - 1 ;
QQuickView * quickView = qobject_cast < QQuickView * > ( view ) ;
if ( quickView ) {
winId = quickView - > winId ( ) ;
}
if ( ! quickView ) {
QQuickWindow * quickWindow = qobject_cast < QQuickWindow * > ( view ) ;
if ( quickWindow ) {
winId = quickWindow - > winId ( ) ;
}
}
if ( winId < 0 ) {
return ;
}
2016-12-28 10:57:31 +03:00
NETWinInfo winfo ( QX11Info : : connection ( )
2019-12-26 17:53:37 +03:00
, static_cast < xcb_window_t > ( winId )
, static_cast < xcb_window_t > ( 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 ) ;
2019-12-26 17:53:37 +03:00
if ( isPanelWindow ) {
KWindowSystem : : setType ( winId , NET : : Dock ) ;
2019-12-26 22:10:11 +03:00
} else {
KWindowSystem : : setType ( winId , NET : : Normal ) ;
2019-12-26 17:53:37 +03:00
}
2019-12-26 22:58:21 +03:00
# if KF5_VERSION_MINOR >= 45
KWindowSystem : : setState ( winId , NET : : SkipTaskbar | NET : : SkipPager | NET : : SkipSwitcher ) ;
# else
2019-12-26 17:53:37 +03:00
KWindowSystem : : setState ( winId , NET : : SkipTaskbar | NET : : SkipPager ) ;
2019-12-26 22:58:21 +03:00
# endif
2019-12-26 17:53:37 +03:00
KWindowSystem : : setOnAllDesktops ( winId , true ) ;
2019-12-26 22:10:11 +03:00
2019-12-26 22:58:21 +03:00
//! Layer to be applied
2019-12-26 22:10:11 +03:00
if ( mode = = Latte : : Types : : WindowsCanCover | | mode = = Latte : : Types : : WindowsAlwaysCover ) {
setKeepBelow ( winId , true ) ;
2019-12-26 22:58:21 +03:00
} else if ( mode = = Latte : : Types : : NormalWindow ) {
setKeepBelow ( winId , false ) ;
setKeepAbove ( winId , false ) ;
2019-12-26 22:10:11 +03:00
} else {
setKeepAbove ( winId , true ) ;
}
2016-12-25 10:25:27 +03:00
}
2018-12-06 17:09:42 +03:00
void XWindowInterface : : setViewStruts ( 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 ) {
2019-11-02 09:47:31 +03:00
case Plasma : : Types : : TopEdge : {
const int topOffset { screen - > geometry ( ) . top ( ) } ;
strut . top_width = rect . height ( ) + topOffset ;
strut . top_start = rect . x ( ) ;
strut . top_end = rect . x ( ) + rect . width ( ) - 1 ;
break ;
}
2017-01-16 22:07:49 +03:00
2019-11-02 09:47:31 +03:00
case Plasma : : Types : : BottomEdge : {
const int bottomOffset { wholeScreen . bottom ( ) - currentScreen . bottom ( ) } ;
strut . bottom_width = rect . height ( ) + bottomOffset ;
strut . bottom_start = rect . x ( ) ;
strut . bottom_end = rect . x ( ) + rect . width ( ) - 1 ;
break ;
}
2017-12-24 21:54:45 +03:00
2019-11-02 09:47:31 +03:00
case Plasma : : Types : : LeftEdge : {
const int leftOffset = { screen - > geometry ( ) . left ( ) } ;
strut . left_width = rect . width ( ) + leftOffset ;
strut . left_start = rect . y ( ) ;
strut . left_end = rect . y ( ) + rect . height ( ) - 1 ;
break ;
}
2017-12-24 21:54:45 +03:00
2019-11-02 09:47:31 +03:00
case Plasma : : Types : : RightEdge : {
const int rightOffset = { wholeScreen . right ( ) - currentScreen . right ( ) } ;
strut . right_width = rect . width ( ) + rightOffset ;
strut . right_start = rect . y ( ) ;
strut . right_end = rect . y ( ) + rect . height ( ) - 1 ;
break ;
}
2017-12-24 21:54:45 +03:00
2019-11-02 09:47:31 +03:00
default :
qWarning ( ) < < " wrong location: " < < qEnumToStr ( location ) ;
return ;
2016-12-29 08:37:53 +03:00
}
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
2019-11-02 09:47:31 +03:00
) ;
2016-12-29 08:37:53 +03:00
}
2019-06-10 17:30:25 +03:00
void XWindowInterface : : switchToNextVirtualDesktop ( ) const
{
int desktops = KWindowSystem : : numberOfDesktops ( ) ;
2019-06-10 17:49:21 +03:00
2019-06-10 17:30:25 +03:00
if ( desktops < = 1 ) {
return ;
}
int curPos = KWindowSystem : : currentDesktop ( ) ;
int nextPos = curPos + 1 ;
2019-06-10 17:49:21 +03:00
if ( curPos = = desktops ) {
nextPos = 1 ;
2019-06-10 17:30:25 +03:00
}
KWindowSystem : : setCurrentDesktop ( nextPos ) ;
}
void XWindowInterface : : switchToPreviousVirtualDesktop ( ) const
{
int desktops = KWindowSystem : : numberOfDesktops ( ) ;
if ( desktops < = 1 ) {
return ;
}
int curPos = KWindowSystem : : currentDesktop ( ) ;
int nextPos = curPos - 1 ;
2019-06-10 17:49:21 +03:00
if ( curPos = = 1 ) {
nextPos = desktops ;
2019-06-10 17:30:25 +03:00
}
KWindowSystem : : setCurrentDesktop ( nextPos ) ;
}
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
}
2018-12-06 17:09:42 +03:00
void XWindowInterface : : removeViewStruts ( 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 ( ) ;
}
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 ) {
2019-11-02 09:47:31 +03:00
case Slide : : Top :
slideLocation = KWindowEffects : : TopEdge ;
break ;
2017-02-25 05:40:47 +03:00
2019-11-02 09:47:31 +03:00
case Slide : : Bottom :
slideLocation = KWindowEffects : : BottomEdge ;
break ;
2017-02-25 05:40:47 +03:00
2019-11-02 09:47:31 +03:00
case Slide : : Left :
slideLocation = KWindowEffects : : LeftEdge ;
break ;
2017-02-25 05:40:47 +03:00
2019-11-02 09:47:31 +03:00
case Slide : : Right :
slideLocation = KWindowEffects : : RightEdge ;
break ;
2017-02-25 05:40:47 +03:00
2019-11-02 09:47:31 +03:00
default :
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
2020-01-03 14:32:08 +03:00
void XWindowInterface : : setActiveEdge ( QWindow * view , bool active ) const
2018-03-28 20:39:52 +03:00
{
2018-12-09 01:15:17 +03:00
ViewPart : : ScreenEdgeGhostWindow * window = qobject_cast < ViewPart : : ScreenEdgeGhostWindow * > ( view ) ;
2018-03-28 20:39:52 +03:00
if ( ! window ) {
return ;
}
xcb_connection_t * c = QX11Info : : connection ( ) ;
const QByteArray effectName = QByteArrayLiteral ( " _KDE_NET_WM_SCREEN_EDGE_SHOW " ) ;
xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked ( c , false , effectName . length ( ) , effectName . constData ( ) ) ;
QScopedPointer < xcb_intern_atom_reply_t , QScopedPointerPodDeleter > atom ( xcb_intern_atom_reply ( c , atomCookie , nullptr ) ) ;
if ( ! atom ) {
return ;
}
if ( ! active ) {
xcb_delete_property ( c , window - > winId ( ) , atom - > atom ) ;
window - > hideWithMask ( ) ;
return ;
}
window - > showWithMask ( ) ;
uint32_t value = 0 ;
switch ( window - > location ( ) ) {
2019-11-02 09:47:31 +03:00
case Plasma : : Types : : TopEdge :
value = 0 ;
break ;
2018-03-28 20:39:52 +03:00
2019-11-02 09:47:31 +03:00
case Plasma : : Types : : RightEdge :
value = 1 ;
break ;
2018-03-28 20:39:52 +03:00
2019-11-02 09:47:31 +03:00
case Plasma : : Types : : BottomEdge :
value = 2 ;
break ;
2018-03-28 20:39:52 +03:00
2019-11-02 09:47:31 +03:00
case Plasma : : Types : : LeftEdge :
value = 3 ;
break ;
2018-03-28 20:39:52 +03:00
2019-11-02 09:47:31 +03:00
case Plasma : : Types : : Floating :
default :
value = 4 ;
break ;
2018-03-28 20:39:52 +03:00
}
int hideType = 0 ;
value | = hideType < < 8 ;
xcb_change_property ( c , XCB_PROP_MODE_REPLACE , window - > winId ( ) , atom - > atom , XCB_ATOM_CARDINAL , 32 , 1 , & value ) ;
}
2020-03-06 22:45:54 +03:00
# if KF5_VERSION_MINOR >= 65
QRect XWindowInterface : : visibleGeometry ( const WindowId & wid , const QRect & frameGeometry ) const
{
NETWinInfo ni ( QX11Info : : connection ( ) , wid . toUInt ( ) , QX11Info : : appRootWindow ( ) , 0 , NET : : WM2GTKFrameExtents ) ;
NETStrut struts = ni . gtkFrameExtents ( ) ;
QMargins margins ( struts . left , struts . top , struts . right , struts . bottom ) ;
QRect visibleGeometry = frameGeometry ;
if ( ! margins . isNull ( ) ) {
visibleGeometry - = margins ;
}
return visibleGeometry ;
}
# endif
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
WindowInfoWrap XWindowInterface : : requestInfo ( WindowId wid ) const
2016-12-25 10:25:27 +03:00
{
2019-06-01 11:04:23 +03:00
const KWindowInfo winfo { wid . value < WId > ( ) , NET : : WMFrameExtents
2019-11-02 09:47:31 +03:00
| NET : : WMWindowType
| NET : : WMGeometry
| NET : : WMDesktop
| NET : : WMState
| NET : : WMName
| NET : : WMVisibleName ,
NET : : WM2WindowClass
| NET : : WM2Activities
2020-01-22 14:02:00 +03:00
| NET : : WM2AllowedActions
2019-11-02 09:47:31 +03:00
| NET : : WM2TransientFor } ;
2019-06-01 11:04:23 +03:00
2016-12-28 10:57:31 +03:00
WindowInfoWrap winfoWrap ;
2017-01-16 22:07:49 +03:00
2019-07-23 12:05:21 +03:00
if ( ! winfo . valid ( ) ) {
winfoWrap . setIsValid ( false ) ;
2020-02-29 18:57:59 +03:00
} else if ( isValidWindow ( winfo ) ) {
2017-01-02 09:04:10 +03:00
winfoWrap . setIsValid ( true ) ;
winfoWrap . setWid ( wid ) ;
2019-07-23 00:05:01 +03:00
winfoWrap . setParentId ( winfo . transientFor ( ) ) ;
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 ) ) ;
2019-05-31 17:44:04 +03:00
winfoWrap . setIsOnAllDesktops ( winfo . onAllDesktops ( ) ) ;
2019-06-08 00:31:30 +03:00
winfoWrap . setIsOnAllActivities ( winfo . activities ( ) . empty ( ) ) ;
2020-03-06 22:45:54 +03:00
# if KF5_VERSION_MINOR >= 65
winfoWrap . setGeometry ( visibleGeometry ( wid , winfo . frameGeometry ( ) ) ) ;
# else
2017-02-11 09:58:25 +03:00
winfoWrap . setGeometry ( winfo . frameGeometry ( ) ) ;
2020-03-06 22:45:54 +03:00
# endif
2017-12-24 21:54:45 +03:00
winfoWrap . setIsKeepAbove ( winfo . hasState ( NET : : KeepAbove ) ) ;
2019-12-26 17:53:37 +03:00
winfoWrap . setIsKeepBelow ( winfo . hasState ( NET : : KeepBelow ) ) ;
2018-10-28 11:03:22 +03:00
winfoWrap . setHasSkipTaskbar ( winfo . hasState ( NET : : SkipTaskbar ) ) ;
2019-06-08 00:31:30 +03:00
2020-02-29 18:57:59 +03:00
//! BEGIN:Window Abilities
2020-01-22 14:02:00 +03:00
winfoWrap . setIsClosable ( winfo . actionSupported ( NET : : ActionClose ) ) ;
winfoWrap . setIsFullScreenable ( winfo . actionSupported ( NET : : ActionFullScreen ) ) ;
winfoWrap . setIsMaximizable ( winfo . actionSupported ( NET : : ActionMax ) ) ;
winfoWrap . setIsMinimizable ( winfo . actionSupported ( NET : : ActionMinimize ) ) ;
winfoWrap . setIsMovable ( winfo . actionSupported ( NET : : ActionMove ) ) ;
winfoWrap . setIsResizable ( winfo . actionSupported ( NET : : ActionResize ) ) ;
winfoWrap . setIsShadeable ( winfo . actionSupported ( NET : : ActionShade ) ) ;
winfoWrap . setIsVirtualDesktopsChangeable ( winfo . actionSupported ( NET : : ActionChangeDesktop ) ) ;
2020-02-29 18:57:59 +03:00
//! END:Window Abilities
2020-01-22 14:02:00 +03:00
winfoWrap . setDisplay ( winfo . visibleName ( ) ) ;
2019-06-08 00:31:30 +03:00
winfoWrap . setDesktops ( { QString ( winfo . desktop ( ) ) } ) ;
winfoWrap . setActivities ( winfo . activities ( ) ) ;
2017-01-02 09:04:10 +03:00
}
2017-01-16 22:07:49 +03:00
2016-12-28 10:57:31 +03:00
return winfoWrap ;
}
2019-06-01 01:20:54 +03:00
AppData XWindowInterface : : appDataFor ( WindowId wid ) const
{
return appDataFromUrl ( windowUrl ( wid ) ) ;
}
QUrl XWindowInterface : : windowUrl ( WindowId wid ) const
{
const KWindowInfo info ( wid . value < WId > ( ) , 0 , NET : : WM2WindowClass | NET : : WM2DesktopFileName ) ;
QString desktopFile = QString : : fromUtf8 ( info . desktopFileName ( ) ) ;
if ( ! desktopFile . isEmpty ( ) ) {
KService : : Ptr service = KService : : serviceByStorageId ( desktopFile ) ;
if ( service ) {
const QString & menuId = service - > menuId ( ) ;
// applications: URLs are used to refer to applications by their KService::menuId
// (i.e. .desktop file name) rather than the absolute path to a .desktop file.
if ( ! menuId . isEmpty ( ) ) {
return QUrl ( QStringLiteral ( " applications: " ) + menuId ) ;
}
return QUrl : : fromLocalFile ( service - > entryPath ( ) ) ;
}
if ( ! desktopFile . endsWith ( QLatin1String ( " .desktop " ) ) ) {
desktopFile . append ( QLatin1String ( " .desktop " ) ) ;
}
if ( KDesktopFile : : isDesktopFile ( desktopFile ) & & QFile : : exists ( desktopFile ) ) {
return QUrl : : fromLocalFile ( desktopFile ) ;
}
}
return windowUrlFromMetadata ( info . windowClassClass ( ) ,
2019-11-02 09:47:31 +03:00
NETWinInfo ( QX11Info : : connection ( ) , wid . value < WId > ( ) , QX11Info : : appRootWindow ( ) , NET : : WMPid , NET : : Properties2 ( ) ) . pid ( ) ,
rulesConfig , info . windowClassName ( ) ) ;
2019-06-01 01:20:54 +03:00
}
2020-02-29 18:57:59 +03:00
bool XWindowInterface : : isFullScreenWindow ( WindowId wid ) const
{
WindowInfoWrap winfo = requestInfo ( wid ) ;
return ( winfo . isValid ( )
& & ! winfo . isMinimized ( )
& & ( winfo . isFullscreen ( ) | | AbstractWindowInterface : : isFullScreenWindow ( winfo . geometry ( ) ) ) ) ;
}
2019-06-01 01:20:54 +03:00
2018-10-28 22:10:08 +03:00
bool XWindowInterface : : windowCanBeDragged ( WindowId wid ) const
2018-10-28 11:03:22 +03:00
{
2020-01-22 14:02:00 +03:00
WindowInfoWrap winfo = requestInfo ( wid ) ;
return ( winfo . isValid ( )
& & ! winfo . isMinimized ( )
& & winfo . isMovable ( )
2020-02-29 18:57:59 +03:00
& & inCurrentDesktopActivity ( winfo ) ) ;
2018-10-28 11:03:22 +03:00
}
2019-07-31 16:44:43 +03:00
bool XWindowInterface : : windowCanBeMaximized ( WindowId wid ) const
{
2020-01-22 14:02:00 +03:00
WindowInfoWrap winfo = requestInfo ( wid ) ;
return ( winfo . isValid ( )
& & ! winfo . isMinimized ( )
& & winfo . isMaximizable ( )
2020-02-29 18:57:59 +03:00
& & inCurrentDesktopActivity ( winfo ) ) ;
2019-07-31 16:44:43 +03:00
}
2019-04-01 23:50:25 +03:00
void XWindowInterface : : requestActivate ( WindowId wid ) const
{
KWindowSystem : : activateWindow ( wid . toInt ( ) ) ;
}
2019-05-27 18:56:24 +03:00
QIcon XWindowInterface : : iconFor ( WindowId wid ) const
{
QIcon icon ;
icon . addPixmap ( KWindowSystem : : icon ( wid . value < WId > ( ) , KIconLoader : : SizeSmall , KIconLoader : : SizeSmall , false ) ) ;
icon . addPixmap ( KWindowSystem : : icon ( wid . value < WId > ( ) , KIconLoader : : SizeSmallMedium , KIconLoader : : SizeSmallMedium , false ) ) ;
icon . addPixmap ( KWindowSystem : : icon ( wid . value < WId > ( ) , KIconLoader : : SizeMedium , KIconLoader : : SizeMedium , false ) ) ;
icon . addPixmap ( KWindowSystem : : icon ( wid . value < WId > ( ) , KIconLoader : : SizeLarge , KIconLoader : : SizeLarge , false ) ) ;
return icon ;
}
2019-04-01 23:50:25 +03:00
WindowId XWindowInterface : : winIdFor ( QString appId , QRect geometry ) const
{
return activeWindow ( ) ;
}
2020-03-02 04:10:59 +03:00
WindowId XWindowInterface : : winIdFor ( QString appId , QString title ) const
{
return activeWindow ( ) ;
}
2019-06-02 01:07:47 +03:00
void XWindowInterface : : requestClose ( WindowId wid ) const
{
WindowInfoWrap wInfo = requestInfo ( wid ) ;
2020-02-29 18:57:59 +03:00
if ( ! wInfo . isValid ( ) ) {
2019-06-02 01:07:47 +03:00
return ;
}
NETRootInfo ri ( QX11Info : : connection ( ) , NET : : CloseWindow ) ;
ri . closeWindowRequest ( wInfo . wid ( ) . toUInt ( ) ) ;
}
2018-10-28 22:10:08 +03:00
void XWindowInterface : : requestMoveWindow ( WindowId wid , QPoint from ) const
2018-10-28 11:03:22 +03:00
{
2018-10-28 22:10:08 +03:00
WindowInfoWrap wInfo = requestInfo ( wid ) ;
2018-10-28 11:03:22 +03:00
2020-02-29 18:57:59 +03:00
if ( ! wInfo . isValid ( ) | | ! inCurrentDesktopActivity ( wInfo ) ) {
2018-10-28 11:03:22 +03:00
return ;
}
2019-11-02 09:47:31 +03:00
int borderX = wInfo . geometry ( ) . width ( ) > 120 ? 60 : 10 ;
2018-10-28 11:03:22 +03:00
int borderY { 10 } ;
//! find min/max values for x,y based on active window geometry
2018-10-28 22:10:08 +03:00
int minX = wInfo . geometry ( ) . x ( ) + borderX ;
int maxX = wInfo . geometry ( ) . x ( ) + wInfo . geometry ( ) . width ( ) - borderX ;
int minY = wInfo . geometry ( ) . y ( ) + borderY ;
int maxY = wInfo . geometry ( ) . y ( ) + wInfo . geometry ( ) . height ( ) - borderY ;
2018-10-28 11:03:22 +03:00
//! set the point from which this window will be moved,
//! make sure that it is in window boundaries
int validX = qBound ( minX , from . x ( ) , maxX ) ;
int validY = qBound ( minY , from . y ( ) , maxY ) ;
NETRootInfo ri ( QX11Info : : connection ( ) , NET : : WMMoveResize ) ;
2018-10-28 22:10:08 +03:00
ri . moveResizeRequest ( wInfo . wid ( ) . toUInt ( ) , validX , validY , NET : : Move ) ;
2018-10-28 11:03:22 +03:00
}
2019-06-02 01:57:03 +03:00
void XWindowInterface : : requestToggleIsOnAllDesktops ( WindowId wid ) const
{
WindowInfoWrap wInfo = requestInfo ( wid ) ;
2020-02-29 18:57:59 +03:00
if ( ! wInfo . isValid ( ) ) {
2019-06-02 01:57:03 +03:00
return ;
}
if ( KWindowSystem : : numberOfDesktops ( ) < = 1 ) {
return ;
}
if ( wInfo . isOnAllDesktops ( ) ) {
KWindowSystem : : setOnDesktop ( wid . toUInt ( ) , KWindowSystem : : currentDesktop ( ) ) ;
KWindowSystem : : forceActiveWindow ( wid . toUInt ( ) ) ;
} else {
KWindowSystem : : setOnAllDesktops ( wid . toUInt ( ) , true ) ;
}
}
2019-06-02 01:07:47 +03:00
void XWindowInterface : : requestToggleKeepAbove ( WindowId wid ) const
{
WindowInfoWrap wInfo = requestInfo ( wid ) ;
2020-02-29 18:57:59 +03:00
if ( ! wInfo . isValid ( ) ) {
2019-06-02 01:07:47 +03:00
return ;
}
NETWinInfo ni ( QX11Info : : connection ( ) , wid . toUInt ( ) , QX11Info : : appRootWindow ( ) , NET : : WMState , NET : : Properties2 ( ) ) ;
if ( wInfo . isKeepAbove ( ) ) {
ni . setState ( NET : : States ( ) , NET : : StaysOnTop ) ;
} else {
ni . setState ( NET : : StaysOnTop , NET : : StaysOnTop ) ;
}
}
2019-12-26 17:53:37 +03:00
void XWindowInterface : : setKeepAbove ( WindowId wid , bool active ) const
{
2019-12-26 18:21:03 +03:00
if ( wid . toUInt ( ) < = 0 ) {
2019-12-26 17:53:37 +03:00
return ;
}
2019-12-26 18:21:03 +03:00
if ( active ) {
KWindowSystem : : setState ( wid . toUInt ( ) , NET : : KeepAbove ) ;
2019-12-26 22:10:11 +03:00
KWindowSystem : : clearState ( wid . toUInt ( ) , NET : : KeepBelow ) ;
2019-12-26 17:53:37 +03:00
} else {
2019-12-26 18:21:03 +03:00
KWindowSystem : : clearState ( wid . toUInt ( ) , NET : : KeepAbove ) ;
2019-12-26 17:53:37 +03:00
}
}
void XWindowInterface : : setKeepBelow ( WindowId wid , bool active ) const
{
2019-12-26 18:21:03 +03:00
if ( wid . toUInt ( ) < = 0 ) {
2019-12-26 17:53:37 +03:00
return ;
}
2019-12-26 18:21:03 +03:00
if ( active ) {
KWindowSystem : : setState ( wid . toUInt ( ) , NET : : KeepBelow ) ;
2019-12-26 22:10:11 +03:00
KWindowSystem : : clearState ( wid . toUInt ( ) , NET : : KeepAbove ) ;
2019-12-26 17:53:37 +03:00
} else {
2019-12-26 18:21:03 +03:00
KWindowSystem : : clearState ( wid . toUInt ( ) , NET : : KeepBelow ) ;
2019-12-26 17:53:37 +03:00
}
}
2019-06-02 01:07:47 +03:00
void XWindowInterface : : requestToggleMinimized ( WindowId wid ) const
{
WindowInfoWrap wInfo = requestInfo ( wid ) ;
2020-02-29 18:57:59 +03:00
if ( ! wInfo . isValid ( ) | | ! inCurrentDesktopActivity ( wInfo ) ) {
2019-06-02 01:07:47 +03:00
return ;
}
if ( wInfo . isMinimized ( ) ) {
2019-06-08 00:31:30 +03:00
bool onCurrent = wInfo . isOnDesktop ( m_currentDesktop ) ;
2019-06-02 01:07:47 +03:00
KWindowSystem : : unminimizeWindow ( wid . toUInt ( ) ) ;
if ( onCurrent ) {
KWindowSystem : : forceActiveWindow ( wid . toUInt ( ) ) ;
}
} else {
KWindowSystem : : minimizeWindow ( wid . toUInt ( ) ) ;
}
}
2018-10-28 22:10:08 +03:00
void XWindowInterface : : requestToggleMaximized ( WindowId wid ) const
{
2019-11-13 15:23:43 +03:00
WindowInfoWrap wInfo = requestInfo ( wid ) ;
if ( ! windowCanBeMaximized ( wid ) | | ! inCurrentDesktopActivity ( wInfo ) ) {
2019-07-31 16:44:43 +03:00
return ;
}
2018-10-28 22:10:08 +03:00
bool restore = wInfo . isMaxHoriz ( ) & & wInfo . isMaxVert ( ) ;
2019-06-02 01:07:47 +03:00
if ( wInfo . isMinimized ( ) ) {
KWindowSystem : : unminimizeWindow ( wid . toUInt ( ) ) ;
}
2018-10-28 22:10:08 +03:00
NETWinInfo ni ( QX11Info : : connection ( ) , wid . toInt ( ) , QX11Info : : appRootWindow ( ) , NET : : WMState , NET : : Properties2 ( ) ) ;
if ( restore ) {
ni . setState ( NET : : States ( ) , NET : : Max ) ;
} else {
ni . setState ( NET : : Max , NET : : Max ) ;
}
}
2017-01-02 09:04:10 +03:00
2019-06-01 02:33:44 +03:00
bool XWindowInterface : : isValidWindow ( WindowId wid ) const
{
2019-06-01 02:43:30 +03:00
if ( windowsTracker ( ) - > isValidFor ( wid ) ) {
return true ;
}
2019-06-01 02:33:44 +03:00
const KWindowInfo winfo { wid . value < WId > ( ) , NET : : WMWindowType } ;
return isValidWindow ( winfo ) ;
}
2017-01-02 09:04:10 +03:00
bool XWindowInterface : : isValidWindow ( const KWindowInfo & winfo ) const
2016-12-28 10:57:31 +03:00
{
2019-06-01 02:43:30 +03:00
if ( windowsTracker ( ) - > isValidFor ( winfo . win ( ) ) ) {
return true ;
}
2019-07-13 14:51:26 +03:00
//! ignored windows from tracking
2020-02-29 18:57:59 +03:00
if ( m_ignoredWindows . contains ( winfo . win ( ) ) | | m_plasmaIgnoredWindows . contains ( winfo . win ( ) ) ) {
2019-02-10 12:38:55 +03:00
return false ;
}
2017-01-16 22:07:49 +03:00
2020-02-29 18:57:59 +03:00
constexpr auto types = NET : : DockMask | NET : : MenuMask | NET : : SplashMask | NET : : PopupMenuMask | NET : : NormalMask | NET : : DialogMask ;
NET : : WindowType winType = winfo . windowType ( types ) ;
const auto winClass = KWindowInfo ( winfo . win ( ) , 0 , NET : : WM2WindowClass ) . windowClassName ( ) ;
2019-06-01 02:57:47 +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
}
2019-06-01 02:33:44 +03:00
bool isMenu = ( ( winType & NET : : Menu ) = = true ) ;
bool isDock = ( ( winType & NET : : Dock ) = = true ) ;
bool isPopup = ( ( winType & NET : : PopupMenu ) = = true ) ;
bool isSplash = ( ( winType & NET : : Splash ) = = true ) ;
//! GTK2+ dialogs case e.g. inkscape, gimp2, etc...
//! are both Popups and Splash types, this is why
//! we can not black list them here
return ! ( isMenu | | isDock ) ;
2016-12-25 10:25:27 +03:00
}
2020-03-05 22:20:25 +03:00
bool XWindowInterface : : isAcceptableWindow ( WId wid )
2016-12-25 10:25:27 +03:00
{
2019-06-01 03:44:42 +03:00
const KWindowInfo info ( wid , NET : : WMGeometry , NET : : WM2WindowClass ) ;
2020-03-02 11:05:43 +03:00
const auto winClass = QString ( info . windowClassName ( ) ) ;
2019-02-10 12:38:55 +03:00
2019-07-13 14:51:26 +03:00
//! ignored windows do not trackd
2020-02-29 18:57:59 +03:00
if ( m_ignoredWindows . contains ( wid ) | | m_plasmaIgnoredWindows . contains ( wid ) ) {
2020-03-05 22:20:25 +03:00
return false ;
2019-02-10 12:38:55 +03:00
}
2017-01-16 22:07:49 +03:00
2020-03-02 11:05:43 +03:00
if ( winClass = = QLatin1String ( " plasmashell " ) ) {
2020-02-29 18:57:59 +03:00
if ( isPlasmaPanel ( info . geometry ( ) ) | | isFullScreenWindow ( wid ) ) {
registerPlasmaIgnoredWindow ( wid ) ;
2020-03-05 22:20:25 +03:00
return false ;
2020-02-29 18:57:59 +03:00
}
2020-03-02 11:05:43 +03:00
} else if ( ( winClass = = QLatin1String ( " latte-dock " ) )
| | ( winClass = = QLatin1String ( " ksmserver " ) ) ) {
2020-02-29 18:57:59 +03:00
if ( isFullScreenWindow ( wid ) ) {
registerPlasmaIgnoredWindow ( wid ) ;
2020-03-05 22:20:25 +03:00
return false ;
2019-11-02 11:45:37 +03:00
}
2017-01-02 09:04:10 +03:00
}
2017-01-16 22:07:49 +03:00
2020-03-05 22:20:25 +03:00
return true ;
}
void XWindowInterface : : windowAddedProxy ( WId wid )
{
if ( ! isAcceptableWindow ( wid ) ) {
return ;
}
emit windowAdded ( wid ) ;
considerWindowChanged ( wid ) ;
}
void XWindowInterface : : windowChangedProxy ( WId wid , NET : : Properties prop1 , NET : : Properties2 prop2 )
{
if ( ! isAcceptableWindow ( wid ) ) {
return ;
}
2018-10-06 16:28:46 +03:00
//! accept only NET::Properties events,
//! ignore when the user presses a key, or a window is sending X events etc.
2018-01-02 15:03:50 +03:00
//! without needing to (e.g. Firefox, https://bugzilla.mozilla.org/show_bug.cgi?id=1389953)
2018-10-06 16:28:46 +03:00
//! NET::WM2UserTime, NET::WM2IconPixmap etc....
2019-07-23 12:05:21 +03:00
if ( prop1 = = 0 & & ! ( prop2 & ( NET : : WM2Activities | NET : : WM2TransientFor ) ) ) {
2017-01-02 09:04:10 +03:00
return ;
}
2017-01-16 22:07:49 +03:00
2019-01-01 12:19:44 +03:00
//! accept only the following NET:Properties changed signals
2018-10-06 16:28:46 +03:00
//! NET::WMState, NET::WMGeometry, NET::ActiveWindow
2019-05-27 18:56:24 +03:00
if ( ! ( prop1 & NET : : WMState )
2019-11-02 09:47:31 +03:00
& & ! ( prop1 & NET : : WMGeometry )
& & ! ( prop1 & NET : : ActiveWindow )
& & ! ( prop1 & NET : : WMDesktop )
& & ! ( prop1 & ( NET : : WMName | NET : : WMVisibleName )
& & ! ( prop2 & NET : : WM2TransientFor )
& & ! ( prop2 & NET : : WM2Activities ) ) ) {
2016-12-28 10:57:31 +03:00
return ;
2018-10-06 16:28:46 +03:00
}
2019-06-01 02:33:44 +03:00
//! ignore windows that do not respect normal windows types
if ( ! isValidWindow ( wid ) ) {
return ;
}
2019-05-27 20:09:48 +03:00
considerWindowChanged ( wid ) ;
2016-12-25 10:25:27 +03:00
}
}
2019-05-11 15:43:10 +03:00
}