diff --git a/app/config/behaviorsettings.ui b/app/config/behaviorsettings.ui
index 9b8305e..58b23d3 100644
--- a/app/config/behaviorsettings.ui
+++ b/app/config/behaviorsettings.ui
@@ -1,207 +1,214 @@
BehaviorSettings003562890GeneralFocus terminals when the mouse pointer is moved over themfalse00If this option is enabled, the shortcut normally used to open and retract the window will give it focus, rather than close it, if it has previously lost focus. Unless the window is set to show on all virtual desktops, this may cause the window manager to switch to the virtual desktop it currently resides on.Use Open/Retract action to focus windowfalse00Keep window above other windowsQt::HorizontalQSizePolicy::Fixed2020Open window after program startIf this option is enabled, the window will automatically open when the mouse pointer is moved to the same edge of the screen that it would open on when using the shortcut.Open window when the mouse pointer touches the screen edge
+
+
+
+ Remember and restore window fullscreen state
+
+
+ Keep window open when it loses focusQt::HorizontalQSizePolicy::Fixed2020Keep window open after the last session is closedDialogsConfirm quit when more than one session is openQt::Vertical200kcfg_OpenAfterStartkcfg_PollMousekcfg_KeepOpenkcfg_KeepAbovekcfg_ToggleToFocuskcfg_KeepOpenAfterLastSessionCloseskcfg_FocusFollowsMousekcfg_ConfirmQuitkcfg_KeepOpentoggled(bool)kcfg_KeepAbovesetEnabled(bool)32598286kcfg_KeepOpentoggled(bool)kcfg_ToggleToFocussetEnabled(bool)245974113
diff --git a/app/config/yakuake.kcfg b/app/config/yakuake.kcfg
index a6d34c0..1d19d21 100644
--- a/app/config/yakuake.kcfg
+++ b/app/config/yakuake.kcfg
@@ -1,187 +1,192 @@
The screen on which the application window will appear. 0 is understood to be the screen the mouse pointer is on.0Width of the application window as a percentage of the screen.9010100Height of the application window as a percentage of the screen.5010100Center point of the application window, as a percentage, measured from the left-hand edge of the screen.500100Whether to show the window on all desktops.trueWhether to keep the application window open when it loses focus.trueWhether to keep the application window open after the last session is closed.falseWhether the open/retract keyboard shortcut can be used to focus the application window when it is already open.falseWhether to keep the application window above other windows on the screen.trueWhether to show the tab bar in the application window.trueWhether to update tab titles along with the title bar.falseWhether an individual terminal in a session will be given focus when the mouse pointer is moved above it.falseWhether the application window should be opened after program start.false
+
+
+ Whether the window will be shown fullscreen again when it has been previously.
+ false
+ The skin to be used by the application window.defaultWhether the currently active skin was installed via KNS.falseWhether to make use of XComposite ARGB translucency.falseBackground color painted below skin elements.#000000The opacity of the background color fill when using translucency.500100Whether to briefly display a colored overlay above the newly focused terminal when moving focus between multiple terminals in a session, as well as over the currently focused terminal when switching to a session with multiple terminals.falseThe opacity of the colored overlay used to highlight a terminal.0.401.0The duration of the terminal highlight overlay.250086400000The color of the keyboard input block indicator overlay.#FF0000The opacity of the keyboard input block indicator overlay.0.501.0The duration of the keyboard input block indicator overlay.250086400000Whether to try and let the window manager perform the window open/retract animation. Yakuake will fall back to an animation strategy of progressively adjusting the window mask if the window manager is unable to provide the requested service.trueThe number of frames of the open/retract animation. One frame is taken to be 10 miliseconds.17050Whether to automatically open the application window when the mouse pointer is found at the edge of the screen.falseThe interval during which the mouse pointer position will be checked to determine whether or not it is at the same edge of the screen as the window.500Whether this is the first time the application is run.trueWhether to prompt the user before quitting the application when multiple sessions are open.true
diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp
index f90af6f..6f29193 100644
--- a/app/mainwindow.cpp
+++ b/app/mainwindow.cpp
@@ -1,1541 +1,1544 @@
/*
Copyright (C) 2008-2014 by Eike Hein
Copyright (C) 2009 by Juan Carlos Torres
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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor appro-
ved by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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 http://www.gnu.org/licenses/.
*/
#include "mainwindow.h"
#include "settings.h"
#include "config/appearancesettings.h"
#include "config/windowsettings.h"
#include "firstrundialog.h"
#include "sessionstack.h"
#include "skin.h"
#include "tabbar.h"
#include "terminal.h"
#include "titlebar.h"
#include "ui_behaviorsettings.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if HAVE_X11
#include
#include
#include
#endif
#if HAVE_KWAYLAND
#include
#include
#include
#include
#endif
MainWindow::MainWindow(QWidget* parent)
: KMainWindow(parent, Qt::CustomizeWindowHint | Qt::FramelessWindowHint)
{
QDBusConnection::sessionBus().registerObject(QStringLiteral("/yakuake/window"), this, QDBusConnection::ExportScriptableSlots);
setAttribute(Qt::WA_TranslucentBackground, true);
setAttribute(Qt::WA_DeleteOnClose, false);
setAttribute(Qt::WA_QuitOnClose, true);
m_skin = new Skin();
m_menu = new QMenu(this);
m_helpMenu = new KHelpMenu(this, KAboutData::applicationData());
m_sessionStack = new SessionStack(this);
m_tabBar = new TabBar(this);
m_titleBar = new TitleBar(this);
m_firstRunDialog = NULL;
+ m_isFullscreen = false;
#if HAVE_X11
m_kwinAssistPropSet = false;
m_isX11 = KWindowSystem::isPlatformX11();
#else
m_isX11 = false;
#endif
m_isWayland = KWindowSystem::isPlatformWayland();
#if HAVE_KWAYLAND
m_plasmaShell = Q_NULLPTR;
m_plasmaShellSurface = Q_NULLPTR;
initWayland();
#endif
m_toggleLock = false;
setupActions();
setupMenu();
connect(m_tabBar, SIGNAL(newTabRequested()), m_sessionStack, SLOT(addSession()));
connect(m_tabBar, SIGNAL(lastTabClosed()), m_tabBar, SIGNAL(newTabRequested()));
connect(m_tabBar, SIGNAL(lastTabClosed()), this, SLOT(handleLastTabClosed()));
connect(m_tabBar, SIGNAL(tabSelected(int)), m_sessionStack, SLOT(raiseSession(int)));
connect(m_tabBar, SIGNAL(tabClosed(int)), m_sessionStack, SLOT(removeSession(int)));
connect(m_tabBar, SIGNAL(requestTerminalHighlight(int)), m_sessionStack, SLOT(handleTerminalHighlightRequest(int)));
connect(m_tabBar, SIGNAL(requestRemoveTerminalHighlight()), m_sessionStack, SIGNAL(removeTerminalHighlight()));
connect(m_tabBar, SIGNAL(tabContextMenuClosed()), m_sessionStack, SIGNAL(removeTerminalHighlight()));
connect(m_sessionStack, SIGNAL(sessionAdded(int,QString)),
m_tabBar, SLOT(addTab(int,QString)));
connect(m_sessionStack, SIGNAL(sessionRaised(int)), m_tabBar, SLOT(selectTab(int)));
connect(m_sessionStack, SIGNAL(sessionRemoved(int)), m_tabBar, SLOT(removeTab(int)));
connect(m_sessionStack, SIGNAL(activeTitleChanged(QString)),
m_titleBar, SLOT(setTitle(QString)));
connect(m_sessionStack, SIGNAL(activeTitleChanged(QString)),
this, SLOT(setWindowTitle(QString)));
connect(&m_mousePoller, SIGNAL(timeout()), this, SLOT(pollMouse()));
connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(applyWindowGeometry()));
connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), this, SLOT(updateScreenMenu()));
applySettings();
m_sessionStack->addSession();
if (Settings::firstRun())
{
QMetaObject::invokeMethod(this, "toggleWindowState", Qt::QueuedConnection);
QMetaObject::invokeMethod(this, "showFirstRunDialog", Qt::QueuedConnection);
}
else
{
showStartupPopup();
if (Settings::pollMouse()) toggleMousePoll(true);
}
if (Settings::openAfterStart())
QMetaObject::invokeMethod(this, "toggleWindowState", Qt::QueuedConnection);
}
MainWindow::~MainWindow()
{
Settings::self()->save();
delete m_skin;
}
#if HAVE_KWAYLAND
void MainWindow::initWayland()
{
if (!m_isWayland) {
return;
}
using namespace KWayland::Client;
auto connection = ConnectionThread::fromApplication(this);
if (!connection) {
return;
}
Registry *registry = new Registry(this);
registry->create(connection);
QObject::connect(registry, &Registry::interfacesAnnounced, this,
[registry, this] {
const auto interface = registry->interface(Registry::Interface::PlasmaShell);
if (interface.name != 0) {
m_plasmaShell = registry->createPlasmaShell(interface.name, interface.version, this);
}
}
);
registry->setup();
connection->roundtrip();
}
void MainWindow::initWaylandSurface()
{
if (m_plasmaShellSurface) {
return;
}
if (!m_plasmaShell) {
return;
}
if (auto surface = KWayland::Client::Surface::fromWindow(windowHandle())) {
m_plasmaShellSurface = m_plasmaShell->createSurface(surface, this);
m_plasmaShellSurface->setPosition(pos());
}
}
#endif
bool MainWindow::queryClose()
{
bool confirmQuit = Settings::confirmQuit();
bool hasUnclosableSessions = m_sessionStack->hasUnclosableSessions();
QString closeQuestion = xi18nc("@info","Are you sure you want to quit?");
QString warningMessage;
if ((confirmQuit && m_sessionStack->count() > 1) || hasUnclosableSessions)
{
if (confirmQuit && m_sessionStack->count() > 1)
{
if (hasUnclosableSessions)
warningMessage = xi18nc("@info", "There are multiple open sessions, some of which you have locked to prevent closing them accidentally. These will be killed if you continue.");
else
warningMessage = xi18nc("@info", "There are multiple open sessions. These will be killed if you continue.");
}
else if (hasUnclosableSessions)
{
warningMessage = xi18nc("@info", "There are one or more open sessions that you have locked to prevent closing them accidentally. These will be killed if you continue.");
}
int result = KMessageBox::warningContinueCancel(this,
warningMessage + QStringLiteral("
") + closeQuestion,
xi18nc("@title:window", "Really Quit?"), KStandardGuiItem::quit(), KStandardGuiItem::cancel());
return result != KMessageBox::Cancel;
}
return true;
}
void MainWindow::setupActions()
{
m_actionCollection = new KActionCollection(this);
KToggleFullScreenAction* fullScreenAction = new KToggleFullScreenAction(this);
fullScreenAction->setWindow(this);
actionCollection()->setDefaultShortcut(fullScreenAction, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_F11));
m_actionCollection->addAction(QStringLiteral("view-full-screen"), fullScreenAction);
connect(fullScreenAction, SIGNAL(toggled(bool)), this, SLOT(setFullScreen(bool)));
QAction* action = KStandardAction::quit(this, SLOT(close()), actionCollection());
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Q));
action = KStandardAction::aboutApp(m_helpMenu, SLOT(aboutApplication()), actionCollection());
action = KStandardAction::reportBug(m_helpMenu, SLOT(reportBug()), actionCollection());
action = KStandardAction::aboutKDE(m_helpMenu, SLOT(aboutKDE()), actionCollection());
action = KStandardAction::keyBindings(this, SLOT(configureKeys()), actionCollection());
action = KStandardAction::configureNotifications(this, SLOT(configureNotifications()), actionCollection());
action = KStandardAction::preferences(this, SLOT(configureApp()), actionCollection());
action = KStandardAction::whatsThis(this, SLOT(whatsThis()), actionCollection());
action = actionCollection()->addAction(QStringLiteral("toggle-window-state"));
action->setText(xi18nc("@action", "Open/Retract Yakuake"));
action->setIcon(QIcon::fromTheme(QStringLiteral("yakuake")));
#ifndef Q_OS_WIN /* PORT */
KGlobalAccel::self()->setGlobalShortcut(action, QList() << QKeySequence(Qt::Key_F12));
#else
KGlobalAccel::self()->setGlobalShortcut(action, QList() << QKeySequence(Qt::Key_F11));
#endif
connect(action, SIGNAL(triggered()), this, SLOT(toggleWindowState()));
action = actionCollection()->addAction(QStringLiteral("keep-open"));
action->setText(xi18nc("@action", "Keep window open when it loses focus"));
action->setCheckable(true);
connect(action, SIGNAL(toggled(bool)), this, SLOT(setKeepOpen(bool)));
action = actionCollection()->addAction(QStringLiteral("manage-profiles"));
action->setText(xi18nc("@action", "Manage Profiles..."));
action->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
connect(action, SIGNAL(triggered()), m_sessionStack, SIGNAL(manageProfiles()));
action = actionCollection()->addAction(QStringLiteral("edit-profile"));
action->setText(xi18nc("@action", "Edit Current Profile..."));
action->setIcon(QIcon::fromTheme(QStringLiteral("document-properties")));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("increase-window-width"));
action->setText(xi18nc("@action", "Increase Window Width"));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Right));
connect(action, SIGNAL(triggered()), this, SLOT(increaseWindowWidth()));
action = actionCollection()->addAction(QStringLiteral("decrease-window-width"));
action->setText(xi18nc("@action", "Decrease Window Width"));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Left));
connect(action, SIGNAL(triggered()), this, SLOT(decreaseWindowWidth()));
action = actionCollection()->addAction(QStringLiteral("increase-window-height"));
action->setText(xi18nc("@action", "Increase Window Height"));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Down));
connect(action, SIGNAL(triggered()), this, SLOT(increaseWindowHeight()));
action = actionCollection()->addAction(QStringLiteral("decrease-window-height"));
action->setText(xi18nc("@action", "Decrease Window Height"));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Up));
connect(action, SIGNAL(triggered()), this, SLOT(decreaseWindowHeight()));
action = actionCollection()->addAction(QStringLiteral("new-session"));
action->setText(xi18nc("@action", "New Session"));
action->setIcon(QIcon::fromTheme(QStringLiteral("tab-new")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_T));
connect(action, SIGNAL(triggered()), m_sessionStack, SLOT(addSession()));
action = actionCollection()->addAction(QStringLiteral("new-session-two-horizontal"));
action->setText(xi18nc("@action", "Two Terminals, Horizontally"));
action->setIcon(QIcon::fromTheme(QStringLiteral("tab-new")));
connect(action, SIGNAL(triggered()), m_sessionStack, SLOT(addSessionTwoHorizontal()));
action = actionCollection()->addAction(QStringLiteral("new-session-two-vertical"));
action->setText(xi18nc("@action", "Two Terminals, Vertically"));
action->setIcon(QIcon::fromTheme(QStringLiteral("tab-new")));
connect(action, SIGNAL(triggered()), m_sessionStack, SLOT(addSessionTwoVertical()));
action = actionCollection()->addAction(QStringLiteral("new-session-quad"));
action->setText(xi18nc("@action", "Four Terminals, Grid"));
action->setIcon(QIcon::fromTheme(QStringLiteral("tab-new")));
connect(action, SIGNAL(triggered()), m_sessionStack, SLOT(addSessionQuad()));
action = actionCollection()->addAction(QStringLiteral("close-session"));
action->setText(xi18nc("@action", "Close Session"));
action->setIcon(QIcon::fromTheme(QStringLiteral("tab-close")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_W));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("previous-session"));
action->setText(xi18nc("@action", "Previous Session"));
action->setIcon(QIcon::fromTheme(QStringLiteral("go-previous")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::Key_Left));
connect(action, SIGNAL(triggered()), m_tabBar, SLOT(selectPreviousTab()));
action = actionCollection()->addAction(QStringLiteral("next-session"));
action->setText(xi18nc("@action", "Next Session"));
action->setIcon(QIcon::fromTheme(QStringLiteral("go-next")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::Key_Right));
connect(action, SIGNAL(triggered()), m_tabBar, SLOT(selectNextTab()));
action = actionCollection()->addAction(QStringLiteral("move-session-left"));
action->setText(xi18nc("@action", "Move Session Left"));
action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Left));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("move-session-right"));
action->setText(xi18nc("@action", "Move Session Right"));
action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Right));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("grow-terminal-right"));
action->setText(xi18nc("@action", "Grow Terminal to the Right"));
action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Right));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("grow-terminal-left"));
action->setText(xi18nc("@action", "Grow Terminal to the Left"));
action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Left));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("grow-terminal-top"));
action->setText(xi18nc("@action", "Grow Terminal to the Top"));
action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Up));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("grow-terminal-bottom"));
action->setText(xi18nc("@action", "Grow Terminal to the Bottom"));
action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Down));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("rename-session"));
action->setText(xi18nc("@action", "Rename Session..."));
action->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_S));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("previous-terminal"));
action->setText(xi18nc("@action", "Previous Terminal"));
action->setIcon(QIcon::fromTheme(QStringLiteral("go-previous")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Up));
connect(action, SIGNAL(triggered()), m_sessionStack, SIGNAL(previousTerminal()));
action = actionCollection()->addAction(QStringLiteral("next-terminal"));
action->setText(xi18nc("@action", "Next Terminal"));
action->setIcon(QIcon::fromTheme(QStringLiteral("go-next")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Down));
connect(action, SIGNAL(triggered()), m_sessionStack, SIGNAL(nextTerminal()));
action = actionCollection()->addAction(QStringLiteral("close-active-terminal"));
action->setText(xi18nc("@action", "Close Active Terminal"));
action->setIcon(QIcon::fromTheme(QStringLiteral("view-close")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_R));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("split-left-right"));
action->setText(xi18nc("@action", "Split Left/Right"));
action->setIcon(QIcon::fromTheme(QStringLiteral("view-split-left-right")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL+ Qt::Key_ParenLeft));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("split-top-bottom"));
action->setText(xi18nc("@action", "Split Top/Bottom"));
action->setIcon(QIcon::fromTheme(QStringLiteral("view-split-top-bottom")));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_ParenRight));
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("toggle-session-prevent-closing"));
action->setText(xi18nc("@action", "Prevent Closing"));
action->setCheckable(true);
connect(action, SIGNAL(triggered(bool)), this, SLOT(handleContextDependentToggleAction(bool)));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("toggle-session-keyboard-input"));
action->setText(xi18nc("@action", "Disable Keyboard Input"));
action->setCheckable(true);
connect(action, SIGNAL(triggered(bool)), this, SLOT(handleContextDependentToggleAction(bool)));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("toggle-session-monitor-activity"));
action->setText(xi18nc("@action", "Monitor for Activity"));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_A));
action->setCheckable(true);
connect(action, SIGNAL(triggered(bool)), this, SLOT(handleContextDependentToggleAction(bool)));
m_contextDependentActions << action;
action = actionCollection()->addAction(QStringLiteral("toggle-session-monitor-silence"));
action->setText(xi18nc("@action", "Monitor for Silence"));
actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I));
action->setCheckable(true);
connect(action, SIGNAL(triggered(bool)), this, SLOT(handleContextDependentToggleAction(bool)));
m_contextDependentActions << action;
for (uint i = 1; i <= 10; ++i)
{
action = actionCollection()->addAction(QString(QStringLiteral("switch-to-session-%1")).arg(i));
action->setText(xi18nc("@action", "Switch to Session %1", i));
action->setData(i);
connect(action, SIGNAL(triggered()), this, SLOT(handleSwitchToAction()));
}
m_actionCollection->associateWidget(this);
m_actionCollection->readSettings();
}
void MainWindow::handleContextDependentAction(QAction* action, int sessionId)
{
if (sessionId == -1) sessionId = m_sessionStack->activeSessionId();
if (sessionId == -1) return;
if (!action) action = qobject_cast(QObject::sender());
if (action == actionCollection()->action(QStringLiteral("edit-profile")))
m_sessionStack->editProfile(sessionId);
if (action == actionCollection()->action(QStringLiteral("close-session")))
m_sessionStack->removeSession(sessionId);
if (action == actionCollection()->action(QStringLiteral("move-session-left")))
m_tabBar->moveTabLeft(sessionId);
if (action == actionCollection()->action(QStringLiteral("move-session-right")))
m_tabBar->moveTabRight(sessionId);
if (action == actionCollection()->action(QStringLiteral("rename-session")))
m_tabBar->interactiveRename(sessionId);
if (action == actionCollection()->action(QStringLiteral("close-active-terminal")))
m_sessionStack->closeActiveTerminal(sessionId);
if (action == actionCollection()->action(QStringLiteral("split-left-right")))
m_sessionStack->splitSessionLeftRight(sessionId);
if (action == actionCollection()->action(QStringLiteral("split-top-bottom")))
m_sessionStack->splitSessionTopBottom(sessionId);
if (action == actionCollection()->action(QStringLiteral("grow-terminal-right")))
m_sessionStack->tryGrowTerminalRight(m_sessionStack->activeTerminalId());
if (action == actionCollection()->action(QStringLiteral("grow-terminal-left")))
m_sessionStack->tryGrowTerminalLeft(m_sessionStack->activeTerminalId());
if (action == actionCollection()->action(QStringLiteral("grow-terminal-top")))
m_sessionStack->tryGrowTerminalTop(m_sessionStack->activeTerminalId());
if (action == actionCollection()->action(QStringLiteral("grow-terminal-bottom")))
m_sessionStack->tryGrowTerminalBottom(m_sessionStack->activeTerminalId());
}
void MainWindow::handleContextDependentToggleAction(bool checked, QAction* action, int sessionId)
{
if (sessionId == -1) sessionId = m_sessionStack->activeSessionId();
if (sessionId == -1) return;
if (!action) action = qobject_cast(QObject::sender());
if (action == actionCollection()->action(QStringLiteral("toggle-session-prevent-closing"))) {
m_sessionStack->setSessionClosable(sessionId, !checked);
// Repaint the tab bar when the Prevent Closing action is toggled
// so the lock icon is added to or removed from the tab label.
m_tabBar->repaint();
}
if (action == actionCollection()->action(QStringLiteral("toggle-session-keyboard-input")))
m_sessionStack->setSessionKeyboardInputEnabled(sessionId, !checked);
if (action == actionCollection()->action(QStringLiteral("toggle-session-monitor-activity")))
m_sessionStack->setSessionMonitorActivityEnabled(sessionId, checked);
if (action == actionCollection()->action(QStringLiteral("toggle-session-monitor-silence")))
m_sessionStack->setSessionMonitorSilenceEnabled(sessionId, checked);
}
void MainWindow::setContextDependentActionsQuiet(bool quiet)
{
QListIterator i(m_contextDependentActions);
while (i.hasNext()) i.next()->blockSignals(quiet);
}
void MainWindow::handleToggleTerminalKeyboardInput(bool checked)
{
QAction* action = qobject_cast(QObject::sender());
if (!action || action->data().isNull()) return;
bool ok = false;
int terminalId = action->data().toInt(&ok);
if (!ok) return;
m_sessionStack->setTerminalKeyboardInputEnabled(terminalId, !checked);
}
void MainWindow::handleToggleTerminalMonitorActivity(bool checked)
{
QAction* action = qobject_cast(QObject::sender());
if (!action || action->data().isNull()) return;
bool ok = false;
int terminalId = action->data().toInt(&ok);
if (!ok) return;
m_sessionStack->setTerminalMonitorActivityEnabled(terminalId, checked);
}
void MainWindow::handleToggleTerminalMonitorSilence(bool checked)
{
QAction* action = qobject_cast(QObject::sender());
if (!action || action->data().isNull()) return;
bool ok = false;
int terminalId = action->data().toInt(&ok);
if (!ok) return;
m_sessionStack->setTerminalMonitorSilenceEnabled(terminalId, checked);
}
void MainWindow::handleTerminalActivity(Terminal* terminal)
{
Session* session = qobject_cast(sender());
if (session)
{
disconnect(terminal, SIGNAL(activityDetected(Terminal*)), session, SIGNAL(activityDetected(Terminal*)));
QString message(xi18nc("@info", "Activity detected in monitored terminal in session \"%1\".",
m_tabBar->tabTitle(session->id())));
KNotification::event(QLatin1String("activity"), message, QPixmap(), terminal->partWidget(),
KNotification::CloseWhenWidgetActivated);
}
}
void MainWindow::handleTerminalSilence(Terminal* terminal)
{
Session* session = qobject_cast(sender());
if (session)
{
QString message(xi18nc("@info", "Silence detected in monitored terminal in session \"%1\".",
m_tabBar->tabTitle(session->id())));
KNotification::event(QLatin1String("silence"), message, QPixmap(), terminal->partWidget(),
KNotification::CloseWhenWidgetActivated);
}
}
void MainWindow::handleLastTabClosed()
{
if (isVisible() && !Settings::keepOpenAfterLastSessionCloses())
toggleWindowState();
}
void MainWindow::handleSwitchToAction()
{
QAction* action = qobject_cast(QObject::sender());
if (action && !action->data().isNull())
m_sessionStack->raiseSession(m_tabBar->sessionAtTab(action->data().toInt()-1));
}
void MainWindow::setupMenu()
{
m_menu->insertSection(0, xi18nc("@title:menu", "Help"));
m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::WhatsThis))));
m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::ReportBug))));
m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::AboutApp))));
m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::AboutKDE))));
m_menu->insertSection(0, xi18nc("@title:menu", "Quick Options"));
m_menu->addAction(actionCollection()->action(QStringLiteral("view-full-screen")));
m_menu->addAction(actionCollection()->action(QStringLiteral("keep-open")));
m_screenMenu = new QMenu(this);
connect(m_screenMenu, SIGNAL(triggered(QAction*)), this, SLOT(setScreen(QAction*)));
m_screenMenu->setTitle(xi18nc("@title:menu", "Screen"));
m_menu->addMenu(m_screenMenu);
m_windowWidthMenu = new QMenu(this);
connect(m_windowWidthMenu, SIGNAL(triggered(QAction*)), this, SLOT(setWindowWidth(QAction*)));
m_windowWidthMenu->setTitle(xi18nc("@title:menu", "Width"));
m_menu->addMenu(m_windowWidthMenu);
m_windowHeightMenu = new QMenu(this);
connect(m_windowHeightMenu, SIGNAL(triggered(QAction*)), this, SLOT(setWindowHeight(QAction*)));
m_windowHeightMenu->setTitle(xi18nc("@title:menu", "Height"));
m_menu->addMenu(m_windowHeightMenu);
m_menu->insertSection(0, xi18nc("@title:menu", "Settings"));
m_menu->addAction(actionCollection()->action(QStringLiteral("manage-profiles")));
m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::KeyBindings))));
m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::ConfigureNotifications))));
m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::Preferences))));
}
void MainWindow::updateScreenMenu()
{
QAction* action;
m_screenMenu->clear();
action = m_screenMenu->addAction(xi18nc("@item:inmenu", "At mouse location"));
action->setCheckable(true);
action->setData(0);
action->setChecked(Settings::screen() == 0);
for (int i = 1; i <= QApplication::desktop()->screenCount(); i++)
{
action = m_screenMenu->addAction(xi18nc("@item:inmenu", "Screen %1", i));
action->setCheckable(true);
action->setData(i);
action->setChecked(i == Settings::screen());
}
action = m_screenMenu->menuAction();
action->setVisible(QApplication::desktop()->screenCount() > 1);
}
void MainWindow::updateWindowSizeMenus()
{
updateWindowWidthMenu();
updateWindowHeightMenu();
}
void MainWindow::updateWindowWidthMenu()
{
QAction* action = 0;
if (m_windowWidthMenu->isEmpty())
{
for (int i = 10; i <= 100; i += 10)
{
action = m_windowWidthMenu->addAction(QString::number(i) + QStringLiteral("%"));
action->setCheckable(true);
action->setData(i);
action->setChecked(i == Settings::width());
}
}
else
{
QListIterator i(m_windowWidthMenu->actions());
while (i.hasNext())
{
action = i.next();
action->setChecked(action->data().toInt() == Settings::width());
}
}
}
void MainWindow::updateWindowHeightMenu()
{
QAction* action = 0;
if (m_windowHeightMenu->isEmpty())
{
for (int i = 10; i <= 100; i += 10)
{
action = m_windowHeightMenu->addAction(QString::number(i) + QStringLiteral("%"));
action->setCheckable(true);
action->setData(i);
action->setChecked(i == Settings::height());
}
}
else
{
QListIterator i(m_windowHeightMenu->actions());
while (i.hasNext())
{
action = i.next();
action->setChecked(action->data().toInt() == Settings::height());
}
}
}
void MainWindow::configureKeys()
{
KShortcutsDialog::configure(actionCollection());
}
void MainWindow::configureNotifications()
{
KNotifyConfigWidget::configure(this);
}
void MainWindow::configureApp()
{
if (KConfigDialog::showDialog(QStringLiteral("settings"))) return;
KConfigDialog* settingsDialog = new KConfigDialog(this, QStringLiteral("settings"), Settings::self());
settingsDialog->setFaceType(KPageDialog::List);
connect(settingsDialog, &KConfigDialog::settingsChanged, this, &MainWindow::applySettings);
WindowSettings* windowSettings = new WindowSettings(settingsDialog);
settingsDialog->addPage(windowSettings, xi18nc("@title Preferences page name", "Window"), QStringLiteral("preferences-system-windows-move"));
connect(windowSettings, SIGNAL(updateWindowGeometry(int,int,int)),
this, SLOT(setWindowGeometry(int,int,int)));
QWidget* behaviorSettings = new QWidget(settingsDialog);
Ui::BehaviorSettings behaviorSettingsUi;
behaviorSettingsUi.setupUi(behaviorSettings);
settingsDialog->addPage(behaviorSettings, xi18nc("@title Preferences page name", "Behavior"),
QStringLiteral("preferences-system-windows-actions"));
AppearanceSettings* appearanceSettings = new AppearanceSettings(settingsDialog);
settingsDialog->addPage(appearanceSettings, xi18nc("@title Preferences page name", "Appearance"),
QStringLiteral("preferences-desktop-theme"));
connect(settingsDialog, &QDialog::rejected, appearanceSettings, &AppearanceSettings::resetSelection);
settingsDialog->button(QDialogButtonBox::Help)->hide();
settingsDialog->button(QDialogButtonBox::Cancel)->setFocus();
connect(settingsDialog, &QDialog::finished, [=]() {
m_toggleLock = true;
KWindowSystem::activateWindow(winId());
KWindowSystem::forceActiveWindow(winId());
});
settingsDialog->show();
}
void MainWindow::applySettings()
{
if (Settings::dynamicTabTitles())
{
connect(m_sessionStack, SIGNAL(titleChanged(int,QString)),
m_tabBar, SLOT(setTabTitle(int,QString)));
m_sessionStack->emitTitles();
}
else
{
disconnect(m_sessionStack, SIGNAL(titleChanged(int,QString)),
m_tabBar, SLOT(setTabTitle(int,QString)));
}
m_animationTimer.setInterval(Settings::frames() ? 10 : 0);
m_tabBar->setVisible(Settings::showTabBar());
setKeepOpen(Settings::keepOpen());
updateScreenMenu();
updateWindowSizeMenus();
updateUseTranslucency();
applySkin();
applyWindowGeometry();
applyWindowProperties();
}
void MainWindow::applySkin()
{
bool gotSkin = m_skin->load(Settings::skin(), Settings::skinInstalledWithKns());
if (!gotSkin)
{
Settings::setSkin(QStringLiteral("default"));
gotSkin = m_skin->load(Settings::skin());
}
if (!gotSkin)
{
KMessageBox::error(parentWidget(),
xi18nc("@info", "Yakuake was unable to load a skin. It is likely that it was installed incorrectly."
"The application will now quit."),
xi18nc("@title:window", "Cannot Load Skin"));
QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);
}
m_titleBar->applySkin();
m_tabBar->applySkin();
}
void MainWindow::applyWindowProperties()
{
if (Settings::keepOpen() && !Settings::keepAbove())
{
KWindowSystem::clearState(winId(), NET::KeepAbove);
KWindowSystem::setState(winId(), NET::Sticky | NET::SkipTaskbar | NET::SkipPager);
}
else
KWindowSystem::setState(winId(), NET::KeepAbove | NET::Sticky | NET::SkipTaskbar | NET::SkipPager);
KWindowSystem::setOnAllDesktops(winId(), Settings::showOnAllDesktops());
}
void MainWindow::applyWindowGeometry()
{
int width, height;
QAction* action = actionCollection()->action(QStringLiteral("view-full-screen"));
if (action->isChecked())
{
width = 100;
height = 100;
}
else
{
width = Settings::width();
height = Settings::height();
}
setWindowGeometry(width, height, Settings::position());
}
void MainWindow::setWindowGeometry(int newWidth, int newHeight, int newPosition)
{
QRect workArea = getDesktopGeometry();
int maxHeight = workArea.height() * newHeight / 100;
int targetWidth = workArea.width() * newWidth / 100;
setGeometry(workArea.x() + workArea.width() * newPosition * (100 - newWidth) / 10000,
workArea.y(), targetWidth, maxHeight);
#if HAVE_KWAYLAND
initWaylandSurface();
#endif
maxHeight -= m_titleBar->height();
m_titleBar->setGeometry(0, maxHeight, targetWidth, m_titleBar->height());
if (!isVisible()) m_titleBar->updateMask();
if (Settings::frames() > 0)
m_animationStepSize = maxHeight / Settings::frames();
else
m_animationStepSize = maxHeight;
if (Settings::showTabBar())
{
maxHeight -= m_tabBar->height();
m_tabBar->setGeometry(m_skin->borderWidth(), maxHeight,
width() - 2 * m_skin->borderWidth(), m_tabBar->height());
}
m_sessionStack->setGeometry(m_skin->borderWidth(), 0,
width() - 2 * m_skin->borderWidth(), maxHeight);
updateMask();
}
void MainWindow::setScreen(QAction* action)
{
Settings::setScreen(action->data().toInt());
Settings::self()->save();
applyWindowGeometry();
updateScreenMenu();
}
void MainWindow::setWindowWidth(int width)
{
Settings::setWidth(width);
Settings::self()->save();
applyWindowGeometry();
updateWindowWidthMenu();
}
void MainWindow::setWindowHeight(int height)
{
Settings::setHeight(height);
Settings::self()->save();
applyWindowGeometry();
updateWindowHeightMenu();
}
void MainWindow::setWindowWidth(QAction* action)
{
setWindowWidth(action->data().toInt());
}
void MainWindow::setWindowHeight(QAction* action)
{
setWindowHeight(action->data().toInt());
}
void MainWindow::increaseWindowWidth()
{
if (Settings::width() <= 90) setWindowWidth(Settings::width() + 10);
}
void MainWindow:: decreaseWindowWidth()
{
if (Settings::width() >= 20) setWindowWidth(Settings::width() - 10);
}
void MainWindow::increaseWindowHeight()
{
if (Settings::height() <= 90) setWindowHeight(Settings::height() + 10);
}
void MainWindow::decreaseWindowHeight()
{
if (Settings::height() >= 20) setWindowHeight(Settings::height() - 10);
}
void MainWindow::updateMask()
{
QRegion region = m_titleBar->mask();
region.translate(0, m_titleBar->y());
region += QRegion(0, 0, width(), m_titleBar->y());
setMask(region);
}
void MainWindow::paintEvent(QPaintEvent* event)
{
QPainter painter(this);
if (useTranslucency())
{
painter.setOpacity(qreal(Settings::backgroundColorOpacity()) / 100);
painter.fillRect(rect(), Settings::backgroundColor());
painter.setOpacity(1.0);
}
else
painter.fillRect(rect(), Settings::backgroundColor());
QRect leftBorder(0, 0, m_skin->borderWidth(), height() - m_titleBar->height());
painter.fillRect(leftBorder, m_skin->borderColor());
QRect rightBorder(width() - m_skin->borderWidth(), 0, m_skin->borderWidth(),
height() - m_titleBar->height());
painter.fillRect(rightBorder, m_skin->borderColor());
KMainWindow::paintEvent(event);
}
void MainWindow::moveEvent(QMoveEvent* event)
{
if (Settings::screen() && QApplication::desktop()->screenNumber(this) != getScreen())
{
Settings::setScreen(QApplication::desktop()->screenNumber(this)+1);
updateScreenMenu();
applyWindowGeometry();
}
KMainWindow::moveEvent(event);
}
void MainWindow::closeEvent(QCloseEvent *event)
{
KMainWindow::closeEvent(event);
if (event->isAccepted()) {
QApplication::quit();
}
}
void MainWindow::wmActiveWindowChanged()
{
if (m_toggleLock) {
m_toggleLock = false;
return;
}
KWindowInfo info(KWindowSystem::activeWindow(), 0, NET::WM2TransientFor);
if (info.valid() && info.transientFor() == winId()) {
return;
}
if (m_isX11) {
if (!Settings::keepOpen() && isVisible() && KWindowSystem::activeWindow() != winId()) {
toggleWindowState();
}
} else {
if (!Settings::keepOpen() && hasFocus()) {
toggleWindowState();
}
}
}
void MainWindow::changeEvent(QEvent* event)
{
if (event->type() == QEvent::WindowStateChange
&& (windowState() & Qt::WindowMaximized)
&& Settings::width() != 100
&& Settings::height() != 100)
{
Settings::setWidth(100);
Settings::setHeight(100);
applyWindowGeometry();
updateWindowWidthMenu();
updateWindowHeightMenu();
}
KMainWindow::changeEvent(event);
}
bool MainWindow::event(QEvent* event)
{
if (event->type() == QEvent::Expose) {
// FIXME TODO: We can remove this once we depend on Qt 5.6.1+.
// See: https://bugreports.qt.io/browse/QTBUG-26978
applyWindowProperties();
#if (QT_VERSION > QT_VERSION_CHECK(5, 5, 0))
} else if (event->type() == QEvent::PlatformSurface) {
const QPlatformSurfaceEvent *pSEvent = static_cast(event);
if (pSEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) {
applyWindowProperties();
}
#endif
}
return KMainWindow::event(event);
}
void MainWindow::toggleWindowState()
{
bool visible = isVisible();
if (visible && KWindowSystem::activeWindow() != winId() && Settings::keepOpen())
{
// Window is open but doesn't have focus; it's set to stay open
// regardless of focus loss.
if (Settings::toggleToFocus())
{
// The open/retract action is set to focus the window when it's
// open but lacks focus. The following will cause it to receive
// focus, and in an environment with multiple virtual desktops
// will also cause the window manager to switch to the virtual
// desktop the window resides on.
KWindowSystem::activateWindow(winId());
KWindowSystem::forceActiveWindow(winId());
return;
}
else if (!Settings::showOnAllDesktops()
&& KWindowInfo(winId(), NET::WMDesktop).desktop() != KWindowSystem::currentDesktop())
{
// The open/restrict action isn't set to focus the window, but
// the window is currently on another virtual desktop (the option
// to show it on all of them is disabled), so closing it doesn't
// make sense and we're opting to show it instead to avoid
// requiring the user to invoke the action twice to get to see
// Yakuake. Just forcing focus would cause the window manager to
// switch to the virtual desktop the window currently resides on,
// so move the window to the current desktop before doing so.
KWindowSystem::setOnDesktop(winId(), KWindowSystem::currentDesktop());
KWindowSystem::activateWindow(winId());
KWindowSystem::forceActiveWindow(winId());
return;
}
}
#if HAVE_X11
if (!Settings::useWMAssist() && m_kwinAssistPropSet)
kwinAssistPropCleanup();
if (m_isX11 && Settings::useWMAssist() && KWindowSystem::compositingActive())
kwinAssistToggleWindowState(visible);
else
#endif
if (!m_isWayland) {
xshapeToggleWindowState(visible);
} else {
if (visible)
{
sharedPreHideWindow();
hide();
sharedAfterHideWindow();
}
else
{
sharedPreOpenWindow();
if (KWindowEffects::isEffectAvailable(KWindowEffects::Slide)) {
KWindowEffects::slideWindow(this, KWindowEffects::TopEdge);
}
show();
sharedAfterOpenWindow();
}
}
}
#if HAVE_X11
void MainWindow::kwinAssistToggleWindowState(bool visible)
{
bool gotEffect = false;
Display* display = QX11Info::display();
Atom atom = XInternAtom(display, "_KDE_SLIDE", false);
int count;
Atom* list = XListProperties(display, DefaultRootWindow(display), &count);
if (list != NULL)
{
gotEffect = (qFind(list, list + count, atom) != list + count);
XFree(list);
}
if (gotEffect)
{
Atom atom = XInternAtom(display, "_KDE_SLIDE", false);
if (Settings::frames() > 0)
{
QVarLengthArray data(4);
data[0] = 0;
data[1] = 1;
data[2] = Settings::frames() * 10;
data[3] = Settings::frames() * 10;
XChangeProperty(display, winId(), atom, atom, 32, PropModeReplace,
reinterpret_cast(data.data()), data.size());
m_kwinAssistPropSet = true;
}
else
XDeleteProperty(display, winId(), atom);
if (visible)
{
sharedPreHideWindow();
hide();
sharedAfterHideWindow();
}
else
{
sharedPreOpenWindow();
show();
sharedAfterOpenWindow();
}
return;
}
// Fall back to legacy animation strategy if kwin doesn't have the
// effect loaded.
xshapeToggleWindowState(visible);
}
void MainWindow::kwinAssistPropCleanup()
{
if (!QX11Info::isPlatformX11())
return;
Display* display = QX11Info::display();
Atom atom = XInternAtom(display, "_KDE_SLIDE", false);
XDeleteProperty(display, winId(), atom);
m_kwinAssistPropSet = false;
}
#endif
void MainWindow::xshapeToggleWindowState(bool visible)
{
if (m_animationTimer.isActive()) return;
if (visible)
{
sharedPreHideWindow();
m_animationFrame = Settings::frames();
connect(&m_animationTimer, SIGNAL(timeout()), this, SLOT(xshapeRetractWindow()));
m_animationTimer.start();
}
else
{
m_animationFrame = 0;
connect(&m_animationTimer, SIGNAL(timeout()), this, SLOT(xshapeOpenWindow()));
m_animationTimer.start();
}
}
void MainWindow::xshapeOpenWindow()
{
if (m_animationFrame == 0)
{
sharedPreOpenWindow();
show();
sharedAfterOpenWindow();
}
if (m_animationFrame == Settings::frames())
{
m_animationTimer.stop();
m_animationTimer.disconnect();
m_titleBar->move(0, height() - m_titleBar->height());
updateMask();
}
else
{
int maskHeight = m_animationStepSize * m_animationFrame;
QRegion newMask = m_titleBar->mask();
newMask.translate(0, maskHeight);
newMask += QRegion(0, 0, width(), maskHeight);
m_titleBar->move(0, maskHeight);
setMask(newMask);
m_animationFrame++;
}
}
void MainWindow::xshapeRetractWindow()
{
if (m_animationFrame == 0)
{
m_animationTimer.stop();
m_animationTimer.disconnect();
hide();
sharedAfterHideWindow();
}
else
{
m_titleBar->move(0,m_titleBar->y() - m_animationStepSize);
setMask(QRegion(mask()).translated(0, -m_animationStepSize));
--m_animationFrame;
}
}
void MainWindow::sharedPreOpenWindow()
{
applyWindowGeometry();
updateUseTranslucency();
if (Settings::pollMouse()) toggleMousePoll(false);
+ if (Settings::rememberFullscreen()) setFullScreen(m_isFullscreen);
}
void MainWindow::sharedAfterOpenWindow()
{
if (!Settings::firstRun()) KWindowSystem::forceActiveWindow(winId());
connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged,
this, &MainWindow::wmActiveWindowChanged);
applyWindowProperties();
#if HAVE_KWAYLAND
initWaylandSurface();
#endif
emit windowOpened();
}
void MainWindow::sharedPreHideWindow()
{
disconnect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged,
this, &MainWindow::wmActiveWindowChanged);
}
void MainWindow::sharedAfterHideWindow()
{
if (Settings::pollMouse()) toggleMousePoll(true);
#if HAVE_KWAYLAND
delete m_plasmaShellSurface;
m_plasmaShellSurface = Q_NULLPTR;
#endif
emit windowClosed();
}
void MainWindow::activate()
{
KWindowSystem::activateWindow(winId());
}
void MainWindow::toggleMousePoll(bool poll)
{
if (poll)
m_mousePoller.start(Settings::pollInterval());
else
m_mousePoller.stop();
}
void MainWindow::pollMouse()
{
QPoint pos = QCursor::pos();
QRect workArea = getDesktopGeometry();
int windowX = workArea.x() + workArea.width() * Settings::position() * (100 - Settings::width()) / 10000;
int windowWidth = workArea.width() * Settings::width() / 100;
if (pos.y() == 0 && pos.x() >= windowX && pos.x() <= (windowX + windowWidth))
toggleWindowState();
}
void MainWindow::setKeepOpen(bool keepOpen)
{
if (Settings::keepOpen() != keepOpen)
{
Settings::setKeepOpen(keepOpen);
Settings::self()->save();
applyWindowProperties();
}
actionCollection()->action(QStringLiteral("keep-open"))->setChecked(keepOpen);
m_titleBar->setFocusButtonState(keepOpen);
}
void MainWindow::setFullScreen(bool state)
{
+ if (isVisible()) m_isFullscreen = state;
if (state)
{
setWindowState(windowState() | Qt::WindowFullScreen);
setWindowGeometry(100, 100, Settings::position());
}
else
{
setWindowState(windowState() & ~Qt::WindowFullScreen);
setWindowGeometry(Settings::width(), Settings::height(), Settings::position());
}
}
int MainWindow::getScreen()
{
if (!Settings::screen())
return QApplication::desktop()->screenNumber(QCursor::pos());
else
return Settings::screen() - 1;
}
QRect MainWindow::getDesktopGeometry()
{
QRect screenGeometry = QApplication::desktop()->screenGeometry(getScreen());
QAction* action = actionCollection()->action(QStringLiteral("view-full-screen"));
if (action->isChecked())
return screenGeometry;
if (m_isWayland) {
// on Wayland it's not possible to get the work area
return screenGeometry;
}
if (QApplication::desktop()->screenCount() > 1)
{
const QList allWindows = KWindowSystem::windows();
QList offScreenWindows;
QListIterator i(allWindows);
while (i.hasNext())
{
WId windowId = i.next();
if (KWindowSystem::hasWId(windowId))
{
KWindowInfo windowInfo = KWindowInfo(windowId, NET::WMDesktop, NET::WM2ExtendedStrut);
// If windowInfo is valid and the window is located at the same (current)
// desktop with the yakuake window...
if (windowInfo.valid() && windowInfo.isOnCurrentDesktop())
{
NETExtendedStrut strut = windowInfo.extendedStrut();
// Get the area covered by each strut.
QRect topStrut(strut.top_start, 0, strut.top_end - strut.top_start, strut.top_width);
QRect bottomStrut(strut.bottom_start, screenGeometry.bottom() - strut.bottom_width,
strut.bottom_end - strut.bottom_start, strut.bottom_width);
QRect leftStrut(0, strut.left_width, strut.left_start, strut.left_end - strut.left_start);
QRect rightStrut(screenGeometry.right() - strut.right_width, strut.right_start,
strut.right_end - strut.right_start, strut.right_width);
// If the window has no strut, no need to bother further.
if (topStrut.isEmpty() && bottomStrut.isEmpty() && leftStrut.isEmpty() && rightStrut.isEmpty())
continue;
// If any of the strut intersects with our screen geometry, it will be correctly handled
// by workArea().
if (topStrut.intersects(screenGeometry) || bottomStrut.intersects(screenGeometry) ||
leftStrut.intersects(screenGeometry) || rightStrut.intersects(screenGeometry))
continue;
// This window has a strut on the same desktop as us but which does not cover our screen
// geometry. It should be ignored, otherwise the returned work area will wrongly include
// the strut.
offScreenWindows << windowId;
}
}
}
return KWindowSystem::workArea(offScreenWindows).intersected(screenGeometry);
}
return KWindowSystem::workArea();
}
void MainWindow::whatsThis()
{
QWhatsThis::enterWhatsThisMode();
}
void MainWindow::showStartupPopup()
{
QAction* action = static_cast(actionCollection()->action(QStringLiteral("toggle-window-state")));
const QList &shortcuts = KGlobalAccel::self()->shortcut(action);
if (shortcuts.isEmpty())
return;
QString shortcut(shortcuts.first().toString(QKeySequence::NativeText));
QString message(xi18nc("@info", "Application successfully started." "Press %1 to use it ...", shortcut));
KNotification::event(QLatin1String("startup"), message, QPixmap(), this);
}
void MainWindow::showFirstRunDialog()
{
if (!m_firstRunDialog)
{
m_firstRunDialog = new FirstRunDialog(this);
connect(m_firstRunDialog, &QDialog::finished, this, &MainWindow::firstRunDialogFinished);
connect(m_firstRunDialog, &QDialog::accepted, this, &MainWindow::firstRunDialogOk);
}
m_firstRunDialog->show();
}
void MainWindow::firstRunDialogFinished()
{
Settings::setFirstRun(false);
Settings::self()->save();
m_firstRunDialog->deleteLater();
KWindowSystem::forceActiveWindow(winId());
}
void MainWindow::firstRunDialogOk()
{
QAction* action = static_cast(actionCollection()->action(QStringLiteral("toggle-window-state")));
KGlobalAccel::self()->setShortcut(action, QList() << m_firstRunDialog->keySequence(),
KGlobalAccel::NoAutoloading);
actionCollection()->writeSettings();
}
void MainWindow::updateUseTranslucency()
{
m_useTranslucency = (Settings::translucency() && KWindowSystem::compositingActive());
}
diff --git a/app/mainwindow.h b/app/mainwindow.h
index b537c27..8a00d38 100644
--- a/app/mainwindow.h
+++ b/app/mainwindow.h
@@ -1,214 +1,215 @@
/*
Copyright (C) 2008-2014 by Eike Hein
Copyright (C) 2009 by Juan Carlos Torres
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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor appro-
ved by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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 http://www.gnu.org/licenses/.
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
class FirstRunDialog;
class SessionStack;
class Skin;
class TabBar;
class Terminal;
class TitleBar;
class KHelpMenu;
class KActionCollection;
#if HAVE_KWAYLAND
namespace KWayland {
namespace Client {
class PlasmaShell;
class PlasmaShellSurface;
}
}
#endif
class MainWindow : public KMainWindow
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.yakuake")
public:
explicit MainWindow(QWidget* parent = 0);
~MainWindow();
KActionCollection* actionCollection() { return m_actionCollection; }
SessionStack* sessionStack() { return m_sessionStack; }
Skin* skin() { return m_skin; }
QMenu* menu() { return m_menu; }
bool useTranslucency() { return m_useTranslucency; }
void setContextDependentActionsQuiet(bool quiet);
public Q_SLOTS:
Q_SCRIPTABLE void toggleWindowState();
void handleContextDependentAction(QAction* action = 0, int sessionId = -1);
void handleContextDependentToggleAction(bool checked, QAction* action = 0, int sessionId = -1);
void handleToggleTerminalKeyboardInput(bool checked);
void handleToggleTerminalMonitorActivity(bool checked);
void handleToggleTerminalMonitorSilence(bool checked);
void handleTerminalActivity(Terminal* terminal);
void handleTerminalSilence(Terminal* terminal);
void handleLastTabClosed();
Q_SIGNALS:
void windowOpened();
void windowClosed();
protected:
void paintEvent(QPaintEvent*) override;
void moveEvent(QMoveEvent*) override;
void changeEvent(QEvent* event) override;
void closeEvent(QCloseEvent *event) override;
bool event(QEvent* event) override;
virtual bool queryClose() override;
private Q_SLOTS:
void applySettings();
void applySkin();
void applyWindowProperties();
void applyWindowGeometry();
void setWindowGeometry(int width, int height, int position);
void updateScreenMenu();
void setScreen(QAction* action);
void setWindowWidth(int width);
void setWindowHeight(int height);
void setWindowWidth(QAction* action);
void setWindowHeight(QAction* action);
void increaseWindowWidth();
void decreaseWindowWidth();
void increaseWindowHeight();
void decreaseWindowHeight();
void wmActiveWindowChanged();
void xshapeOpenWindow();
void xshapeRetractWindow();
void activate();
void toggleMousePoll(bool poll);
void pollMouse();
void setKeepOpen(bool keepOpen);
void setFullScreen(bool state);
void handleSwitchToAction();
void whatsThis();
void configureKeys();
void configureNotifications();
void configureApp();
void showFirstRunDialog();
void firstRunDialogFinished();
void firstRunDialogOk();
private:
void setupActions();
void setupMenu();
void updateWindowSizeMenus();
void updateWindowHeightMenu();
void updateWindowWidthMenu();
#if HAVE_X11
void kwinAssistToggleWindowState(bool visible);
void kwinAssistPropCleanup();
bool m_kwinAssistPropSet;
#endif
void xshapeToggleWindowState(bool visible);
void sharedPreOpenWindow();
void sharedAfterOpenWindow();
void sharedPreHideWindow();
void sharedAfterHideWindow();
void updateMask();
int getScreen();
QRect getDesktopGeometry();
void showStartupPopup();
void updateUseTranslucency();
bool m_useTranslucency;
+ bool m_isFullscreen;
KActionCollection* m_actionCollection;
QList m_contextDependentActions;
Skin* m_skin;
TitleBar* m_titleBar;
TabBar* m_tabBar;
SessionStack* m_sessionStack;
QMenu* m_menu;
KHelpMenu* m_helpMenu;
QMenu* m_screenMenu;
QMenu* m_windowWidthMenu;
QMenu* m_windowHeightMenu;
FirstRunDialog* m_firstRunDialog;
QTimer m_animationTimer;
QTimer m_mousePoller;
int m_animationFrame;
int m_animationStepSize;
bool m_toggleLock;
bool m_isX11;
bool m_isWayland;
#if HAVE_KWAYLAND
void initWayland();
void initWaylandSurface();
KWayland::Client::PlasmaShell *m_plasmaShell;
KWayland::Client::PlasmaShellSurface *m_plasmaShellSurface;
#endif
};
#endif