diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,8 @@ decorationbuttongroup.cpp decorationsettings.cpp decorationshadow.cpp + decorationtab.cpp + decorationtabgroup.cpp ) add_library(kdecorations2 SHARED ${libkdecoration2_SRCS}) @@ -36,6 +38,8 @@ DecorationButtonGroup DecorationSettings DecorationShadow + DecorationTab + DecorationTabGroup PREFIX KDecoration2 REQUIRED_HEADERS KDecoration2_HEADERS diff --git a/src/decoratedclient.h b/src/decoratedclient.h --- a/src/decoratedclient.h +++ b/src/decoratedclient.h @@ -202,6 +202,14 @@ int width() const; int height() const; + //Begin Window Tabbing + int tabCount() const; // tab count + void activate(); // activates the client + QList> clients() const; // get list of clients in the client group + bool isTabDragOp(Qt::MouseButtons btn) const; + bool isOperationsOp(Qt::MouseButtons btn) const; + //End Window Tabbing + QPointer decoration() const; QPalette palette() const; /** @@ -247,6 +255,9 @@ void paletteChanged(const QPalette &palette); void adjacentScreenEdgesChanged(Qt::Edges edges); + //for window tabbing + void tabGroupNeedsUpdate(); //emitted when a client is tabbed/untabbed + private: friend class Decoration; DecoratedClient(Decoration *parent, DecorationBridge *bridge); diff --git a/src/decoratedclient.cpp b/src/decoratedclient.cpp --- a/src/decoratedclient.cpp +++ b/src/decoratedclient.cpp @@ -66,9 +66,31 @@ DELEGATE(int, height) DELEGATE(QPalette, palette) DELEGATE(Qt::Edges, adjacentScreenEdges) - +// win tabbing +DELEGATE(int, tabCount) +// end win tabbing #undef DELEGATE +void DecoratedClient::activate() +{ + d->activate(); +} + +QList> DecoratedClient::clients() const +{ + return d->clients(); +} + +bool DecoratedClient::isTabDragOp(Qt::MouseButtons btn) const +{ + return d->isTabDragOp(btn); +} + +bool DecoratedClient::isOperationsOp(Qt::MouseButtons btn) const +{ + return d->isOperationsOp(btn); +} + QPointer< Decoration > DecoratedClient::decoration() const { return QPointer(d->decoration()); diff --git a/src/decoration.h b/src/decoration.h --- a/src/decoration.h +++ b/src/decoration.h @@ -43,6 +43,7 @@ class DecorationPrivate; class DecoratedClient; class DecorationButton; +class DecorationTabGroup; class DecorationSettings; /** @@ -230,6 +231,7 @@ private: friend class DecorationButton; + friend class DecorationTabGroup; class Private; QScopedPointer d; }; diff --git a/src/decoration.cpp b/src/decoration.cpp --- a/src/decoration.cpp +++ b/src/decoration.cpp @@ -23,6 +23,7 @@ #include "private/decoratedclientprivate.h" #include "private/decorationbridge.h" #include "decorationbutton.h" +#include "decorationtabgroup.h" #include "decorationsettings.h" #include "decorationshadow.h" @@ -144,6 +145,14 @@ ); } +void Decoration::Private::setTabGroup(DecorationTabGroup *grp) +{ + if (tabGroup == grp) { + return; + } + tabGroup = grp; +} + Decoration::Decoration(QObject *parent, const QVariantList &args) : QObject(parent) , d(new Private(this, args)) @@ -338,6 +347,14 @@ return; } } + + // for tabgoup + if (d->tabGroup) { + if (d->tabGroup->geometry().contains(event->localPos())) { + QCoreApplication::instance()->sendEvent(d->tabGroup, event); + return; + } + } } void Decoration::mouseReleaseEvent(QMouseEvent *event) @@ -348,6 +365,12 @@ return; } } + + // for tabgoup + if (d->tabGroup->isButtonPressed()) { + QCoreApplication::instance()->sendEvent(d->tabGroup, event); + return; + } // not handled, take care ourselves d->updateSectionUnderMouse(event->pos()); } diff --git a/src/decoration_p.h b/src/decoration_p.h --- a/src/decoration_p.h +++ b/src/decoration_p.h @@ -41,6 +41,7 @@ class DecoratedClient; class DecorationSettings; class DecorationShadow; +class DecorationTabGroup; class Decoration::Private { @@ -57,12 +58,14 @@ QRect titleBar; void addButton(DecorationButton *button); + void setTabGroup(DecorationTabGroup *grp); QSharedPointer settings; DecorationBridge *bridge; QSharedPointer client; bool opaque; QVector buttons; + QPointer tabGroup; QSharedPointer shadow; private: diff --git a/src/decorationtab.h b/src/decorationtab.h new file mode 100644 --- /dev/null +++ b/src/decorationtab.h @@ -0,0 +1,71 @@ +/* + * Copyright 2016 Chinmoy Ranjan Pradhan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef KDECORATION2_DECORATIONTAB_H +#define KDECORATION2_DECORATIONTAB_H +#include + +#include +#include +#include + +namespace KDecoration2 +{ + +class DecoratedClient; + +class KDECORATIONS2_EXPORT DecorationTab : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QPointer client READ client) + + Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry NOTIFY geometryChanged) + + Q_PROPERTY(bool active READ isActive) + +public: + + explicit DecorationTab(DecoratedClient *client, QObject *parent = nullptr); + virtual ~DecorationTab(); + + DecoratedClient *client() const; + + QRectF geometry() const; + void setGeometry(const QRectF &geom); + + bool isActive() const; + void activate(); + + virtual void paint(QPainter *painter, const QRect &repaintArea) = 0; + +Q_SIGNALS: + void geometryChanged(const QRectF&); + + +private: + DecoratedClient *m_client; + QRectF m_geometry; + bool m_active; +}; + +} + +#endif diff --git a/src/decorationtab.cpp b/src/decorationtab.cpp new file mode 100644 --- /dev/null +++ b/src/decorationtab.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2016 Chinmoy Ranjan Pradhan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "decoratedclient.h" +#include "decorationtab.h" + +namespace KDecoration2 +{ + +DecorationTab::DecorationTab(DecoratedClient *client, QObject *parent) + : QObject(parent) + , m_client(client) + , m_geometry(QRectF()) + , m_active(client->isActive()) +{ +} + +DecorationTab::~DecorationTab() = default; + +DecoratedClient *DecorationTab::client() const +{ + return m_client; +} + +QRectF DecorationTab::geometry() const +{ + return m_geometry; +} + +void DecorationTab::setGeometry(const QRectF &geom) +{ + if (m_geometry == geom) { + return; + } + m_geometry = geom; + emit geometryChanged(m_geometry); +} + +bool DecorationTab::isActive() const +{ + return m_active; +} + +void DecorationTab::activate() +{ + if (m_active) { + return; + } + client()->activate(); + +} + +} diff --git a/src/decorationtabgroup.h b/src/decorationtabgroup.h new file mode 100644 --- /dev/null +++ b/src/decorationtabgroup.h @@ -0,0 +1,73 @@ +/* + * Copyright 2016 Chinmoy Ranjan Pradhan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef KDECORATION2_DECORATIONTABGROUP_H +#define KDECORATION2_DECORATIONTABGROUP_H + +#include + +#include + +namespace KDecoration2 +{ + +class Decoration; +class DecorationTab; +class DecoratedClient; + +class KDECORATIONS2_EXPORT DecorationTabGroup : public QObject +{ + + Q_OBJECT + + Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry) + +public: + explicit DecorationTabGroup(Decoration *parent); + virtual ~DecorationTabGroup(); + + QRectF geometry() const; + void setGeometry(const QRectF &geom); + bool needTabs() const; + void setNeedTabs(bool set); + int count() const; + void createDecorationTab(std::function tabCreator); + bool isButtonPressed() const; + + virtual void layoutTabs(); + virtual void paint(QPainter *painter, const QRect &repaintArea); + virtual bool event(QEvent *event) override; + +protected: + virtual void hoverEnterEvent(QHoverEvent *event); + virtual void hoverLeaveEvent(QHoverEvent *event); + virtual void hoverMoveEvent(QHoverEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + +private: + class Private; + QScopedPointer d; +}; + +} + +#endif diff --git a/src/decorationtabgroup.cpp b/src/decorationtabgroup.cpp new file mode 100644 --- /dev/null +++ b/src/decorationtabgroup.cpp @@ -0,0 +1,257 @@ +/* + * Copyright 2016 Chinmoy Ranjan Pradhan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "decoration.h" +#include "decoration_p.h" +#include "decoratedclient.h" +#include "decorationtab.h" +#include "decorationtabgroup.h" +#include "decorationtabgroup_p.h" + +#include + +namespace KDecoration2 +{ + +DecorationTabGroup::Private::Private(Decoration *decoration, DecorationTabGroup *parent) + : deco(decoration) + , needTabs(false) + , mouseButtonPressed(false) + , tab(NULL) + , q(parent) +{ +} + +DecorationTabGroup::Private::~Private() = default; + +QPointer DecorationTabGroup::Private::decoration() const +{ + return deco; +} + +QList> DecorationTabGroup::Private::getClientList() const +{ + return decoration()->client().data()->clients(); +} + +QPointer DecorationTabGroup::Private::tabAt(const QPointF &pos) const +{ + auto it = windowTabs.begin(); + while (it != windowTabs.end()) { + const QRectF tabRect((*it)->geometry()); + if (tabRect.contains(pos)) { + return *it; + } + it++; + } + return nullptr; +} + +bool DecorationTabGroup::Private::isTabDragOp(Qt::MouseButtons btn) const +{ + return decoration()->client().data()->isTabDragOp(btn); +} + +bool DecorationTabGroup::Private::isOperationsOp(Qt::MouseButtons btn) const +{ + return decoration()->client().data()->isOperationsOp(btn); +} + +DecorationTabGroup::DecorationTabGroup(Decoration *parent) + :QObject(parent) + ,d(new Private(parent,this)) +{ + d->decoration()->d->setTabGroup(this); + DecoratedClient *c = parent->client().data(); + connect(c, &DecoratedClient::tabGroupNeedsUpdate, this, + [this]() { + setNeedTabs(count()!=0); + } + ); +} + +DecorationTabGroup::~DecorationTabGroup() = default; + + +QRectF DecorationTabGroup::geometry() const +{ + return d->geometry; +} + +void DecorationTabGroup::setGeometry(const QRectF &geom) +{ + if (d->geometry == geom) { + return; + } + d->geometry = geom; +} + +bool DecorationTabGroup::needTabs() const +{ + return d->needTabs; +} + +void DecorationTabGroup::setNeedTabs(bool set) +{ + if (d->needTabs == set) { + return; + } + d->needTabs = set; +} + +bool DecorationTabGroup::isButtonPressed() const +{ + return d->mouseButtonPressed; +} + +int DecorationTabGroup::count() const +{ + auto c = d->decoration()->client().data(); + return c->tabCount(); +} + +void DecorationTabGroup::createDecorationTab(std::function tabCreator) +{ + // for every update empty the tab container and then (again) fetch the client list + + if (!d->windowTabs.isEmpty()) { + qDeleteAll(d->windowTabs); + d->windowTabs.clear(); + } + + if (!needTabs()) { + return; + } + + d->clients = d->getClientList(); + for (int i=0; iclients.size(); i++) { + DecorationTab *tab = tabCreator(d->clients.at(i), this); + d->windowTabs.push_back(tab); + } + layoutTabs(); //set tabs' geometry +} + +void DecorationTabGroup::layoutTabs() +{ + int i = 0; + const QSizeF size = geometry().size(); + int tabWidth = size.width()/count(); + auto it = d->windowTabs.constBegin(); + while (it != d->windowTabs.constEnd()) { + const QRectF tabGeom(geometry().x() + i*tabWidth, 0, tabWidth, size.height()); + (*it)->setGeometry(tabGeom); + it++; + i++; + } +} + +void DecorationTabGroup::paint(QPainter *painter, const QRect &repaintArea) +{ + const auto &tabs = d->windowTabs; + for (auto tab: tabs) { + tab->paint(painter, repaintArea); + } +} + +bool DecorationTabGroup::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::HoverEnter: + hoverEnterEvent(static_cast(event)); + return true; + case QEvent::HoverLeave: + hoverLeaveEvent(static_cast(event)); + return true; + case QEvent::HoverMove: + hoverMoveEvent(static_cast(event)); + return true; + case QEvent::MouseButtonPress: + mousePressEvent(static_cast(event)); + return true; + case QEvent::MouseButtonRelease: + mouseReleaseEvent(static_cast(event)); + return true; + case QEvent::MouseMove: + mouseMoveEvent(static_cast(event)); + return true; + default: + return QObject::event(event); + } +} + +void DecorationTabGroup::hoverEnterEvent(QHoverEvent *event) +{ + Q_UNUSED(event); +} + +void DecorationTabGroup::hoverLeaveEvent(QHoverEvent *event) +{ + Q_UNUSED(event); +} + +void DecorationTabGroup::hoverMoveEvent(QHoverEvent *event) +{ + Q_UNUSED(event); +} + +void DecorationTabGroup::mouseMoveEvent(QMouseEvent *event) +{ + Q_UNUSED(event); +} + +void DecorationTabGroup::mousePressEvent(QMouseEvent *event) +{ + bool accepted = false; + d->btn = event->button(); + d->mouseButtonPressed = true; + d->tab = d->tabAt(event->pos()); + + if (d->isTabDragOp(d->btn)) { + accepted = true; + + } else if (d->isOperationsOp(d->btn)) { + if (d->tab) { + d->tab->client()->decoration()->requestShowWindowMenu(); + } else { + d->decoration()->requestShowWindowMenu(); + } + accepted = true; + + } + event->setAccepted(accepted); +} + +void DecorationTabGroup::mouseReleaseEvent(QMouseEvent *event) +{ + bool accepted = false; + if (d->btn == event->button() && !d->isOperationsOp(d->btn)) { + if (d->tab) { + if (!d->tab->client()->isActive()) { + d->tab->client()->activate(); + accepted = true; + } + } + } + d->btn = Qt::NoButton; + d->mouseButtonPressed = false; + event->setAccepted(accepted); +} + +} diff --git a/src/decorationtabgroup_p.h b/src/decorationtabgroup_p.h new file mode 100644 --- /dev/null +++ b/src/decorationtabgroup_p.h @@ -0,0 +1,60 @@ +/* + * Copyright 2016 Chinmoy Ranjan Pradhan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef KDECORATION_DECORATIONTABGROUP_P_H +#define KDECORATION_DECORATIONTABGROUP_P_H + +#include "decorationtabgroup.h" + +namespace KDecoration2 +{ + +class DecoratedClient; +class DecorationTab; + +class DecorationTabGroup::Private +{ +public: + explicit Private(Decoration *decoration, DecorationTabGroup *parent); + ~Private(); + + bool isTabDragOp(Qt::MouseButtons btn) const; + bool isOperationsOp(Qt::MouseButtons btn) const; + QPointer decoration() const; + QPointer tabAt(const QPointF &pos) const; + QList> getClientList() const; + + Decoration *deco; + QRectF geometry; + QList> windowTabs; + QList> clients; + bool needTabs; + bool mouseButtonPressed; + DecorationTab *tab; + Qt::MouseButton btn; + +private: + DecorationTabGroup *q; + +}; + +} + +#endif diff --git a/src/private/decoratedclientprivate.h b/src/private/decoratedclientprivate.h --- a/src/private/decoratedclientprivate.h +++ b/src/private/decoratedclientprivate.h @@ -25,6 +25,7 @@ #include #include +#include // // W A R N I N G @@ -85,6 +86,13 @@ virtual void requestToggleKeepAbove() = 0; virtual void requestToggleKeepBelow() = 0; virtual void requestShowWindowMenu() = 0; + + // Window Tabbing + virtual int tabCount() const = 0; + virtual void activate() = 0; + virtual QList> clients() const = 0; + virtual bool isTabDragOp(Qt::MouseButtons btn) const = 0; + virtual bool isOperationsOp(Qt::MouseButtons btn) const = 0; Decoration *decoration(); Decoration *decoration() const;