26#include <config-kwin.h> 
   38#if KWIN_BUILD_ACTIVITIES 
   40#include <PlasmaActivities/Info> 
   50#include <KGlobalAccel> 
   51#include <KLazyLocalizedString> 
   52#include <KLocalizedString> 
   54#include <QActionGroup> 
   56#include <QRegularExpression> 
   57#include <kauthorized.h> 
   71    , m_desktopMenu(nullptr)
 
   72    , m_multipleDesktopsMenu(nullptr)
 
   73    , m_screenMenu(nullptr)
 
   74    , m_activityMenu(nullptr)
 
   75    , m_scriptsMenu(nullptr)
 
   76    , m_resizeOperation(nullptr)
 
   77    , m_moveOperation(nullptr)
 
   78    , m_maximizeOperation(nullptr)
 
   79    , m_shadeOperation(nullptr)
 
   80    , m_keepAboveOperation(nullptr)
 
   81    , m_keepBelowOperation(nullptr)
 
   82    , m_fullScreenOperation(nullptr)
 
   83    , m_noBorderOperation(nullptr)
 
   84    , m_minimizeOperation(nullptr)
 
   85    , m_closeOperation(nullptr)
 
   86    , m_shortcutOperation(nullptr)
 
 
   97    return m_menu && m_menu->isVisible();
 
 
  115    return window && window == m_window;
 
 
  121    QPointer<Window> windowPtr(window);
 
  124    if (windowPtr.isNull()) {
 
  130    if (windowPtr->isDesktop() || windowPtr->isDock()) {
 
  133    if (!KAuthorized::authorizeAction(QStringLiteral(
"kwin_rmb"))) {
 
  136    m_window = windowPtr;
 
  138    m_menu->popup(pos.bottomLeft());
 
 
  143    m_menu->windowHandle()->setMouseGrabEnabled(
true);
 
  144    m_menu->windowHandle()->setKeyboardGrabEnabled(
true);
 
 
  147void UserActionsMenu::helperDialog(
const QString &message)
 
  151    auto shortcut = [](
const QString &name) {
 
  153        Q_ASSERT(action != 
nullptr);
 
  154        const auto shortcuts = KGlobalAccel::self()->shortcut(action);
 
  155        return QStringLiteral(
"%1 (%2)").arg(action->text(), shortcuts.isEmpty() ? QString() : shortcuts.first().toString(QKeySequence::NativeText));
 
  157    if (message == QStringLiteral(
"noborderaltf3")) {
 
  158        args << QStringLiteral(
"--msgbox") << i18n(
"You have selected to show a window without its border.\n" 
  159                                                   "Without the border, you will not be able to enable the border " 
  160                                                   "again using the mouse: use the window operations menu instead, " 
  161                                                   "activated using the %1 keyboard shortcut.",
 
  162                                                   shortcut(QStringLiteral(
"Window Operations Menu")));
 
  163        type = QStringLiteral(
"altf3warning");
 
  164    } 
else if (message == QLatin1String(
"fullscreenaltf3")) {
 
  165        args << QStringLiteral(
"--msgbox") << i18n(
"You have selected to show a window in fullscreen mode.\n" 
  166                                                   "If the application itself does not have an option to turn the fullscreen " 
  167                                                   "mode off you will not be able to disable it " 
  168                                                   "again using the mouse: use the window operations menu instead, " 
  169                                                   "activated using the %1 keyboard shortcut.",
 
  170                                                   shortcut(QStringLiteral(
"Window Operations Menu")));
 
  171        type = QStringLiteral(
"altf3warning");
 
  175    if (!
type.isEmpty()) {
 
  176        KConfig cfg(QStringLiteral(
"kwin_dialogsrc"));
 
  177        KConfigGroup cg(&cfg, QStringLiteral(
"Notification Messages")); 
 
  178        if (!cg.readEntry(
type, 
true)) {
 
  181        args << QStringLiteral(
"--dontagain") << QLatin1String(
"kwin_dialogsrc:") + 
type;
 
  183    KProcess::startDetached(QStringLiteral(
"kdialog"), args);
 
  186void UserActionsMenu::init()
 
  192    connect(m_menu, &QMenu::aboutToShow, 
this, &UserActionsMenu::menuAboutToShow);
 
  195    connect(m_menu, &QMenu::aboutToHide, 
this, &UserActionsMenu::menuAboutToHide, Qt::QueuedConnection);
 
  196    connect(m_menu, &QMenu::triggered, 
this, &UserActionsMenu::slotWindowOperation);
 
  198    QMenu *advancedMenu = 
new QMenu(m_menu);
 
  199    connect(advancedMenu, &QMenu::aboutToShow, 
this, [
this, advancedMenu]() {
 
  201            advancedMenu->setPalette(m_window->palette());
 
  205    auto setShortcut = [](QAction *action, 
const QString &actionName) {
 
  206        const auto shortcuts = KGlobalAccel::self()->shortcut(
Workspace::self()->findChild<QAction *>(actionName));
 
  207        if (!shortcuts.isEmpty()) {
 
  208            action->setShortcut(shortcuts.first());
 
  212    m_moveOperation = advancedMenu->addAction(i18n(
"&Move"));
 
  213    m_moveOperation->setIcon(QIcon::fromTheme(QStringLiteral(
"transform-move")));
 
  214    setShortcut(m_moveOperation, QStringLiteral(
"Window Move"));
 
  217    m_resizeOperation = advancedMenu->addAction(i18n(
"&Resize"));
 
  218    m_resizeOperation->setIcon(QIcon::fromTheme(QStringLiteral(
"transform-scale")));
 
  219    setShortcut(m_resizeOperation, QStringLiteral(
"Window Resize"));
 
  222    m_keepAboveOperation = advancedMenu->addAction(i18n(
"Keep &Above Others"));
 
  223    m_keepAboveOperation->setIcon(QIcon::fromTheme(QStringLiteral(
"window-keep-above")));
 
  224    setShortcut(m_keepAboveOperation, QStringLiteral(
"Window Above Other Windows"));
 
  225    m_keepAboveOperation->setCheckable(
true);
 
  228    m_keepBelowOperation = advancedMenu->addAction(i18n(
"Keep &Below Others"));
 
  229    m_keepBelowOperation->setIcon(QIcon::fromTheme(QStringLiteral(
"window-keep-below")));
 
  230    setShortcut(m_keepBelowOperation, QStringLiteral(
"Window Below Other Windows"));
 
  231    m_keepBelowOperation->setCheckable(
true);
 
  234    m_fullScreenOperation = advancedMenu->addAction(i18n(
"&Fullscreen"));
 
  235    m_fullScreenOperation->setIcon(QIcon::fromTheme(QStringLiteral(
"view-fullscreen")));
 
  236    setShortcut(m_fullScreenOperation, QStringLiteral(
"Window Fullscreen"));
 
  237    m_fullScreenOperation->setCheckable(
true);
 
  240    m_shadeOperation = advancedMenu->addAction(i18n(
"&Shade"));
 
  241    m_shadeOperation->setIcon(QIcon::fromTheme(QStringLiteral(
"window-shade")));
 
  242    setShortcut(m_shadeOperation, QStringLiteral(
"Window Shade"));
 
  243    m_shadeOperation->setCheckable(
true);
 
  246    m_noBorderOperation = advancedMenu->addAction(i18n(
"&No Titlebar and Frame"));
 
  247    m_noBorderOperation->setIcon(QIcon::fromTheme(QStringLiteral(
"edit-none-border")));
 
  248    setShortcut(m_noBorderOperation, QStringLiteral(
"Window No Border"));
 
  249    m_noBorderOperation->setCheckable(
true);
 
  252    advancedMenu->addSeparator();
 
  254    m_shortcutOperation = advancedMenu->addAction(i18n(
"Set Window Short&cut…"));
 
  255    m_shortcutOperation->setIcon(QIcon::fromTheme(QStringLiteral(
"configure-shortcuts")));
 
  256    setShortcut(m_shortcutOperation, QStringLiteral(
"Setup Window Shortcut"));
 
  260    QAction *action = advancedMenu->addAction(i18n(
"Configure Special &Window Settings…"));
 
  261    action->setIcon(QIcon::fromTheme(QStringLiteral(
"preferences-system-windows-actions")));
 
  263    m_rulesOperation = action;
 
  265    action = advancedMenu->addAction(i18n(
"Configure S&pecial Application Settings…"));
 
  266    action->setIcon(QIcon::fromTheme(QStringLiteral(
"preferences-system-windows-actions")));
 
  268    m_applicationRulesOperation = action;
 
  271    m_maximizeOperation = m_menu->addAction(i18n(
"Ma&ximize"));
 
  272    m_maximizeOperation->setIcon(QIcon::fromTheme(QStringLiteral(
"window-maximize")));
 
  273    setShortcut(m_maximizeOperation, QStringLiteral(
"Window Maximize"));
 
  274    m_maximizeOperation->setCheckable(
true);
 
  277    m_minimizeOperation = m_menu->addAction(i18n(
"Mi&nimize"));
 
  278    m_minimizeOperation->setIcon(QIcon::fromTheme(QStringLiteral(
"window-minimize")));
 
  279    setShortcut(m_minimizeOperation, QStringLiteral(
"Window Minimize"));
 
  282    QAction *overflowAction = m_menu->addMenu(advancedMenu);
 
  283    overflowAction->setText(i18n(
"&More Actions"));
 
  284    overflowAction->setIcon(QIcon::fromTheme(QStringLiteral(
"overflow-menu")));
 
  286    m_menu->addSeparator();
 
  288    m_closeOperation = m_menu->addAction(i18n(
"&Close"));
 
  289    m_closeOperation->setIcon(QIcon::fromTheme(QStringLiteral(
"window-close")));
 
  290    setShortcut(m_closeOperation, QStringLiteral(
"Window Close"));
 
  298    m_desktopMenu = 
nullptr;
 
  299    m_multipleDesktopsMenu = 
nullptr;
 
  300    m_screenMenu = 
nullptr;
 
  301    m_activityMenu = 
nullptr;
 
  302    m_scriptsMenu = 
nullptr;
 
 
  305void UserActionsMenu::menuAboutToShow()
 
  307    if (m_window.isNull() || !m_menu) {
 
  311    m_window->blockActivityUpdates(
true);
 
  313    if (VirtualDesktopManager::self()->count() == 1) {
 
  314        delete m_desktopMenu;
 
  315        m_desktopMenu = 
nullptr;
 
  316        delete m_multipleDesktopsMenu;
 
  317        m_multipleDesktopsMenu = 
nullptr;
 
  321    if (
workspace()->
outputs().count() == 1 || (!m_window->isMovable() && !m_window->isMovableAcrossScreens())) {
 
  323        m_screenMenu = 
nullptr;
 
  328    m_menu->setPalette(m_window->palette());
 
  329    m_resizeOperation->setEnabled(m_window->isResizable());
 
  330    m_moveOperation->setEnabled(m_window->isMovableAcrossScreens());
 
  331    m_maximizeOperation->setEnabled(m_window->isMaximizable());
 
  332    m_maximizeOperation->setChecked(m_window->maximizeMode() == 
MaximizeFull);
 
  333    m_shadeOperation->setEnabled(m_window->isShadeable());
 
  334    m_shadeOperation->setChecked(m_window->shadeMode() != 
ShadeNone);
 
  335    m_keepAboveOperation->setChecked(m_window->keepAbove());
 
  336    m_keepBelowOperation->setChecked(m_window->keepBelow());
 
  337    m_fullScreenOperation->setEnabled(m_window->isFullScreenable());
 
  338    m_fullScreenOperation->setChecked(m_window->isFullScreen());
 
  339    m_noBorderOperation->setEnabled(m_window->userCanSetNoBorder());
 
  340    m_noBorderOperation->setChecked(m_window->noBorder());
 
  341    m_minimizeOperation->setEnabled(m_window->isMinimizable());
 
  342    m_closeOperation->setEnabled(m_window->isCloseable());
 
  343    m_shortcutOperation->setEnabled(m_window->rules()->checkShortcut(QString()).isNull());
 
  346    delete m_scriptsMenu;
 
  347    m_scriptsMenu = 
nullptr;
 
  350    if (!scriptActions.isEmpty()) {
 
  351        m_scriptsMenu = 
new QMenu(m_menu);
 
  352        m_scriptsMenu->setPalette(m_window->palette());
 
  353        m_scriptsMenu->addActions(scriptActions);
 
  355        QAction *action = m_scriptsMenu->menuAction();
 
  357        m_menu->insertAction(m_closeOperation, action);
 
  358        action->setText(i18n(
"&Extensions"));
 
  361    if (m_rulesOperation) {
 
  362        m_rulesOperation->setEnabled(m_window->supportsWindowRules());
 
  364    if (m_applicationRulesOperation) {
 
  365        m_applicationRulesOperation->setEnabled(m_window->supportsWindowRules());
 
  371void UserActionsMenu::menuAboutToHide()
 
  374        m_window->blockActivityUpdates(
false);
 
  381#if KWIN_BUILD_ACTIVITIES 
  385    const QStringList &openActivities_ = 
Workspace::self()->activities()->running();
 
  386    qCDebug(KWIN_CORE) << 
"activities:" << openActivities_.size();
 
  387    if (openActivities_.size() < 2) {
 
  388        delete m_activityMenu;
 
  389        m_activityMenu = 
nullptr;
 
 
  396void UserActionsMenu::initDesktopPopup()
 
  399        if (m_multipleDesktopsMenu) {
 
  403        m_multipleDesktopsMenu = 
new QMenu(m_menu);
 
  404        connect(m_multipleDesktopsMenu, &QMenu::aboutToShow, 
this, &UserActionsMenu::multipleDesktopsPopupAboutToShow);
 
  406        QAction *action = m_multipleDesktopsMenu->menuAction();
 
  408        m_menu->insertAction(m_maximizeOperation, action);
 
  409        action->setText(i18n(
"&Desktops"));
 
  410        action->setIcon(QIcon::fromTheme(QStringLiteral(
"virtual-desktops")));
 
  417        m_desktopMenu = 
new QMenu(m_menu);
 
  418        connect(m_desktopMenu, &QMenu::aboutToShow, 
this, &UserActionsMenu::desktopPopupAboutToShow);
 
  420        QAction *action = m_desktopMenu->menuAction();
 
  422        m_menu->insertAction(m_maximizeOperation, action);
 
  423        action->setText(i18n(
"Move to &Desktop"));
 
  424        action->setIcon(QIcon::fromTheme(QStringLiteral(
"virtual-desktops")));
 
  428void UserActionsMenu::initScreenPopup()
 
  434    m_screenMenu = 
new QMenu(m_menu);
 
  435    connect(m_screenMenu, &QMenu::aboutToShow, 
this, &UserActionsMenu::screenPopupAboutToShow);
 
  437    QAction *action = m_screenMenu->menuAction();
 
  439    m_menu->insertAction(m_activityMenu ? m_activityMenu->menuAction() : m_minimizeOperation, action);
 
  440    action->setText(i18n(
"Move to &Screen"));
 
  441    action->setIcon(QIcon::fromTheme(QStringLiteral(
"computer")));
 
  444void UserActionsMenu::initActivityPopup()
 
  446    if (m_activityMenu) {
 
  450    m_activityMenu = 
new QMenu(m_menu);
 
  451    connect(m_activityMenu, &QMenu::aboutToShow, 
this, &UserActionsMenu::activityPopupAboutToShow);
 
  453    QAction *action = m_activityMenu->menuAction();
 
  455    m_menu->insertAction(m_maximizeOperation, action);
 
  456    action->setText(i18n(
"Show in &Activities"));
 
  457    action->setIcon(QIcon::fromTheme(QStringLiteral(
"activities")));
 
  460void UserActionsMenu::desktopPopupAboutToShow()
 
  462    if (!m_desktopMenu) {
 
  465    const VirtualDesktopManager *vds = VirtualDesktopManager::self();
 
  467    m_desktopMenu->clear();
 
  469        m_desktopMenu->setPalette(m_window->palette());
 
  471    QActionGroup *group = 
new QActionGroup(m_desktopMenu);
 
  473    QAction *action = m_desktopMenu->addAction(i18n(
"Move &To Current Desktop"));
 
  474    action->setEnabled(m_window && (m_window->isOnAllDesktops() || !m_window->isOnDesktop(vds->currentDesktop())));
 
  475    connect(action, &QAction::triggered, 
this, [
this]() {
 
  479        VirtualDesktopManager *vds = VirtualDesktopManager::self();
 
  483    action = m_desktopMenu->addAction(i18n(
"&All Desktops"));
 
  484    connect(action, &QAction::triggered, 
this, [
this]() {
 
  486            m_window->setOnAllDesktops(!m_window->isOnAllDesktops());
 
  489    action->setCheckable(
true);
 
  490    if (m_window && m_window->isOnAllDesktops()) {
 
  491        action->setChecked(
true);
 
  493    group->addAction(action);
 
  495    m_desktopMenu->addSeparator();
 
  497    const uint BASE = 10;
 
  499    const auto desktops = vds->desktops();
 
  500    for (VirtualDesktop *desktop : desktops) {
 
  501        const uint legacyId = desktop->x11DesktopNumber();
 
  503        QString basic_name(QStringLiteral(
"%1  %2"));
 
  504        if (legacyId < BASE) {
 
  505            basic_name.prepend(QLatin1Char(
'&'));
 
  507        action = m_desktopMenu->addAction(basic_name.arg(legacyId).arg(desktop->name().replace(QLatin1Char(
'&'), QStringLiteral(
"&&"))));
 
  508        connect(action, &QAction::triggered, 
this, [
this, desktop]() {
 
  513        action->setCheckable(
true);
 
  514        group->addAction(action);
 
  516        if (m_window && !m_window->isOnAllDesktops() && m_window->isOnDesktop(desktop)) {
 
  517            action->setChecked(
true);
 
  521    m_desktopMenu->addSeparator();
 
  523    action = m_desktopMenu->addAction(i18nc(
"Create a new desktop and move the window there", 
"&New Desktop"));
 
  524    action->setIcon(QIcon::fromTheme(QStringLiteral(
"list-add")));
 
  525    connect(action, &QAction::triggered, 
this, [
this]() {
 
  529        VirtualDesktopManager *vds = VirtualDesktopManager::self();
 
  530        VirtualDesktop *desktop = vds->createVirtualDesktop(vds->count());
 
  535    action->setEnabled(vds->count() < vds->maximum());
 
  538void UserActionsMenu::multipleDesktopsPopupAboutToShow()
 
  540    if (!m_multipleDesktopsMenu) {
 
  543    VirtualDesktopManager *vds = VirtualDesktopManager::self();
 
  545    m_multipleDesktopsMenu->clear();
 
  547        m_multipleDesktopsMenu->setPalette(m_window->palette());
 
  550    QAction *action = m_multipleDesktopsMenu->addAction(i18n(
"&All Desktops"));
 
  551    connect(action, &QAction::triggered, 
this, [
this]() {
 
  553            m_window->setOnAllDesktops(!m_window->isOnAllDesktops());
 
  556    action->setCheckable(
true);
 
  557    if (m_window && m_window->isOnAllDesktops()) {
 
  558        action->setChecked(
true);
 
  561    m_multipleDesktopsMenu->addSeparator();
 
  563    const uint BASE = 10;
 
  565    const auto desktops = vds->desktops();
 
  566    for (VirtualDesktop *desktop : desktops) {
 
  567        const uint legacyId = desktop->x11DesktopNumber();
 
  569        QString basic_name(QStringLiteral(
"%1  %2"));
 
  570        if (legacyId < BASE) {
 
  571            basic_name.prepend(QLatin1Char(
'&'));
 
  574        QAction *action = m_multipleDesktopsMenu->addAction(basic_name.arg(legacyId).arg(desktop->name().replace(QLatin1Char(
'&'), QStringLiteral(
"&&"))));
 
  575        connect(action, &QAction::triggered, 
this, [
this, desktop]() {
 
  577                if (m_window->desktops().contains(desktop)) {
 
  578                    m_window->leaveDesktop(desktop);
 
  580                    m_window->enterDesktop(desktop);
 
  584        action->setCheckable(
true);
 
  585        if (m_window && !m_window->isOnAllDesktops() && m_window->isOnDesktop(desktop)) {
 
  586            action->setChecked(
true);
 
  590    m_multipleDesktopsMenu->addSeparator();
 
  592    for (VirtualDesktop *desktop : desktops) {
 
  593        const uint legacyId = desktop->x11DesktopNumber();
 
  594        QString name = i18n(
"Move to %1 %2", legacyId, desktop->name());
 
  595        QAction *action = m_multipleDesktopsMenu->addAction(name);
 
  596        connect(action, &QAction::triggered, 
this, [
this, desktop]() {
 
  598                m_window->setDesktops({desktop});
 
  603    m_multipleDesktopsMenu->addSeparator();
 
  605    bool allowNewDesktops = vds->count() < vds->maximum();
 
  607    action = m_multipleDesktopsMenu->addAction(i18nc(
"Create a new desktop and add the window to that desktop", 
"Add to &New Desktop"));
 
  608    connect(action, &QAction::triggered, 
this, [
this, vds]() {
 
  612        VirtualDesktop *desktop = vds->createVirtualDesktop(vds->count());
 
  614            m_window->enterDesktop(desktop);
 
  617    action->setEnabled(allowNewDesktops);
 
  619    action = m_multipleDesktopsMenu->addAction(i18nc(
"Create a new desktop and move the window to that desktop", 
"Move to New Desktop"));
 
  620    connect(action, &QAction::triggered, 
this, [
this, vds]() {
 
  624        VirtualDesktop *desktop = vds->createVirtualDesktop(vds->count());
 
  626            m_window->setDesktops({desktop});
 
  629    action->setEnabled(allowNewDesktops);
 
  632void UserActionsMenu::screenPopupAboutToShow()
 
  637    m_screenMenu->clear();
 
  642    m_screenMenu->setPalette(m_window->palette());
 
  643    QActionGroup *group = 
new QActionGroup(m_screenMenu);
 
  646    for (
int i = 0; i < 
outputs.count(); ++i) {
 
  649        QAction *action = m_screenMenu->addAction(i18nc(
"@item:inmenu List of all Screens to send a window to. First argument is a number, second the output identifier. E.g. Screen 1 (HDMI1)",
 
  650                                                        "Screen &%1 (%2)", (i + 1), output->name()));
 
  651        connect(action, &QAction::triggered, 
this, [
this, output]() {
 
  654        action->setCheckable(
true);
 
  655        if (m_window && output == m_window->output()) {
 
  656            action->setChecked(
true);
 
  658        group->addAction(action);
 
  662void UserActionsMenu::activityPopupAboutToShow()
 
  664    if (!m_activityMenu) {
 
  668#if KWIN_BUILD_ACTIVITIES 
  672    m_activityMenu->clear();
 
  674        m_activityMenu->setPalette(m_window->palette());
 
  676    QAction *action = m_activityMenu->addAction(i18n(
"&All Activities"));
 
  677    action->setCheckable(
true);
 
  678    connect(action, &QAction::triggered, 
this, [
this]() {
 
  680            m_window->setOnAllActivities(!m_window->isOnAllActivities());
 
  683    static QPointer<QActionGroup> allActivitiesGroup;
 
  684    if (!allActivitiesGroup) {
 
  685        allActivitiesGroup = 
new QActionGroup(m_activityMenu);
 
  687    allActivitiesGroup->addAction(action);
 
  689    if (m_window && m_window->isOnAllActivities()) {
 
  690        action->setChecked(
true);
 
  692    m_activityMenu->addSeparator();
 
  695    for (
const QString &
id : activities) {
 
  696        KActivities::Info activity(
id);
 
  697        QString name = activity.name();
 
  698        name.replace(
'&', 
"&&");
 
  699        auto action = m_activityMenu->addAction(name);
 
  700        action->setCheckable(
true);
 
  701        const QString icon = activity.icon();
 
  702        if (!icon.isEmpty()) {
 
  703            action->setIcon(QIcon::fromTheme(icon));
 
  705        m_activityMenu->addAction(action);
 
  706        connect(action, &QAction::triggered, 
this, [
this, 
id]() {
 
  708                Workspace::self()->activities()->toggleWindowOnActivity(m_window, 
id, 
false);
 
  712        if (m_window && !m_window->isOnAllActivities() && m_window->isOnActivity(
id)) {
 
  713            action->setChecked(
true);
 
  717    m_activityMenu->addSeparator();
 
  718    for (
const QString &
id : activities) {
 
  719        const KActivities::Info activity(
id);
 
  720        if (m_window->activities().size() == 1 && m_window->activities().front() == 
id) {
 
  724        const QString name = i18n(
"Move to %1", activity.name().replace(
'&', 
"&&"));
 
  725        const auto action = m_activityMenu->addAction(name);
 
  726        if (
const QString icon = activity.icon(); !icon.isEmpty()) {
 
  727            action->setIcon(QIcon::fromTheme(icon));
 
  729        connect(action, &QAction::triggered, 
this, [
this, 
id] {
 
  730            m_window->setOnActivities({
id});
 
  732        m_activityMenu->addAction(action);
 
  737void UserActionsMenu::slotWindowOperation(QAction *action)
 
  739    if (!action->data().isValid()) {
 
  744    QPointer<Window> c = m_window ? m_window : QPointer<Window>(
Workspace::self()->activeWindow());
 
  751        if (!c->isFullScreen() && c->isFullScreenable()) {
 
  752            type = QStringLiteral(
"fullscreenaltf3");
 
  756        if (!c->noBorder() && c->userCanSetNoBorder()) {
 
  757            type = QStringLiteral(
"noborderaltf3");
 
  763    if (!
type.isEmpty()) {
 
  768    QMetaObject::invokeMethod(
 
  772        Qt::QueuedConnection);
 
  782    m_ui.keySequenceEdit->setKeySequence(cut);
 
  783    m_ui.warning->hide();
 
  787    connect(m_ui.clearButton, &QToolButton::clicked, 
this, [
this] {
 
  788        _shortcut = QKeySequence();
 
  790    m_ui.keySequenceEdit->setFocus();
 
  792    setWindowFlags(Qt::Popup | Qt::X11BypassWindowManagerHint);
 
 
  798    if (!seq.isEmpty()) {
 
  799        if (seq[0] == QKeyCombination(Qt::Key_Escape)) {
 
  803        if (seq[0] == QKeyCombination(Qt::Key_Space) || seq[0].keyboardModifiers() == Qt::NoModifier) {
 
  805            m_ui.keySequenceEdit->clear();
 
 
  822    QKeySequence seq = m_ui.keySequenceEdit->keySequence();
 
  823    if (_shortcut == seq) {
 
  831    if (seq.count() > 1) {
 
  832        seq = QKeySequence(seq[0]);
 
  833        m_ui.keySequenceEdit->setKeySequence(seq);
 
  837    QString sc = seq.toString();
 
  839    QList<KGlobalShortcutInfo> conflicting = KGlobalAccel::globalShortcutsByKey(seq);
 
  840    if (!conflicting.isEmpty()) {
 
  841        const KGlobalShortcutInfo &conflict = conflicting.at(0);
 
  842        m_ui.warning->setText(i18nc(
"'%1' is a keyboard shortcut like 'ctrl+w'",
 
  843                                    "<b>%1</b> is already in use", sc));
 
  844        m_ui.warning->setToolTip(i18nc(
"keyboard shortcut '%1' is used by action '%2' in application '%3'",
 
  845                                       "<b>%1</b> is used by %2 in %3", sc, conflict.friendlyName(), conflict.componentFriendlyName()));
 
  846        m_ui.warning->show();
 
  847        m_ui.keySequenceEdit->setKeySequence(
shortcut());
 
  848    } 
else if (seq != _shortcut) {
 
  849        m_ui.warning->hide();
 
  850        if (QPushButton *ok = m_ui.buttonBox->button(QDialogButtonBox::Ok)) {
 
 
  869    if (!m_activeWindow) {
 
 
  877    if (!m_activeWindow) {
 
 
  883void Workspace::closeActivePopup()
 
  886        active_popup->close();
 
  887        active_popup = 
nullptr;
 
  888        m_activePopupWindow = 
nullptr;
 
  890    m_userActionsMenu->
close();
 
  893template<
typename Slot>
 
  894void Workspace::initShortcut(
const QString &actionName, 
const QString &description, 
const QKeySequence &shortcut, Slot slot)
 
  896    initShortcut(actionName, description, shortcut, 
this, slot);
 
  899template<
typename T, 
typename Slot>
 
  900void Workspace::initShortcut(
const QString &actionName, 
const QString &description, 
const QKeySequence &shortcut, T *receiver, Slot slot)
 
  902    QAction *a = 
new QAction(
this);
 
  903    a->setProperty(
"componentName", QStringLiteral(
"kwin"));
 
  904    a->setObjectName(actionName);
 
  905    a->setText(description);
 
  906    KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>() << shortcut);
 
  907    KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>() << shortcut);
 
  908    connect(a, &QAction::triggered, receiver, slot);
 
  914void Workspace::initShortcuts()
 
  925    initShortcut(
"Window Operations Menu", i18n(
"Window Operations Menu"),
 
  927    initShortcut(
"Window Close", i18n(
"Close Window"),
 
  929    initShortcut(
"Window Maximize", i18n(
"Maximize Window"),
 
  931    initShortcut(
"Window Maximize Vertical", i18n(
"Maximize Window Vertically"),
 
  933    initShortcut(
"Window Maximize Horizontal", i18n(
"Maximize Window Horizontally"),
 
  935    initShortcut(
"Window Minimize", i18n(
"Minimize Window"),
 
  937    initShortcut(
"Window Shade", i18n(
"Shade Window"),
 
  939    initShortcut(
"Window Move", i18n(
"Move Window"),
 
  941    initShortcut(
"Window Resize", i18n(
"Resize Window"),
 
  943    initShortcut(
"Window Raise", i18n(
"Raise Window"),
 
  945    initShortcut(
"Window Lower", i18n(
"Lower Window"),
 
  947    initShortcut(
"Toggle Window Raise/Lower", i18n(
"Toggle Window Raise/Lower"),
 
  949    initShortcut(
"Window Fullscreen", i18n(
"Make Window Fullscreen"),
 
  951    initShortcut(
"Window No Border", i18n(
"Toggle Window Titlebar and Frame"),
 
  953    initShortcut(
"Window Above Other Windows", i18n(
"Keep Window Above Others"),
 
  955    initShortcut(
"Window Below Other Windows", i18n(
"Keep Window Below Others"),
 
  957    initShortcut(
"Activate Window Demanding Attention", i18n(
"Activate Window Demanding Attention"),
 
  959    initShortcut(
"Setup Window Shortcut", i18n(
"Setup Window Shortcut"),
 
  961    initShortcut(
"Window Move Center", i18n(
"Move Window to the Center"), 0,
 
  963    initShortcut(
"Window Pack Right", i18n(
"Move Window Right"),
 
  965    initShortcut(
"Window Pack Left", i18n(
"Move Window Left"),
 
  967    initShortcut(
"Window Pack Up", i18n(
"Move Window Up"),
 
  969    initShortcut(
"Window Pack Down", i18n(
"Move Window Down"),
 
  971    initShortcut(
"Window Grow Horizontal", i18n(
"Expand Window Horizontally"),
 
  973    initShortcut(
"Window Grow Vertical", i18n(
"Expand Window Vertically"),
 
  975    initShortcut(
"Window Shrink Horizontal", i18n(
"Shrink Window Horizontally"),
 
  977    initShortcut(
"Window Shrink Vertical", i18n(
"Shrink Window Vertically"),
 
  979    initShortcut(
"Window Quick Tile Left", i18n(
"Quick Tile Window to the Left"),
 
  981    initShortcut(
"Window Quick Tile Right", i18n(
"Quick Tile Window to the Right"),
 
  983    initShortcut(
"Window Quick Tile Top", i18n(
"Quick Tile Window to the Top"),
 
  985    initShortcut(
"Window Quick Tile Bottom", i18n(
"Quick Tile Window to the Bottom"),
 
  987    initShortcut(
"Window Quick Tile Top Left", i18n(
"Quick Tile Window to the Top Left"),
 
  989    initShortcut(
"Window Quick Tile Bottom Left", i18n(
"Quick Tile Window to the Bottom Left"),
 
  991    initShortcut(
"Window Quick Tile Top Right", i18n(
"Quick Tile Window to the Top Right"),
 
  993    initShortcut(
"Window Quick Tile Bottom Right", i18n(
"Quick Tile Window to the Bottom Right"),
 
  995    initShortcut(
"Switch Window Up", i18n(
"Switch to Window Above"),
 
  997    initShortcut(
"Switch Window Down", i18n(
"Switch to Window Below"),
 
  999    initShortcut(
"Switch Window Right", i18n(
"Switch to Window to the Right"),
 
 1001    initShortcut(
"Switch Window Left", i18n(
"Switch to Window to the Left"),
 
 1003    initShortcut(
"Increase Opacity", i18n(
"Increase Opacity of Active Window by 5%"),
 
 1005    initShortcut(
"Decrease Opacity", i18n(
"Decrease Opacity of Active Window by 5%"),
 
 1008    initShortcut(
"Window On All Desktops", i18n(
"Keep Window on All Desktops"),
 
 1011    VirtualDesktopManager *vds = VirtualDesktopManager::self();
 
 1012    for (uint i = 0; i < vds->maximum(); ++i) {
 
 1013        auto handler = [
this, i]() {
 
 1014            const QList<VirtualDesktop *> desktops = VirtualDesktopManager::self()->desktops();
 
 1015            if (i < uint(desktops.count())) {
 
 1019        initShortcut(QStringLiteral(
"Window to Desktop %1").arg(i + 1), i18n(
"Window to Desktop %1", i + 1), 0, handler);
 
 1023    initShortcut(
"Window One Desktop to the Right", i18n(
"Window One Desktop to the Right"),
 
 1025    initShortcut(
"Window One Desktop to the Left", i18n(
"Window One Desktop to the Left"),
 
 1027    initShortcut(
"Window One Desktop Up", i18n(
"Window One Desktop Up"),
 
 1029    initShortcut(
"Window One Desktop Down", i18n(
"Window One Desktop Down"),
 
 1032    for (
int i = 0; i < 8; ++i) {
 
 1033        initShortcut(QStringLiteral(
"Window to Screen %1").arg(i), i18n(
"Move Window to Screen %1", i), 0, [
this, i]() {
 
 1034            Output *output = 
outputs().value(i);
 
 1040    initShortcut(
"Window to Next Screen", i18n(
"Move Window to Next Screen"),
 
 1042    initShortcut(
"Window to Previous Screen", i18n(
"Move Window to Previous Screen"),
 
 1044    initShortcut(
"Window One Screen to the Right", i18n(
"Move Window One Screen to the Right"),
 
 1046    initShortcut(
"Window One Screen to the Left", i18n(
"Move Window One Screen to the Left"),
 
 1048    initShortcut(
"Window One Screen Up", i18n(
"Move Window One Screen Up"),
 
 1050    initShortcut(
"Window One Screen Down", i18n(
"Move Window One Screen Down"),
 
 1053    for (
int i = 0; i < 8; ++i) {
 
 1054        initShortcut(QStringLiteral(
"Switch to Screen %1").arg(i), i18n(
"Switch to Screen %1", i), 0, [
this, i]() {
 
 1055            Output *output = 
outputs().value(i);
 
 1063    initShortcut(
"Switch to Screen to the Right", i18n(
"Switch to Screen to the Right"),
 
 1065    initShortcut(
"Switch to Screen to the Left", i18n(
"Switch to Screen to the Left"),
 
 1067    initShortcut(
"Switch to Screen Above", i18n(
"Switch to Screen Above"),
 
 1069    initShortcut(
"Switch to Screen Below", i18n(
"Switch to Screen Below"),
 
 1072    initShortcut(
"Show Desktop", i18n(
"Peek at Desktop"),
 
 1077#if KWIN_BUILD_TABBOX 
 1078    m_tabbox->initShortcuts();
 
 1080    vds->initShortcuts();
 
 1084void Workspace::setupWindowShortcut(
Window *window)
 
 1086    Q_ASSERT(m_windowKeysDialog == 
nullptr);
 
 1091    m_windowKeysDialog = 
new ShortcutDialog(window->shortcut());
 
 1092    m_windowKeysWindow = window;
 
 1095    QSize size = m_windowKeysDialog->sizeHint();
 
 1096    QPointF pos(window->frameGeometry().left() + window->frameMargins().left(),
 
 1097                window->frameGeometry().top() + window->frameMargins().top());
 
 1098    if (pos.x() + size.width() >= r.right()) {
 
 1099        pos.setX(r.right() - size.width());
 
 1101    if (pos.y() + size.height() >= r.bottom()) {
 
 1102        pos.setY(r.bottom() - size.height());
 
 1104    m_windowKeysDialog->move(pos.toPoint());
 
 1105    m_windowKeysDialog->show();
 
 1106    active_popup = m_windowKeysDialog;
 
 1107    m_activePopupWindow = window;
 
 1119    m_windowKeysDialog->deleteLater();
 
 1120    m_windowKeysDialog = 
nullptr;
 
 1121    m_windowKeysWindow = 
nullptr;
 
 1122    if (m_activeWindow) {
 
 
 1129    QString key = QStringLiteral(
"_k_session:%1").arg(window->
internalId().toString());
 
 1130    QAction *action = findChild<QAction *>(key);
 
 1131    if (!window->
shortcut().isEmpty()) {
 
 1132        if (action == 
nullptr) { 
 
 1133            action = 
new QAction(
this);
 
 1135                KGlobalAccel::self()->removeAllShortcuts(action);
 
 1139            action->setProperty(
"componentName", QStringLiteral(
"kwin"));
 
 1140            action->setObjectName(key);
 
 1141            action->setText(i18n(
"Activate Window (%1)", window->
caption()));
 
 1147        KGlobalAccel::self()->setShortcut(action, QList<QKeySequence>() << window->
shortcut(),
 
 1148                                          KGlobalAccel::NoAutoloading);
 
 1149        action->setEnabled(
true);
 
 1151        KGlobalAccel::self()->removeAllShortcuts(action);
 
 
 1240        m_rulebook->edit(window, 
false);
 
 1243        m_rulebook->edit(window, 
true);
 
 1246        setupWindowShortcut(window);
 
 
 1258    if (attention_chain.count() > 0) {
 
 
 1263#define USABLE_ACTIVE_WINDOW (m_activeWindow && !(m_activeWindow->isDesktop() || m_activeWindow->isDock())) 
 1272static bool screenSwitchImpossible()
 
 1278    args << QStringLiteral(
"--passivepopup") << i18n(
"The window manager is configured to consider the screen with the mouse on it as active one.\n" 
 1279                                                     "Therefore it is not possible to switch to a screen explicitly.")
 
 1280         << QStringLiteral(
"20");
 
 1281    KProcess::startDetached(QStringLiteral(
"kdialog"), args);
 
 1287    if (!screenSwitchImpossible()) {
 
 
 1294    if (!screenSwitchImpossible()) {
 
 
 1301    if (!screenSwitchImpossible()) {
 
 
 1308    if (!screenSwitchImpossible()) {
 
 
 1315    if (!screenSwitchImpossible()) {
 
 
 1322    if (!screenSwitchImpossible()) {
 
 
 1329    if (!screenSwitchImpossible()) {
 
 
 1456                if (next && next != m_activeWindow) {
 
 
 1530    const auto desktop = vds->
inDirection(
nullptr, direction, 
true);
 
 
 1575    if (newCurrent == current) {
 
 
 1616    if (!m_windowKiller) {
 
 1617        m_windowKiller = std::make_unique<KillWindow>();
 
 1619    m_windowKiller->start();
 
 
 1627    if (!m_activeWindow) {
 
 1630    Window *window = m_activeWindow;
 
 1631    VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop();
 
 1634    QPoint curPos(window->
x() + window->
width() / 2, window->
y() + window->
height() / 2);
 
 1636    if (!
switchWindow(window, direction, curPos, desktop)) {
 
 1637        auto opposite = [&] {
 
 1638            switch (direction) {
 
 1640                return QPoint(curPos.x(), 
geometry().height());
 
 1642                return QPoint(curPos.x(), 0);
 
 1644                return QPoint(0, curPos.y());
 
 1646                return QPoint(
geometry().width(), curPos.y());
 
 
 1658    Window *switchTo = 
nullptr;
 
 1662    for (
auto i = clist.rbegin(); i != clist.rend(); ++i) {
 
 1664        if (!other->isClient()) {
 
 1667        if (other->wantsTabFocus() && *i != window && other->
isOnDesktop(desktop) && !other->isMinimized() && (*i)->isOnCurrentActivity()) {
 
 1669            const QPoint otherCenter(other->x() + other->width() / 2, other->y() + other->height() / 2);
 
 1673            switch (direction) {
 
 1675                distance = curPos.y() - otherCenter.y();
 
 1676                offset = std::abs(otherCenter.x() - curPos.x());
 
 1679                distance = otherCenter.x() - curPos.x();
 
 1680                offset = std::abs(otherCenter.y() - curPos.y());
 
 1683                distance = otherCenter.y() - curPos.y();
 
 1684                offset = std::abs(otherCenter.x() - curPos.x());
 
 1687                distance = curPos.x() - otherCenter.x();
 
 1688                offset = std::abs(otherCenter.y() - curPos.y());
 
 1697                int score = distance + offset + ((offset * offset) / distance);
 
 1698                if (score < bestScore || !switchTo) {
 
 1717    if (!m_activeWindow) {
 
 
 1727    m_userActionsMenu->
show(pos, window);
 
 
 1768#undef USABLE_ACTIVE_WINDOW 
 1773    auto updateShortcut = [
this](
const QKeySequence &cut = QKeySequence()) {
 
 1780    if (cut.isEmpty()) {
 
 1784    if (cut == 
shortcut().toString()) {
 
 1790    if (!cut.contains(QLatin1Char(
'(')) && !cut.contains(QLatin1Char(
')')) && !cut.contains(QLatin1String(
" - "))) {
 
 1791        if (
workspace()->shortcutAvailable(cut, 
this)) {
 
 1792            updateShortcut(QKeySequence(cut));
 
 1798    static const QRegularExpression reg(QStringLiteral(
"(.*\\+)\\((.*)\\)"));
 
 1799    QList<QKeySequence> keys;
 
 1800    const QStringList groups = cut.split(QStringLiteral(
" - "));
 
 1801    for (
auto it = groups.begin(); it != groups.end(); ++it) {
 
 1802        const QRegularExpressionMatch 
match = reg.match(*it);
 
 1803        if (
match.hasMatch()) {
 
 1804            const QString base = 
match.captured(1);
 
 1805            const QString list = 
match.captured(2);
 
 1806            for (
int i = 0; i < list.length(); ++i) {
 
 1807                QKeySequence c(base + list[i]);
 
 1814            QKeySequence c(*it);
 
 1820    for (
auto it = keys.constBegin(); it != keys.cend(); ++it) {
 
 1825    for (
auto it = keys.cbegin(); it != keys.cend(); ++it) {
 
 1827            updateShortcut(*it);
 
 
 1840void X11Window::setShortcutInternal()
 
 1855    if (ignore && cut == ignore->
shortcut()) {
 
 1860    const QList<KGlobalShortcutInfo> registeredShortcuts = KGlobalAccel::globalShortcutsByKey(cut);
 
 1861    for (
const auto &shortcut : registeredShortcuts) {
 
 1863        if (!shortcut.uniqueName().startsWith(QStringLiteral(
"_k_session:"))) {
 
 1868    for (
const auto window : std::as_const(m_windows)) {
 
 1869        if (window != ignore && window->
shortcut() == cut) {
 
 
 1878#include "moc_useractions.cpp" 
@ OperationModeXwayland
KWin uses Wayland and controls a nested Xwayland server.
@ OperationModeWaylandOnly
KWin uses only Wayland.
void setPos(const QPointF &pos)
@ MouseUnrestrictedResize
bool isRollOverDesktops() const
bool focusPolicyIsReasonable
bool isNextFocusPrefersMouse() const
QList< QAction * > actionsForUserActionMenu(Window *c, QMenu *parent)
Invokes all registered callbacks to add actions to the UserActionsMenu.
static Scripting * self()
void keySequenceChanged()
void done(int r) override
QKeySequence shortcut() const
ShortcutDialog(const QKeySequence &cut)
Manages the number of available virtual desktops, the layout of those and which virtual desktop is th...
VirtualDesktop * inDirection(VirtualDesktop *desktop, Direction direction, bool wrap=true)
VirtualDesktop * currentDesktop() const
bool setCurrent(uint current)
void setOpacity(qreal opacity)
virtual void updateCaption()=0
void setMinimized(bool set)
virtual void setShortcutInternal()
virtual void setFullScreen(bool set)
virtual void maximize(MaximizeMode mode)
void setOnAllDesktops(bool set)
virtual bool isFullScreen() const
bool isOnAllDesktops() const
virtual bool takeFocus()=0
virtual void closeWindow()=0
bool performMouseCommand(Options::MouseCommand, const QPointF &globalPos)
QMargins frameMargins() const
bool isOnDesktop(VirtualDesktop *desktop) const
const WindowRules * rules() const
virtual void setNoBorder(bool set)
const QKeySequence & shortcut() const
virtual bool userCanSetNoBorder() const
virtual MaximizeMode maximizeMode() const
void setShortcut(const QString &cut)
QString checkShortcut(QString s, bool init=false) const
void slotToggleShowDesktop()
void slotSwitchToNextScreen()
void slotWindowToLeftScreen()
void showApplicationMenu(const QRect &pos, Window *window, int actionId)
Window * activeWindow() const
ApplicationMenu * applicationMenu() const
void quickTileWindow(QuickTileMode mode)
void windowShortcutUpdated(Window *window)
QRectF clientArea(clientAreaOption, const Output *output, const VirtualDesktop *desktop) const
void activateWindow(Window *window, bool force=false)
const QList< Window * > & stackingOrder() const
void sendWindowToOutput(Window *window, Output *output)
void slotWindowOperations()
void windowToNextDesktop(Window *window)
void slotWindowMinimize()
Window * windowUnderMouse(Output *output) const
void slotWindowShrinkHorizontal()
void showWindowMenu(const QRect &pos, Window *cl)
void slotWindowToPrevScreen()
void slotWindowExpandHorizontal()
void slotSwitchToLeftScreen()
void slotWindowMaximizeVertical()
void slotLowerWindowOpacity()
void slotSwitchToRightScreen()
Output * activeOutput() const
void slotWindowToNextDesktop()
void setupWindowShortcutDone(bool)
void slotWindowMaximize()
void performWindowOperation(KWin::Window *window, Options::WindowOperation op)
void switchToOutput(Output *output)
void slotWindowOnAllDesktops()
void raiseWindow(Window *window, bool nogroup=false)
void switchWindow(Direction direction)
void slotWindowToBelowScreen()
void slotWindowToPreviousDesktop()
void slotSwitchToScreen(Output *output)
void slotWindowNoBorder()
void slotSwitchToPrevScreen()
static Workspace * self()
Window * topWindowOnDesktop(VirtualDesktop *desktop, Output *output=nullptr, bool unconstrained=false, bool only_normal=true) const
void slotWindowToDesktopDown()
void slotWindowFullScreen()
void slotWindowMoveDown()
void slotSwitchToAboveScreen()
void slotWindowToDesktopLeft()
bool showingDesktop() const
void slotWindowToNextScreen()
void setMoveResizeWindow(Window *window)
void slotWindowToRightScreen()
void lowerWindow(Window *window, bool nogroup=false)
void slotWindowMoveRight()
void slotWindowShrinkVertical()
QList< Output * > outputs() const
void sendWindowToDesktops(Window *window, const QList< VirtualDesktop * > &desktops, bool dont_activate)
void slotWindowToDesktopUp()
bool requestFocus(Window *window, bool force=false)
void slotWindowExpandVertical()
bool takeActivity(Window *window, ActivityFlags flags)
void setShowingDesktop(bool showing, bool animated=true)
void slotWindowMaximizeHorizontal()
void slotWindowToScreen(Output *output)
void slotIncreaseWindowOpacity()
void slotSwitchToBelowScreen()
void slotWindowToAboveScreen()
void slotSetupWindowShortcut()
void windowToPreviousDesktop(Window *window)
bool shortcutAvailable(const QKeySequence &cut, Window *ignore=nullptr) const
Output * findOutput(Output *reference, Direction direction, bool wrapAround=false) const
void slotWindowRaiseOrLower()
void raiseOrLowerWindow(Window *window)
void slotWindowToDesktopRight()
void slotActivateAttentionWindow()
void slotWindowMoveLeft()
void slotWindowToDesktop(VirtualDesktop *desktop)
void updateCaption() override
QList< KWayland::Client::Output * > outputs
void activeWindowToDesktop(VirtualDesktopManager::Direction direction)
@ MaximizeVertical
The window is maximized vertically.
@ MaximizeRestore
The window is not maximized in any direction.
@ MaximizeFull
Equal to MaximizeVertical | MaximizeHorizontal.
bool match(QList< GlobalShortcut > &shortcuts, Args... args)
void windowToDesktop(Window *window, VirtualDesktopManager::Direction direction)
#define USABLE_ACTIVE_WINDOW