diff --git a/activation.cpp b/activation.cpp
index 7c07d5e1bb..12fbabde59 100644
--- a/activation.cpp
+++ b/activation.cpp
@@ -39,6 +39,7 @@ along with this program. If not, see .
#include "atoms.h"
#include "group.h"
#include "rules.h"
+#include "useractions.h"
#include
namespace KWin
@@ -228,6 +229,9 @@ void Workspace::setActiveClient(Client* c, allowed_t)
if (active_popup && active_popup_client != c && set_active_client_recursion == 0)
closeActivePopup();
+ if (m_userActionsMenu->hasClient() && !m_userActionsMenu->isMenuClient(c) && set_active_client_recursion == 0) {
+ m_userActionsMenu->close();
+ }
StackingUpdatesBlocker blocker(this);
++set_active_client_recursion;
updateFocusMousePosition(cursorPos());
diff --git a/composite.cpp b/composite.cpp
index c65716b5ca..b6406e8cd0 100644
--- a/composite.cpp
+++ b/composite.cpp
@@ -52,6 +52,7 @@ along with this program. If not, see .
#include "scene_xrender.h"
#include "scene_opengl.h"
#include "shadow.h"
+#include "useractions.h"
#include "compositingprefs.h"
#include "notifications.h"
@@ -192,7 +193,7 @@ void Workspace::slotCompositingOptionsInitialized()
c->setupCompositing();
foreach (Unmanaged * c, unmanaged)
c->setupCompositing();
- discardPopup(); // force re-creation of the Alt+F3 popup (opacity option)
+ m_userActionsMenu->discard(); // force re-creation of the Alt+F3 popup (opacity option)
// render at least once
compositeTimer.stop();
@@ -238,7 +239,7 @@ void Workspace::finishCompositing()
i.setOpacity(static_cast< unsigned long >((*it)->opacity() * 0xffffffff));
}
}
- discardPopup(); // force re-creation of the Alt+F3 popup (opacity option)
+ m_userActionsMenu->discard(); // force re-creation of the Alt+F3 popup (opacity option)
// discard all Deleted windows (#152914)
while (!deleted.isEmpty())
deleted.first()->discard(Allowed);
diff --git a/events.cpp b/events.cpp
index 6856922e76..2c54da31f7 100644
--- a/events.cpp
+++ b/events.cpp
@@ -37,6 +37,7 @@ along with this program. If not, see .
#include "overlaywindow.h"
#include "rules.h"
#include "unmanaged.h"
+#include "useractions.h"
#include "effects.h"
#include
@@ -879,7 +880,7 @@ void Client::enterNotifyEvent(XCrossingEvent* e)
}
#undef MOUSE_DRIVEN_FOCUS
- if (options->focusPolicy() == Options::ClickToFocus || workspace()->windowMenuShown())
+ if (options->focusPolicy() == Options::ClickToFocus || workspace()->userActionsMenu()->isShown())
return;
if (options->isAutoRaise() && !isDesktop() &&
diff --git a/useractions.cpp b/useractions.cpp
index a50178256f..c2778b69b6 100755
--- a/useractions.cpp
+++ b/useractions.cpp
@@ -31,6 +31,7 @@ along with this program. If not, see .
// NOTE: if you change the menu, keep kde-workspace/libs/taskmanager/taskactions.cpp in sync
//////////////////////////////////////////////////////////////////////////////
+#include "useractions.h"
#include "client.h"
#include "workspace.h"
#include "effects.h"
@@ -39,6 +40,9 @@ along with this program. If not, see .
#include
#endif
+#include
+#include
+
#include
#ifndef KWIN_NO_XF86VM
#include
@@ -68,158 +72,697 @@ along with this program. If not, see .
namespace KWin
{
+UserActionsMenu::UserActionsMenu(QObject *parent)
+ : QObject(parent)
+ , m_menu(NULL)
+ , m_desktopMenu(NULL)
+ , m_screenMenu(NULL)
+ , m_activityMenu(NULL)
+ , m_addTabsMenu(NULL)
+ , m_switchToTabMenu(NULL)
+ , m_resizeOperation(NULL)
+ , m_moveOperation(NULL)
+ , m_maximizeOperation(NULL)
+ , m_shadeOperation(NULL)
+ , m_keepAboveOperation(NULL)
+ , m_keepBelowOperation(NULL)
+ , m_fullScreenOperation(NULL)
+ , m_noBorderOperation(NULL)
+ , m_minimizeOperation(NULL)
+ , m_closeOperation(NULL)
+ , m_removeFromTabGroup(NULL)
+ , m_closeTabGroup(NULL)
+ , m_client(QWeakPointer())
+{
+}
+
+UserActionsMenu::~UserActionsMenu()
+{
+ discard();
+}
+
+bool UserActionsMenu::isShown() const
+{
+ return m_menu && m_menu->isVisible();
+}
+
+bool UserActionsMenu::hasClient() const
+{
+ return !m_client.isNull();
+}
+
+void UserActionsMenu::close()
+{
+ if (!m_menu) {
+ return;
+ }
+ m_menu->close();
+ m_client.clear();;
+}
+
+bool UserActionsMenu::isMenuClient(const Client *c) const
+{
+ if (!c || m_client.isNull()) {
+ return false;
+ }
+ return c == m_client.data();
+}
+
+void UserActionsMenu::show(const QRect &pos, const QWeakPointer &cl)
+{
+ if (!KAuthorized::authorizeKAction("kwin_rmb"))
+ return;
+ if (cl.isNull())
+ return;
+ if (!m_client.isNull()) // recursion
+ return;
+ if (cl.data()->isDesktop()
+ || cl.data()->isDock())
+ return;
+
+ m_client = cl;
+ init();
+ Workspace *ws = Workspace::self();
+ int x = pos.left();
+ int y = pos.bottom();
+ if (y == pos.top())
+ m_menu->exec(QPoint(x, y));
+ else {
+ QRect area = ws->clientArea(ScreenArea, QPoint(x, y), ws->currentDesktop());
+ menuAboutToShow(); // needed for sizeHint() to be correct :-/
+ int popupHeight = m_menu->sizeHint().height();
+ if (y + popupHeight < area.height())
+ m_menu->exec(QPoint(x, y));
+ else
+ m_menu->exec(QPoint(x, pos.top() - popupHeight));
+ }
+ m_client.clear();;
+}
+
+void UserActionsMenu::helperDialog(const QString& message, const QWeakPointer &c)
+{
+ QStringList args;
+ QString type;
+ KActionCollection *keys = Workspace::self()->actionCollection();
+ if (message == "noborderaltf3") {
+ KAction* action = qobject_cast(keys->action("Window Operations Menu"));
+ assert(action != NULL);
+ QString shortcut = QString("%1 (%2)").arg(action->text())
+ .arg(action->globalShortcut().primary().toString(QKeySequence::NativeText));
+ args << "--msgbox" << i18n(
+ "You have selected to show a window without its border.\n"
+ "Without the border, you will not be able to enable the border "
+ "again using the mouse: use the window operations menu instead, "
+ "activated using the %1 keyboard shortcut.",
+ shortcut);
+ type = "altf3warning";
+ } else if (message == "fullscreenaltf3") {
+ KAction* action = qobject_cast(keys->action("Window Operations Menu"));
+ assert(action != NULL);
+ QString shortcut = QString("%1 (%2)").arg(action->text())
+ .arg(action->globalShortcut().primary().toString(QKeySequence::NativeText));
+ args << "--msgbox" << i18n(
+ "You have selected to show a window in fullscreen mode.\n"
+ "If the application itself does not have an option to turn the fullscreen "
+ "mode off you will not be able to disable it "
+ "again using the mouse: use the window operations menu instead, "
+ "activated using the %1 keyboard shortcut.",
+ shortcut);
+ type = "altf3warning";
+ } else
+ abort();
+ if (!type.isEmpty()) {
+ KConfig cfg("kwin_dialogsrc");
+ KConfigGroup cg(&cfg, "Notification Messages"); // Depends on KMessageBox
+ if (!cg.readEntry(type, true))
+ return;
+ args << "--dontagain" << "kwin_dialogsrc:" + type;
+ }
+ if (!c.isNull())
+ args << "--embed" << QString::number(c.data()->window());
+ KProcess::startDetached("kdialog", args);
+}
+
+
+QStringList configModules(bool controlCenter)
+{
+ QStringList args;
+ args << "kwindecoration";
+ if (controlCenter)
+ args << "kwinoptions";
+ else if (KAuthorized::authorizeControlModule("kde-kwinoptions.desktop"))
+ args << "kwinactions" << "kwinfocus" << "kwinmoving" << "kwinadvanced"
+ << "kwinrules" << "kwincompositing"
+#ifdef KWIN_BUILD_TABBOX
+ << "kwintabbox"
+#endif
+#ifdef KWIN_BUILD_SCREENEDGES
+ << "kwinscreenedges"
+#endif
+#ifdef KWIN_BUILD_SCRIPTING
+ << "kwinscripts"
+#endif
+ ;
+ return args;
+}
+
+void UserActionsMenu::configureWM()
+{
+ QStringList args;
+ args << "--icon" << "preferences-system-windows" << configModules(false);
+ KToolInvocation::kdeinitExec("kcmshell4", args);
+}
+
+void UserActionsMenu::init()
+{
+ if (m_menu) {
+ return;
+ }
+ m_menu = new QMenu;
+ m_menu->setFont(KGlobalSettings::menuFont());
+ connect(m_menu, SIGNAL(aboutToShow()), this, SLOT(menuAboutToShow()));
+ connect(m_menu, SIGNAL(triggered(QAction*)), this, SLOT(slotWindowOperation(QAction*)));
+
+ QMenu *advancedMenu = new QMenu(m_menu);
+ advancedMenu->setFont(KGlobalSettings::menuFont());
+
+ m_moveOperation = advancedMenu->addAction(i18n("&Move"));
+ m_moveOperation->setIcon(KIcon("transform-move"));
+ KActionCollection *keys = Workspace::self()->actionCollection();
+ KAction *kaction = qobject_cast(keys->action("Window Move"));
+ if (kaction != 0)
+ m_moveOperation->setShortcut(kaction->globalShortcut().primary());
+ m_moveOperation->setData(Options::UnrestrictedMoveOp);
+
+ m_resizeOperation = advancedMenu->addAction(i18n("Re&size"));
+ kaction = qobject_cast(keys->action("Window Resize"));
+ if (kaction != 0)
+ m_resizeOperation->setShortcut(kaction->globalShortcut().primary());
+ m_resizeOperation->setData(Options::ResizeOp);
+
+ m_keepAboveOperation = advancedMenu->addAction(i18n("Keep &Above Others"));
+ m_keepAboveOperation->setIcon(KIcon("go-up"));
+ kaction = qobject_cast(keys->action("Window Above Other Windows"));
+ if (kaction != 0)
+ m_keepAboveOperation->setShortcut(kaction->globalShortcut().primary());
+ m_keepAboveOperation->setCheckable(true);
+ m_keepAboveOperation->setData(Options::KeepAboveOp);
+
+ m_keepBelowOperation = advancedMenu->addAction(i18n("Keep &Below Others"));
+ m_keepBelowOperation->setIcon(KIcon("go-down"));
+ kaction = qobject_cast(keys->action("Window Below Other Windows"));
+ if (kaction != 0)
+ m_keepBelowOperation->setShortcut(kaction->globalShortcut().primary());
+ m_keepBelowOperation->setCheckable(true);
+ m_keepBelowOperation->setData(Options::KeepBelowOp);
+
+ m_fullScreenOperation = advancedMenu->addAction(i18n("&Fullscreen"));
+ m_fullScreenOperation->setIcon(KIcon("view-fullscreen"));
+ kaction = qobject_cast(keys->action("Window Fullscreen"));
+ if (kaction != 0)
+ m_fullScreenOperation->setShortcut(kaction->globalShortcut().primary());
+ m_fullScreenOperation->setCheckable(true);
+ m_fullScreenOperation->setData(Options::FullScreenOp);
+
+ m_shadeOperation = advancedMenu->addAction(i18n("Sh&ade"));
+ kaction = qobject_cast(keys->action("Window Shade"));
+ if (kaction != 0)
+ m_shadeOperation->setShortcut(kaction->globalShortcut().primary());
+ m_shadeOperation->setCheckable(true);
+ m_shadeOperation->setData(Options::ShadeOp);
+
+ m_noBorderOperation = advancedMenu->addAction(i18n("&No Border"));
+ kaction = qobject_cast(keys->action("Window No Border"));
+ if (kaction != 0)
+ m_noBorderOperation->setShortcut(kaction->globalShortcut().primary());
+ m_noBorderOperation->setCheckable(true);
+ m_noBorderOperation->setData(Options::NoBorderOp);
+
+ advancedMenu->addSeparator();
+
+ QAction *action = advancedMenu->addAction(i18n("Window &Shortcut..."));
+ action->setIcon(KIcon("configure-shortcuts"));
+ kaction = qobject_cast(keys->action("Setup Window Shortcut"));
+ if (kaction != 0)
+ action->setShortcut(kaction->globalShortcut().primary());
+ action->setData(Options::SetupWindowShortcutOp);
+
+ action = advancedMenu->addAction(i18n("&Special Window Settings..."));
+ action->setIcon(KIcon("preferences-system-windows-actions"));
+ action->setData(Options::WindowRulesOp);
+
+ action = advancedMenu->addAction(i18n("S&pecial Application Settings..."));
+ action->setIcon(KIcon("preferences-system-windows-actions"));
+ action->setData(Options::ApplicationRulesOp);
+ if (!KGlobal::config()->isImmutable() &&
+ !KAuthorized::authorizeControlModules(configModules(true)).isEmpty()) {
+ advancedMenu->addSeparator();
+ action = advancedMenu->addAction(i18nc("Entry in context menu of window decoration to open the configuration module of KWin",
+ "Window &Manager Settings..."));
+ action->setIcon(KIcon("configure"));
+ connect(action, SIGNAL(triggered()), this, SLOT(configureWM()));
+ }
+
+ m_minimizeOperation = m_menu->addAction(i18n("Mi&nimize"));
+ kaction = qobject_cast(keys->action("Window Minimize"));
+ if (kaction != 0)
+ m_minimizeOperation->setShortcut(kaction->globalShortcut().primary());
+ m_minimizeOperation->setData(Options::MinimizeOp);
+
+ m_maximizeOperation = m_menu->addAction(i18n("Ma&ximize"));
+ kaction = qobject_cast(keys->action("Window Maximize"));
+ if (kaction != 0)
+ m_maximizeOperation->setShortcut(kaction->globalShortcut().primary());
+ m_maximizeOperation->setCheckable(true);
+ m_maximizeOperation->setData(Options::MaximizeOp);
+
+ m_menu->addSeparator();
+
+ // Actions for window tabbing
+ if (Workspace::self()->decorationSupportsTabbing()) {
+ m_removeFromTabGroup = m_menu->addAction(i18n("&Untab"));
+ kaction = qobject_cast(keys->action("Untab"));
+ if (kaction != 0)
+ m_removeFromTabGroup->setShortcut(kaction->globalShortcut().primary());
+ m_removeFromTabGroup->setData(Options::RemoveTabFromGroupOp);
+
+ m_closeTabGroup = m_menu->addAction(i18n("Close Entire &Group"));
+ m_closeTabGroup->setIcon(KIcon("window-close"));
+ kaction = qobject_cast(keys->action("Close TabGroup"));
+ if (kaction != 0)
+ m_closeTabGroup->setShortcut(kaction->globalShortcut().primary());
+ m_closeTabGroup->setData(Options::CloseTabGroupOp);
+
+ m_menu->addSeparator();
+ }
+
+ m_menu->addSeparator();
+
+ action = m_menu->addMenu(advancedMenu);
+ action->setText(i18n("More Actions"));
+
+ m_menu->addSeparator();
+
+ m_closeOperation = m_menu->addAction(i18n("&Close"));
+ m_closeOperation->setIcon(KIcon("window-close"));
+ kaction = qobject_cast(keys->action("Window Close"));
+ if (kaction != 0)
+ m_closeOperation->setShortcut(kaction->globalShortcut().primary());
+ m_closeOperation->setData(Options::CloseOp);
+}
+
+void UserActionsMenu::discard()
+{
+ delete m_menu;
+ m_menu = NULL;
+ m_desktopMenu = NULL;
+ m_screenMenu = NULL;
+ m_activityMenu = NULL;
+ m_switchToTabMenu = NULL;
+ m_addTabsMenu = NULL;
+}
+
+void UserActionsMenu::menuAboutToShow()
+{
+ if (m_client.isNull() || !m_menu)
+ return;
+ Workspace *ws = Workspace::self();
+
+ if (ws->numberOfDesktops() == 1) {
+ delete m_desktopMenu;
+ m_desktopMenu = 0;
+ } else {
+ initDesktopPopup();
+ }
+ if (ws->numScreens() == 1 || (!m_client.data()->isMovable() && !m_client.data()->isMovableAcrossScreens())) {
+ delete m_screenMenu;
+ m_screenMenu = NULL;
+ } else {
+ initScreenPopup();
+ }
+#ifdef KWIN_BUILD_ACTIVITIES
+ ws->updateActivityList(true, false, this, "showHideActivityMenu");
+#endif
+
+ m_resizeOperation->setEnabled(m_client.data()->isResizable());
+ m_moveOperation->setEnabled(m_client.data()->isMovableAcrossScreens());
+ m_maximizeOperation->setEnabled(m_client.data()->isMaximizable());
+ m_maximizeOperation->setChecked(m_client.data()->maximizeMode() == Client::MaximizeFull);
+ m_shadeOperation->setEnabled(m_client.data()->isShadeable());
+ m_shadeOperation->setChecked(m_client.data()->shadeMode() != ShadeNone);
+ m_keepAboveOperation->setChecked(m_client.data()->keepAbove());
+ m_keepBelowOperation->setChecked(m_client.data()->keepBelow());
+ m_fullScreenOperation->setEnabled(m_client.data()->userCanSetFullScreen());
+ m_fullScreenOperation->setChecked(m_client.data()->isFullScreen());
+ m_noBorderOperation->setEnabled(m_client.data()->userCanSetNoBorder());
+ m_noBorderOperation->setChecked(m_client.data()->noBorder());
+ m_minimizeOperation->setEnabled(m_client.data()->isMinimizable());
+ m_closeOperation->setEnabled(m_client.data()->isCloseable());
+
+ if (ws->decorationSupportsTabbing()) {
+ initTabbingPopups();
+ } else {
+ delete m_addTabsMenu;
+ m_addTabsMenu = 0;
+ }
+}
+
+void UserActionsMenu::showHideActivityMenu()
+{
+#ifdef KWIN_BUILD_ACTIVITIES
+ const QStringList &openActivities_ = Workspace::self()->openActivities();
+ kDebug() << "activities:" << openActivities_.size();
+ if (openActivities_.size() < 2) {
+ delete m_activityMenu;
+ m_activityMenu = 0;
+ } else {
+ initActivityPopup();
+ }
+#endif
+}
+
+void UserActionsMenu::selectPopupClientTab(QAction* action)
+{
+ if (!(!m_client.isNull() && m_client.data()->tabGroup()) || !action->data().isValid())
+ return;
+
+ if (Client *other = action->data().value()) {
+ m_client.data()->tabGroup()->setCurrent(other);
+ return;
+ }
+
+ // failed conversion, try "1" & "2", being prev and next
+ int direction = action->data().toInt();
+ if (direction == 1)
+ m_client.data()->tabGroup()->activatePrev();
+ else if (direction == 2)
+ m_client.data()->tabGroup()->activateNext();
+}
+
+static QString shortCaption(const QString &s)
+{
+ if (s.length() < 64)
+ return s;
+ QString ss = s;
+ return ss.replace(32,s.length()-64,"...");
+}
+
+void UserActionsMenu::rebuildTabListPopup()
+{
+ Q_ASSERT(m_switchToTabMenu);
+
+ m_switchToTabMenu->clear();
+ // whatever happens "0x1" and "0x2" are no heap positions ;-)
+ m_switchToTabMenu->addAction(i18nc("Switch to tab -> Previous", "Previous"))->setData(1);
+ m_switchToTabMenu->addAction(i18nc("Switch to tab -> Next", "Next"))->setData(2);
+
+ m_switchToTabMenu->addSeparator();
+
+ for (QList::const_iterator i = m_client.data()->tabGroup()->clients().constBegin(),
+ end = m_client.data()->tabGroup()->clients().constEnd(); i != end; ++i) {
+ if ((*i)->noBorder() || *i == m_client.data()->tabGroup()->current())
+ continue; // cannot tab there anyway
+ m_switchToTabMenu->addAction(shortCaption((*i)->caption()))->setData(QVariant::fromValue(*i));
+ }
+
+}
+
+void UserActionsMenu::entabPopupClient(QAction* action)
+{
+ if (m_client.isNull() || !action->data().isValid())
+ return;
+ Client *other = action->data().value();
+ if (!Workspace::self()->clientList().contains(other)) // might have been lost betwenn pop-up and selection
+ return;
+ m_client.data()->tabBehind(other, true);
+ if (options->focusPolicyIsReasonable())
+ Workspace::self()->requestFocus(m_client.data());
+}
+
+void UserActionsMenu::rebuildTabGroupPopup()
+{
+ Q_ASSERT(m_addTabsMenu);
+
+ m_addTabsMenu->clear();
+ QList handled;
+ const ClientList &clientList = Workspace::self()->clientList();
+ for (QList::const_iterator i = clientList.constBegin(), end = clientList.constEnd(); i != end; ++i) {
+ if (*i == m_client.data() || (*i)->noBorder())
+ continue;
+ m_addTabsMenu->addAction(shortCaption((*i)->caption()))->setData(QVariant::fromValue(*i));
+ }
+}
+
+void UserActionsMenu::initTabbingPopups()
+{
+ bool needTabManagers = false;
+ if (m_client.data()->tabGroup() && m_client.data()->tabGroup()->count() > 1) {
+ needTabManagers = true;
+ if (!m_switchToTabMenu) {
+ m_switchToTabMenu = new QMenu(i18n("Switch to Tab"), m_menu);
+ m_switchToTabMenu->setFont(KGlobalSettings::menuFont());
+ connect(m_switchToTabMenu, SIGNAL(triggered(QAction*)), SLOT(selectPopupClientTab(QAction*)));
+ connect(m_switchToTabMenu, SIGNAL(aboutToShow()), SLOT(rebuildTabListPopup()));
+ m_menu->insertMenu(m_removeFromTabGroup, m_switchToTabMenu);
+ }
+ } else {
+ delete m_switchToTabMenu;
+ m_switchToTabMenu = 0;
+ }
+
+ if (!m_addTabsMenu) {
+ m_addTabsMenu = new QMenu(i18n("Attach as tab to"), m_menu);
+ m_addTabsMenu->setFont(KGlobalSettings::menuFont());
+ connect(m_addTabsMenu, SIGNAL(triggered(QAction*)), SLOT(entabPopupClient(QAction*)));
+ connect(m_addTabsMenu, SIGNAL(aboutToShow()), SLOT(rebuildTabGroupPopup()));
+ m_menu->insertMenu(m_removeFromTabGroup, m_addTabsMenu);
+ }
+
+ m_removeFromTabGroup->setVisible(needTabManagers);
+ m_closeTabGroup->setVisible(needTabManagers);
+}
+
+void UserActionsMenu::initDesktopPopup()
+{
+ if (m_desktopMenu)
+ return;
+
+ m_desktopMenu = new QMenu(m_menu);
+ m_desktopMenu->setFont(KGlobalSettings::menuFont());
+ connect(m_desktopMenu, SIGNAL(triggered(QAction*)), SLOT(slotSendToDesktop(QAction*)));
+ connect(m_desktopMenu, SIGNAL(aboutToShow()), SLOT(desktopPopupAboutToShow()));
+
+ QAction *action = m_desktopMenu->menuAction();
+ // set it as the first item
+ m_menu->insertAction(m_minimizeOperation, action);
+ action->setText(i18n("Move To &Desktop"));
+}
+
+void UserActionsMenu::initScreenPopup()
+{
+ if (m_screenMenu) {
+ return;
+ }
+
+ m_screenMenu = new QMenu(m_menu);
+ m_screenMenu->setFont(KGlobalSettings::menuFont());
+ connect(m_screenMenu, SIGNAL(triggered(QAction*)), SLOT(slotSendToScreen(QAction*)));
+ connect(m_screenMenu, SIGNAL(aboutToShow()), SLOT(screenPopupAboutToShow()));
+
+ QAction *action = m_screenMenu->menuAction();
+ // set it as the first item after desktop
+ m_menu->insertAction(m_activityMenu ? m_activityMenu->menuAction() : m_minimizeOperation, action);
+ action->setText(i18n("Move To &Screen"));
+}
+
+void UserActionsMenu::initActivityPopup()
+{
+ if (m_activityMenu)
+ return;
+
+ m_activityMenu = new QMenu(m_menu);
+ m_activityMenu->setFont(KGlobalSettings::menuFont());
+ connect(m_activityMenu, SIGNAL(triggered(QAction*)),
+ this, SLOT(slotToggleOnActivity(QAction*)));
+ connect(m_activityMenu, SIGNAL(aboutToShow()),
+ this, SLOT(activityPopupAboutToShow()));
+
+ QAction *action = m_activityMenu->menuAction();
+ // set it as the first item
+ m_menu->insertAction(m_minimizeOperation, action);
+ action->setText(i18n("Ac&tivities")); //FIXME is that a good string?
+}
+
+void UserActionsMenu::desktopPopupAboutToShow()
+{
+ if (!m_desktopMenu)
+ return;
+ const Workspace *ws = Workspace::self();
+
+ m_desktopMenu->clear();
+ QActionGroup *group = new QActionGroup(m_desktopMenu);
+ QAction *action = m_desktopMenu->addAction(i18n("&All Desktops"));
+ action->setData(0);
+ action->setCheckable(true);
+ group->addAction(action);
+
+ if (!m_client.isNull() && m_client.data()->isOnAllDesktops())
+ action->setChecked(true);
+ m_desktopMenu->addSeparator();
+
+ const int BASE = 10;
+ for (int i = 1; i <= ws->numberOfDesktops(); ++i) {
+ QString basic_name("%1 %2");
+ if (i < BASE) {
+ basic_name.prepend('&');
+ }
+ action = m_desktopMenu->addAction(basic_name.arg(i).arg(ws->desktopName(i).replace('&', "&&")));
+ action->setData(i);
+ action->setCheckable(true);
+ group->addAction(action);
+
+ if (!m_client.isNull() &&
+ !m_client.data()->isOnAllDesktops() && m_client.data()->desktop() == i)
+ action->setChecked(true);
+ }
+
+ m_desktopMenu->addSeparator();
+ action = m_desktopMenu->addAction(i18nc("Create a new desktop and move there the window", "&New Desktop"));
+ action->setData(ws->numberOfDesktops() + 1);
+
+ if (ws->numberOfDesktops() >= Workspace::self()->maxNumberOfDesktops())
+ action->setEnabled(false);
+}
+
+void UserActionsMenu::screenPopupAboutToShow()
+{
+ if (!m_screenMenu) {
+ return;
+ }
+
+ m_screenMenu->clear();
+ QActionGroup *group = new QActionGroup(m_screenMenu);
+
+ for (int i = 0; inumScreens(); ++i) {
+ // TODO: retrieve the screen name?
+ // assumption: there are not more than 9 screens attached.
+ QAction *action = m_screenMenu->addAction(i18nc("@item:inmenu List of all Screens to send a window to",
+ "Screen &%1", (i+1)));
+ action->setData(i);
+ action->setCheckable(true);
+ if (!m_client.isNull() && i == m_client.data()->screen()) {
+ action->setChecked(true);
+ }
+ group->addAction(action);
+ }
+}
+
+void UserActionsMenu::activityPopupAboutToShow()
+{
+ if (!m_activityMenu)
+ return;
+
+#ifdef KWIN_BUILD_ACTIVITIES
+ m_activityMenu->clear();
+ QAction *action = m_activityMenu->addAction(i18n("&All Activities"));
+ action->setData(QString());
+ action->setCheckable(true);
+
+ if (!m_client.isNull() && m_client.data()->isOnAllActivities())
+ action->setChecked(true);
+ m_activityMenu->addSeparator();
+
+ foreach (const QString &id, Workspace::self()->openActivities()) {
+ KActivities::Info activity(id);
+ QString name = activity.name();
+ name.replace('&', "&&");
+ action = m_activityMenu->addAction(KIcon(activity.icon()), name);
+ action->setData(id);
+ action->setCheckable(true);
+
+ if (!m_client.isNull() &&
+ !m_client.data()->isOnAllActivities() && m_client.data()->isOnActivity(id))
+ action->setChecked(true);
+ }
+#endif
+}
+
+void UserActionsMenu::slotWindowOperation(QAction *action)
+{
+ if (!action->data().isValid())
+ return;
+
+ Options::WindowOperation op = static_cast< Options::WindowOperation >(action->data().toInt());
+ QWeakPointer c = (!m_client.isNull()) ? m_client : QWeakPointer(Workspace::self()->activeClient());
+ if (c.isNull())
+ return;
+ QString type;
+ switch(op) {
+ case Options::FullScreenOp:
+ if (!c.data()->isFullScreen() && c.data()->userCanSetFullScreen())
+ type = "fullscreenaltf3";
+ break;
+ case Options::NoBorderOp:
+ if (!c.data()->noBorder() && c.data()->userCanSetNoBorder())
+ type = "noborderaltf3";
+ break;
+ default:
+ break;
+ };
+ if (!type.isEmpty())
+ helperDialog(type, c);
+ Workspace::self()->performWindowOperation(c.data(), op);
+}
+
+void UserActionsMenu::slotSendToDesktop(QAction *action)
+{
+ int desk = action->data().toInt();
+ if (m_client.isNull())
+ return;
+ Workspace *ws = Workspace::self();
+ if (desk == 0) {
+ // the 'on_all_desktops' menu entry
+ m_client.data()->setOnAllDesktops(!m_client.data()->isOnAllDesktops());
+ return;
+ } else if (desk > ws->numberOfDesktops()) {
+ ws->setNumberOfDesktops(desk);
+ }
+
+ ws->sendClientToDesktop(m_client.data(), desk, false);
+}
+
+void UserActionsMenu::slotSendToScreen(QAction *action)
+{
+ const int screen = action->data().toInt();
+ if (m_client.isNull()) {
+ return;
+ }
+ Workspace *ws = Workspace::self();
+ if (screen >= ws->numScreens()) {
+ return;
+ }
+
+ ws->sendClientToScreen(m_client.data(), screen);
+}
+
+void UserActionsMenu::slotToggleOnActivity(QAction *action)
+{
+ QString activity = action->data().toString();
+ if (m_client.isNull())
+ return;
+ if (activity.isEmpty()) {
+ // the 'on_all_activities' menu entry
+ m_client.data()->setOnAllActivities(!m_client.data()->isOnAllActivities());
+ return;
+ }
+
+ Workspace::self()->toggleClientOnActivity(m_client.data(), activity, false);
+}
+
//****************************************
// Workspace
//****************************************
-QMenu* Workspace::clientPopup()
-{
- if (!popup) {
- popup = new QMenu;
- popup->setFont(KGlobalSettings::menuFont());
- connect(popup, SIGNAL(aboutToShow()), this, SLOT(clientPopupAboutToShow()));
- connect(popup, SIGNAL(triggered(QAction*)), this, SLOT(clientPopupActivated(QAction*)));
-
- advanced_popup = new QMenu(popup);
- advanced_popup->setFont(KGlobalSettings::menuFont());
-
- mMoveOpAction = advanced_popup->addAction(i18n("&Move"));
- mMoveOpAction->setIcon(KIcon("transform-move"));
- KAction *kaction = qobject_cast(keys->action("Window Move"));
- if (kaction != 0)
- mMoveOpAction->setShortcut(kaction->globalShortcut().primary());
- mMoveOpAction->setData(Options::UnrestrictedMoveOp);
-
- mResizeOpAction = advanced_popup->addAction(i18n("Re&size"));
- kaction = qobject_cast(keys->action("Window Resize"));
- if (kaction != 0)
- mResizeOpAction->setShortcut(kaction->globalShortcut().primary());
- mResizeOpAction->setData(Options::ResizeOp);
-
- mKeepAboveOpAction = advanced_popup->addAction(i18n("Keep &Above Others"));
- mKeepAboveOpAction->setIcon(KIcon("go-up"));
- kaction = qobject_cast(keys->action("Window Above Other Windows"));
- if (kaction != 0)
- mKeepAboveOpAction->setShortcut(kaction->globalShortcut().primary());
- mKeepAboveOpAction->setCheckable(true);
- mKeepAboveOpAction->setData(Options::KeepAboveOp);
-
- mKeepBelowOpAction = advanced_popup->addAction(i18n("Keep &Below Others"));
- mKeepBelowOpAction->setIcon(KIcon("go-down"));
- kaction = qobject_cast(keys->action("Window Below Other Windows"));
- if (kaction != 0)
- mKeepBelowOpAction->setShortcut(kaction->globalShortcut().primary());
- mKeepBelowOpAction->setCheckable(true);
- mKeepBelowOpAction->setData(Options::KeepBelowOp);
-
- mFullScreenOpAction = advanced_popup->addAction(i18n("&Fullscreen"));
- mFullScreenOpAction->setIcon(KIcon("view-fullscreen"));
- kaction = qobject_cast(keys->action("Window Fullscreen"));
- if (kaction != 0)
- mFullScreenOpAction->setShortcut(kaction->globalShortcut().primary());
- mFullScreenOpAction->setCheckable(true);
- mFullScreenOpAction->setData(Options::FullScreenOp);
-
- mShadeOpAction = advanced_popup->addAction(i18n("Sh&ade"));
- kaction = qobject_cast(keys->action("Window Shade"));
- if (kaction != 0)
- mShadeOpAction->setShortcut(kaction->globalShortcut().primary());
- mShadeOpAction->setCheckable(true);
- mShadeOpAction->setData(Options::ShadeOp);
-
- mNoBorderOpAction = advanced_popup->addAction(i18n("&No Border"));
- kaction = qobject_cast(keys->action("Window No Border"));
- if (kaction != 0)
- mNoBorderOpAction->setShortcut(kaction->globalShortcut().primary());
- mNoBorderOpAction->setCheckable(true);
- mNoBorderOpAction->setData(Options::NoBorderOp);
-
- advanced_popup->addSeparator();
-
- QAction *action = advanced_popup->addAction(i18n("Window &Shortcut..."));
- action->setIcon(KIcon("configure-shortcuts"));
- kaction = qobject_cast(keys->action("Setup Window Shortcut"));
- if (kaction != 0)
- action->setShortcut(kaction->globalShortcut().primary());
- action->setData(Options::SetupWindowShortcutOp);
-
- action = advanced_popup->addAction(i18n("&Special Window Settings..."));
- action->setIcon(KIcon("preferences-system-windows-actions"));
- action->setData(Options::WindowRulesOp);
-
- action = advanced_popup->addAction(i18n("S&pecial Application Settings..."));
- action->setIcon(KIcon("preferences-system-windows-actions"));
- action->setData(Options::ApplicationRulesOp);
- if (!KGlobal::config()->isImmutable() &&
- !KAuthorized::authorizeControlModules(Workspace::configModules(true)).isEmpty()) {
- advanced_popup->addSeparator();
- action = advanced_popup->addAction(i18nc("Entry in context menu of window decoration to open the configuration module of KWin",
- "Window &Manager Settings..."));
- action->setIcon(KIcon("configure"));
- connect(action, SIGNAL(triggered()), this, SLOT(configureWM()));
- }
-
- mMinimizeOpAction = popup->addAction(i18n("Mi&nimize"));
- kaction = qobject_cast(keys->action("Window Minimize"));
- if (kaction != 0)
- mMinimizeOpAction->setShortcut(kaction->globalShortcut().primary());
- mMinimizeOpAction->setData(Options::MinimizeOp);
-
- mMaximizeOpAction = popup->addAction(i18n("Ma&ximize"));
- kaction = qobject_cast(keys->action("Window Maximize"));
- if (kaction != 0)
- mMaximizeOpAction->setShortcut(kaction->globalShortcut().primary());
- mMaximizeOpAction->setCheckable(true);
- mMaximizeOpAction->setData(Options::MaximizeOp);
-
- popup->addSeparator();
-
- // Actions for window tabbing
- if (decorationSupportsTabbing()) {
- mRemoveFromTabGroup = popup->addAction(i18n("&Untab"));
- kaction = qobject_cast(keys->action("Untab"));
- if (kaction != 0)
- mRemoveFromTabGroup->setShortcut(kaction->globalShortcut().primary());
- mRemoveFromTabGroup->setData(Options::RemoveTabFromGroupOp);
-
- mCloseTabGroup = popup->addAction(i18n("Close Entire &Group"));
- mCloseTabGroup->setIcon(KIcon("window-close"));
- kaction = qobject_cast(keys->action("Close TabGroup"));
- if (kaction != 0)
- mCloseTabGroup->setShortcut(kaction->globalShortcut().primary());
- mCloseTabGroup->setData(Options::CloseTabGroupOp);
-
- popup->addSeparator();
- }
-
- popup->addSeparator();
-
- action = popup->addMenu(advanced_popup);
- action->setText(i18n("More Actions"));
-
- popup->addSeparator();
-
- mCloseOpAction = popup->addAction(i18n("&Close"));
- mCloseOpAction->setIcon(KIcon("window-close"));
- kaction = qobject_cast(keys->action("Window Close"));
- if (kaction != 0)
- mCloseOpAction->setShortcut(kaction->globalShortcut().primary());
- mCloseOpAction->setData(Options::CloseOp);
- }
- return popup;
-}
-
-void Workspace::discardPopup()
-{
- delete popup;
- popup = NULL;
- desk_popup = NULL;
- screen_popup = NULL;
- activity_popup = NULL;
- switch_to_tab_popup = NULL;
- add_tabs_popup = NULL;
-}
-
void Workspace::slotIncreaseWindowOpacity()
{
if (!active_client) {
@@ -236,329 +779,6 @@ void Workspace::slotLowerWindowOpacity()
active_client->setOpacity(qMax(active_client->opacity() - 0.05, 0.05));
}
-/*!
- The client popup menu will become visible soon.
-
- Adjust the items according to the respective popup client.
- */
-void Workspace::clientPopupAboutToShow()
-{
- if (!active_popup_client || !popup)
- return;
-
- if (numberOfDesktops() == 1) {
- delete desk_popup;
- desk_popup = 0;
- } else {
- initDesktopPopup();
- }
- if (numScreens() == 1 || (!active_popup_client->isMovable() && !active_popup_client->isMovableAcrossScreens())) {
- delete screen_popup;
- screen_popup = NULL;
- } else {
- initScreenPopup();
- }
-#ifdef KWIN_BUILD_ACTIVITIES
- updateActivityList(true, false, "showHideActivityMenu");
-#endif
-
- mResizeOpAction->setEnabled(active_popup_client->isResizable());
- mMoveOpAction->setEnabled(active_popup_client->isMovableAcrossScreens());
- mMaximizeOpAction->setEnabled(active_popup_client->isMaximizable());
- mMaximizeOpAction->setChecked(active_popup_client->maximizeMode() == Client::MaximizeFull);
- mShadeOpAction->setEnabled(active_popup_client->isShadeable());
- mShadeOpAction->setChecked(active_popup_client->shadeMode() != ShadeNone);
- mKeepAboveOpAction->setChecked(active_popup_client->keepAbove());
- mKeepBelowOpAction->setChecked(active_popup_client->keepBelow());
- mFullScreenOpAction->setEnabled(active_popup_client->userCanSetFullScreen());
- mFullScreenOpAction->setChecked(active_popup_client->isFullScreen());
- mNoBorderOpAction->setEnabled(active_popup_client->userCanSetNoBorder());
- mNoBorderOpAction->setChecked(active_popup_client->noBorder());
- mMinimizeOpAction->setEnabled(active_popup_client->isMinimizable());
- mCloseOpAction->setEnabled(active_popup_client->isCloseable());
-
- if (decorationSupportsTabbing()) {
- initTabbingPopups();
- } else {
- delete add_tabs_popup;
- add_tabs_popup = 0;
- }
-}
-
-void Workspace::showHideActivityMenu()
-{
-#ifdef KWIN_BUILD_ACTIVITIES
- kDebug() << "activities:" << openActivities_.size();
- if (openActivities_.size() < 2) {
- delete activity_popup;
- activity_popup = 0;
- } else {
- initActivityPopup();
- }
-#endif
-}
-
-void Workspace::selectPopupClientTab(QAction* action)
-{
- if (!(active_popup_client && active_popup_client->tabGroup()) || !action->data().isValid())
- return;
-
- if (Client *other = action->data().value()) {
- active_popup_client->tabGroup()->setCurrent(other);
- return;
- }
-
- // failed conversion, try "1" & "2", being prev and next
- int direction = action->data().toInt();
- if (direction == 1)
- active_popup_client->tabGroup()->activatePrev();
- else if (direction == 2)
- active_popup_client->tabGroup()->activateNext();
-}
-
-static QString shortCaption(const QString &s)
-{
- if (s.length() < 64)
- return s;
- QString ss = s;
- return ss.replace(32,s.length()-64,"...");
-}
-
-void Workspace::rebuildTabListPopup()
-{
- Q_ASSERT(switch_to_tab_popup);
-
- switch_to_tab_popup->clear();
- // whatever happens "0x1" and "0x2" are no heap positions ;-)
- switch_to_tab_popup->addAction(i18nc("Switch to tab -> Previous", "Previous"))->setData(1);
- switch_to_tab_popup->addAction(i18nc("Switch to tab -> Next", "Next"))->setData(2);
-
- switch_to_tab_popup->addSeparator();
-
- for (QList::const_iterator i = active_popup_client->tabGroup()->clients().constBegin(),
- end = active_popup_client->tabGroup()->clients().constEnd(); i != end; ++i) {
- if ((*i)->noBorder() || *i == active_popup_client->tabGroup()->current())
- continue; // cannot tab there anyway
- switch_to_tab_popup->addAction(shortCaption((*i)->caption()))->setData(QVariant::fromValue(*i));
- }
-
-}
-
-void Workspace::entabPopupClient(QAction* action)
-{
- if (!active_popup_client || !action->data().isValid())
- return;
- Client *other = action->data().value();
- if (!clients.contains(other)) // might have been lost betwenn pop-up and selection
- return;
- active_popup_client->tabBehind(other, true);
- if (options->focusPolicyIsReasonable())
- requestFocus(active_popup_client);
-}
-
-void Workspace::rebuildTabGroupPopup()
-{
- Q_ASSERT(add_tabs_popup);
-
- add_tabs_popup->clear();
- QList handled;
- for (QList::const_iterator i = clientList().constBegin(), end = clientList().constEnd(); i != end; ++i) {
- if (*i == active_popup_client || (*i)->noBorder())
- continue;
- add_tabs_popup->addAction(shortCaption((*i)->caption()))->setData(QVariant::fromValue(*i));
- }
-}
-
-void Workspace::initTabbingPopups()
-{
- bool needTabManagers = false;
- if (active_popup_client->tabGroup() && active_popup_client->tabGroup()->count() > 1) {
- needTabManagers = true;
- if (!switch_to_tab_popup) {
- switch_to_tab_popup = new QMenu(i18n("Switch to Tab"), popup);
- switch_to_tab_popup->setFont(KGlobalSettings::menuFont());
- connect(switch_to_tab_popup, SIGNAL(triggered(QAction*)), SLOT(selectPopupClientTab(QAction*)));
- connect(switch_to_tab_popup, SIGNAL(aboutToShow()), SLOT(rebuildTabListPopup()));
- popup->insertMenu(mRemoveFromTabGroup, switch_to_tab_popup);
- }
- } else {
- delete switch_to_tab_popup;
- switch_to_tab_popup = 0;
- }
-
- if (!add_tabs_popup) {
- add_tabs_popup = new QMenu(i18n("Attach as tab to"), popup);
- add_tabs_popup->setFont(KGlobalSettings::menuFont());
- connect(add_tabs_popup, SIGNAL(triggered(QAction*)), SLOT(entabPopupClient(QAction*)));
- connect(add_tabs_popup, SIGNAL(aboutToShow()), SLOT(rebuildTabGroupPopup()));
- popup->insertMenu(mRemoveFromTabGroup, add_tabs_popup);
- }
-
- mRemoveFromTabGroup->setVisible(needTabManagers);
- mCloseTabGroup->setVisible(needTabManagers);
-}
-
-void Workspace::initDesktopPopup()
-{
- if (desk_popup)
- return;
-
- desk_popup = new QMenu(popup);
- desk_popup->setFont(KGlobalSettings::menuFont());
- connect(desk_popup, SIGNAL(triggered(QAction*)), SLOT(slotSendToDesktop(QAction*)));
- connect(desk_popup, SIGNAL(aboutToShow()), SLOT(desktopPopupAboutToShow()));
-
- QAction *action = desk_popup->menuAction();
- // set it as the first item
- popup->insertAction(mMinimizeOpAction, action);
- action->setText(i18n("Move To &Desktop"));
-}
-
-void Workspace::initScreenPopup()
-{
- if (screen_popup) {
- return;
- }
-
- screen_popup = new QMenu(popup);
- screen_popup->setFont(KGlobalSettings::menuFont());
- connect(screen_popup, SIGNAL(triggered(QAction*)), SLOT(slotSendToScreen(QAction*)));
- connect(screen_popup, SIGNAL(aboutToShow()), SLOT(screenPopupAboutToShow()));
-
- QAction *action = screen_popup->menuAction();
- // set it as the first item after desktop
- popup->insertAction(activity_popup ? activity_popup->menuAction() : mMinimizeOpAction, action);
- action->setText(i18n("Move To &Screen"));
-}
-
-/*!
- Creates activity popup.
- I'm going with checkable ones instead of "copy to" and "move to" menus; I *think* it's an easier way.
- Oh, and an 'all' option too of course
- */
-void Workspace::initActivityPopup()
-{
- if (activity_popup)
- return;
-
- activity_popup = new QMenu(popup);
- activity_popup->setFont(KGlobalSettings::menuFont());
- connect(activity_popup, SIGNAL(triggered(QAction*)),
- this, SLOT(slotToggleOnActivity(QAction*)));
- connect(activity_popup, SIGNAL(aboutToShow()),
- this, SLOT(activityPopupAboutToShow()));
-
- QAction *action = activity_popup->menuAction();
- // set it as the first item
- popup->insertAction(mMinimizeOpAction, action);
- action->setText(i18n("Ac&tivities")); //FIXME is that a good string?
-}
-
-/*!
- Adjusts the desktop popup to the current values and the location of
- the popup client.
- */
-void Workspace::desktopPopupAboutToShow()
-{
- if (!desk_popup)
- return;
-
- desk_popup->clear();
- QActionGroup *group = new QActionGroup(desk_popup);
- QAction *action = desk_popup->addAction(i18n("&All Desktops"));
- action->setData(0);
- action->setCheckable(true);
- group->addAction(action);
-
- if (active_popup_client && active_popup_client->isOnAllDesktops())
- action->setChecked(true);
- desk_popup->addSeparator();
-
- const int BASE = 10;
- for (int i = 1; i <= numberOfDesktops(); i++) {
- QString basic_name("%1 %2");
- if (i < BASE) {
- basic_name.prepend('&');
- }
- action = desk_popup->addAction(basic_name.arg(i).arg(desktopName(i).replace('&', "&&")));
- action->setData(i);
- action->setCheckable(true);
- group->addAction(action);
-
- if (active_popup_client &&
- !active_popup_client->isOnAllDesktops() && active_popup_client->desktop() == i)
- action->setChecked(true);
- }
-
- desk_popup->addSeparator();
- action = desk_popup->addAction(i18nc("Create a new desktop and move there the window", "&New Desktop"));
- action->setData(numberOfDesktops() + 1);
-
- if (numberOfDesktops() >= Workspace::self()->maxNumberOfDesktops())
- action->setEnabled(false);
-}
-
-/*!
- Adjusts the screen popup to the current values and the location of
- the popup client.
- */
-void Workspace::screenPopupAboutToShow()
-{
- if (!screen_popup) {
- return;
- }
-
- screen_popup->clear();
- QActionGroup *group = new QActionGroup(screen_popup);
-
- for (int i = 0; iaddAction(i18nc("@item:inmenu List of all Screens to send a window to",
- "Screen &%1", (i+1)));
- action->setData(i);
- action->setCheckable(true);
- if (active_popup_client && i == active_popup_client->screen()) {
- action->setChecked(true);
- }
- group->addAction(action);
- }
-}
-
-/*!
- Adjusts the activity popup to the current values and the location of
- the popup client.
- */
-void Workspace::activityPopupAboutToShow()
-{
- if (!activity_popup)
- return;
-
-#ifdef KWIN_BUILD_ACTIVITIES
- activity_popup->clear();
- QAction *action = activity_popup->addAction(i18n("&All Activities"));
- action->setData(QString());
- action->setCheckable(true);
-
- if (active_popup_client && active_popup_client->isOnAllActivities())
- action->setChecked(true);
- activity_popup->addSeparator();
-
- foreach (const QString &id, openActivities_) {
- KActivities::Info activity(id);
- QString name = activity.name();
- name.replace('&', "&&");
- action = activity_popup->addAction(KIcon(activity.icon()), name);
- action->setData(id);
- action->setCheckable(true);
-
- if (active_popup_client &&
- !active_popup_client->isOnAllActivities() && active_popup_client->isOnActivity(id))
- action->setChecked(true);
- }
-#endif
-}
-
void Workspace::closeActivePopup()
{
if (active_popup) {
@@ -566,6 +786,7 @@ void Workspace::closeActivePopup()
active_popup = NULL;
active_popup_client = NULL;
}
+ m_userActionsMenu->close();
}
/*!
@@ -590,7 +811,7 @@ void Workspace::initShortcuts()
tab_box->initShortcuts(actionCollection);
}
#endif
- discardPopup(); // so that it's recreated next time
+ m_userActionsMenu->discard(); // so that it's recreated next time
}
void Workspace::setupWindowShortcut(Client* c)
@@ -655,34 +876,6 @@ void Workspace::clientShortcutUpdated(Client* c)
}
}
-void Workspace::clientPopupActivated(QAction *action)
-{
- if (!action->data().isValid())
- return;
-
- WindowOperation op = static_cast< WindowOperation >(action->data().toInt());
- Client* c = active_popup_client ? active_popup_client : active_client;
- if (!c)
- return;
- QString type;
- switch(op) {
- case FullScreenOp:
- if (!c->isFullScreen() && c->userCanSetFullScreen())
- type = "fullscreenaltf3";
- break;
- case NoBorderOp:
- if (!c->noBorder() && c->userCanSetNoBorder())
- type = "noborderaltf3";
- break;
- default:
- break;
- };
- if (!type.isEmpty())
- helperDialog(type, c);
- performWindowOperation(c, op);
-}
-
-
void Workspace::performWindowOperation(Client* c, Options::WindowOperation op)
{
if (!c)
@@ -1432,66 +1625,6 @@ void Workspace::slotKillWindow()
kill.start();
}
-/*!
- Sends the popup client to desktop \a desk
-
- Internal slot for the window operation menu
- */
-void Workspace::slotSendToDesktop(QAction *action)
-{
- int desk = action->data().toInt();
- if (!active_popup_client)
- return;
- if (desk == 0) {
- // the 'on_all_desktops' menu entry
- active_popup_client->setOnAllDesktops(!active_popup_client->isOnAllDesktops());
- return;
- } else if (desk > numberOfDesktops()) {
- setNumberOfDesktops(desk);
- }
-
- sendClientToDesktop(active_popup_client, desk, false);
-
-}
-
-/*!
- Sends the popup client to screen \a screen
-
- Internal slot for the window operation menu
- */
-void Workspace::slotSendToScreen(QAction *action)
-{
- const int screen = action->data().toInt();
- if (!active_popup_client) {
- return;
- }
- if (screen >= numScreens()) {
- return;
- }
-
- sendClientToScreen(active_popup_client, screen);
-}
-
-/*!
- Toggles whether the popup client is on the \a activity
-
- Internal slot for the window operation menu
- */
-void Workspace::slotToggleOnActivity(QAction *action)
-{
- QString activity = action->data().toString();
- if (!active_popup_client)
- return;
- if (activity.isEmpty()) {
- // the 'on_all_activities' menu entry
- active_popup_client->setOnAllActivities(!active_popup_client->isOnAllActivities());
- return;
- }
-
- toggleClientOnActivity(active_popup_client, activity, false);
-
-}
-
/*!
Switches to the nearest window in given direction
*/
@@ -1605,35 +1738,7 @@ void Workspace::slotWindowOperations()
void Workspace::showWindowMenu(const QRect &pos, Client* cl)
{
- if (!KAuthorized::authorizeKAction("kwin_rmb"))
- return;
- if (!cl)
- return;
- if (active_popup_client != NULL) // recursion
- return;
- if (cl->isDesktop()
- || cl->isDock())
- return;
-
- active_popup_client = cl;
- QMenu* p = clientPopup();
- active_popup = p;
- int x = pos.left();
- int y = pos.bottom();
- if (y == pos.top())
- p->exec(QPoint(x, y));
- else {
- QRect area = clientArea(ScreenArea, QPoint(x, y), currentDesktop());
- clientPopupAboutToShow(); // needed for sizeHint() to be correct :-/
- int popupHeight = p->sizeHint().height();
- if (y + popupHeight < area.height())
- p->exec(QPoint(x, y));
- else
- p->exec(QPoint(x, pos.top() - popupHeight));
- }
- // active popup may be already changed (e.g. the window shortcut dialog)
- if (active_popup == p)
- closeActivePopup();
+ m_userActionsMenu->show(pos, cl);
}
/*!
diff --git a/useractions.h b/useractions.h
new file mode 100644
index 0000000000..094a614ef4
--- /dev/null
+++ b/useractions.h
@@ -0,0 +1,255 @@
+/********************************************************************
+KWin - the KDE window manager
+This file is part of the KDE project.
+
+Copyright (C) 2012 Martin Gräßlin
+
+This program 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.
+
+This program 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 .
+*********************************************************************/
+#ifndef KWIN_USERACTIONS_H
+#define KWIN_USERACTIONS_H
+
+#include
+#include
+
+class QAction;
+class QMenu;
+class QRect;
+
+namespace KWin
+{
+class Client;
+
+/**
+ * @brief Menu shown for a Client.
+ *
+ * The UserActionsMenu implements the Menu which is shown on:
+ * @li context-menu event on Window decoration
+ * @li window menu button
+ * @li Keyboard Shortcut (by default Alt+F3)
+ *
+ * The menu contains various window management related actions for the Client the menu is opened
+ * for, this is normally the active Client.
+ *
+ * The menu which is shown is tried to be as close as possible to the menu implemented in
+ * libtaskmanager, though there are differences as there are some actions only the window manager
+ * can provide and on the other hand the libtaskmanager cares also about things like e.g. grouping.
+ *
+ * Whenever the menu is changed it should be tried to also adjust the menu in libtaskmanager.
+ *
+ * @author Martin Gräßlin
+ **/
+class UserActionsMenu : public QObject
+{
+ Q_OBJECT
+public:
+ explicit UserActionsMenu(QObject *parent = 0);
+ virtual ~UserActionsMenu();
+ /**
+ * Discards the constructed menu, so that it gets recreates
+ * on next show event.
+ * @see show
+ **/
+ void discard();
+
+ /**
+ * @returns Whether the menu is currently visible
+ **/
+ bool isShown() const;
+ /**
+ * @returns Whether the menu has a Client set to operate on.
+ **/
+ bool hasClient() const;
+ /**
+ * Checks whether the given Client @p c is the Client
+ * for which the Menu is shown.
+ * @param c The Client to compare
+ * @returns Whether the Client is the one related to this Menu
+ **/
+ bool isMenuClient(const Client *c) const;
+ /**
+ * Closes the Menu and prepares it for next usage.
+ **/
+ void close();
+ /**
+ * @brief Shows the menu at the given @p pos for the given @p client.
+ *
+ * @param pos The position where the menu should be shown.
+ * @param client The Client for which the Menu has to be shown.
+ **/
+ void show(const QRect &pos, const QWeakPointer &client);
+
+public slots:
+ /**
+ * Delayed initialization of the activity menu.
+ *
+ * The call to retrieve the current list of activities is performed in a thread and this
+ * slot is invoked once the list has been fetched. Only task of this method is to decide
+ * whether to show the activity menu and to invoke the initialization of it.
+ *
+ * @see initActivityPopup
+ **/
+ void showHideActivityMenu();
+
+private slots:
+ /**
+ * The menu will become visible soon.
+ *
+ * Adjust the items according to the respective Client.
+ **/
+ void menuAboutToShow();
+ /**
+ * Adjusts the add to tab group menu to the current value of the Client.
+ **/
+ void rebuildTabGroupPopup();
+ /**
+ * Adjusts the switch to tab menu to the current values of the Client.
+ **/
+ void rebuildTabListPopup();
+ /**
+ * Adds the Client as tab to the Client identified by the @p action.
+ *
+ * @param action The invoked action containing the Client to which the active Client should be tabbed.
+ **/
+ void entabPopupClient(QAction *action);
+ /**
+ * Activates the selected tabbed Client.
+ *
+ * @param action The invoked action containing the tabbed Client which should be activated.
+ **/
+ void selectPopupClientTab(QAction *action);
+ /**
+ * Adjusts the desktop popup to the current values and the location of
+ * the Client.
+ **/
+ void desktopPopupAboutToShow();
+ /**
+ * Adjusts the screen popup to the current values and the location of
+ * the Client.
+ **/
+ void screenPopupAboutToShow();
+ /**
+ * Adjusts the activity popup to the current values and the location of
+ * the Client.
+ **/
+ void activityPopupAboutToShow();
+ /**
+ * Sends the client to desktop \a desk
+ *
+ * @param action Invoked Action containing the Desktop as data element
+ **/
+ void slotSendToDesktop(QAction *action);
+ /**
+ * Sends the Client to screen \a screen
+ *
+ * @param action Invoked Action containing the Screen as data element
+ **/
+ void slotSendToScreen(QAction *action);
+ /**
+ * Toggles whether the Client is on the \a activity
+ *
+ * @param action Invoked Action containing the Id of the Activity to toggle the Client on
+ **/
+ void slotToggleOnActivity(QAction *action);
+ /**
+ * Performs a window operation.
+ *
+ * @param action Invoked Action containing the Window Operation to perform for the Client
+ **/
+ void slotWindowOperation(QAction *action);
+ /**
+ * Invokes the kcmshell with the Window Manager related config modules.
+ **/
+ void configureWM();
+
+private:
+ /**
+ * Creates the menu if not already created.
+ **/
+ void init();
+ /**
+ * Creates the Move To Desktop sub-menu.
+ **/
+ void initDesktopPopup();
+ /**
+ * Creates the Move To Screen sub-menu.
+ **/
+ void initScreenPopup();
+ /**
+ * Creates activity popup.
+ * I'm going with checkable ones instead of "copy to" and "move to" menus; I *think* it's an easier way.
+ * Oh, and an 'all' option too of course
+ **/
+ void initActivityPopup();
+ /**
+ * Creates the Window Tabbing related menus.
+ **/
+ void initTabbingPopups();
+ /**
+ * Shows a helper Dialog to inform the user how to get back in case he triggered
+ * an action which hides the window decoration (e.g. NoBorder or Fullscreen).
+ * @param message The message type to be shown
+ * @param c The Client for which the dialog should be shown.
+ **/
+ void helperDialog(const QString &message, const QWeakPointer &c);
+ /**
+ * The actual main context menu which is show when the UserActionsMenu is invoked.
+ **/
+ QMenu* m_menu;
+ /**
+ * The move to desktop sub menu.
+ **/
+ QMenu* m_desktopMenu;
+ /**
+ * The move to screen sub menu.
+ **/
+ QMenu* m_screenMenu;
+ /**
+ * The activities sub menu.
+ **/
+ QMenu* m_activityMenu;
+ /**
+ * Menu to add the group to other group.
+ **/
+ QMenu* m_addTabsMenu;
+ /**
+ * Menu to change tab.
+ **/
+ QMenu* m_switchToTabMenu;
+ QAction* m_resizeOperation;
+ QAction* m_moveOperation;
+ QAction* m_maximizeOperation;
+ QAction* m_shadeOperation;
+ QAction* m_keepAboveOperation;
+ QAction* m_keepBelowOperation;
+ QAction* m_fullScreenOperation;
+ QAction* m_noBorderOperation;
+ QAction* m_minimizeOperation;
+ QAction* m_closeOperation;
+ /**
+ * Remove client from group.
+ **/
+ QAction* m_removeFromTabGroup;
+ /**
+ * Close all clients in the group.
+ **/
+ QAction* m_closeTabGroup;
+ /**
+ * The Client for which the menu is shown.
+ **/
+ QWeakPointer m_client;
+};
+} // namespace
+
+#endif // KWIN_USERACTIONS_H
diff --git a/workspace.cpp b/workspace.cpp
index cf3f308a86..f60015e915 100644
--- a/workspace.cpp
+++ b/workspace.cpp
@@ -59,6 +59,7 @@ along with this program. If not, see .
#include "deleted.h"
#include "effects.h"
#include "overlaywindow.h"
+#include "useractions.h"
#include
#include
#ifdef KWIN_BUILD_SCRIPTING
@@ -71,8 +72,6 @@ along with this program. If not, see .
#include
#include
#include
-#include
-#include
#include
#include
#include
@@ -128,13 +127,7 @@ Workspace::Workspace(bool restore)
#ifdef KWIN_BUILD_TABBOX
, tab_box(0)
#endif
- , popup(0)
- , advanced_popup(0)
- , desk_popup(0)
- , screen_popup(NULL)
- , activity_popup(0)
- , add_tabs_popup(0)
- , switch_to_tab_popup(0)
+ , m_userActionsMenu(new UserActionsMenu(this))
, keys(0)
, client_keys(NULL)
, disable_shortcuts_keys(NULL)
@@ -520,7 +513,6 @@ Workspace::~Workspace()
for (UnmanagedList::iterator it = unmanaged.begin(), end = unmanaged.end(); it != end; ++it)
(*it)->release(true);
delete m_outline;
- discardPopup();
XDeleteProperty(display(), rootWindow(), atoms->kwin_running);
writeWindowRules();
@@ -632,6 +624,9 @@ void Workspace::removeClient(Client* c, allowed_t)
if (c == active_popup_client)
closeActivePopup();
+ if (m_userActionsMenu->isMenuClient(c)) {
+ m_userActionsMenu->close();
+ }
c->untab();
@@ -932,7 +927,7 @@ void Workspace::slotSettingsChanged(int category)
{
kDebug(1212) << "Workspace::slotSettingsChanged()";
if (category == KGlobalSettings::SETTINGS_SHORTCUTS)
- discardPopup();
+ m_userActionsMenu->discard();
}
/**
@@ -957,7 +952,7 @@ void Workspace::slotReconfigure()
unsigned long changed = options->updateSettings();
emit configChanged();
- discardPopup();
+ m_userActionsMenu->discard();
updateToolWindows(true);
if (hasDecorationPlugin() && mgr->reset(changed)) {
@@ -1140,35 +1135,6 @@ void Workspace::saveDesktopSettings()
group.sync();
}
-QStringList Workspace::configModules(bool controlCenter)
-{
- QStringList args;
- args << "kwindecoration";
- if (controlCenter)
- args << "kwinoptions";
- else if (KAuthorized::authorizeControlModule("kde-kwinoptions.desktop"))
- args << "kwinactions" << "kwinfocus" << "kwinmoving" << "kwinadvanced"
- << "kwinrules" << "kwincompositing"
-#ifdef KWIN_BUILD_TABBOX
- << "kwintabbox"
-#endif
-#ifdef KWIN_BUILD_SCREENEDGES
- << "kwinscreenedges"
-#endif
-#ifdef KWIN_BUILD_SCRIPTING
- << "kwinscripts"
-#endif
- ;
- return args;
-}
-
-void Workspace::configureWM()
-{
- QStringList args;
- args << "--icon" << "preferences-system-windows" << configModules(false);
- KToolInvocation::kdeinitExec("kcmshell4", args);
-}
-
/**
* Avoids managing a window with title \a title
*/
@@ -1429,19 +1395,23 @@ fetchActivityListAndCurrent(KActivities::Controller *controller)
return CurrentAndList(c, l);
}
-void Workspace::updateActivityList(bool running, bool updateCurrent, QString slot)
+void Workspace::updateActivityList(bool running, bool updateCurrent, QObject *target, QString slot)
{
if (updateCurrent) {
QFutureWatcher* watcher = new QFutureWatcher;
connect( watcher, SIGNAL(finished()), SLOT(handleActivityReply()) );
- if (!slot.isEmpty())
+ if (!slot.isEmpty()) {
watcher->setProperty("activityControllerCallback", slot); // "activity reply trigger"
+ watcher->setProperty("activityControllerCallbackTarget", qVariantFromValue((void*)target));
+ }
watcher->setFuture(QtConcurrent::run(fetchActivityListAndCurrent, &activityController_ ));
} else {
QFutureWatcher* watcher = new QFutureWatcher;
connect(watcher, SIGNAL(finished()), SLOT(handleActivityReply()));
- if (!slot.isEmpty())
+ if (!slot.isEmpty()) {
watcher->setProperty("activityControllerCallback", slot); // "activity reply trigger"
+ watcher->setProperty("activityControllerCallbackTarget", qVariantFromValue((void*)target));
+ }
QStringList *target = running ? &openActivities_ : &allActivities_;
watcher->setFuture(QtConcurrent::run(fetchActivityList, &activityController_, target, running));
}
@@ -1465,9 +1435,10 @@ void Workspace::handleActivityReply()
if (watcherObject) {
QString slot = watcherObject->property("activityControllerCallback").toString();
+ QObject *target = static_cast(watcherObject->property("activityControllerCallbackTarget").value());
watcherObject->deleteLater(); // has done it's job
if (!slot.isEmpty())
- QMetaObject::invokeMethod(this, slot.toAscii().data(), Qt::DirectConnection);
+ QMetaObject::invokeMethod(target, slot.toAscii().data(), Qt::DirectConnection);
}
}
//END threaded activity list fetching
@@ -1971,49 +1942,6 @@ void Workspace::focusToNull()
XSetInputFocus(display(), null_focus_window, RevertToPointerRoot, xTime());
}
-void Workspace::helperDialog(const QString& message, const Client* c)
-{
- QStringList args;
- QString type;
- if (message == "noborderaltf3") {
- KAction* action = qobject_cast(keys->action("Window Operations Menu"));
- assert(action != NULL);
- QString shortcut = QString("%1 (%2)").arg(action->text())
- .arg(action->globalShortcut().primary().toString(QKeySequence::NativeText));
- args << "--msgbox" << i18n(
- "You have selected to show a window without its border.\n"
- "Without the border, you will not be able to enable the border "
- "again using the mouse: use the window operations menu instead, "
- "activated using the %1 keyboard shortcut.",
- shortcut);
- type = "altf3warning";
- } else if (message == "fullscreenaltf3") {
- KAction* action = qobject_cast(keys->action("Window Operations Menu"));
- assert(action != NULL);
- QString shortcut = QString("%1 (%2)").arg(action->text())
- .arg(action->globalShortcut().primary().toString(QKeySequence::NativeText));
- args << "--msgbox" << i18n(
- "You have selected to show a window in fullscreen mode.\n"
- "If the application itself does not have an option to turn the fullscreen "
- "mode off you will not be able to disable it "
- "again using the mouse: use the window operations menu instead, "
- "activated using the %1 keyboard shortcut.",
- shortcut);
- type = "altf3warning";
- } else
- abort();
- if (!type.isEmpty()) {
- KConfig cfg("kwin_dialogsrc");
- KConfigGroup cg(&cfg, "Notification Messages"); // Depends on KMessageBox
- if (!cg.readEntry(type, true))
- return;
- args << "--dontagain" << "kwin_dialogsrc:" + type;
- }
- if (c != NULL)
- args << "--embed" << QString::number(c->window());
- KProcess::startDetached("kdialog", args);
-}
-
void Workspace::setShowingDesktop(bool showing)
{
rootInfo->setShowingDesktop(showing);
diff --git a/workspace.h b/workspace.h
index 16630f7569..554d1df30e 100644
--- a/workspace.h
+++ b/workspace.h
@@ -78,6 +78,7 @@ class PluginMgr;
class Placement;
class Rules;
class Scripting;
+class UserActionsMenu;
class WindowRules;
class Workspace : public QObject, public KDecorationDefines
@@ -325,6 +326,12 @@ public:
QStringList activityList() const {
return allActivities_;
}
+ const QStringList &openActivities() const {
+ return openActivities_;
+ }
+#ifdef KWIN_BUILD_ACTIVITIES
+ void updateActivityList(bool running, bool updateCurrent, QObject *target = NULL, QString slot = QString());
+#endif
// True when performing Workspace::updateClientArea().
// The calls below are valid only in that case.
bool inUpdateClientArea() const;
@@ -397,7 +404,9 @@ public:
*/
void showWindowMenu(int x, int y, Client* cl);
void showWindowMenu(QPoint pos, Client* cl);
- bool windowMenuShown();
+ const UserActionsMenu *userActionsMenu() const {
+ return m_userActionsMenu;
+ }
void updateMinimizedOfTransients(Client*);
void updateOnAllDesktopsOfTransients(Client*);
@@ -503,8 +512,6 @@ public:
int packPositionUp(const Client* cl, int oldy, bool top_edge) const;
int packPositionDown(const Client* cl, int oldy, bool bottom_edge) const;
- static QStringList configModules(bool controlCenter);
-
void cancelDelayFocus();
void requestDelayFocus(Client*);
void updateFocusMousePosition(const QPoint& pos);
@@ -628,19 +635,6 @@ public slots:
void slotUntab(); // Slot to remove the active client from its group.
private slots:
- void rebuildTabGroupPopup();
- void rebuildTabListPopup();
- void entabPopupClient(QAction*);
- void selectPopupClientTab(QAction*);
- void desktopPopupAboutToShow();
- void screenPopupAboutToShow();
- void activityPopupAboutToShow();
- void clientPopupAboutToShow();
- void slotSendToDesktop(QAction*);
- void slotSendToScreen(QAction*);
- void slotToggleOnActivity(QAction*);
- void clientPopupActivated(QAction*);
- void configureWM();
void desktopResized();
void screenChangeTimeout();
void slotUpdateToolWindows();
@@ -667,7 +661,6 @@ private slots:
void slotActivityAdded(const QString &activity);
void reallyStopActivity(const QString &id); //dbus deadlocks suck
void handleActivityReply();
- void showHideActivityMenu();
protected:
void timerEvent(QTimerEvent *te);
@@ -717,17 +710,9 @@ signals:
private:
void init();
void initShortcuts();
- void initDesktopPopup();
- void initScreenPopup();
- void initActivityPopup();
- void initTabbingPopups();
void restartKWin(const QString &reason);
- void discardPopup();
void setupWindowShortcut(Client* c);
void checkCursorPos();
-#ifdef KWIN_BUILD_ACTIVITIES
- void updateActivityList(bool running, bool updateCurrent, QString slot = QString());
-#endif
enum Direction {
DirectionNorth,
DirectionEast,
@@ -765,9 +750,6 @@ private:
//---------------------------------------------------------------------
- void helperDialog(const QString& message, const Client* c);
-
- QMenu* clientPopup();
void closeActivePopup();
void updateClientArea(bool force);
@@ -843,31 +825,17 @@ private:
TabBox::TabBox* tab_box;
#endif
- QMenu* popup;
- QMenu* advanced_popup;
- QMenu* desk_popup;
- QMenu* screen_popup;
- QMenu* activity_popup;
- QMenu* add_tabs_popup; // Menu to add the group to other group
- QMenu* switch_to_tab_popup; // Menu to change tab
+ /**
+ * Holds the menu containing the user actions which is shown
+ * on e.g. right click the window decoration.
+ **/
+ UserActionsMenu *m_userActionsMenu;
void modalActionsSwitch(bool enabled);
KActionCollection* keys;
KActionCollection* client_keys;
KActionCollection* disable_shortcuts_keys;
- QAction* mResizeOpAction;
- QAction* mMoveOpAction;
- QAction* mMaximizeOpAction;
- QAction* mShadeOpAction;
- QAction* mKeepAboveOpAction;
- QAction* mKeepBelowOpAction;
- QAction* mFullScreenOpAction;
- QAction* mNoBorderOpAction;
- QAction* mMinimizeOpAction;
- QAction* mCloseOpAction;
- QAction* mRemoveFromTabGroup; // Remove client from group
- QAction* mCloseTabGroup; // Close all clients in the group
ShortcutDialog* client_keys_dialog;
Client* client_keys_client;
bool global_shortcuts_disabled;
@@ -1068,11 +1036,6 @@ inline void Workspace::showWindowMenu(int x, int y, Client* cl)
showWindowMenu(QRect(QPoint(x, y), QPoint(x, y)), cl);
}
-inline bool Workspace::windowMenuShown()
-{
- return popup && ((QWidget*)popup)->isVisible();
-}
-
inline void Workspace::setWasUserInteraction()
{
was_user_interaction = true;