diff --git a/clients/aurorae/src/aurorae.cpp b/clients/aurorae/src/aurorae.cpp
index 19db4811df..9a6965cece 100644
--- a/clients/aurorae/src/aurorae.cpp
+++ b/clients/aurorae/src/aurorae.cpp
@@ -21,6 +21,7 @@ along with this program. If not, see .
#include
#include
+#include
#include
#include
@@ -99,6 +100,8 @@ bool AuroraeFactory::supports(Ability ability) const
return m_theme->hasButton(HelpButton);
case AbilityProvidesShadow:
return true; // TODO: correct value from theme
+ case AbilityClientGrouping:
+ return true;
default:
return false;
}
@@ -125,6 +128,7 @@ AuroraeFactory *AuroraeFactory::s_instance = NULL;
*******************************************************/
AuroraeClient::AuroraeClient(KDecorationBridge *bridge, KDecorationFactory *factory)
: KDecorationUnstable(bridge, factory)
+ , m_clickInProgress(false)
{
m_scene = new AuroraeScene(AuroraeFactory::instance()->theme(),
options()->customButtonPositions() ? options()->titleButtonsLeft() : AuroraeFactory::instance()->theme()->defaultButtonsLeft(),
@@ -148,6 +152,10 @@ AuroraeClient::AuroraeClient(KDecorationBridge *bridge, KDecorationFactory *fact
connect(m_scene, SIGNAL(titleMouseMoved(Qt::MouseButton,Qt::MouseButtons)),
SLOT(titleMouseMoved(Qt::MouseButton,Qt::MouseButtons)));
connect(m_scene, SIGNAL(wheelEvent(int)), SLOT(titlebarMouseWheelOperation(int)));
+ connect(m_scene, SIGNAL(tabMouseButtonPress(QGraphicsSceneMouseEvent*,int)),
+ SLOT(tabMouseButtonPress(QGraphicsSceneMouseEvent*,int)));
+ connect(m_scene, SIGNAL(tabMouseButtonRelease(QGraphicsSceneMouseEvent*,int)),
+ SLOT(tabMouseButtonRelease(QGraphicsSceneMouseEvent*,int)));
connect(this, SIGNAL(keepAboveChanged(bool)), SLOT(keepAboveChanged(bool)));
connect(this, SIGNAL(keepBelowChanged(bool)), SLOT(keepBelowChanged(bool)));
}
@@ -162,6 +170,7 @@ void AuroraeClient::init()
createMainWidget();
widget()->setAttribute(Qt::WA_TranslucentBackground);
widget()->setAttribute(Qt::WA_NoSystemBackground);
+ widget()->installEventFilter(this);
m_view = new QGraphicsView(m_scene, widget());
m_view->setAttribute(Qt::WA_TranslucentBackground);
m_view->setFrameShape(QFrame::NoFrame);
@@ -181,7 +190,6 @@ void AuroraeClient::init()
m_scene->setShade(isShade());
m_scene->setKeepAbove(keepAbove());
m_scene->setKeepBelow(keepBelow());
- m_scene->setCaption(caption());
AuroraeFactory::instance()->theme()->setCompositingActive(compositingActive());
}
@@ -194,7 +202,7 @@ void AuroraeClient::activeChange()
void AuroraeClient::captionChange()
{
- m_scene->setCaption(caption());
+ checkTabs(true);
}
void AuroraeClient::iconChange()
@@ -395,6 +403,55 @@ void AuroraeClient::titleMouseMoved(Qt::MouseButton button, Qt::MouseButtons but
event = 0;
}
+void AuroraeClient::checkTabs(bool force)
+{
+ if (m_scene->tabCount() == 1 && clientGroupItems().count() == 1 && !force) {
+ return;
+ }
+ while (m_scene->tabCount() < clientGroupItems().count()) {
+ m_scene->addTab(QString());
+ }
+ while (m_scene->tabCount() > clientGroupItems().count()) {
+ m_scene->removeLastTab();
+ }
+ QStringList captions;
+ foreach (const ClientGroupItem &item, clientGroupItems()) {
+ captions << item.title();
+ }
+ m_scene->setCaptions(captions);
+ m_scene->setFocusedTab(visibleClientGroupItem());
+}
+
+bool AuroraeClient::eventFilter(QObject *o, QEvent *e)
+{
+ if (o != widget()) {
+ return false;
+ }
+ if (e->type() == QEvent::Paint) {
+ checkTabs();
+ }
+ return false;
+}
+
+void AuroraeClient::tabMouseButtonPress(QGraphicsSceneMouseEvent *e, int index)
+{
+ if (buttonToWindowOperation(e->buttons()) == OperationsOp) {
+ displayClientMenu(index, e->screenPos());
+ return;
+ }
+ titlePressed(e->button(), e->buttons());
+ m_clickInProgress = true;
+}
+
+void AuroraeClient::tabMouseButtonRelease(QGraphicsSceneMouseEvent *e, int index)
+{
+ if (m_clickInProgress) {
+ setVisibleClientGroupItem(index);
+ }
+ titleReleased(e->button(), e->buttons());
+ m_clickInProgress = false;
+}
+
} // namespace Aurorae
extern "C"
diff --git a/clients/aurorae/src/aurorae.h b/clients/aurorae/src/aurorae.h
index 9821bacc7a..9336b81eba 100644
--- a/clients/aurorae/src/aurorae.h
+++ b/clients/aurorae/src/aurorae.h
@@ -23,6 +23,7 @@ along with this program. If not, see .
#include
#include
+class QGraphicsSceneMouseEvent;
class QGraphicsView;
class QGraphicsScene;
@@ -86,11 +87,18 @@ private slots:
void titlePressed(Qt::MouseButton button, Qt::MouseButtons buttons);
void titleReleased(Qt::MouseButton button, Qt::MouseButtons buttons);
void titleMouseMoved(Qt::MouseButton button, Qt::MouseButtons buttons);
+ void tabMouseButtonPress(QGraphicsSceneMouseEvent *e, int index);
+ void tabMouseButtonRelease(QGraphicsSceneMouseEvent *e, int index);
+
+protected:
+ virtual bool eventFilter(QObject *o, QEvent *e);
private:
void updateWindowShape();
+ void checkTabs(bool force = false);
AuroraeScene *m_scene;
QGraphicsView *m_view;
+ bool m_clickInProgress;
};
}
diff --git a/clients/aurorae/src/lib/auroraescene.cpp b/clients/aurorae/src/lib/auroraescene.cpp
index c69b6fc4d7..48f69a426d 100644
--- a/clients/aurorae/src/lib/auroraescene.cpp
+++ b/clients/aurorae/src/lib/auroraescene.cpp
@@ -54,6 +54,7 @@ AuroraeScene::AuroraeScene(Aurorae::AuroraeTheme* theme, const QString& leftButt
, m_rightButtonOrder(rightButtons)
, m_dblClicked(false)
, m_contextHelp(contextHelp)
+ , m_tabCount(0)
{
init();
connect(m_theme, SIGNAL(themeChanged()), SLOT(resetTheme()));
@@ -69,6 +70,7 @@ void AuroraeScene::init()
if (!m_theme->isValid()) {
return;
}
+ m_tabCount = 0;
Qt::Orientation orientation = Qt::Horizontal;
switch ((DecorationPosition)m_theme->themeConfig().decorationPosition()) {
case DecorationLeft: // fall through
@@ -109,12 +111,8 @@ void AuroraeScene::init()
titleLayout->setContentsMargins(0, 0, 0, 0);
titleLayout->setOrientation(orientation);
m_title = new QGraphicsWidget;
- AuroraeTab *tab = new AuroraeTab(m_theme, m_caption);
- connect(this, SIGNAL(activeChanged()), tab, SLOT(activeChanged()));
- titleLayout->addItem(tab);
m_title->setLayout(titleLayout);
addItem(m_title);
- tab->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setActive(m_active, false);
updateLayout();
@@ -759,16 +757,96 @@ void AuroraeScene::setButtons(const QString &left, const QString &right)
resetTheme();
}
-void AuroraeScene::setCaption(const QString &caption)
+void AuroraeScene::setCaption(const QString &caption, int index)
{
- m_caption = caption;
foreach (QGraphicsItem *item, items()) {
if (AuroraeTab *tab = dynamic_cast(item)) {
- tab->setCaption(caption);
+ if (tab->index() == index) {
+ tab->setCaption(caption);
+ }
}
}
}
+void AuroraeScene::setCaptions(const QStringList &captions)
+{
+ foreach (QGraphicsItem *item, items()) {
+ if (AuroraeTab *tab = dynamic_cast(item)) {
+ if (tab->index() < captions.size()) {
+ tab->setCaption(captions[tab->index()]);
+ }
+ }
+ }
+}
+
+void AuroraeScene::addTab(const QString &caption)
+{
+ AuroraeTab *tab = new AuroraeTab(m_theme, caption, m_tabCount);
+ ++m_tabCount;
+ connect(this, SIGNAL(activeChanged()), tab, SLOT(activeChanged()));
+ connect(tab, SIGNAL(mouseButtonPress(QGraphicsSceneMouseEvent*,int)),
+ SIGNAL(tabMouseButtonPress(QGraphicsSceneMouseEvent*,int)));
+ connect(tab, SIGNAL(mouseButtonRelease(QGraphicsSceneMouseEvent*,int)),
+ SIGNAL(tabMouseButtonRelease(QGraphicsSceneMouseEvent*,int)));
+ connect(tab, SIGNAL(mouseDblClicked()), SIGNAL(titleDoubleClicked()));
+ connect(tab, SIGNAL(mouseMoved(Qt::MouseButton,Qt::MouseButtons)),
+ SIGNAL(titleMouseMoved(Qt::MouseButton,Qt::MouseButtons)));
+ static_cast(m_title->layout())->addItem(tab);
+ tab->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ m_title->layout()->invalidate();
+}
+
+void AuroraeScene::addTabs(const QStringList &captions)
+{
+ foreach (const QString &caption, captions) {
+ addTab(caption);
+ }
+}
+
+void AuroraeScene::removeLastTab()
+{
+ if (m_tabCount < 2) {
+ return;
+ }
+ foreach (QGraphicsItem *item, items()) {
+ if (AuroraeTab *tab = dynamic_cast(item)) {
+ if (tab->index() == m_tabCount-1) {
+ m_title->layout()->removeAt(tab->index());
+ removeItem(tab);
+ --m_tabCount;
+ m_title->layout()->invalidate();
+ return;
+ }
+ }
+ }
+}
+
+int AuroraeScene::tabCount() const
+{
+ return m_tabCount;
+}
+
+int AuroraeScene::focusedTab() const
+{
+ return m_focusedTab;
+}
+
+void AuroraeScene::setFocusedTab(int index)
+{
+ if (m_focusedTab != index) {
+ m_focusedTab = index;
+ m_title->update();
+ }
+}
+
+bool AuroraeScene::isFocusedTab(int index) const
+{
+ if (m_tabCount == 1) {
+ return true;
+ }
+ return (index == m_focusedTab);
+}
+
void AuroraeScene::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
QGraphicsScene::mousePressEvent(event);
diff --git a/clients/aurorae/src/lib/auroraescene.h b/clients/aurorae/src/lib/auroraescene.h
index 0e5a497a59..601f8347af 100644
--- a/clients/aurorae/src/lib/auroraescene.h
+++ b/clients/aurorae/src/lib/auroraescene.h
@@ -66,7 +66,39 @@ public:
int rightButtonsWidth() const;
void setButtons(const QString &left, const QString &right);
- void setCaption(const QString &caption);
+ /**
+ * Updates the caption for the decoration with given index.
+ * @param caption The new caption
+ * @param index The index of the tab
+ */
+ void setCaption(const QString &caption, int index = 0);
+ /**
+ * Updates the captions of all tabs.
+ * @param captions The new captions
+ */
+ void setCaptions(const QStringList &captions);
+ /**
+ * Adds a tab with given caption to the end of the tab list.
+ */
+ void addTab(const QString &caption);
+ /**
+ * Adds a tab for each of the given captions to the end of the tab list.
+ */
+ void addTabs(const QStringList &captions);
+ /**
+ * Removes the last tab from the list, if there are at least two tabs.
+ */
+ void removeLastTab();
+ /**
+ * current number of tabs
+ */
+ int tabCount() const;
+ void setFocusedTab(int index);
+ int focusedTab() const;
+ /**
+ * @returns true if the tab at given index is the focused one.
+ */
+ bool isFocusedTab(int index) const;
const QString &leftButtons() const;
const QString &rightButtons() const;
@@ -86,6 +118,8 @@ Q_SIGNALS:
void titleDoubleClicked();
void titleMouseMoved(Qt::MouseButton, Qt::MouseButtons);
void wheelEvent(int delta);
+ void tabMouseButtonPress(QGraphicsSceneMouseEvent*, int);
+ void tabMouseButtonRelease(QGraphicsSceneMouseEvent*, int);
void activeChanged();
@@ -120,9 +154,10 @@ private:
bool m_keepBelow;
QString m_leftButtonOrder;
QString m_rightButtonOrder;
- QString m_caption;
bool m_dblClicked;
bool m_contextHelp;
+ int m_tabCount;
+ int m_focusedTab;
};
} // namespace
diff --git a/clients/aurorae/src/lib/auroraetab.cpp b/clients/aurorae/src/lib/auroraetab.cpp
index b447e57016..c6ab26c049 100644
--- a/clients/aurorae/src/lib/auroraetab.cpp
+++ b/clients/aurorae/src/lib/auroraetab.cpp
@@ -28,21 +28,23 @@
#include
#include
#include
+#include
#include
namespace Aurorae
{
-AuroraeTab::AuroraeTab(AuroraeTheme* theme, const QString& caption)
+AuroraeTab::AuroraeTab(AuroraeTheme* theme, const QString& caption, int index)
: QGraphicsWidget()
, m_theme(theme)
, m_caption(caption)
+ , m_index(index)
+ , m_dblClicked(false)
{
m_effect = new QGraphicsDropShadowEffect(this);
if (m_theme->themeConfig().useTextShadow()) {
setGraphicsEffect(m_effect);
}
- setAcceptedMouseButtons(Qt::NoButton);
connect(m_theme, SIGNAL(buttonSizesChanged()), SLOT(buttonSizesChanged()));
}
@@ -72,6 +74,11 @@ void AuroraeTab::setCaption(const QString& caption)
update();
}
+void AuroraeTab::setIndex(int index)
+{
+ m_index = index;
+}
+
void AuroraeTab::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
@@ -81,7 +88,47 @@ void AuroraeTab::paint(QPainter *painter, const QStyleOptionGraphicsItem *option
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
AuroraeScene *s = static_cast(scene());
const bool active = s->isActive();
+ const bool useTabs = (s->tabCount() > 1);
+ const bool focused = s->isFocusedTab(m_index);
const ThemeConfig &conf = m_theme->themeConfig();
+ if (useTabs) {
+ painter->save();
+ Plasma::FrameSvg *decoration = m_theme->decoration();
+ if (!decoration->hasElementPrefix("tab-active-focused") && m_index < s->tabCount()-1) {
+ QColor color = active ? conf.activeTextColor(true, false) : conf.inactiveTextColor(true, false);
+ painter->setPen(color);
+ QPointF point1 = rect().topRight();
+ QPointF point2 = rect().bottomRight();
+ if (m_theme->decorationPosition() == DecorationLeft ||
+ m_theme->decorationPosition() == DecorationRight) {
+ point1 = rect().topRight();
+ point2 = rect().topLeft();
+ }
+ painter->drawLine(point1, point2);
+ } else if (decoration->hasElementPrefix("tab-active-focused")) {
+ QString element = "tab-active-";
+ if (!active && decoration->hasElementPrefix("tab-inactive-focused")) {
+ element = "tab-inactive-";
+ }
+ bool useFocused = true;
+ if (!focused) {
+ if (element.startsWith(QLatin1String("tab-active")) &&
+ decoration->hasElementPrefix("tab-active-unfocused")) {
+ useFocused = false;
+ }
+ if (element.startsWith(QLatin1String("tab-inactive")) &&
+ decoration->hasElementPrefix("tab-inactive-unfocused")) {
+ useFocused = false;
+ }
+ }
+ element.append(useFocused ? "focused" : "unfocused");
+ decoration->setElementPrefix(element);
+ decoration->setEnabledBorders(Plasma::FrameSvg::AllBorders);
+ decoration->resizeFrame(size());
+ decoration->paintFrame(painter);
+ }
+ painter->restore();
+ }
Qt::Alignment align = conf.alignment();
if (align != Qt::AlignCenter && QApplication::layoutDirection() == Qt::RightToLeft) {
// have to swap the alignment to be consistent with other kwin decos.
@@ -124,14 +171,14 @@ void AuroraeTab::paint(QPainter *painter, const QStyleOptionGraphicsItem *option
QPainter p(&pix);
QColor color;
if (active) {
- color = conf.activeTextColor();
+ color = conf.activeTextColor(useTabs, focused);
if (s->isAnimating()) {
- color = KColorUtils::mix(conf.inactiveTextColor(), conf.activeTextColor(), s->animationProgress());
+ color = KColorUtils::mix(conf.inactiveTextColor(useTabs, focused), conf.activeTextColor(useTabs, focused), s->animationProgress());
}
} else {
- color = conf.inactiveTextColor();
+ color = conf.inactiveTextColor(useTabs, focused);
if (s->isAnimating()){
- color = KColorUtils::mix(conf.activeTextColor(), conf.inactiveTextColor(), s->animationProgress());
+ color = KColorUtils::mix(conf.activeTextColor(useTabs, focused), conf.inactiveTextColor(useTabs, focused), s->animationProgress());
}
}
p.setPen(color);
@@ -175,4 +222,31 @@ void AuroraeTab::buttonSizesChanged()
updateGeometry();
}
+void AuroraeTab::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ QGraphicsItem::mousePressEvent(event);
+ event->accept();
+ emit mouseButtonPress(event, m_index);
+}
+
+void AuroraeTab::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ QGraphicsItem::mouseReleaseEvent(event);
+ if (m_dblClicked && event->button() == Qt::LeftButton) {
+ // eat event
+ m_dblClicked = false;
+ return;
+ }
+ emit mouseButtonRelease(event, m_index);
+}
+
+void AuroraeTab::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ QGraphicsItem::mouseDoubleClickEvent(event);
+ if (event->button() == Qt::LeftButton) {
+ m_dblClicked = true;
+ emit mouseDblClicked();
+ }
+}
+
} // namespace
diff --git a/clients/aurorae/src/lib/auroraetab.h b/clients/aurorae/src/lib/auroraetab.h
index 99138cba25..224e437095 100644
--- a/clients/aurorae/src/lib/auroraetab.h
+++ b/clients/aurorae/src/lib/auroraetab.h
@@ -31,21 +31,38 @@ class AuroraeTab : public QGraphicsWidget
{
Q_OBJECT
public:
- AuroraeTab(AuroraeTheme *theme, const QString &caption);
+ AuroraeTab(AuroraeTheme *theme, const QString &caption, int index);
virtual ~AuroraeTab();
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
void setCaption(const QString &caption);
+ void setIndex(int index);
+ int index() const {
+ return m_index;
+ }
+
+Q_SIGNALS:
+ void mouseButtonPress(QGraphicsSceneMouseEvent *e, int index);
+ void mouseButtonRelease(QGraphicsSceneMouseEvent *e, int index);
+ void mouseDblClicked();
+ void mouseMoved(Qt::MouseButton, Qt::MouseButtons);
public Q_SLOTS:
void activeChanged();
+protected:
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+
private Q_SLOTS:
void buttonSizesChanged();
private:
AuroraeTheme *m_theme;
QString m_caption;
+ int m_index;
QGraphicsDropShadowEffect *m_effect;
+ bool m_dblClicked;
};
}
diff --git a/clients/aurorae/src/lib/themeconfig.cpp b/clients/aurorae/src/lib/themeconfig.cpp
index fd903eda07..2268b2fedb 100644
--- a/clients/aurorae/src/lib/themeconfig.cpp
+++ b/clients/aurorae/src/lib/themeconfig.cpp
@@ -32,6 +32,10 @@ void ThemeConfig::load(const KConfig &conf)
KConfigGroup general(&conf, "General");
m_activeTextColor = general.readEntry("ActiveTextColor", QColor(Qt::black));
m_inactiveTextColor = general.readEntry("InactiveTextColor", QColor(Qt::black));
+ m_activeFocusedTextColor = general.readEntry("ActiveFocusedTabColor", m_activeTextColor);
+ m_activeUnfocusedTextColor = general.readEntry("ActiveUnfocusedTabColor", m_inactiveTextColor);
+ m_inactiveFocusedTextColor = general.readEntry("InactiveFocusedTabColor", m_inactiveTextColor);
+ m_inactiveUnfocusedTextColor = general.readEntry("InactiveUnfocusedTabColor", m_inactiveTextColor);
m_useTextShadow = general.readEntry("UseTextShadow", false);
m_activeTextShadowColor = general.readEntry("ActiveTextShadowColor", QColor(Qt::white));
m_inactiveTextShadowColor = general.readEntry("InactiveTextShadowColor", QColor(Qt::white));
@@ -105,4 +109,28 @@ void ThemeConfig::load(const KConfig &conf)
m_paddingBottom = border.readEntry("PaddingBottom", 0);
}
+QColor ThemeConfig::activeTextColor(bool useTabs, bool focused) const
+{
+ if (!useTabs) {
+ return m_activeTextColor;
+ }
+ if (focused) {
+ return m_activeFocusedTextColor;
+ } else {
+ return m_activeUnfocusedTextColor;
+ }
+}
+
+QColor ThemeConfig::inactiveTextColor(bool useTabs, bool focused) const
+{
+ if (!useTabs) {
+ return m_inactiveTextColor;
+ }
+ if (focused) {
+ return m_inactiveFocusedTextColor;
+ } else {
+ return m_inactiveUnfocusedTextColor;
+ }
+}
+
} //namespace
diff --git a/clients/aurorae/src/lib/themeconfig.h b/clients/aurorae/src/lib/themeconfig.h
index 6dd73faa9e..48e05d547b 100644
--- a/clients/aurorae/src/lib/themeconfig.h
+++ b/clients/aurorae/src/lib/themeconfig.h
@@ -33,13 +33,9 @@ public:
void load(const KConfig &conf);
~ThemeConfig() {};
// active window
- QColor activeTextColor() const {
- return m_activeTextColor;
- }
+ QColor activeTextColor(bool useTabs = false, bool focused = true) const;
// inactive window
- QColor inactiveTextColor() const {
- return m_inactiveTextColor;
- }
+ QColor inactiveTextColor(bool useTabs = false, bool focused = true) const;
QColor activeTextShadowColor() const {
return m_activeTextShadowColor;
}
@@ -191,7 +187,11 @@ public:
private:
QColor m_activeTextColor;
+ QColor m_activeFocusedTextColor;
+ QColor m_activeUnfocusedTextColor;
QColor m_inactiveTextColor;
+ QColor m_inactiveFocusedTextColor;
+ QColor m_inactiveUnfocusedTextColor;
QColor m_activeTextShadowColor;
QColor m_inactiveTextShadowColor;
int m_textShadowOffsetX;