2020-11-07 02:03:57 +00:00
/*
KWin - the KDE window manager
This file is part of the KDE project .
SPDX - FileCopyrightText : 2020 Aleix Pol Gonzalez < aleixpol @ kde . org >
SPDX - License - Identifier : GPL - 2.0 - or - later
*/
# include "xdgactivationv1.h"
# include "effects.h"
2022-01-18 08:35:52 +00:00
# include "utils/common.h"
2022-04-22 09:27:33 +00:00
# include "wayland/display.h"
# include "wayland/plasmawindowmanagement_interface.h"
# include "wayland/surface_interface.h"
# include "wayland/xdgactivation_v1_interface.h"
2020-11-07 02:03:57 +00:00
# include "wayland_server.h"
2022-04-22 17:39:12 +00:00
# include "window.h"
2020-11-07 02:03:57 +00:00
# include "workspace.h"
2022-05-17 17:14:09 +00:00
# include <KDesktopFile>
2020-11-07 02:03:57 +00:00
using namespace KWaylandServer ;
namespace KWin
{
2021-06-14 15:48:00 +00:00
static bool isPrivilegedInWindowManagement ( const ClientConnection * client )
{
2022-05-16 14:58:53 +00:00
Q_ASSERT ( client ) ;
2021-06-14 15:48:00 +00:00
auto requestedInterfaces = client - > property ( " requestedInterfaces " ) . toStringList ( ) ;
return requestedInterfaces . contains ( QLatin1String ( " org_kde_plasma_window_management " ) ) ;
}
2020-11-07 02:03:57 +00:00
XdgActivationV1Integration : : XdgActivationV1Integration ( XdgActivationV1Interface * activation , QObject * parent )
: QObject ( parent )
{
Workspace * ws = Workspace : : self ( ) ;
2022-04-23 08:33:23 +00:00
connect ( ws , & Workspace : : windowActivated , this , [ this ] ( Window * window ) {
if ( ! m_currentActivationToken | | ! window | | window - > property ( " token " ) . toString ( ) = = m_currentActivationToken - > token ) {
2020-11-07 02:03:57 +00:00
return ;
}
2022-05-05 00:19:24 +00:00
// We check that it's not the app that we are trying to activate
if ( window - > desktopFileName ( ) ! = m_currentActivationToken - > applicationId ) {
// But also that the new one has been requested after the token was requested
if ( window - > lastUsageSerial ( ) < m_currentActivationToken - > serial ) {
return ;
}
}
2020-11-07 02:03:57 +00:00
clear ( ) ;
} ) ;
2021-06-14 15:48:00 +00:00
activation - > setActivationTokenCreator ( [ this ] ( ClientConnection * client , SurfaceInterface * surface , uint serial , SeatInterface * seat , const QString & appId ) - > QString {
2020-11-07 02:03:57 +00:00
Workspace * ws = Workspace : : self ( ) ;
2022-05-16 14:58:53 +00:00
Q_ASSERT ( client ) ; // Should always be available as it's coming straight from the wayland implementation
const bool isPrivileged = isPrivilegedInWindowManagement ( client ) ;
if ( ! isPrivileged & & ws - > activeWindow ( ) & & ws - > activeWindow ( ) - > surface ( ) ! = surface ) {
2021-06-14 15:48:00 +00:00
qCWarning ( KWIN_CORE ) < < " Cannot grant a token to " < < client ;
return QStringLiteral ( " not-granted-666 " ) ;
2020-11-07 02:03:57 +00:00
}
2022-05-16 14:58:53 +00:00
return requestToken ( isPrivileged , surface , serial , seat , appId ) ;
2020-11-07 02:03:57 +00:00
} ) ;
connect ( activation , & XdgActivationV1Interface : : activateRequested , this , & XdgActivationV1Integration : : activateSurface ) ;
}
2022-05-16 14:58:53 +00:00
QString XdgActivationV1Integration : : requestToken ( bool isPrivileged , SurfaceInterface * surface , uint serial , SeatInterface * seat , const QString & appId )
{
static int i = 0 ;
const auto newToken = QStringLiteral ( " kwin-%1 " ) . arg ( + + i ) ;
if ( m_currentActivationToken ) {
clear ( ) ;
}
2022-05-17 17:14:09 +00:00
bool showNotify = false ;
QIcon icon ;
if ( const QString desktopFilePath = Window : : findDesktopFile ( appId ) ; ! desktopFilePath . isEmpty ( ) ) {
KDesktopFile df ( desktopFilePath ) ;
2022-07-01 13:07:12 +00:00
Window * window = Workspace : : self ( ) - > activeWindow ( ) ;
showNotify = ( ! window | | appId ! = window - > desktopFileName ( ) )
& & ( df . desktopGroup ( ) . readEntry ( " StartupNotify " , true ) | | df . desktopGroup ( ) . readEntry ( " X-KDE-StartupNotify " , true ) ) ;
2022-05-17 17:14:09 +00:00
icon = QIcon : : fromTheme ( df . readIcon ( ) , QIcon : : fromTheme ( QStringLiteral ( " system-run " ) ) ) ;
}
2022-05-17 10:36:34 +00:00
m_currentActivationToken . reset ( new ActivationToken { newToken , isPrivileged , surface , serial , seat , appId , showNotify , waylandServer ( ) - > plasmaActivationFeedback ( ) - > createActivation ( appId ) } ) ;
2022-05-17 17:14:09 +00:00
if ( showNotify ) {
2022-05-16 14:58:53 +00:00
const auto icon = QIcon : : fromTheme ( Window : : iconFromDesktopFile ( appId ) , QIcon : : fromTheme ( QStringLiteral ( " system-run " ) ) ) ;
Q_EMIT effects - > startupAdded ( m_currentActivationToken - > token , icon ) ;
}
return newToken ;
}
2020-11-07 02:03:57 +00:00
void XdgActivationV1Integration : : activateSurface ( SurfaceInterface * surface , const QString & token )
{
Workspace * ws = Workspace : : self ( ) ;
2022-04-23 08:33:23 +00:00
auto window = waylandServer ( ) - > findWindow ( surface ) ;
if ( ! window ) {
2020-11-07 02:03:57 +00:00
qCWarning ( KWIN_CORE ) < < " could not find the toplevel to activate " < < surface ;
return ;
}
if ( ! m_currentActivationToken | | m_currentActivationToken - > token ! = token ) {
2022-04-23 08:33:23 +00:00
qCDebug ( KWIN_CORE ) < < " Refusing to activate " < < window < < " (provided token: " < < token < < " , current token: " < < ( m_currentActivationToken ? m_currentActivationToken - > token : QStringLiteral ( " null " ) ) < < " ) " ;
window - > demandAttention ( ) ;
2020-11-07 02:03:57 +00:00
return ;
}
2022-04-23 08:33:23 +00:00
auto ownerWindow = waylandServer ( ) - > findWindow ( m_currentActivationToken - > surface ) ;
qCDebug ( KWIN_CORE ) < < " activating " < < window < < surface < < " on behalf of " < < m_currentActivationToken - > surface < < " into " < < ownerWindow ;
2022-05-16 14:58:53 +00:00
if ( ws - > activeWindow ( ) = = ownerWindow | | ws - > activeWindow ( ) - > lastUsageSerial ( ) < m_currentActivationToken - > serial | | m_currentActivationToken - > isPrivileged ) {
2022-04-23 08:33:23 +00:00
ws - > activateWindow ( window ) ;
2020-11-07 02:03:57 +00:00
} else {
2022-05-05 00:19:24 +00:00
qCWarning ( KWIN_CORE ) < < " Activation requested while owner isn't active " < < ( ownerWindow ? ownerWindow - > desktopFileName ( ) : " null " )
2022-03-23 10:13:38 +00:00
< < m_currentActivationToken - > applicationId ;
2022-04-23 08:33:23 +00:00
window - > demandAttention ( ) ;
2020-11-07 02:03:57 +00:00
clear ( ) ;
}
}
void XdgActivationV1Integration : : clear ( )
{
Q_ASSERT ( m_currentActivationToken ) ;
2022-05-17 17:14:09 +00:00
if ( m_currentActivationToken - > showNotify ) {
2021-06-17 00:01:03 +00:00
Q_EMIT effects - > startupRemoved ( m_currentActivationToken - > token ) ;
}
2020-11-07 02:03:57 +00:00
m_currentActivationToken . reset ( ) ;
}
}