2017-04-25 17:48:36 +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/>.
*/
# include "waylandinterface.h"
2018-12-02 02:05:52 +02:00
// local
2020-04-24 14:52:16 +03:00
# include <coretypes.h>
2020-07-11 18:13:47 +03:00
# include "../view/positioner.h"
# include "../view/view.h"
# include "../view/settings/subconfigview.h"
# include "../view/helpers/screenedgeghostwindow.h"
2018-12-06 14:35:34 +02:00
# include "../lattecorona.h"
2017-04-25 17:48:36 +03:00
2018-12-02 02:05:52 +02:00
// Qt
2017-04-25 17:48:36 +03:00
# include <QDebug>
# include <QTimer>
2017-06-10 16:33:46 -05:00
# include <QApplication>
2017-04-25 17:48:36 +03:00
# include <QtX11Extras/QX11Info>
2017-06-29 15:33:12 -05:00
# include <QRasterWindow>
2017-04-25 17:48:36 +03:00
2018-12-02 02:05:52 +02:00
// KDE
2017-04-25 17:48:36 +03:00
# include <KWindowSystem>
# include <KWindowInfo>
2018-03-28 20:39:52 +03:00
# include <KWayland/Client/surface.h>
2017-06-29 15:33:12 -05:00
2019-05-26 00:58:42 +03:00
# if KF5_VERSION_MINOR >= 52
# include <KWayland/Client/plasmavirtualdesktop.h>
# endif
2018-12-02 02:05:52 +02:00
// X11
# include <NETWM>
2017-06-10 16:33:46 -05:00
using namespace KWayland : : Client ;
2017-04-25 17:48:36 +03:00
namespace Latte {
2018-07-03 22:15:45 +03:00
class Private : : GhostWindow : public QRasterWindow
{
2017-06-29 15:33:12 -05:00
Q_OBJECT
public :
2019-07-15 14:53:40 +03:00
WindowSystem : : WindowId m_winId ;
2019-05-11 15:43:10 +03:00
GhostWindow ( WindowSystem : : WaylandInterface * waylandInterface )
2017-12-24 20:54:45 +02:00
: m_waylandInterface ( waylandInterface ) {
2017-06-29 15:33:12 -05:00
setFlags ( Qt : : FramelessWindowHint
2017-12-24 20:54:45 +02:00
| Qt : : WindowStaysOnTopHint
| Qt : : NoDropShadowWindowHint
| Qt : : WindowDoesNotAcceptFocus ) ;
2017-06-29 15:33:12 -05:00
2019-07-15 19:15:53 +03:00
connect ( m_waylandInterface , & WindowSystem : : AbstractWindowInterface : : latteWindowAdded , this , & GhostWindow : : identifyWinId ) ;
2017-06-29 15:33:12 -05:00
setupWaylandIntegration ( ) ;
show ( ) ;
}
2017-12-24 20:54:45 +02:00
~ GhostWindow ( ) {
2019-07-15 14:53:40 +03:00
m_waylandInterface - > unregisterIgnoredWindow ( m_winId ) ;
2017-06-29 15:33:12 -05:00
delete m_shellSurface ;
}
2017-12-24 20:54:45 +02:00
void setGeometry ( const QRect & rect ) {
2019-06-24 17:22:37 +03:00
if ( geometry ( ) = = rect ) {
return ;
}
2019-07-15 19:15:53 +03:00
m_validGeometry = rect ;
2019-07-15 14:53:40 +03:00
2019-06-24 17:22:37 +03:00
setMinimumSize ( rect . size ( ) ) ;
2018-03-03 14:14:44 +02:00
setMaximumSize ( rect . size ( ) ) ;
2019-06-24 17:22:37 +03:00
resize ( rect . size ( ) ) ;
2017-06-29 15:33:12 -05:00
m_shellSurface - > setPosition ( rect . topLeft ( ) ) ;
}
2017-12-24 20:54:45 +02:00
void setupWaylandIntegration ( ) {
2017-06-29 15:33:12 -05:00
using namespace KWayland : : Client ;
if ( m_shellSurface )
return ;
Surface * s { Surface : : fromWindow ( this ) } ;
if ( ! s )
return ;
2018-12-06 14:35:34 +02:00
m_shellSurface = m_waylandInterface - > waylandCoronaInterface ( ) - > createSurface ( s , this ) ;
2017-06-29 15:33:12 -05:00
qDebug ( ) < < " wayland ghost window surface was created... " ;
m_shellSurface - > setSkipTaskbar ( true ) ;
m_shellSurface - > setPanelTakesFocus ( false ) ;
m_shellSurface - > setRole ( PlasmaShellSurface : : Role : : Panel ) ;
m_shellSurface - > setPanelBehavior ( PlasmaShellSurface : : PanelBehavior : : AlwaysVisible ) ;
}
2017-12-24 20:54:45 +02:00
KWayland : : Client : : PlasmaShellSurface * m_shellSurface { nullptr } ;
2019-05-11 15:43:10 +03:00
WindowSystem : : WaylandInterface * m_waylandInterface { nullptr } ;
2019-07-15 19:15:53 +03:00
//! geometry() function under wayland does not return nice results
QRect m_validGeometry ;
public slots :
void identifyWinId ( ) {
if ( m_winId . isNull ( ) ) {
m_winId = m_waylandInterface - > winIdFor ( " latte-dock " , m_validGeometry ) ;
m_waylandInterface - > registerIgnoredWindow ( m_winId ) ;
}
}
2017-06-29 15:33:12 -05:00
} ;
2019-05-11 15:43:10 +03:00
namespace WindowSystem {
2017-04-25 17:48:36 +03:00
WaylandInterface : : WaylandInterface ( QObject * parent )
: AbstractWindowInterface ( parent )
{
2018-12-06 14:35:34 +02:00
m_corona = qobject_cast < Latte : : Corona * > ( parent ) ;
2017-04-25 17:48:36 +03:00
}
WaylandInterface : : ~ WaylandInterface ( )
{
}
2017-06-10 16:33:46 -05:00
void WaylandInterface : : init ( )
{
}
2018-03-01 23:53:28 +02:00
void WaylandInterface : : initWindowManagement ( KWayland : : Client : : PlasmaWindowManagement * windowManagement )
{
2019-05-26 00:58:42 +03:00
if ( m_windowManagement = = windowManagement ) {
return ;
}
2018-03-01 23:53:28 +02:00
m_windowManagement = windowManagement ;
connect ( m_windowManagement , & PlasmaWindowManagement : : windowCreated , this , & WaylandInterface : : windowCreatedProxy ) ;
connect ( m_windowManagement , & PlasmaWindowManagement : : activeWindowChanged , this , [ & ] ( ) noexcept {
2020-02-29 17:57:59 +02:00
auto w = m_windowManagement - > activeWindow ( ) ;
if ( ! w | | ( w & & ( ! m_ignoredWindows . contains ( w - > internalId ( ) ) ) ) ) {
emit activeWindowChanged ( w ? w - > internalId ( ) : 0 ) ;
}
2019-05-26 00:58:42 +03:00
2020-02-29 17:57:59 +02:00
} , Qt : : QueuedConnection ) ;
2019-05-26 00:58:42 +03:00
}
# if KF5_VERSION_MINOR >= 52
void WaylandInterface : : initVirtualDesktopManagement ( KWayland : : Client : : PlasmaVirtualDesktopManagement * virtualDesktopManagement )
{
if ( m_virtualDesktopManagement = = virtualDesktopManagement ) {
return ;
}
m_virtualDesktopManagement = virtualDesktopManagement ;
connect ( m_virtualDesktopManagement , & KWayland : : Client : : PlasmaVirtualDesktopManagement : : desktopCreated , this ,
[ this ] ( const QString & id , quint32 position ) {
addDesktop ( id , position ) ;
} ) ;
connect ( m_virtualDesktopManagement , & KWayland : : Client : : PlasmaVirtualDesktopManagement : : desktopRemoved , this ,
[ this ] ( const QString & id ) {
m_desktops . removeAll ( id ) ;
if ( m_currentDesktop = = id ) {
setCurrentDesktop ( QString ( ) ) ;
2019-02-11 18:40:13 +02:00
}
2019-05-26 00:58:42 +03:00
} ) ;
}
void WaylandInterface : : addDesktop ( const QString & id , quint32 position )
{
if ( m_desktops . contains ( id ) ) {
return ;
}
2019-02-11 18:40:13 +02:00
2019-05-26 00:58:42 +03:00
m_desktops . append ( id ) ;
const KWayland : : Client : : PlasmaVirtualDesktop * desktop = m_virtualDesktopManagement - > getVirtualDesktop ( id ) ;
QObject : : connect ( desktop , & KWayland : : Client : : PlasmaVirtualDesktop : : activated , this ,
[ desktop , this ] ( ) {
setCurrentDesktop ( desktop - > id ( ) ) ;
}
) ;
if ( desktop - > isActive ( ) ) {
setCurrentDesktop ( id ) ;
}
2018-03-01 23:53:28 +02:00
}
2019-05-26 00:58:42 +03:00
void WaylandInterface : : setCurrentDesktop ( QString desktop )
{
if ( m_currentDesktop = = desktop ) {
return ;
}
m_currentDesktop = desktop ;
emit currentDesktopChanged ( ) ;
}
# endif
2018-12-06 14:35:34 +02:00
KWayland : : Client : : PlasmaShell * WaylandInterface : : waylandCoronaInterface ( ) const
2018-03-01 23:53:28 +02:00
{
2018-12-06 14:35:34 +02:00
return m_corona - > waylandCoronaInterface ( ) ;
2018-03-01 23:53:28 +02:00
}
2019-07-15 14:53:40 +03:00
//! Register Latte Ignored Windows in order to NOT be tracked
void WaylandInterface : : registerIgnoredWindow ( WindowId wid )
{
if ( ! wid . isNull ( ) & & ! m_ignoredWindows . contains ( wid ) ) {
m_ignoredWindows . append ( wid ) ;
KWayland : : Client : : PlasmaWindow * w = windowFor ( wid ) ;
2019-12-22 13:36:51 +02:00
if ( w ) {
untrackWindow ( w ) ;
2019-07-15 14:53:40 +03:00
}
emit windowChanged ( wid ) ;
}
}
void WaylandInterface : : unregisterIgnoredWindow ( WindowId wid )
{
if ( m_ignoredWindows . contains ( wid ) ) {
m_ignoredWindows . removeAll ( wid ) ;
emit windowRemoved ( wid ) ;
}
}
2019-12-26 16:53:37 +02:00
void WaylandInterface : : setViewExtraFlags ( QObject * view , bool isPanelWindow , Latte : : Types : : Visibility mode )
2017-04-25 17:48:36 +03:00
{
2019-12-26 16:53:37 +02:00
KWayland : : Client : : PlasmaShellSurface * surface = qobject_cast < KWayland : : Client : : PlasmaShellSurface * > ( view ) ;
2019-12-26 22:24:04 +02:00
Latte : : View * latteView = qobject_cast < Latte : : View * > ( view ) ;
2020-07-11 18:13:47 +03:00
Latte : : ViewPart : : SubConfigView * configView = qobject_cast < Latte : : ViewPart : : SubConfigView * > ( view ) ;
WindowId winId ;
2019-12-26 22:24:04 +02:00
if ( latteView ) {
surface = latteView - > surface ( ) ;
2020-07-11 18:13:47 +03:00
winId = latteView - > positioner ( ) - > trackedWindowId ( ) ;
} else if ( configView ) {
surface = configView - > surface ( ) ;
winId = configView - > trackedWindowId ( ) ;
2019-12-26 22:24:04 +02:00
}
2019-12-26 16:53:37 +02:00
if ( ! surface ) {
return ;
}
surface - > setSkipTaskbar ( true ) ;
# if KF5_VERSION_MINOR >= 47
surface - > setSkipSwitcher ( true ) ;
# endif
2019-12-26 22:24:04 +02:00
bool atBottom { ! isPanelWindow & & ( mode = = Latte : : Types : : WindowsCanCover | | mode = = Latte : : Types : : WindowsAlwaysCover ) } ;
2019-12-26 16:53:37 +02:00
if ( isPanelWindow ) {
surface - > setRole ( PlasmaShellSurface : : Role : : Panel ) ;
2019-12-27 00:21:20 +02:00
surface - > setPanelBehavior ( PlasmaShellSurface : : PanelBehavior : : AutoHide ) ;
2019-12-26 22:24:04 +02:00
} else {
surface - > setRole ( PlasmaShellSurface : : Role : : Normal ) ;
}
2020-07-11 18:13:47 +03:00
if ( latteView | | configView ) {
2019-12-26 22:24:04 +02:00
auto w = windowFor ( winId ) ;
if ( w & & ! w - > isOnAllDesktops ( ) ) {
requestToggleIsOnAllDesktops ( winId ) ;
}
//! Layer to be applied
if ( mode = = Latte : : Types : : WindowsCanCover | | mode = = Latte : : Types : : WindowsAlwaysCover ) {
setKeepBelow ( winId , true ) ;
} else if ( mode = = Latte : : Types : : NormalWindow ) {
setKeepBelow ( winId , false ) ;
setKeepAbove ( winId , false ) ;
} else {
setKeepAbove ( winId , true ) ;
}
}
if ( atBottom ) {
//! trying to workaround WM behavior in order
//! 1. View at the end MUST NOT HAVE FOCUSABILITY (issue example: clicking a single active task is not minimized)
//! 2. View at the end MUST BE AT THE BOTTOM of windows stack
QTimer : : singleShot ( 50 , [ this , surface ] ( ) {
surface - > setRole ( PlasmaShellSurface : : Role : : ToolTip ) ;
} ) ;
2019-12-26 16:53:37 +02:00
}
2017-04-25 17:48:36 +03:00
}
2018-12-06 16:09:42 +02:00
void WaylandInterface : : setViewStruts ( QWindow & view , const QRect & rect , Plasma : : Types : : Location location )
2017-04-25 17:48:36 +03:00
{
2019-06-24 17:22:37 +03:00
if ( ! m_ghostWindows . contains ( view . winId ( ) ) ) {
2017-06-29 15:33:12 -05:00
m_ghostWindows [ view . winId ( ) ] = new Private : : GhostWindow ( this ) ;
2019-06-24 17:22:37 +03:00
}
2017-06-29 15:33:12 -05:00
auto w = m_ghostWindows [ view . winId ( ) ] ;
2017-12-24 20:54:45 +02:00
switch ( location ) {
2019-05-26 00:58:42 +03:00
case Plasma : : Types : : TopEdge :
case Plasma : : Types : : BottomEdge :
w - > setGeometry ( { rect . x ( ) + rect . width ( ) / 2 , rect . y ( ) , 1 , rect . height ( ) } ) ;
break ;
case Plasma : : Types : : LeftEdge :
case Plasma : : Types : : RightEdge :
w - > setGeometry ( { rect . x ( ) , rect . y ( ) + rect . height ( ) / 2 , rect . width ( ) , 1 } ) ;
break ;
default :
break ;
2017-06-29 15:33:12 -05:00
}
2017-04-25 17:48:36 +03:00
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : switchToNextVirtualDesktop ( )
2019-06-10 17:30:25 +03:00
{
# if KF5_VERSION_MINOR >= 52
if ( ! m_virtualDesktopManagement | | m_desktops . count ( ) < = 1 ) {
return ;
}
int curPos = m_desktops . indexOf ( m_currentDesktop ) ;
int nextPos = curPos + 1 ;
if ( curPos = = m_desktops . count ( ) - 1 ) {
nextPos = 0 ;
}
KWayland : : Client : : PlasmaVirtualDesktop * desktopObj = m_virtualDesktopManagement - > getVirtualDesktop ( m_desktops [ nextPos ] ) ;
if ( desktopObj ) {
desktopObj - > requestActivate ( ) ;
}
# endif
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : switchToPreviousVirtualDesktop ( )
2019-06-10 17:30:25 +03:00
{
# if KF5_VERSION_MINOR >= 52
if ( ! m_virtualDesktopManagement | | m_desktops . count ( ) < = 1 ) {
return ;
}
int curPos = m_desktops . indexOf ( m_currentDesktop ) ;
int nextPos = curPos - 1 ;
if ( curPos = = 0 ) {
nextPos = m_desktops . count ( ) - 1 ;
}
KWayland : : Client : : PlasmaVirtualDesktop * desktopObj = m_virtualDesktopManagement - > getVirtualDesktop ( m_desktops [ nextPos ] ) ;
if ( desktopObj ) {
desktopObj - > requestActivate ( ) ;
}
# endif
}
2018-01-21 11:53:15 +02:00
void WaylandInterface : : setWindowOnActivities ( QWindow & window , const QStringList & activities )
2018-01-13 12:55:13 +02:00
{
//! needs to updated to wayland case
// KWindowSystem::setOnActivities(view.winId(), activities);
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : removeViewStruts ( QWindow & view )
2017-04-25 17:48:36 +03:00
{
2017-06-29 15:33:12 -05:00
delete m_ghostWindows . take ( view . winId ( ) ) ;
2017-04-25 17:48:36 +03:00
}
2020-03-25 18:40:48 +02:00
WindowId WaylandInterface : : activeWindow ( )
2017-04-25 17:48:36 +03:00
{
2018-03-01 23:53:28 +02:00
if ( ! m_windowManagement ) {
return 0 ;
}
auto wid = m_windowManagement - > activeWindow ( ) ;
2017-06-10 16:33:46 -05:00
return wid ? wid - > internalId ( ) : 0 ;
2017-04-25 17:48:36 +03:00
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : skipTaskBar ( const QDialog & dialog )
2017-04-25 17:48:36 +03:00
{
KWindowSystem : : setState ( dialog . winId ( ) , NET : : SkipTaskbar ) ;
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : slideWindow ( QWindow & view , AbstractWindowInterface : : Slide location )
2017-04-25 17:48:36 +03:00
{
auto slideLocation = KWindowEffects : : NoEdge ;
switch ( location ) {
2019-05-26 00:58:42 +03:00
case Slide : : Top :
slideLocation = KWindowEffects : : TopEdge ;
break ;
2017-04-25 17:48:36 +03:00
2019-05-26 00:58:42 +03:00
case Slide : : Bottom :
slideLocation = KWindowEffects : : BottomEdge ;
break ;
2017-04-25 17:48:36 +03:00
2019-05-26 00:58:42 +03:00
case Slide : : Left :
slideLocation = KWindowEffects : : LeftEdge ;
break ;
2017-04-25 17:48:36 +03:00
2019-05-26 00:58:42 +03:00
case Slide : : Right :
slideLocation = KWindowEffects : : RightEdge ;
break ;
2017-04-25 17:48:36 +03:00
2019-05-26 00:58:42 +03:00
default :
break ;
2017-04-25 17:48:36 +03:00
}
KWindowEffects : : slideWindow ( view . winId ( ) , slideLocation , - 1 ) ;
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : enableBlurBehind ( QWindow & view )
2017-04-25 17:48:36 +03:00
{
KWindowEffects : : enableBlurBehind ( view . winId ( ) ) ;
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : setActiveEdge ( QWindow * view , bool active )
2018-03-28 20:39:52 +03:00
{
2018-12-09 00:15:17 +02:00
ViewPart : : ScreenEdgeGhostWindow * window = qobject_cast < ViewPart : : ScreenEdgeGhostWindow * > ( view ) ;
2018-03-28 20:39:52 +03:00
if ( ! window ) {
return ;
}
2018-12-06 16:09:42 +02:00
if ( window - > parentView ( ) - > surface ( ) & & window - > parentView ( ) - > visibility ( )
2019-05-26 00:58:42 +03:00
& & ( window - > parentView ( ) - > visibility ( ) - > mode ( ) = = Types : : DodgeActive
| | window - > parentView ( ) - > visibility ( ) - > mode ( ) = = Types : : DodgeMaximized
| | window - > parentView ( ) - > visibility ( ) - > mode ( ) = = Types : : DodgeAllWindows
| | window - > parentView ( ) - > visibility ( ) - > mode ( ) = = Types : : AutoHide ) ) {
2018-03-28 20:39:52 +03:00
if ( active ) {
window - > showWithMask ( ) ;
window - > surface ( ) - > requestHideAutoHidingPanel ( ) ;
} else {
window - > hideWithMask ( ) ;
window - > surface ( ) - > requestShowAutoHidingPanel ( ) ;
}
}
}
2020-05-11 17:31:03 +03:00
void WaylandInterface : : setFrameExtents ( QWindow * view , const QMargins & extents )
{
//! do nothing yet until there is a wayland way to provide this
}
2020-03-25 18:40:48 +02:00
WindowInfoWrap WaylandInterface : : requestInfoActive ( )
2017-04-25 17:48:36 +03:00
{
2018-03-01 23:53:28 +02:00
if ( ! m_windowManagement ) {
return { } ;
}
auto w = m_windowManagement - > activeWindow ( ) ;
2017-06-10 16:33:46 -05:00
if ( ! w ) return { } ;
2019-07-23 00:05:01 +03:00
return requestInfo ( w - > internalId ( ) ) ;
2017-04-25 17:48:36 +03:00
}
2020-03-25 18:40:48 +02:00
WindowInfoWrap WaylandInterface : : requestInfo ( WindowId wid )
2017-04-25 17:48:36 +03:00
{
2018-10-28 21:10:08 +02:00
WindowInfoWrap winfoWrap ;
2017-04-25 17:48:36 +03:00
2018-10-28 21:10:08 +02:00
auto w = windowFor ( wid ) ;
2020-02-29 17:57:59 +02:00
if ( w & & isValidWindow ( w ) ) {
winfoWrap . setIsValid ( true ) ;
winfoWrap . setWid ( wid ) ;
winfoWrap . setParentId ( w - > parentWindow ( ) ? w - > parentWindow ( ) - > internalId ( ) : 0 ) ;
winfoWrap . setIsActive ( w - > isActive ( ) ) ;
winfoWrap . setIsMinimized ( w - > isMinimized ( ) ) ;
winfoWrap . setIsMaxVert ( w - > isMaximized ( ) ) ;
winfoWrap . setIsMaxHoriz ( w - > isMaximized ( ) ) ;
winfoWrap . setIsFullscreen ( w - > isFullscreen ( ) ) ;
winfoWrap . setIsShaded ( w - > isShaded ( ) ) ;
winfoWrap . setIsOnAllDesktops ( w - > isOnAllDesktops ( ) ) ;
winfoWrap . setIsOnAllActivities ( true ) ;
winfoWrap . setIsKeepAbove ( w - > isKeepAbove ( ) ) ;
winfoWrap . setIsKeepBelow ( w - > isKeepBelow ( ) ) ;
winfoWrap . setGeometry ( w - > geometry ( ) ) ;
2020-04-07 13:00:45 +03:00
# if KF5_VERSION_MINOR >= 47
winfoWrap . setHasSkipSwitcher ( w - > skipSwitcher ( ) ) ;
# endif
2020-02-29 17:57:59 +02:00
winfoWrap . setHasSkipTaskbar ( w - > skipTaskbar ( ) ) ;
//! BEGIN:Window Abilities
winfoWrap . setIsClosable ( w - > isCloseable ( ) ) ;
winfoWrap . setIsFullScreenable ( w - > isFullscreenable ( ) ) ;
winfoWrap . setIsMaximizable ( w - > isMaximizeable ( ) ) ;
winfoWrap . setIsMinimizable ( w - > isMinimizeable ( ) ) ;
winfoWrap . setIsMovable ( w - > isMovable ( ) ) ;
winfoWrap . setIsResizable ( w - > isResizable ( ) ) ;
winfoWrap . setIsShadeable ( w - > isShadeable ( ) ) ;
winfoWrap . setIsVirtualDesktopsChangeable ( w - > isVirtualDesktopChangeable ( ) ) ;
//! END:Window Abilities
winfoWrap . setDisplay ( w - > title ( ) ) ;
2019-06-08 00:31:30 +03:00
# if KF5_VERSION_MINOR >= 52
2020-02-29 17:57:59 +02:00
winfoWrap . setDesktops ( w - > plasmaVirtualDesktops ( ) ) ;
2019-06-08 00:31:30 +03:00
# endif
2020-02-29 17:57:59 +02:00
winfoWrap . setActivities ( QStringList ( ) ) ;
2018-10-28 21:10:08 +02:00
} else {
2019-07-23 12:05:21 +03:00
winfoWrap . setIsValid ( false ) ;
2018-10-28 21:10:08 +02:00
}
2017-06-29 17:02:25 -05:00
2018-10-28 21:10:08 +02:00
return winfoWrap ;
}
2020-03-25 18:40:48 +02:00
AppData WaylandInterface : : appDataFor ( WindowId wid )
2019-06-01 01:20:54 +03:00
{
auto window = windowFor ( wid ) ;
2019-12-26 22:15:08 +02:00
if ( window ) {
const AppData & data = appDataFromUrl ( windowUrlFromMetadata ( window - > appId ( ) ,
window - > pid ( ) , rulesConfig ) ) ;
return data ;
}
AppData empty ;
2019-06-01 02:43:30 +03:00
2019-12-26 22:15:08 +02:00
return empty ;
2019-06-01 01:20:54 +03:00
}
2020-03-25 18:40:48 +02:00
KWayland : : Client : : PlasmaWindow * WaylandInterface : : windowFor ( WindowId wid )
2018-10-28 21:10:08 +02:00
{
auto it = std : : find_if ( m_windowManagement - > windows ( ) . constBegin ( ) , m_windowManagement - > windows ( ) . constEnd ( ) , [ & wid ] ( PlasmaWindow * w ) noexcept {
2019-05-26 00:58:42 +03:00
return w - > isValid ( ) & & w - > internalId ( ) = = wid ;
} ) ;
2017-12-24 20:54:45 +02:00
2018-10-28 21:10:08 +02:00
if ( it = = m_windowManagement - > windows ( ) . constEnd ( ) ) {
return nullptr ;
2017-06-10 16:33:46 -05:00
}
2017-04-25 17:48:36 +03:00
2018-10-28 21:10:08 +02:00
return * it ;
}
2020-03-25 18:40:48 +02:00
QIcon WaylandInterface : : iconFor ( WindowId wid )
2019-05-27 18:56:24 +03:00
{
auto window = windowFor ( wid ) ;
if ( window ) {
return window - > icon ( ) ;
}
return QIcon ( ) ;
}
2020-03-25 18:40:48 +02:00
WindowId WaylandInterface : : winIdFor ( QString appId , QString title )
2020-03-02 03:10:59 +02:00
{
auto it = std : : find_if ( m_windowManagement - > windows ( ) . constBegin ( ) , m_windowManagement - > windows ( ) . constEnd ( ) , [ & appId , & title ] ( PlasmaWindow * w ) noexcept {
return w - > isValid ( ) & & w - > appId ( ) = = appId & & w - > title ( ) . startsWith ( title ) ;
} ) ;
if ( it = = m_windowManagement - > windows ( ) . constEnd ( ) ) {
return QVariant ( ) ;
}
return ( * it ) - > internalId ( ) ;
}
2020-03-25 18:40:48 +02:00
WindowId WaylandInterface : : winIdFor ( QString appId , QRect geometry )
2019-04-01 23:50:25 +03:00
{
auto it = std : : find_if ( m_windowManagement - > windows ( ) . constBegin ( ) , m_windowManagement - > windows ( ) . constEnd ( ) , [ & appId , & geometry ] ( PlasmaWindow * w ) noexcept {
return w - > isValid ( ) & & w - > appId ( ) = = appId & & w - > geometry ( ) = = geometry ;
} ) ;
if ( it = = m_windowManagement - > windows ( ) . constEnd ( ) ) {
2019-07-15 14:53:40 +03:00
return QVariant ( ) ;
2019-04-01 23:50:25 +03:00
}
return ( * it ) - > internalId ( ) ;
}
2020-03-25 18:40:48 +02:00
bool WaylandInterface : : windowCanBeDragged ( WindowId wid )
2018-10-28 21:10:08 +02:00
{
2019-07-31 16:34:05 +03:00
auto w = windowFor ( wid ) ;
if ( w & & isValidWindow ( w ) ) {
WindowInfoWrap winfo = requestInfo ( wid ) ;
return ( winfo . isValid ( )
& & w - > isMovable ( )
& & ! winfo . isMinimized ( )
2020-02-29 17:57:59 +02:00
& & inCurrentDesktopActivity ( winfo ) ) ;
2019-07-31 16:34:05 +03:00
}
return false ;
2017-04-25 17:48:36 +03:00
}
2020-03-25 18:40:48 +02:00
bool WaylandInterface : : windowCanBeMaximized ( WindowId wid )
2019-07-31 16:44:43 +03:00
{
auto w = windowFor ( wid ) ;
if ( w & & isValidWindow ( w ) ) {
WindowInfoWrap winfo = requestInfo ( wid ) ;
return ( winfo . isValid ( )
& & w - > isMaximizeable ( )
& & ! winfo . isMinimized ( )
2020-02-29 17:57:59 +02:00
& & inCurrentDesktopActivity ( winfo ) ) ;
2019-07-31 16:44:43 +03:00
}
return false ;
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : requestActivate ( WindowId wid )
2019-04-01 23:50:25 +03:00
{
auto w = windowFor ( wid ) ;
if ( w ) {
w - > requestActivate ( ) ;
}
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : requestClose ( WindowId wid )
2019-06-02 01:07:47 +03:00
{
auto w = windowFor ( wid ) ;
if ( w ) {
w - > requestClose ( ) ;
}
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : requestMoveWindow ( WindowId wid , QPoint from )
2018-10-28 10:03:22 +02:00
{
2019-11-13 14:23:43 +02:00
WindowInfoWrap wInfo = requestInfo ( wid ) ;
if ( windowCanBeDragged ( wid ) & & inCurrentDesktopActivity ( wInfo ) ) {
2018-10-28 21:10:08 +02:00
auto w = windowFor ( wid ) ;
if ( w & & isValidWindow ( w ) ) {
w - > requestMove ( ) ;
}
}
2018-10-28 10:03:22 +02:00
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : requestToggleIsOnAllDesktops ( WindowId wid )
2019-06-02 01:57:03 +03:00
{
# if KF5_VERSION_MINOR >= 52
auto w = windowFor ( wid ) ;
if ( w & & isValidWindow ( w ) & & m_desktops . count ( ) > 1 ) {
if ( w - > isOnAllDesktops ( ) ) {
w - > requestEnterVirtualDesktop ( m_currentDesktop ) ;
} else {
const QStringList & now = w - > plasmaVirtualDesktops ( ) ;
foreach ( const QString & desktop , now ) {
w - > requestLeaveVirtualDesktop ( desktop ) ;
}
}
}
# endif
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : requestToggleKeepAbove ( WindowId wid )
2019-06-02 01:07:47 +03:00
{
auto w = windowFor ( wid ) ;
if ( w ) {
w - > requestToggleKeepAbove ( ) ;
}
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : setKeepAbove ( WindowId wid , bool active )
2019-12-26 16:53:37 +02:00
{
auto w = windowFor ( wid ) ;
if ( w ) {
2019-12-26 21:10:11 +02:00
if ( active ) {
setKeepBelow ( wid , false ) ;
}
2019-12-26 16:53:37 +02:00
if ( ( w - > isKeepAbove ( ) & & active ) | | ( ! w - > isKeepAbove ( ) & & ! active ) ) {
return ;
}
w - > requestToggleKeepAbove ( ) ;
}
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : setKeepBelow ( WindowId wid , bool active )
2019-12-26 16:53:37 +02:00
{
auto w = windowFor ( wid ) ;
if ( w ) {
2019-12-26 21:10:11 +02:00
if ( active ) {
setKeepAbove ( wid , false ) ;
}
2019-12-26 16:53:37 +02:00
if ( ( w - > isKeepBelow ( ) & & active ) | | ( ! w - > isKeepBelow ( ) & & ! active ) ) {
return ;
}
w - > requestToggleKeepBelow ( ) ;
}
}
2020-03-25 18:40:48 +02:00
void WaylandInterface : : requestToggleMinimized ( WindowId wid )
2018-10-28 10:03:22 +02:00
{
2018-10-28 21:10:08 +02:00
auto w = windowFor ( wid ) ;
2019-11-13 14:23:43 +02:00
WindowInfoWrap wInfo = requestInfo ( wid ) ;
2018-10-28 21:10:08 +02:00
2019-11-13 14:23:43 +02:00
if ( w & & isValidWindow ( w ) & & inCurrentDesktopActivity ( wInfo ) ) {
2019-06-02 01:07:47 +03:00
# if KF5_VERSION_MINOR >= 52
if ( ! m_currentDesktop . isEmpty ( ) ) {
w - > requestEnterVirtualDesktop ( m_currentDesktop ) ;
}
# endif
w - > requestToggleMinimized ( ) ;
2018-10-28 21:10:08 +02:00
}
2018-10-28 10:03:22 +02:00
}
2017-04-25 17:48:36 +03:00
2020-03-25 18:40:48 +02:00
void WaylandInterface : : requestToggleMaximized ( WindowId wid )
2019-06-02 01:07:47 +03:00
{
auto w = windowFor ( wid ) ;
2019-11-13 14:23:43 +02:00
WindowInfoWrap wInfo = requestInfo ( wid ) ;
2019-06-02 01:07:47 +03:00
2019-11-13 14:23:43 +02:00
if ( w & & isValidWindow ( w ) & & windowCanBeMaximized ( wid ) & & inCurrentDesktopActivity ( wInfo ) ) {
2019-06-02 01:07:47 +03:00
# if KF5_VERSION_MINOR >= 52
if ( ! m_currentDesktop . isEmpty ( ) ) {
w - > requestEnterVirtualDesktop ( m_currentDesktop ) ;
}
# endif
w - > requestToggleMaximized ( ) ;
2019-07-15 19:15:53 +03:00
}
2019-06-02 01:07:47 +03:00
}
2020-02-29 17:57:59 +02:00
bool WaylandInterface : : isPlasmaPanel ( const KWayland : : Client : : PlasmaWindow * w ) const
2019-02-11 19:40:24 +02:00
{
if ( ! w | | ( w - > appId ( ) ! = QLatin1String ( " org.kde.plasmashell " ) ) ) {
return false ;
}
2020-02-29 17:57:59 +02:00
return AbstractWindowInterface : : isPlasmaPanel ( w - > geometry ( ) ) ;
2019-11-02 10:45:37 +02:00
}
2019-02-11 19:40:24 +02:00
2020-02-29 17:57:59 +02:00
bool WaylandInterface : : isFullScreenWindow ( const KWayland : : Client : : PlasmaWindow * w ) const
2019-11-02 10:45:37 +02:00
{
2020-02-29 17:57:59 +02:00
if ( ! w ) {
2019-11-02 10:45:37 +02:00
return false ;
2019-02-11 19:40:24 +02:00
}
2020-02-29 17:57:59 +02:00
return w - > isFullscreen ( ) | | AbstractWindowInterface : : isFullScreenWindow ( w - > geometry ( ) ) ;
2019-02-11 19:40:24 +02:00
}
2020-03-25 18:40:48 +02:00
bool WaylandInterface : : isSidepanel ( const KWayland : : Client : : PlasmaWindow * w ) const
2017-04-25 17:48:36 +03:00
{
2020-03-25 18:40:48 +02:00
if ( ! w ) {
return false ;
}
return AbstractWindowInterface : : isSidepanel ( w - > geometry ( ) ) ;
}
bool WaylandInterface : : isValidWindow ( const KWayland : : Client : : PlasmaWindow * w )
{
if ( ! w | | ! w - > isValid ( ) ) {
return false ;
}
2019-02-11 19:40:24 +02:00
2020-03-25 18:40:48 +02:00
if ( windowsTracker ( ) - > isValidFor ( w - > internalId ( ) ) ) {
return true ;
}
return isAcceptableWindow ( w ) ;
}
bool WaylandInterface : : isAcceptableWindow ( const KWayland : : Client : : PlasmaWindow * w )
{
if ( ! w | | ! w - > isValid ( ) ) {
return false ;
}
//! ignored windows that are not tracked
if ( hasBlockedTracking ( w - > internalId ( ) ) ) {
return false ;
}
//! whitelisted/approved windows
if ( isWhitelistedWindow ( w - > internalId ( ) ) ) {
return true ;
}
//! Window Checks
2020-03-25 15:03:19 +02:00
bool hasSkipTaskbar = w - > skipTaskbar ( ) ;
2020-04-05 10:42:00 +03:00
bool isSkipped = hasSkipTaskbar ;
# if KF5_VERSION_MINOR >= 47
2020-03-25 15:03:19 +02:00
bool hasSkipSwitcher = w - > skipSwitcher ( ) ;
2020-04-05 10:42:00 +03:00
isSkipped = hasSkipTaskbar & & hasSkipSwitcher ;
# endif
2020-03-25 15:03:19 +02:00
2020-03-26 14:16:04 +02:00
if ( isSkipped
& & ( ( w - > appId ( ) = = QLatin1String ( " yakuake " )
| | ( w - > appId ( ) = = QLatin1String ( " krunner " ) ) ) ) ) {
registerWhitelistedWindow ( w - > internalId ( ) ) ;
} else if ( w - > appId ( ) = = QLatin1String ( " org.kde.plasmashell " ) ) {
2020-03-25 18:40:48 +02:00
if ( isSkipped & & isSidepanel ( w ) ) {
registerWhitelistedWindow ( w - > internalId ( ) ) ;
return true ;
} else if ( isPlasmaPanel ( w ) | | isFullScreenWindow ( w ) ) {
registerPlasmaIgnoredWindow ( w - > internalId ( ) ) ;
return false ;
}
} else if ( ( w - > appId ( ) = = QLatin1String ( " latte-dock " ) )
| | ( w - > appId ( ) . startsWith ( QLatin1String ( " ksmserver " ) ) ) ) {
if ( isFullScreenWindow ( w ) ) {
registerIgnoredWindow ( w - > internalId ( ) ) ;
return false ;
}
}
return ! isSkipped ;
2017-04-25 17:48:36 +03:00
}
2019-12-22 13:36:51 +02:00
void WaylandInterface : : updateWindow ( )
2017-04-25 17:48:36 +03:00
{
2019-12-22 13:36:51 +02:00
PlasmaWindow * pW = qobject_cast < PlasmaWindow * > ( QObject : : sender ( ) ) ;
2017-04-25 17:48:36 +03:00
2020-03-25 18:40:48 +02:00
if ( isValidWindow ( pW ) ) {
2019-12-22 13:36:51 +02:00
considerWindowChanged ( pW - > internalId ( ) ) ;
}
}
2017-04-25 17:48:36 +03:00
2019-12-22 13:36:51 +02:00
void WaylandInterface : : windowUnmapped ( )
{
PlasmaWindow * pW = qobject_cast < PlasmaWindow * > ( QObject : : sender ( ) ) ;
2017-06-10 16:33:46 -05:00
2019-12-22 13:36:51 +02:00
if ( pW ) {
untrackWindow ( pW ) ;
emit windowRemoved ( pW - > internalId ( ) ) ;
}
}
void WaylandInterface : : trackWindow ( KWayland : : Client : : PlasmaWindow * w )
{
if ( ! w ) {
return ;
}
connect ( w , & PlasmaWindow : : activeChanged , this , & WaylandInterface : : updateWindow ) ;
connect ( w , & PlasmaWindow : : titleChanged , this , & WaylandInterface : : updateWindow ) ;
connect ( w , & PlasmaWindow : : fullscreenChanged , this , & WaylandInterface : : updateWindow ) ;
connect ( w , & PlasmaWindow : : geometryChanged , this , & WaylandInterface : : updateWindow ) ;
connect ( w , & PlasmaWindow : : maximizedChanged , this , & WaylandInterface : : updateWindow ) ;
connect ( w , & PlasmaWindow : : minimizedChanged , this , & WaylandInterface : : updateWindow ) ;
connect ( w , & PlasmaWindow : : shadedChanged , this , & WaylandInterface : : updateWindow ) ;
connect ( w , & PlasmaWindow : : skipTaskbarChanged , this , & WaylandInterface : : updateWindow ) ;
connect ( w , & PlasmaWindow : : onAllDesktopsChanged , this , & WaylandInterface : : updateWindow ) ;
connect ( w , & PlasmaWindow : : parentWindowChanged , this , & WaylandInterface : : updateWindow ) ;
2019-05-26 00:58:42 +03:00
# if KF5_VERSION_MINOR >= 52
2019-12-22 13:36:51 +02:00
connect ( w , & PlasmaWindow : : plasmaVirtualDesktopEntered , this , & WaylandInterface : : updateWindow ) ;
connect ( w , & PlasmaWindow : : plasmaVirtualDesktopLeft , this , & WaylandInterface : : updateWindow ) ;
# else
connect ( w , & PlasmaWindow : : virtualDesktopChanged , this , & WaylandInterface : : updateWindow ) ;
# endif
2019-05-26 00:58:42 +03:00
2019-12-22 13:36:51 +02:00
connect ( w , & PlasmaWindow : : unmapped , this , & WaylandInterface : : windowUnmapped ) ;
}
void WaylandInterface : : untrackWindow ( KWayland : : Client : : PlasmaWindow * w )
{
if ( ! w ) {
return ;
}
disconnect ( w , & PlasmaWindow : : activeChanged , this , & WaylandInterface : : updateWindow ) ;
disconnect ( w , & PlasmaWindow : : titleChanged , this , & WaylandInterface : : updateWindow ) ;
disconnect ( w , & PlasmaWindow : : fullscreenChanged , this , & WaylandInterface : : updateWindow ) ;
disconnect ( w , & PlasmaWindow : : geometryChanged , this , & WaylandInterface : : updateWindow ) ;
disconnect ( w , & PlasmaWindow : : maximizedChanged , this , & WaylandInterface : : updateWindow ) ;
disconnect ( w , & PlasmaWindow : : minimizedChanged , this , & WaylandInterface : : updateWindow ) ;
disconnect ( w , & PlasmaWindow : : shadedChanged , this , & WaylandInterface : : updateWindow ) ;
disconnect ( w , & PlasmaWindow : : skipTaskbarChanged , this , & WaylandInterface : : updateWindow ) ;
disconnect ( w , & PlasmaWindow : : onAllDesktopsChanged , this , & WaylandInterface : : updateWindow ) ;
disconnect ( w , & PlasmaWindow : : parentWindowChanged , this , & WaylandInterface : : updateWindow ) ;
# if KF5_VERSION_MINOR >= 52
disconnect ( w , & PlasmaWindow : : plasmaVirtualDesktopEntered , this , & WaylandInterface : : updateWindow ) ;
disconnect ( w , & PlasmaWindow : : plasmaVirtualDesktopLeft , this , & WaylandInterface : : updateWindow ) ;
# else
disconnect ( w , & PlasmaWindow : : virtualDesktopChanged , this , & WaylandInterface : : updateWindow ) ;
2019-05-26 00:58:42 +03:00
# endif
2017-06-10 16:33:46 -05:00
2019-12-22 13:36:51 +02:00
disconnect ( w , & PlasmaWindow : : unmapped , this , & WaylandInterface : : windowUnmapped ) ;
}
2019-11-02 10:45:37 +02:00
2017-04-25 17:48:36 +03:00
2019-12-22 13:36:51 +02:00
void WaylandInterface : : windowCreatedProxy ( KWayland : : Client : : PlasmaWindow * w )
{
2020-03-25 18:40:48 +02:00
if ( ! isAcceptableWindow ( w ) ) {
2019-12-22 13:36:51 +02:00
return ;
2019-11-02 10:45:37 +02:00
}
2020-02-29 17:57:59 +02:00
trackWindow ( w ) ;
emit windowAdded ( w - > internalId ( ) ) ;
2019-07-15 19:15:53 +03:00
if ( w - > appId ( ) = = " latte-dock " ) {
emit latteWindowAdded ( ) ;
}
2017-04-25 17:48:36 +03:00
}
2019-05-11 15:43:10 +03:00
}
2017-04-25 17:48:36 +03:00
}
2017-06-29 15:34:36 -05:00
# include "waylandinterface.moc"