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