Commit f4a2ead2 authored by Eike Hein's avatar Eike Hein
Browse files

* Introduce a framework to display notifications (and po-

  tentially other information) on top of the terminals,
  and start using it for a bunch of things:
  - Flash terminal red when typing into a terminal which
    has keyboard input disabled.
  - (Optionally) Indicating the newly-focussed terminal
    when moving focus between multiple terminals in a
    session, as well as the currently focussed terminal
    when switching to a session with multiple terminals.
  - Indicate the affected terminal when hovering a per-
    terminal action in the tab context menu.
* Make the disable-keyboard-input toggle per-terminal,
  available from the tab context menu.
* Various cleanup.

More details are available in the changelog file.

svn path=/trunk/extragear/utils/yakuake/; revision=950299
parent daaf007f
Changes since 2.9.5:
* Fixed linking with the new gold linker in binutils.
* Fixed a regression from the background painting changes in 2.9.4 that
caused splitter handles between terminals to appear in the user-confi-
gured background color.
* Improved graphics for the window state lock button in the default skin.
* Added an option to open the application window after program start.
* Slightly improved options layout on the Behavior page of the configura-
tion dialog.
* Added a new framework, referred to as the visual event overlay, to display
notifications (and potentially other information) on top of the terminals.
It's used for a number of new features found in this release, as described
in their separate entries.
* Added an option to visually indicate the newly-focussed terminal when mo-
ving focus in a session with multiple terminals (i.e. via splits), or the
currently focussed terminal when switching to a session with multiple ter-
minals. This make the lives of users easier who prefer to use the "I-Beam"
or "Underline" cursors styles in the terminal, as those cursor styles do
not indicate terminal focus as the "Block" style does. The visual indica-
tion used here is a brief, translucent overlay in the global color scheme's
hover decoration color. This feature is realized using the new visual event
overlay described in a separate entry.
* Added a feature to disable keyboard input for all or individual terminals
in a session. Both variants are available from the tab context menu; the
session-wide toggle is also available in the keyboard shortcuts configura-
tion. When typing into a terminal that has keyboard input disabled the
terminal will briefly flash red. When hovering one of the per-terminal
toggles in the context menu, the affected terminal will be highlighted
in the global color scheme's hover decoration color. The latter two aspects
of this new feature have been realized using the new visual event overlay
described in a separate entry. Furthermore, new D-Bus interfaces have been
added to get/set this state bit for both sessions and terminals.
* Added a feature to lock a session to prevent it from being closed acciden-
tally, available from the tab context menu as well as in the keyboard short-
cuts configuration. When trying to close a locked session or its active ter-
minal via Yakuake's own actions/shortcuts, a warning dialog will be display-
ed, and also when trying to quit Yakuake with any locked sessions. Note that
this doesn't cover closing a terminal from within the Konsole KPart provi-
ding the terminal (such as running "exit" or via the terminal's context
menu), however. New D-Bus interfaces have been added to get/set this state
bit for sessions.
* Added support for moving tabs on the tab bar by drag and drop.
* Added an option to open the application window after program start.
* Improved graphics for the window state lock button in the default skin.
* Added D-Bus interfaces for splitting.
* Added the frequently-requested 'sessionIdForTerminalId(int terminalId)'
and 'terminalIdsForSessionId(int sessionId)' D-Bus interfaces.
* Rewrote the translucency support not to use X11-specific code on Qt 4.5
or higher and KDE 4.3 or higher.
* Added a feature to disable keyboard input for a session (via a user-con-
figured shortcut or the context menu), including D-Bus calls to get/set
this state bit.
* On KDE 4.2 and higher, the first-run dialog now no longer allows setting
a multi-key shortcut to open/close the window, consistent with the short-
cut configuration dialog (the required API is new in 4.2). The reason
multi-key global shortcuts are not allowed in KDE is that they don't work.
* Added D-Bus interfaces for splitting.
* Fix crashes when closing sessions with certain split setups (also on quit).
* Fixed the 'removeTerminal(int terminalId)' D-Bus call always closing the
active terminal of the session containing the target terminal, rather than
the target terminal.
* Added a feature to prevent a session from being closed (toggled via a user-
configured shortcut or the context menu) by way of Yakuake's own shortcuts
and actions, including D-Bus calls to get/set this state bit.
* The auto-open-on-mouse-pointer-hitting-the-screen edge feature now checks
the position of the mouse pointer against the actual position and width of
the window rather than triggering on the entire screen edge. This way, the
......@@ -34,6 +44,22 @@ Changes since 2.9.5:
the default Yakuake window width of 90% work area width.
* Rewrote fullscreen handling, fixing bugs such as exiting fullscreen mode
on virtual desktop switch.
* Rewrote the translucency support not to use X11-specific code on Qt 4.5
or higher and KDE 4.3 or higher.
* Fixed a regression from the background painting changes in 2.9.4 that
caused splitter handles between terminals to appear in the user-confi-
gured background color.
* Fix crashes when closing sessions with certain split setups (also on quit).
* Fixed the 'removeTerminal(int terminalId)' D-Bus call always closing the
active terminal of the session containing the target terminal, rather than
the target terminal.
* Slightly improved options layout on the Behavior page of the configura-
tion dialog.
* On KDE 4.2 and higher, the first-run dialog now no longer allows setting
a multi-key shortcut to open/close the window, consistent with the short-
cut configuration dialog (the required API is new in 4.2). The reason
multi-key global shortcuts are not allowed in KDE is that they don't work.
* Fixed linking with the new gold linker in binutils.
Changes in 2.9.4:
......
......@@ -14,11 +14,12 @@ set(yakuake_SRCS
terminal.cpp
splitter.cpp
firstrundialog.cpp
visualeventoverlay.cpp
config/windowsettings.cpp
config/appearancesettings.cpp
config/skinlistdelegate.cpp
)
kde4_add_kcfg_files(yakuake_SRCS config/settings.kcfgc)
kde4_add_ui_files(yakuake_SRCS
......
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AppearanceSettings</class>
<widget class="QWidget" name="AppearanceSettings" >
<property name="geometry" >
<widget class="QWidget" name="AppearanceSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>245</width>
<height>289</height>
<width>307</width>
<height>355</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" >
<property name="margin" >
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_1" >
<property name="title" >
<string comment="@title:group" >Window Background</string>
<widget class="QGroupBox" name="groupBox_1">
<property name="title">
<string comment="@title:group">General</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<layout class="QVBoxLayout" name="verticalLayout_1">
<item>
<layout class="QHBoxLayout" >
<widget class="QCheckBox" name="kcfg_TerminalHighlightOnManualActivation">
<property name="whatsThis">
<string comment="@info:whatsthis">Enabling this option will make Yakuake briefly display a colored overlay above the newly-focussed terminal when moving focus between multple terminals in a session, as well as over the currently focussed terminal when switching to a session with multiple terminals.</string>
</property>
<property name="text">
<string comment="@option:check">Highlight terminals when moving focus between them</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string comment="@title:group">Window Background</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="backgroundColorLabel" >
<property name="text" >
<string comment="@label:chooser" >Background color:</string>
<widget class="QLabel" name="backgroundColorLabel">
<property name="text">
<string comment="@label:chooser">Background color:</string>
</property>
</widget>
</item>
<item>
<widget class="KColorButton" name="kcfg_BackgroundColor" >
<property name="text" >
<widget class="KColorButton" name="kcfg_BackgroundColor">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>41</width>
<height>20</height>
......@@ -51,29 +71,29 @@
</layout>
</item>
<item>
<widget class="QCheckBox" name="kcfg_Translucency" >
<property name="whatsThis" >
<string comment="@info:whatsthis" >Translucency requires support by the selected skin as well as your desktop environment. The default skin supports translucency.</string>
<widget class="QCheckBox" name="kcfg_Translucency">
<property name="whatsThis">
<string comment="@info:whatsthis">Translucency requires support by the selected skin as well as your desktop environment. The default skin supports translucency.</string>
</property>
<property name="text" >
<string comment="@option:check" >Use skin translucency if supported</string>
<property name="text">
<string comment="@option:check">Use skin translucency if supported</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" >
<property name="leftMargin" >
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>7</number>
</property>
<item>
<spacer name="spacer" >
<property name="orientation" >
<spacer name="spacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
......@@ -82,40 +102,40 @@
</spacer>
</item>
<item>
<widget class="QLabel" name="backgroundColorOpacityLabel" >
<property name="enabled" >
<widget class="QLabel" name="backgroundColorOpacityLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text" >
<string comment="@label:spinbox" >Background color opacity:</string>
<property name="text">
<string comment="@label:spinbox">Background color opacity:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="kcfg_BackgroundColorOpacity" >
<property name="enabled" >
<widget class="QSpinBox" name="kcfg_BackgroundColorOpacity">
<property name="enabled">
<bool>false</bool>
</property>
<property name="whatsThis" >
<string comment="@info:whatsthis" >When using translucency, the background color will be filled in using the given opacity before the skin elements are painted on top of the background. This allows influencing the opacity and color tint of translucent areas of the skin.</string>
<property name="whatsThis">
<string comment="@info:whatsthis">When using translucency, the background color will be filled in using the given opacity before the skin elements are painted on top of the background. This allows influencing the opacity and color tint of translucent areas of the skin.</string>
</property>
<property name="suffix" >
<string comment="@label Spinbox unit suffix" >%</string>
<property name="suffix">
<string comment="@label Spinbox unit suffix">%</string>
</property>
<property name="maximum" >
<property name="maximum">
<number>100</number>
</property>
<property name="value" >
<property name="value">
<number>50</number>
</property>
</widget>
</item>
<item>
<spacer name="spacer_2" >
<property name="orientation" >
<spacer name="spacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>64</width>
<height>17</height>
......@@ -129,44 +149,44 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<string comment="@title:group" >Skin</string>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string comment="@title:group">Skin</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" colspan="2" >
<widget class="QListView" name="skinList" >
<property name="contextMenuPolicy" >
<layout class="QGridLayout">
<item row="0" column="0" colspan="2">
<widget class="QListView" name="skinList">
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
<property name="horizontalScrollBarPolicy" >
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QPushButton" name="installButton" >
<property name="enabled" >
<item row="1" column="0">
<widget class="QPushButton" name="installButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text" >
<string comment="@action:button" >Install Skin...</string>
<property name="text">
<string comment="@action:button">Install Skin...</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QPushButton" name="removeButton" >
<property name="enabled" >
<item row="1" column="1">
<widget class="QPushButton" name="removeButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text" >
<string comment="@action:button" >Remove Skin</string>
<property name="text">
<string comment="@action:button">Remove Skin</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2" >
<widget class="KLineEdit" name="kcfg_Skin" >
<property name="frame" >
<item row="2" column="0" colspan="2">
<widget class="KLineEdit" name="kcfg_Skin">
<property name="frame">
<bool>false</bool>
</property>
</widget>
......@@ -189,6 +209,7 @@
</customwidget>
</customwidgets>
<tabstops>
<tabstop>kcfg_TerminalHighlightOnManualActivation</tabstop>
<tabstop>kcfg_BackgroundColor</tabstop>
<tabstop>kcfg_Translucency</tabstop>
<tabstop>kcfg_BackgroundColorOpacity</tabstop>
......@@ -205,11 +226,11 @@
<receiver>kcfg_BackgroundColorOpacity</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>152</x>
<y>76</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>192</x>
<y>106</y>
</hint>
......@@ -221,11 +242,11 @@
<receiver>backgroundColorOpacityLabel</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>152</x>
<y>76</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>95</x>
<y>106</y>
</hint>
......
/*
Copyright (C) 2008 by Eike Hein <hein@kde.org>
Copyright (C) 2009 by Eike Hein <hein@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
......
......@@ -97,6 +97,44 @@
<min>0</min>
<max>100</max>
</entry>
<entry name="TerminalHighlightOnManualActivation" type="Bool">
<label context="@label">Highlight newly-focussed terminals</label>
<whatsthis context="@info:whatsthis">Whether to briefly display a colored overlay above the newly-focussed terminal when moving focus between multiple terminals in a session, as well as over the currently focussed terminal when switching to a session with multiple terminals.</whatsthis>
<default>false</default>
</entry>
<entry name="TerminalHighlightOpacity" type="Double">
<label context="@label">Terminal highlight opacity</label>
<whatsthis context="@info:whatsthis">The opacity of the colored overlay used to highlight a terminal.</whatsthis>
<default>0.4</default>
<min>0</min>
<max>1.0</max>
</entry>
<entry name="TerminalHighlightDuration" type="Int">
<label context="@label">Terminal highlight duration</label>
<whatsthis context="@info:whatsthis">The duration of the terminal highlight overlay.</whatsthis>
<default>250</default>
<min>0</min>
<max>86400000</max>
</entry>
<entry name="KeyboardInputBlockIndicatorColor" type="Color">
<label context="@label">Keyboard input block indicator color</label>
<whatsthis context="@info:whatsthis">The color of the keyboard input block indicator overlay.</whatsthis>
<default>#FF0000</default>
</entry>
<entry name="KeyboardInputBlockIndicatorOpacity" type="Double">
<label context="@label">Keyboard input block indicator opacity</label>
<whatsthis context="@info:whatsthis">The opacity of the keyboard input block indicator overlay.</whatsthis>
<default>0.5</default>
<min>0</min>
<max>1.0</max>
</entry>
<entry name="KeyboardInputBlockIndicatorDuration" type="Int">
<label context="@label">Keyboard input block indicator duration</label>
<whatsthis context="@info:whatsthis">The duration of the keyboard input block indicator overlay.</whatsthis>
<default>250</default>
<min>0</min>
<max>86400000</max>
</entry>
</group>
<group name="Animation">
<entry name="Frames" type="Int">
......
......@@ -78,6 +78,9 @@ MainWindow::MainWindow(QWidget* parent)
connect(m_tabBar, SIGNAL(newTabRequested()), m_sessionStack, SLOT(addSession()));
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, const QString&)),
m_tabBar, SLOT(addTab(int, const QString&)));
......@@ -308,13 +311,13 @@ void MainWindow::setupActions()
connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction()));
m_contextDependentActions << action;
action = actionCollection()->addAction("toggle-keyboard-input");
action = actionCollection()->addAction("toggle-session-keyboard-input");
action->setText(i18nc("@action", "Disable Keyboard Input"));
action->setCheckable(true);
connect(action, SIGNAL(triggered(bool)), this, SLOT(handleContextDependentToggleAction(bool)));
m_contextDependentActions << action;
action = actionCollection()->addAction("toggle-prevent-closing");
action = actionCollection()->addAction("toggle-session-prevent-closing");
action->setText(i18nc("@action", "Prevent Closing"));
action->setCheckable(true);
connect(action, SIGNAL(triggered(bool)), this, SLOT(handleContextDependentToggleAction(bool)));
......@@ -364,18 +367,18 @@ void MainWindow::handleContextDependentAction(QAction* action, int sessionId)
m_sessionStack->splitSessionTopBottom(sessionId);
}
void MainWindow::handleContextDependentToggleAction(bool toggle, QAction* action, int sessionId)
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<QAction*>(QObject::sender());
if (action == actionCollection()->action("toggle-keyboard-input"))
m_sessionStack->setKeyboardInputEnabled(sessionId, !toggle);
if (action == actionCollection()->action("toggle-session-keyboard-input"))
m_sessionStack->setSessionKeyboardInputEnabled(sessionId, !checked);
if (action == actionCollection()->action("toggle-prevent-closing"))
m_sessionStack->setSessionClosable(sessionId, !toggle);
if (action == actionCollection()->action("toggle-session-prevent-closing"))
m_sessionStack->setSessionClosable(sessionId, !checked);
}
void MainWindow::setContextDependentActionsQuiet(bool quiet)
......@@ -386,6 +389,19 @@ void MainWindow::setContextDependentActionsQuiet(bool quiet)
}
}
void MainWindow::handleToggleTerminalKeyboardInput(bool checked)
{
QAction* action = qobject_cast<QAction*>(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::handleSwitchToAction()
{
QAction* action = qobject_cast<QAction*>(QObject::sender());
......
......@@ -70,7 +70,8 @@ class MainWindow : public KMainWindow
Q_SCRIPTABLE void toggleWindowState();
void handleContextDependentAction(QAction* action = 0, int sessionId = -1);
void handleContextDependentToggleAction(bool toggle, QAction* action = 0, int sessionId = -1);
void handleContextDependentToggleAction(bool checked, QAction* action = 0, int sessionId = -1);
void handleToggleTerminalKeyboardInput(bool checked);
protected:
......
......@@ -32,8 +32,7 @@ Session::Session(SessionType type, QWidget* parent) : QObject(parent)
m_activeTerminalId = -1;
m_keyboardInputEnabled = true;
m_sessionClosable = true;
m_closable = true;
m_baseSplitter = new Splitter(Qt::Horizontal, parent);
connect(m_baseSplitter, SIGNAL(destroyed()), this, SLOT(prepareShutdown()));
......@@ -142,14 +141,14 @@ void Session::setupSession(SessionType type)
Terminal* Session::addTerminal(QWidget* parent)
{
Terminal* terminal = new Terminal(parent);
connect(terminal, SIGNAL(titleChanged(int, const QString&)), this, SLOT(setTitle(int, const QString&)));
connect(terminal, SIGNAL(activated(int)), this, SLOT(setActiveTerminal(int)));
connect(terminal, SIGNAL(manuallyActivated(Terminal*)), this, SIGNAL(terminalManuallyActivated(Terminal*)));
connect(terminal, SIGNAL(titleChanged(int, const QString&)), this, SLOT(setTitle(int, const QString&)));
connect(terminal, SIGNAL(keyboardInputBlocked(Terminal*)), this, SIGNAL(keyboardInputBlocked(Terminal*)));
connect(terminal, SIGNAL(destroyed(int)), this, SLOT(cleanup(int)));
m_terminals.insert(terminal->id(), terminal);
terminal->setKeyboardInputEnabled(m_keyboardInputEnabled);
QWidget* terminalWidget = terminal->terminalWidget();
if (terminalWidget) terminalWidget->setFocus();
......@@ -362,7 +361,14 @@ const QString Session::terminalIdList()
bool Session::hasTerminal(int terminalId)
{
return (m_terminals.contains(terminalId));
return m_terminals.contains(terminalId);
}
Terminal* Session::getTerminal(int terminalId)
{
if (!m_terminals.contains(terminalId)) return 0;
return m_terminals.value(terminalId);
}
void Session::runCommand(const QString& command, int terminalId)
......@@ -385,26 +391,65 @@ void Session::manageProfiles()
void Session::editProfile()
{
if ( m_activeTerminalId == -1) return;
if (!m_terminals.contains( m_activeTerminalId)) return;
if (!m_terminals.contains(m_activeTerminalId)) return;
m_terminals[m_activeTerminalId]->editProfile();
}
void Session::setKeyboardInputEnabled(bool keyboardInputEnabled)
bool Session::keyboardInputEnabled()
{
m_keyboardInputEnabled = keyboardInputEnabled;
int keyboardInputDisabledCount = 0;
QMapIterator<int, Terminal*> it(m_terminals);
QMapIterator<int, Terminal*> i(m_terminals);
while (it.hasNext())
while (i.hasNext())
{
it.next();
i.next();
it.value()->setKeyboardInputEnabled(m_keyboardInputEnabled);
if (!i.value()->keyboardInputEnabled())
++keyboardInputDisabledCount;
}
return m_terminals.count() != keyboardInputDisabledCount;
}
void Session::setSessionClosable(bool sessionClosable)
void Session::setKeyboardInputEnabled(bool enabled)
{
m_sessionClosable = sessionClosable;
QMapIterator<int, Terminal*> i(m_terminals);
while (i.hasNext())
{
i.next();
i.value()->setKeyboardInputEnabled(enabled);
}
}
bool Session::keyboardInputEnabled(int terminalId)
{
if (!m_terminals.contains(terminalId)) return false;
return m_terminals.value(terminalId)->keyboardInputEnabled();
}