From d245035a1768ad094951b3262d04a11025c6c7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20L=C3=BCbking?= Date: Thu, 12 Jan 2012 07:42:55 +0100 Subject: [PATCH] fix tabbing BUG: 290959 BUG: 265160 BUG: 229292 BUG: 238279 BUG: 290758 BUG: 222831 BUG: 278275 BUG: 245747 BUG: 230000 BUG: 253697 BUG: 230570 BUG: 265977 BUG: 225337 BUG: 225339 REVIEW: 103855 --- CMakeLists.txt | 2 +- activation.cpp | 4 +- bridge.cpp | 159 ++++--- bridge.h | 28 +- client.cpp | 128 ++++-- client.h | 33 +- clientgroup.cpp | 357 --------------- clientgroup.h | 266 ----------- clients/CMakeLists.txt | 1 - clients/aurorae/src/aurorae.cpp | 4 +- clients/oxygen/oxygenclient.cpp | 117 +++-- clients/oxygen/oxygenclient.h | 8 +- clients/oxygen/oxygenclientgroupitemdata.cpp | 6 +- clients/oxygen/oxygenclientgroupitemdata.h | 2 +- clients/oxygen/oxygenfactory.cpp | 2 +- clients/tabstrip/CMakeLists.txt | 15 - clients/tabstrip/config/CMakeLists.txt | 10 - clients/tabstrip/config/tabstripconfig.cpp | 96 ---- clients/tabstrip/config/tabstripconfig.h | 56 --- clients/tabstrip/config/tabstripconfig.ui | 78 ---- clients/tabstrip/tabstrip.desktop | 63 --- clients/tabstrip/tabstripbutton.cpp | 317 ------------- clients/tabstrip/tabstripbutton.h | 55 --- clients/tabstrip/tabstripdecoration.cpp | 443 ------------------- clients/tabstrip/tabstripdecoration.h | 60 --- clients/tabstrip/tabstripfactory.cpp | 113 ----- clients/tabstrip/tabstripfactory.h | 63 --- effects.cpp | 22 +- effects.h | 6 +- effects/boxswitch/boxswitch.cpp | 2 +- effects/desktopgrid/desktopgrid.cpp | 8 +- effects/flipswitch/flipswitch.cpp | 4 +- effects/highlightwindow/highlightwindow.cpp | 6 +- effects/presentwindows/presentwindows.cpp | 6 +- effects/slideback/slideback.cpp | 2 +- events.cpp | 6 +- geometry.cpp | 30 +- kcmkwin/kwindecoration/preview.cpp | 33 +- kcmkwin/kwindecoration/preview.h | 23 +- kwinbindings.cpp | 6 +- layers.cpp | 8 +- libkdecorations/kcommondecoration.cpp | 49 +- libkdecorations/kcommondecoration.h | 24 +- libkdecorations/kdecoration.cpp | 55 ++- libkdecorations/kdecoration.h | 97 ++-- libkdecorations/kdecorationbridge.h | 26 +- libkwineffects/kwineffects.cpp | 2 +- libkwineffects/kwineffects.h | 10 +- manage.cpp | 121 +++-- options.cpp | 10 +- options.h | 4 +- scene.cpp | 4 +- scene.h | 2 +- scripting/meta.cpp | 17 +- scripting/meta.h | 11 - scripting/workspace_wrapper.cpp | 4 - scripting/workspace_wrapper.h | 4 - sm.cpp | 24 +- sm.h | 4 +- tabgroup.cpp | 295 ++++++++++++ tabgroup.h | 186 ++++++++ toplevel.cpp | 4 + useractions.cpp | 288 +++++------- workspace.cpp | 98 +--- workspace.h | 44 +- 65 files changed, 1252 insertions(+), 2779 deletions(-) delete mode 100644 clientgroup.cpp delete mode 100644 clientgroup.h delete mode 100644 clients/tabstrip/CMakeLists.txt delete mode 100644 clients/tabstrip/config/CMakeLists.txt delete mode 100644 clients/tabstrip/config/tabstripconfig.cpp delete mode 100644 clients/tabstrip/config/tabstripconfig.h delete mode 100644 clients/tabstrip/config/tabstripconfig.ui delete mode 100644 clients/tabstrip/tabstrip.desktop delete mode 100644 clients/tabstrip/tabstripbutton.cpp delete mode 100644 clients/tabstrip/tabstripbutton.h delete mode 100644 clients/tabstrip/tabstripdecoration.cpp delete mode 100644 clients/tabstrip/tabstripdecoration.h delete mode 100644 clients/tabstrip/tabstripfactory.cpp delete mode 100644 clients/tabstrip/tabstripfactory.h create mode 100644 tabgroup.cpp create mode 100644 tabgroup.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c4b75c0b2c..c741cb4b82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,7 @@ add_subdirectory( effects ) set(kwin_KDEINIT_SRCS workspace.cpp client.cpp - clientgroup.cpp + tabgroup.cpp placement.cpp atoms.cpp utils.cpp diff --git a/activation.cpp b/activation.cpp index f4fe3ee36d..d9540593ce 100644 --- a/activation.cpp +++ b/activation.cpp @@ -361,8 +361,8 @@ void Workspace::takeActivity(Client* c, int flags, bool handled) flags &= ~ActivityFocus; handled = false; // no point, can't get clicks } - if (c->clientGroup() && c->clientGroup()->visible() != c) - c->clientGroup()->setVisible(c); + if (c->tabGroup() && c->tabGroup()->current() != c) + c->tabGroup()->setCurrent(c); if (!c->isShown(true)) { // shouldn't happen, call activateClient() if needed kWarning(1212) << "takeActivity: not shown" ; return; diff --git a/bridge.cpp b/bridge.cpp index 06dde5588f..897d432b55 100644 --- a/bridge.cpp +++ b/bridge.cpp @@ -39,7 +39,6 @@ Bridge::Bridge(Client* cl) return c->prototype( args2 ); \ } -BRIDGE_HELPER(bool, isActive, , , const) BRIDGE_HELPER(bool, isCloseable, , , const) BRIDGE_HELPER(bool, isMaximizable, , , const) BRIDGE_HELPER(Bridge::MaximizeMode, maximizeMode, , , const) @@ -62,6 +61,11 @@ BRIDGE_HELPER(void, minimize, , ,) BRIDGE_HELPER(void, showContextHelp, , ,) BRIDGE_HELPER(void, setDesktop, int desktop, desktop,) +bool Bridge::isActive() const +{ + return c->isActive() || (c->tabGroup() && c->tabGroup()->isActive()); +} + void Bridge::setKeepAbove(bool set) { if (c->keepAbove() != set) @@ -93,7 +97,15 @@ bool Bridge::isSetShade() const void Bridge::showWindowMenu(const QPoint &p) { - c->workspace()->showWindowMenu(p, c); + c->workspace()->showWindowMenu(QRect(p,p), c); +} + +void Bridge::showWindowMenu(const QPoint &p, long id) +{ + Client *cc = clientForId(id); + if (!cc) + cc = c; + cc->workspace()->showWindowMenu(QRect(p,p), cc); } void Bridge::showWindowMenu(const QRect &p) @@ -207,90 +219,119 @@ QRect Bridge::transparentRect() const return c->transparentRect().translated(-c->decorationRect().topLeft()); } -bool Bridge::isClientGroupActive() -{ - if (c->clientGroup()) - return c->clientGroup()->containsActiveClient(); - return isActive(); -} +//BEGIN TABBING -QList< ClientGroupItem > Bridge::clientGroupItems() const +Client *Bridge::clientForId(long id) const { - if (c->clientGroup()) - return c->clientGroup()->items(); - QList< ClientGroupItem > items; - QIcon icon(c->icon()); - icon.addPixmap(c->miniIcon()); - items.append(ClientGroupItem(c->caption(), icon)); - return items; -} - -long Bridge::itemId(int index) -{ - if (!c->clientGroup()) + Client* client = reinterpret_cast(id); + if (!c->workspace()->hasClient(client)) { + kWarning(1212) << "****** ARBITRARY CODE EXECUTION ATTEMPT DETECTED ******" << id; return 0; - const ClientList list = c->clientGroup()->clients(); - return reinterpret_cast(list.at(index)); + } + return client; } -int Bridge::visibleClientGroupItem() +int Bridge::tabCount() const { - if (c->clientGroup()) - return c->clientGroup()->indexOfVisibleClient(); + if (c->tabGroup()) + return c->tabGroup()->count(); + return 1; +} + +long Bridge::tabId(int idx) const +{ + if (c->tabGroup()) + return tabIdOf(c->tabGroup()->clients().at(idx)); + return tabIdOf(c); +} + +QIcon Bridge::icon(int idx) const +{ + if (c->tabGroup()) { + Client *tabC = c->tabGroup()->clients().at(idx); + QIcon icon(tabC->icon()); + icon.addPixmap(tabC->miniIcon()); + return icon; + } + return icon(); +} + +QString Bridge::caption(int idx) const +{ + if (c->tabGroup()) + return c->tabGroup()->clients().at(idx)->caption(); + return c->caption(); +} + +long Bridge::currentTabId() const +{ + if (c->tabGroup()) + return tabIdOf(c->tabGroup()->current()); return 0; } -void Bridge::setVisibleClientGroupItem(int index) +void Bridge::setCurrentTab(long id) { - if (c->clientGroup()) - c->clientGroup()->setVisible(index); + if (c->tabGroup()) + c->tabGroup()->setCurrent(clientForId(id)); } -void Bridge::moveItemInClientGroup(int index, int before) +void Bridge::tab_A_before_B(long A, long B) { - if (c->clientGroup()) - c->clientGroup()->move(index, before); -} - -void Bridge::moveItemToClientGroup(long itemId, int before) -{ - Client* item = reinterpret_cast(itemId); - if (!c->workspace()->hasClient(item)) { - kWarning(1212) << "****** ARBITRARY CODE EXECUTION ATTEMPT DETECTED ******"; + if (!B) { + if (c->tabGroup()) { + if (Client *a = clientForId(A)) + a->untab(); + } return; } - if (item->clientGroup()) - c->workspace()->moveItemToClientGroup(item->clientGroup(), item->clientGroup()->indexOfClient(item), - c->clientGroup(), before); + + if (Client *a = clientForId(A)) + if (Client *b = clientForId(B)) + a->tabBefore(b, true); } -void Bridge::removeFromClientGroup(int index, const QRect& newGeom) +void Bridge::tab_A_behind_B(long A, long B) { - if (c->clientGroup()) - c->clientGroup()->remove(index, newGeom); -} - -void Bridge::closeClientGroupItem(int index) -{ - if (!c->clientGroup()) + if (!B) { + if (c->tabGroup()) { + if (Client *a = clientForId(A)) + a->untab(); + } return; - const ClientList list = c->clientGroup()->clients(); - if (index >= 0 || index <= list.count()) - list.at(index)->closeWindow(); + } + + if (Client *a = clientForId(A)) + if (Client *b = clientForId(B)) + a->tabBehind(b, true); } -void Bridge::closeAllInClientGroup() + +void Bridge::untab(long id, const QRect& newGeom) { - if (c->clientGroup()) - c->clientGroup()->closeAll(); + if (c->tabGroup()) + if (Client* client = clientForId(id)) + if (client->untab(newGeom)) { + if (options->focusPolicyIsReasonable()) + c->workspace()->takeActivity(client, ActivityFocus | ActivityRaise, true); + c->workspace()->raiseClient(client); + } } -void Bridge::displayClientMenu(int index, const QPoint& pos) +void Bridge::closeTab(long id) { - if (c->clientGroup()) - c->clientGroup()->displayClientMenu(index, pos); + if (Client* client = clientForId(id)) + client->closeWindow(); } +void Bridge::closeTabGroup() +{ + if (c->tabGroup()) + c->tabGroup()->closeAll(); +} + +//END TABBING + KDecoration::WindowOperation Bridge::buttonToWindowOperation(Qt::MouseButtons button) { return c->mouseButtonToWindowOperation(button); diff --git a/bridge.h b/bridge.h index 3085fda62d..64108e5e32 100644 --- a/bridge.h +++ b/bridge.h @@ -79,20 +79,26 @@ public: virtual QRect transparentRect() const; // Window tabbing - virtual bool isClientGroupActive(); - virtual QList< ClientGroupItem > clientGroupItems() const; - virtual long itemId(int index); - virtual int visibleClientGroupItem(); - virtual void setVisibleClientGroupItem(int index); - virtual void moveItemInClientGroup(int index, int before); - virtual void moveItemToClientGroup(long itemId, int before); - virtual void removeFromClientGroup(int index, const QRect& newGeom); - virtual void closeClientGroupItem(int index); - virtual void closeAllInClientGroup(); - virtual void displayClientMenu(int index, const QPoint& pos); + virtual QString caption(int idx) const; + virtual void closeTab(long id); + virtual void closeTabGroup(); + virtual long currentTabId() const; + virtual QIcon icon(int idx) const; + virtual void setCurrentTab(long id); + virtual void showWindowMenu(const QPoint &, long id); + virtual void tab_A_before_B(long A, long B); + virtual void tab_A_behind_B(long A, long B); + virtual int tabCount() const; + virtual long tabId(int idx) const; + virtual void untab(long id, const QRect& newGeom); + virtual WindowOperation buttonToWindowOperation(Qt::MouseButtons button); private: + Client *clientForId(long id) const; + static inline long tabIdOf(Client *c) { + return reinterpret_cast(c); + } Client* c; }; diff --git a/client.cpp b/client.cpp index 5d23768b05..34e9006d4a 100644 --- a/client.cpp +++ b/client.cpp @@ -102,7 +102,7 @@ Client::Client(Workspace* ws) , delayedMoveResizeTimer(NULL) , in_group(NULL) , window_group(None) - , client_group(NULL) + , tab_group(NULL) , in_layer(UnknownLayer) , ping_timer(NULL) , process_killer(NULL) @@ -265,15 +265,14 @@ void Client::releaseWindow(bool on_shutdown) XUnmapWindow(display(), frameId()); // Destroying decoration would cause ugly visual effect destroyDecoration(); cleanGrouping(); - if (clientGroup()) - clientGroup()->remove(this, QRect(), true); if (!on_shutdown) { workspace()->removeClient(this, Allowed); // Only when the window is being unmapped, not when closing down KWin (NETWM sections 5.5,5.7) info->setDesktop(0); desk = 0; info->setState(0, info->state()); // Reset all state flags - } + } else + untab(); XDeleteProperty(display(), client, atoms->kde_net_wm_user_creation_time); XDeleteProperty(display(), client, atoms->net_frame_extents); XDeleteProperty(display(), client, atoms->kde_net_wm_frame_strut); @@ -326,8 +325,6 @@ void Client::destroyClient() workspace()->clientHidden(this); destroyDecoration(); cleanGrouping(); - if (clientGroup()) - clientGroup()->remove(this, QRect(), true); workspace()->removeClient(this, Allowed); client = None; // invalidate XDestroyWindow(display(), wrapper); @@ -791,7 +788,7 @@ bool Client::noBorder() const bool Client::userCanSetNoBorder() const { - return !isFullScreen() && !isShade() && (clientGroup() == NULL || !(clientGroup()->items().count() > 1)); + return !isFullScreen() && !isShade() && !tabGroup(); } void Client::setNoBorder(bool set) @@ -993,8 +990,8 @@ void Client::minimize(bool avoid_animation) emit clientMinimized(this, !avoid_animation); // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); emit minimizedChanged(); } @@ -1019,8 +1016,8 @@ void Client::unminimize(bool avoid_animation) emit clientUnminimized(this, !avoid_animation); // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); emit minimizedChanged(); } @@ -1123,8 +1120,8 @@ void Client::setShade(ShadeMode mode) updateWindowRules(Rules::Shade); // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); emit shadeChanged(); } @@ -1156,7 +1153,7 @@ void Client::updateVisibility() { if (deleting) return; - if (hidden && (clientGroup() == NULL || clientGroup()->visible() == this)) { + if (hidden && isCurrentTab()) { info->setState(NET::Hidden, NET::Hidden); setSkipTaskbar(true, false); // Also hide from taskbar if (compositing() && options->hiddenPreviews == HiddenPreviewsAlways) @@ -1165,7 +1162,7 @@ void Client::updateVisibility() internalHide(Allowed); return; } - if (clientGroup() == NULL || clientGroup()->visible() == this) + if (isCurrentTab()) setSkipTaskbar(original_skip_taskbar, false); // Reset from 'hidden' if (minimized) { info->setState(NET::Hidden, NET::Hidden); @@ -1584,8 +1581,8 @@ void Client::setDesktop(int desktop) updateWindowRules(Rules::Desktop); // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); emit desktopChanged(); } @@ -1647,8 +1644,8 @@ void Client::updateActivities(bool includeTransients) // TODO: add activity rule // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); } /** @@ -1689,8 +1686,8 @@ void Client::setOnAllDesktops(bool b) setDesktop(workspace()->currentDesktop()); // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); } /** @@ -1853,9 +1850,7 @@ void Client::setCaption(const QString& _s, bool force) // Keep the same suffix in iconic name if it's set info->setVisibleIconName(QString(cap_iconic + cap_suffix).toUtf8()); - if (isManaged() && decoration != NULL) { - if (client_group) - client_group->updateItems(); + if (isManaged() && decoration) { decoration->captionChange(); } emit captionChanged(); @@ -1894,21 +1889,62 @@ QString Client::caption(bool full) const return full ? cap_normal + cap_suffix : cap_normal; } -void Client::setClientGroup(ClientGroup* group) +bool Client::tabTo(Client *other, bool behind, bool activate) { - client_group = group; - unsigned long data[1] = {(unsigned long)workspace()->indexOfClientGroup(group)}; - XChangeProperty(display(), window(), atoms->kde_net_wm_tab_group, XA_CARDINAL, 32, - PropModeReplace, (unsigned char*)(data), 1); - emit clientGroupChanged(); -} + Q_ASSERT(other && other != this); -bool Client::isVisibleInClientGroup() const -{ - if (!client_group) { + if (tab_group && tab_group == other->tabGroup()) { // special case: move inside group + tab_group->move(this, other, behind); return true; } - return (client_group->visible() == this); + + GeometryUpdatesBlocker blocker(this); + const bool wasBlocking = signalsBlocked(); + blockSignals(true); // prevent client emitting "retabbed to nowhere" cause it's about to be entabbed the next moment + untab(); + blockSignals(wasBlocking); + + TabGroup *newGroup = other->tabGroup() ? other->tabGroup() : new TabGroup(other); + + if (!newGroup->add(this, other, behind, activate)) { + if (newGroup->count() < 2) { // adding "c" to "to" failed for whatever reason + newGroup->remove(other); + delete newGroup; + } + return false; + } + return true; +} + +bool Client::untab(const QRect &toGeometry) +{ + TabGroup *group = tab_group; + if (group && group->remove(this, toGeometry)) { // remove sets the tabgroup to "0", therefore the pointer is cached + if (group->isEmpty()) { + delete group; + } + setClientShown(!(isMinimized() || isShade())); + return true; + } + return false; +} + +void Client::setTabGroup(TabGroup *group) +{ + tab_group = group; + if (group) { + unsigned long data = qHash(group); //->id(); + XChangeProperty(display(), window(), atoms->kde_net_wm_tab_group, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*)(&data), 1); + } + else + XDeleteProperty(display(), window(), atoms->kde_net_wm_tab_group); + emit tabGroupChanged(); +} + +bool Client::isCurrentTab() const +{ + return !tab_group || tab_group->current() == this; } void Client::dontMoveResize() @@ -1923,26 +1959,20 @@ void Client::setClientShown(bool shown) { if (deleting) return; // Don't change shown status if this client is being deleted - if (shown && hidden) { + if (shown != hidden) + return; // nothing to change + hidden = !shown; + if (options->inactiveTabsSkipTaskbar) + setSkipTaskbar(hidden, false); // TODO: Causes reshuffle of the taskbar + if (shown) { map(Allowed); - hidden = false; - //updateVisibility(); - //updateAllowedActions(); - if (options->inactiveTabsSkipTaskbar) - setSkipTaskbar(false, false); takeFocus(Allowed); autoRaise(); workspace()->updateFocusChains(this, Workspace::FocusChainMakeFirst); - } - if (!shown && !hidden) { + } else { unmap(Allowed); - hidden = true; - //updateVisibility(); - //updateAllowedActions(); - if (options->inactiveTabsSkipTaskbar) - setSkipTaskbar(true, false); // TODO: Causes reshuffle of the taskbar // Don't move tabs to the end of the list when another tab get's activated - if (!clientGroup() || clientGroup()->visible() == this) + if (isCurrentTab()) workspace()->updateFocusChains(this, Workspace::FocusChainMakeLast); addWorkspaceRepaint(visibleRect()); } diff --git a/client.h b/client.h index 93b79ce0ff..526c710706 100644 --- a/client.h +++ b/client.h @@ -41,7 +41,7 @@ along with this program. If not, see . #include "kdecoration.h" #include "rules.h" #include "toplevel.h" -#include "clientgroup.h" +#include "tabgroup.h" #ifdef HAVE_XSYNC #include @@ -221,12 +221,12 @@ class Client /** * The "Window Tabs" Group this Client belongs to. **/ - Q_PROPERTY(KWin::ClientGroup* clientGroup READ clientGroup NOTIFY clientGroupChanged) + Q_PROPERTY(KWin::TabGroup* tabGroup READ tabGroup NOTIFY tabGroupChanged) /** * Whether this Client is the currently visible Client in its Client Group (Window Tabs). * For change connect to the visibleChanged signal on the Client's Group. **/ - Q_PROPERTY(bool visibleInClientGroup READ isVisibleInClientGroup) + Q_PROPERTY(bool isCurrentTab READ isCurrentTab) /** * Minimum size as specified in WM_NORMAL_HINTS **/ @@ -500,8 +500,14 @@ public: bool hasStrut() const; // Tabbing functions - ClientGroup* clientGroup() const; // Returns a pointer to client_group - void setClientGroup(ClientGroup* group); + TabGroup* tabGroup() const; // Returns a pointer to client_group + Q_INVOKABLE inline bool tabBefore(Client *other, bool activate) { return tabTo(other, false, activate); } + Q_INVOKABLE inline bool tabBehind(Client *other, bool activate) { return tabTo(other, true, activate); } + Q_INVOKABLE bool untab(const QRect &toGeometry = QRect()); + /** + * Set tab group - this is to be invoked by TabGroup::add/remove(client) and NO ONE ELSE + */ + void setTabGroup(TabGroup* group); /* * If shown is true the client is mapped and raised, if false * the client is unmapped and hidden, this function is called @@ -515,7 +521,7 @@ public: * client, this function stops it. */ void dontMoveResize(); - bool isVisibleInClientGroup() const; + bool isCurrentTab() const; /** * Whether or not the window has a strut that expands through the invisible area of @@ -628,6 +634,7 @@ private: bool processDecorationButtonPress(int button, int state, int x, int y, int x_root, int y_root, bool ignoreMenu = false); + Client* findAutogroupCandidate() const; protected: virtual void debug(QDebug& stream) const; @@ -670,10 +677,10 @@ signals: void iconChanged(); void skipSwitcherChanged(); /** - * Emitted whenever the Client's ClientGroup changed. That is whenever the Client is moved to + * Emitted whenever the Client's TabGroup changed. That is whenever the Client is moved to * another group, but not when a Client gets added or removed to the Client's ClientGroup. **/ - void clientGroupChanged(); + void tabGroupChanged(); private: void exportMappingState(int s); // ICCCM 4.1.3.1, 4.1.4, NETWM 2.5.1 @@ -744,6 +751,8 @@ private: void updateInputWindow(); + bool tabTo(Client *other, bool behind, bool activate); + Window client; Window wrapper; KDecoration* decoration; @@ -845,7 +854,7 @@ private: QString cap_normal, cap_iconic, cap_suffix; Group* in_group; Window window_group; - ClientGroup* client_group; + TabGroup* tab_group; Layer in_layer; QTimer* ping_timer; QProcess* process_killer; @@ -994,9 +1003,9 @@ inline Group* Client::group() return in_group; } -inline ClientGroup* Client::clientGroup() const +inline TabGroup* Client::tabGroup() const { - return client_group; + return tab_group; } inline bool Client::isMinimized() const @@ -1012,7 +1021,7 @@ inline bool Client::isActive() const inline bool Client::isShown(bool shaded_is_shown) const { return !isMinimized() && (!isShade() || shaded_is_shown) && !hidden && - (clientGroup() == NULL || clientGroup()->visible() == this); + (!tabGroup() || tabGroup()->current() == this); } inline bool Client::isHiddenInternal() const diff --git a/clientgroup.cpp b/clientgroup.cpp deleted file mode 100644 index 3677fc64a1..0000000000 --- a/clientgroup.cpp +++ /dev/null @@ -1,357 +0,0 @@ -/******************************************************************************* -KWin - the KDE window manager -This file is part of the KDE project. - -Copyright (C) 2009 Jorge Mata -Copyright (C) 2009 Lucas Murray - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*******************************************************************************/ - -#include "clientgroup.h" - -#include "client.h" -#include "effects.h" - -namespace KWin -{ - -ClientGroup::ClientGroup(Client *c) - : clients_() - , items_() - , visible_(0) - , minSize_(0, 0) - , maxSize_(INT_MAX, INT_MAX) -{ - clients_.append(c); - updateItems(); - updateMinMaxSize(); - Workspace::self()->addClientGroup(this); - c->setClientShown(true); // Ensure the client is visible - c->triggerDecorationRepaint(); // TODO: Required? Maybe for creating new group? -} - -ClientGroup::~ClientGroup() -{ - Workspace::self()->removeClientGroup(this); -} - -void ClientGroup::add(Client* c, int before, bool becomeVisible) -{ - if (contains(c) || !c->workspace()->decorationSupportsClientGrouping()) - return; - - // Remove the Client->ClientGroup reference if the client is already in another group so we - // don't change the geometry of other clients in their current group by accident. However - // don't REMOVE them from the actual group until we are certain that the client will be moved. - ClientGroup* oldGroup = NULL; - if (c->clientGroup()) { - oldGroup = c->clientGroup(); - c->setClientGroup(NULL); - } - - // If it's not possible to have the same states then ungroup them, TODO: Check all states - // We do this here as the ungroup code in updateStates() cannot be called until add() completes - ShadeMode oldShadeMode = c->shadeMode(); - if (c->shadeMode() != clients_[visible_]->shadeMode()) - c->setShade(clients_[visible_]->shadeMode()); - if (c->shadeMode() != clients_[visible_]->shadeMode()) { - if (oldGroup) // Re-add to old group if required - c->setClientGroup(oldGroup); - // One need to trigger decoration repaint on the group to - // make sure hover animations are properly reset. - clients_[visible_]->triggerDecorationRepaint(); - return; - } - QRect oldGeom = c->geometry(); - if (c->geometry() != clients_[visible_]->geometry()) - c->setGeometry(clients_[visible_]->geometry()); - if (c->geometry() != clients_[visible_]->geometry()) { - if (c->shadeMode() != oldShadeMode) - c->setShade(oldShadeMode); // Restore old shade mode - if (oldGroup) // Re-add to old group if required - c->setClientGroup(oldGroup); - clients_[visible_]->triggerDecorationRepaint(); - return; - } - if (c->desktop() != clients_[visible_]->desktop()) - c->setDesktop(clients_[visible_]->desktop()); - if (c->desktop() != clients_[visible_]->desktop()) { - if (c->geometry() != oldGeom) - c->setGeometry(oldGeom); // Restore old geometry - if (c->shadeMode() != oldShadeMode) - c->setShade(oldShadeMode); // Restore old shade mode - if (oldGroup) // Re-add to old group if required - c->setClientGroup(oldGroup); - clients_[visible_]->triggerDecorationRepaint(); - return; - } - - // Tabbed windows MUST have a decoration - if (c->noBorder()) - c->setNoBorder(false); - if (clients_[visible_]->noBorder()) - clients_[visible_]->setNoBorder(false); - - // Re-add to old group if required for the effect hook - if (oldGroup) - c->setClientGroup(oldGroup); - - // Notify effects of merge - if (effects != NULL) - static_cast(effects)->slotClientGroupItemAdded( - c->effectWindow(), clients_[visible_]->effectWindow()); - - // Actually remove from old group if required and update - if (c->clientGroup()) - c->clientGroup()->remove(c); - c->setClientGroup(this); // Let the client know which group it belongs to - - // Actually add to new group - if (before >= 0) { - if (visible_ >= before) - visible_++; - clients_.insert(before, c); - } else - clients_.append(c); - if (!becomeVisible) // Hide before adding - c->setClientShown(false); - updateItems(); - updateMinMaxSize(); - updateStates(clients_[visible_], c); - - if (becomeVisible) // Set visible after settings geometry - setVisible(c); - - // Activate the new visible window - clients_[visible_]->setActive(true); - //clients_[visible_]->takeFocus( Allowed ); - //clients_[visible_]->workspace()->raiseClient( clients_[visible_] ); - - clients_[visible_]->triggerDecorationRepaint(); -} - -void ClientGroup::remove(int index, const QRect& newGeom, bool toNullGroup) -{ - remove(clients_[index], newGeom, toNullGroup); -} - -void ClientGroup::remove(Client* c, const QRect& newGeom, bool toNullGroup) -{ - if (!c) - return; - if (clients_.count() < 2) { - c->setClientGroup(NULL); - Workspace::self()->removeClientGroup(this); // Remove immediately - delete this; - return; - } - - ClientList::const_iterator i; - Client* newVisible = clients_[visible_]; - if (newVisible == c) - newVisible = (visible_ != clients_.size() - 1) ? clients_[visible_ + 1] : clients_[visible_ - 1]; - - // Notify effects of removal - if (effects) - static_cast(effects)->slotClientGroupItemRemoved( - c->effectWindow(), newVisible->effectWindow()); - - setVisible(newVisible); // Display new window before removing old one - clients_.removeAll(c); - visible_ = indexOfClient(newVisible); // Index may have changed - updateItems(); - updateMinMaxSize(); - - c->setClientGroup(toNullGroup ? NULL : new ClientGroup(c)); - if (newGeom.isValid()) { - // HACK: if the group was maximized, one needs to make some checks on the future client maximize mode - // because the transition from maximized to MaximizeRestore is not handled properly in setGeometry when - // the new geometry size is unchanged. - // since newGeom has the same size as the old client geometry, one just needs to check the topLeft position of newGeom - // and compare that to the group maximize mode. - // when the new mode is predicted to be MaximizeRestore, one must set it manually, in order to avoid decoration artifacts - Client::MaximizeMode groupMaxMode(newVisible->maximizeMode()); - if (((groupMaxMode & Client::MaximizeHorizontal) && newGeom.left() != newVisible->geometry().left()) || - ((groupMaxMode & Client::MaximizeVertical) && newGeom.top() != newVisible->geometry().top())) - c->maximize(Client::MaximizeRestore); - c->setGeometry(newGeom); - } - newVisible->triggerDecorationRepaint(); -} - -void ClientGroup::removeAll() -{ - while (clients_.count() > 1) - remove(clients_.at(1)); -} - -void ClientGroup::closeAll() -{ - Client* front; - ClientList list(clients_); - while (!list.isEmpty()) { - front = list.front(); - list.pop_front(); - if (front != clients_[visible_]) - front->closeWindow(); - } - clients_[visible_]->closeWindow(); -} - -void ClientGroup::move(int index, int before) -{ - move(clients_[index], (before >= 0 && before < clients_.size()) ? clients_[before] : NULL); -} - -void ClientGroup::move(Client* c, Client* before) -{ - if (c == before) // Impossible to do - return; - - Client* wasVisible = clients_[visible_]; - clients_.removeAll(c); - clients_.insert(before ? indexOfClient(before) : clients_.size(), c); - visible_ = indexOfClient(wasVisible); - updateItems(); - - clients_[visible_]->triggerDecorationRepaint(); -} - -void ClientGroup::displayClientMenu(int index, const QPoint& pos) -{ - if (index == -1) - index = visible_; - displayClientMenu(clients_[index], pos); -} - -void ClientGroup::displayClientMenu(Client* c, const QPoint& pos) -{ - c->workspace()->showWindowMenu(pos, c); -} - -bool ClientGroup::containsActiveClient() -{ - return contains(Workspace::self()->activeClient()); -} - -void ClientGroup::setVisible(int index) -{ - setVisible(clients_[index]); -} - -void ClientGroup::setVisible(Client* c) -{ - if (c == clients_[visible_] || !contains(c)) - return; - - // Notify effects of switch - if (effects != NULL) - static_cast(effects)->slotClientGroupItemSwitched( - clients_[visible_]->effectWindow(), c->effectWindow()); - - visible_ = indexOfClient(c); - c->setClientShown(true); - for (ClientList::const_iterator i = clients_.constBegin(); i != clients_.constEnd(); ++i) - if ((*i) != c) - (*i)->setClientShown(false); - emit visibleChanged(); -} - -void ClientGroup::updateStates(Client* main, Client* only) -{ - ClientList toBeRemoved; - for (ClientList::const_iterator i = clients_.constBegin(), end = clients_.constEnd(); i != end; ++i) { - Client *c = (*i); - if (c != main && (!only || c == only)) { - if (c->isMinimized() != main->isMinimized()) { - if (main->isMinimized()) - c->minimize(true); - else - c->unminimize(true); - } - if (c->isShade() != main->isShade()) - c->setShade(main->isShade() ? ShadeNormal : ShadeNone); - if (c->geometry() != main->geometry()) - c->setGeometry(main->geometry()); - if (c->desktop() != main->desktop()) - c->setDesktop(main->desktop()); - if (c->isOnAllDesktops() != main->isOnAllDesktops()) - c->setOnAllDesktops(main->isOnAllDesktops()); - if (c->activities() != main->activities()) - c->setOnActivities(main->activities()); - if (c->keepAbove() != main->keepAbove()) - c->setKeepAbove(main->keepAbove()); - if (c->keepBelow() != main->keepBelow()) - c->setKeepBelow(main->keepBelow()); - - // If it's not possible to have the same states then ungroup them, TODO: Check all states - if (c->geometry() != main->geometry() || c->desktop() != main->desktop()) - toBeRemoved << c; - } - } - - for (ClientList::const_iterator i = toBeRemoved.constBegin(), end = toBeRemoved.constEnd(); i != end; ++i) - remove(*i); -} - -void ClientGroup::updateItems() -{ - items_.clear(); - for (ClientList::const_iterator i = clients_.constBegin(); i != clients_.constEnd(); ++i) { - QIcon icon((*i)->icon()); - icon.addPixmap((*i)->miniIcon()); - items_.append(ClientGroupItem((*i)->caption(), icon)); - } -} - -void ClientGroup::updateMinMaxSize() -{ - // Determine entire group's minimum and maximum sizes - minSize_ = QSize(0, 0); - maxSize_ = QSize(INT_MAX, INT_MAX); - for (ClientList::const_iterator i = clients_.constBegin(); i != clients_.constEnd(); ++i) { - if ((*i)->minSize().width() > minSize_.width()) - minSize_.setWidth((*i)->minSize().width()); - if ((*i)->minSize().height() > minSize_.height()) - minSize_.setHeight((*i)->minSize().height()); - if ((*i)->maxSize().width() < maxSize_.width()) - maxSize_.setWidth((*i)->maxSize().width()); - if ((*i)->maxSize().height() < maxSize_.height()) - maxSize_.setHeight((*i)->maxSize().height()); - } - if (minSize_.width() > maxSize_.width() || - minSize_.height() > maxSize_.height()) { - //kWarning(1212) << "ClientGroup's min size is greater than its max size. Setting max to min."; - maxSize_ = minSize_; - } - // TODO: only emit if really changed - emit minSizeChanged(); - emit maxSizeChanged(); - - // Ensure all windows are within these sizes - const QSize size = clients_[visible_]->clientSize(); - QSize newSize( - qBound(minSize_.width(), size.width(), maxSize_.width()), - qBound(minSize_.height(), size.height(), maxSize_.height())); - if (newSize != size) - for (ClientList::const_iterator i = clients_.constBegin(); i != clients_.constEnd(); ++i) - // TODO: Doesn't affect shaded windows? - // There seems to be a race condition when using plainResize() which causes the window - // to sometimes be located at new window's location instead of the visible window's location - // when a window with a large min size is added to a group with a small window size. - (*i)->setGeometry(QRect(clients_[visible_]->pos(), (*i)->sizeForClientSize(newSize))); -} - -} diff --git a/clientgroup.h b/clientgroup.h deleted file mode 100644 index b70c54403f..0000000000 --- a/clientgroup.h +++ /dev/null @@ -1,266 +0,0 @@ -/******************************************************************************* -KWin - the KDE window manager -This file is part of the KDE project. - -Copyright (C) 2009 Jorge Mata -Copyright (C) 2009 Lucas Murray - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*******************************************************************************/ - -#ifndef KWIN_CLIENTGROUP_H -#define KWIN_CLIENTGROUP_H - -#include - -#include "kdecoration.h" -#include "utils.h" - -namespace KWin -{ - -class Client; - -/** - * This class represents a group of clients for use in window tabbing. All - * clients in the group share the same geometry and state information; I.e if - * one client changes then all others should also be changed. - * - * Workspace::clientGroups is a list of all currently-existing client groups. - * - * A group MUST contain at least one client and MUST NOT contain multiple - * copies of the same client. A client MUST NOT be in two groups at the same - * time. All decorated clients SHOULD be in a group, even if it's a group of - * one client. - * - * rohanp: Had to convert this object to a QObject to make it easier for adding - * scripting interface to ClientGroup. - * - * If a group contains multiple clients then only one will ever be mapped at - * any given time. - */ -class ClientGroup : public QObject -{ - Q_OBJECT - /** - * Currently visible client in this group. - **/ - Q_PROPERTY(KWin::Client* visible READ visible WRITE setVisible NOTIFY visibleChanged) - /** - * Combined minimum size of all clients in the group. - **/ - Q_PROPERTY(QSize minSize READ minSize NOTIFY minSizeChanged) - /** - * Combined maximum size of all clients in the group. - **/ - Q_PROPERTY(QSize maxSize READ maxSize NOTIFY maxSizeChanged) - /** - * The index of the visible Client in this group. - **/ - Q_PROPERTY(int visibleClientIndex READ indexOfVisibleClient NOTIFY visibleChanged) - /** - * The Clients in this group. - **/ - Q_PROPERTY(QList clients READ clients) -public: - /** - * Creates a new group containing \p c. - */ - ClientGroup(Client* c); - ~ClientGroup(); - -public Q_SLOTS: - /** - * Adds \p c to the group before \p before in the list. If \p becomeVisible is \i true then - * the added client will become also the visible client. - */ - void add(KWin::Client* c, int before = -1, bool becomeVisible = false); - /** - * Remove the client at index \p index from the group. If \p newGeom is set then the client - * will move and resize to the specified geometry, otherwise it will stay where the group - * is located. If \p toNullGroup is not true then the client will be added to a new group - * of its own. - */ - void remove(int index, const QRect& newGeom = QRect(), bool toNullGroup = false); - /** - * Remove \p c from the group. If \p newGeom is set then the client will move and resize to - * the specified geometry, otherwise it will stay where the group is located. If - * \p toNullGroup is not true then the client will be added to a new group of its own. - */ - void remove(KWin::Client* c, const QRect& newGeom = QRect(), bool toNullGroup = false); - /** - * Remove all clients from this group. Results in all clients except the first being moved - to a group of their own. - */ - void removeAll(); - /** - * Close all clients in this group. - */ - void closeAll(); - /** - * Move the client at index \p index to the position before the client at index \p before - * in the list. - */ - void move(int index, int before); - /** - * Move \p c to the position before \p before in the list. - */ - void move(KWin::Client* c, KWin::Client* before); - /** - * Display the right-click client menu belonging to the client at index \p index at the - * global coordinates specified by \p pos. - */ - void displayClientMenu(int index, const QPoint& pos); - /** - * Display the right-click client menu belonging to \p c at the global coordinates - * specified by \p pos. - */ - void displayClientMenu(KWin::Client* c, const QPoint& pos); - -public: - /** - * Returns the list index of \p c. - */ - Q_SCRIPTABLE int indexOfClient(KWin::Client* c); - /** - * Returns the list index of the currently visible client in the group. - */ - int indexOfVisibleClient(); - /** - * Returns whether or not this group contains \p c. - */ - Q_SCRIPTABLE bool contains(KWin::Client* c); - /** - * Returns whether or not this group contains the active client. - */ - bool containsActiveClient(); - - /** - * Returns the list of all the clients contained in this group in their current order. - */ - const ClientList &clients() const; - /** - * Returns a list of the captions and icons of all the clients contained in this group - * in their current order. - */ - QList< ClientGroupItem > items() const; - - /** - * Returns the currently visible client. - */ - Client* visible(); - /** - * Makes the client at index \p index the visible one in the group. - */ - void setVisible(int index); - /** - * Makes \p c the visible client in the group. - */ - void setVisible(Client* c); - - /** - * Returns combined minimum size of all clients in the group. - */ - QSize minSize() const; - /** - * Returns combined maximum size of all clients in the group. - */ - QSize maxSize() const; - - /** - * Ensures that all the clients in the group have identical geometries and states using - * \p main as the primary client to copy the settings off. If \p only is set then only - * that client is updated to match \p main. - */ - void updateStates(Client* main, Client* only = NULL); - -Q_SIGNALS: - /** - * Emitted when the visible Client in this group changes. - **/ - void visibleChanged(); - /** - * Emitted when the group's minimum size changes. - **/ - void minSizeChanged(); - /** - * Emitted when the group's maximum size changes. - **/ - void maxSizeChanged(); - -private: - /** - * Regenerate the list of client captions and icons. - */ - void updateItems(); - /** - * Determine the combined minimum and maximum sizes of all clients in the group. - */ - void updateMinMaxSize(); - - ClientList clients_; - QList< ClientGroupItem > items_; - int visible_; - - QSize minSize_; - QSize maxSize_; - - friend class Client; -}; - -inline int ClientGroup::indexOfClient(Client* c) -{ - return clients_.indexOf(c); -} - -inline int ClientGroup::indexOfVisibleClient() -{ - return visible_; -} - -inline bool ClientGroup::contains(Client* c) -{ - return clients_.contains(c); -} - -inline const ClientList &ClientGroup::clients() const -{ - return clients_; -} - -inline QList< ClientGroupItem > ClientGroup::items() const -{ - return items_; -} - -inline Client* ClientGroup::visible() -{ - return clients_.at(visible_); -} - -inline QSize ClientGroup::minSize() const -{ - return minSize_; -} - -inline QSize ClientGroup::maxSize() const -{ - return maxSize_; -} - -} -Q_DECLARE_METATYPE(KWin::ClientGroup*) -Q_DECLARE_METATYPE(QList) - -#endif diff --git a/clients/CMakeLists.txt b/clients/CMakeLists.txt index 1453d8232a..6019a9e7aa 100644 --- a/clients/CMakeLists.txt +++ b/clients/CMakeLists.txt @@ -3,4 +3,3 @@ add_subdirectory( oxygen ) add_subdirectory( plastik ) add_subdirectory( b2 ) add_subdirectory( laptop ) -add_subdirectory( tabstrip ) diff --git a/clients/aurorae/src/aurorae.cpp b/clients/aurorae/src/aurorae.cpp index 352f751126..76eb527240 100644 --- a/clients/aurorae/src/aurorae.cpp +++ b/clients/aurorae/src/aurorae.cpp @@ -56,7 +56,7 @@ void AuroraeFactory::init() m_theme->loadTheme(themeName, config); m_theme->setBorderSize((KDecorationDefines::BorderSize)themeGroup.readEntry("BorderSize", KDecorationDefines::BorderNormal)); m_theme->setButtonSize((KDecorationDefines::BorderSize)themeGroup.readEntry("ButtonSize", KDecorationDefines::BorderNormal)); - m_theme->setTabDragMimeType(clientGroupItemDragMimeType()); + m_theme->setTabDragMimeType(tabDragMimeType()); // setup the QML engine foreach (const QString &importPath, KGlobal::dirs()->findDirs("module", "imports")) { m_engine->addImportPath(importPath); @@ -117,7 +117,7 @@ bool AuroraeFactory::supports(Ability ability) const case AbilityButtonHelp: case AbilityProvidesShadow: return true; // TODO: correct value from theme - case AbilityClientGrouping: + case AbilityTabbing: return false; case AbilityUsesBlurBehind: return true; diff --git a/clients/oxygen/oxygenclient.cpp b/clients/oxygen/oxygenclient.cpp index 98b3a74993..8818e11efc 100644 --- a/clients/oxygen/oxygenclient.cpp +++ b/clients/oxygen/oxygenclient.cpp @@ -511,7 +511,7 @@ namespace Oxygen const QRect titleRect( this->titleRect() ); // get tabs - const int items( clientGroupItems().count() ); + const int items( tabCount() ); // make sure item data have the correct number of items while( _itemData.count() < items ) _itemData.push_back( ClientGroupItemData() ); @@ -574,7 +574,7 @@ namespace Oxygen } // button activity - _itemData.updateButtonActivity( visibleClientGroupItem() ); + _itemData.updateButtonActivity( currentTabId() ); // reset buttons location _itemData.updateButtons( alsoUpdate ); @@ -685,7 +685,7 @@ namespace Oxygen const int titleHeight( layoutMetric( LM_TitleEdgeTop ) + layoutMetric( LM_TitleEdgeBottom ) + layoutMetric( LM_TitleHeight ) ); // make titlebar background darker for tabbed, non-outline window - if( ( clientGroupItems().count() >= 2 || _itemData.isAnimated() ) && !(configuration().drawTitleOutline() && isActive() ) ) + if( ( tabCount() >= 2 || _itemData.isAnimated() ) && !(configuration().drawTitleOutline() && isActive() ) ) { const QPoint topLeft( r.topLeft()-position ); @@ -917,7 +917,6 @@ namespace Oxygen renderTitleText( painter, rect, color, contrast ); } else if( !caption().isEmpty() ) { - renderTitleText( painter, rect, caption(), color, contrast ); } @@ -942,7 +941,6 @@ namespace Oxygen if( isMaximized() ) painter->translate( 0, -2 ); } else if( !caption().isEmpty() ) { - renderTitleText( painter, rect, caption(), color, contrast ); } @@ -1019,11 +1017,10 @@ namespace Oxygen { textRect.adjust( 0, 0, - configuration().buttonSize() - layoutMetric(LM_TitleEdgeRight), 0 ); } // check if current item is active - const bool active( index == visibleClientGroupItem() ); + const bool active( tabId(index) == currentTabId() ); // get current item caption and update text rect - const QList< ClientGroupItem >& items( clientGroupItems() ); - const QString caption( itemCount == 1 ? this->caption() : items[index].title() ); + const QString caption( itemCount == 1 ? this->caption() : this->caption(index) ); if( !configuration().centerTitleOnFullWidth() ) { boundRectTo( textRect, titleRect() ); } @@ -1110,7 +1107,7 @@ namespace Oxygen if( ( index == itemCount-1 && buttonsRightWidth() > 0 ) || ( index+1 < itemCount && ( _itemData.isTarget( index+1 ) || - !( index+1 == visibleClientGroupItem() && _itemData[index+1]._boundingRect.isValid() ) ) ) ) + !( tabId(index+1) == currentTabId() && _itemData[index+1]._boundingRect.isValid() ) ) ) ) { const QRect local( item._boundingRect.topRight()+QPoint(0,2), QSize( 2, item._boundingRect.height()-3 ) ); @@ -1553,12 +1550,12 @@ namespace Oxygen } - // make sure ItemData and clientGroupItems are synchronized + // make sure ItemData and tabList are synchronized /* this needs to be done before calling RenderWindowBorder since some painting in there depend on the clientGroups state */ - if( _itemData.isDirty() || _itemData.count() != clientGroupItems().count() ) + if( _itemData.isDirty() || _itemData.count() != tabCount() ) { updateItemBoundingRects( false ); } // window background @@ -1606,12 +1603,12 @@ namespace Oxygen { const QPoint point = event->pos(); - if( itemClicked( point ) < 0 ) return false; + if( tabIndexAt( point ) < 0 ) return false; _dragPoint = point; _mouseButton = event->button(); bool accepted( false ); - if( buttonToWindowOperation( _mouseButton ) == ClientGroupDragOp ) + if( buttonToWindowOperation( _mouseButton ) == TabDragOp ) { accepted = true; @@ -1619,9 +1616,10 @@ namespace Oxygen } else if( buttonToWindowOperation( _mouseButton ) == OperationsOp ) { QPoint point = event->pos(); - int itemClicked( this->itemClicked( point ) ); + const int clickedIndex( tabIndexAt( point ) ); _mouseButton = Qt::NoButton; - displayClientMenu( itemClicked, widget()->mapToGlobal( event->pos() ) ); + if ( tabIndexAt( point ) > -1) + showWindowMenu( widget()->mapToGlobal( event->pos() ), tabId(clickedIndex) ); accepted = true; // displayClientMenu can possibly destroy the deco... } @@ -1639,11 +1637,11 @@ namespace Oxygen const QPoint point = event->pos(); - const int visibleItem = visibleClientGroupItem(); - const int itemClicked( this->itemClicked( point ) ); - if( itemClicked >= 0 && visibleItem != itemClicked ) + const long visibleItem = currentTabId(); + const int clickedIndex( tabIndexAt( point ) ); + if( clickedIndex >= 0 && visibleItem != tabId(clickedIndex) ) { - setVisibleClientGroupItem( itemClicked ); + setCurrentTab( tabId(clickedIndex) ); setForceActive( true ); accepted = true; } @@ -1664,23 +1662,23 @@ namespace Oxygen { return false; } bool accepted( false ); - if( buttonToWindowOperation( _mouseButton ) == ClientGroupDragOp ) + if( buttonToWindowOperation( _mouseButton ) == TabDragOp ) { const QPoint point = event->pos(); - const int itemClicked( this->itemClicked( point ) ); - if( itemClicked < 0 ) return false; + const int clickedIndex( tabIndexAt( point ) ); + if( clickedIndex < 0 ) return false; _titleAnimationData->reset(); QDrag *drag = new QDrag( widget() ); QMimeData *groupData = new QMimeData(); - groupData->setData( clientGroupItemDragMimeType(), QString().setNum( itemId( itemClicked )).toAscii() ); + groupData->setData( tabDragMimeType(), QString().setNum( tabId(clickedIndex) ).toAscii() ); drag->setMimeData( groupData ); - _sourceItem = this->itemClicked( _dragPoint ); + _sourceItem = tabIndexAt( _dragPoint ); // get tab geometry - QRect geometry( _itemData[itemClicked]._boundingRect ); + QRect geometry( _itemData[clickedIndex]._boundingRect ); // remove space used for buttons if( _itemData.count() > 1 ) @@ -1697,7 +1695,7 @@ namespace Oxygen } - drag->setPixmap( itemDragPixmap( itemClicked, geometry ) ); + drag->setPixmap( itemDragPixmap( clickedIndex, geometry ) ); // note: the pixmap is moved just above the pointer on purpose // because overlapping pixmap and pointer slows down the pixmap a lot. @@ -1717,7 +1715,7 @@ namespace Oxygen if( drag->target() == 0 && _itemData.count() > 1 ) { _itemData.setDirty( true ); - removeFromClientGroup( _sourceItem, + untab( tabId(_sourceItem), widget()->frameGeometry().adjusted( layoutMetric( LM_OuterPaddingLeft ), layoutMetric( LM_OuterPaddingTop ), @@ -1743,7 +1741,7 @@ namespace Oxygen { // check if drag enter is allowed - if( !event->mimeData()->hasFormat( clientGroupItemDragMimeType() ) || hideTitleBar() ) return false; + if( !event->mimeData()->hasFormat( tabDragMimeType() ) || hideTitleBar() ) return false; // event->acceptProposedAction(); @@ -1751,13 +1749,13 @@ namespace Oxygen { const QPoint position( event->pos() ); - _itemData.animate( AnimationEnter, itemClicked( position, true ) ); + _itemData.animate( AnimationEnter, tabIndexAt( position, true ) ); } else if( _itemData.count() > 1 ) { const QPoint position( event->pos() ); - const int itemClicked( this->itemClicked( position, false ) ); - _itemData.animate( AnimationEnter|AnimationSameTarget, itemClicked ); + const int clickedIndex( tabIndexAt( position, false ) ); + _itemData.animate( AnimationEnter|AnimationSameTarget, clickedIndex ); } @@ -1791,20 +1789,20 @@ namespace Oxygen { // check format - if( !event->mimeData()->hasFormat( clientGroupItemDragMimeType() ) ) return false; + if( !event->mimeData()->hasFormat( tabDragMimeType() ) ) return false; if( event->source() != widget() ) { const QPoint position( event->pos() ); - _itemData.animate( AnimationMove, itemClicked( position, true ) ); + _itemData.animate( AnimationMove, tabIndexAt( position, true ) ); } else if( _itemData.count() > 1 ) { if( _dragStartTimer.isActive() ) _dragStartTimer.stop(); const QPoint position( event->pos() ); - const int itemClicked( this->itemClicked( position, false ) ); - _itemData.animate( AnimationMove|AnimationSameTarget, itemClicked ); + const int clickedIndex( tabIndexAt( position, false ) ); + _itemData.animate( AnimationMove|AnimationSameTarget, clickedIndex ); } @@ -1820,35 +1818,25 @@ namespace Oxygen _itemData.animate( AnimationNone ); const QMimeData *groupData = event->mimeData(); - if( !groupData->hasFormat( clientGroupItemDragMimeType() ) ) return false; + if( !groupData->hasFormat( tabDragMimeType() ) ) return false; + + _itemData.setDirty( true ); + + if( widget() != event->source() ) + setForceActive( true ); + + const long source = QString( groupData->data( tabDragMimeType() ) ).toLong(); + int clickedIndex( tabIndexAt( point, true ) ); + if (clickedIndex < 0) + tab_A_behind_B(source, tabId(_itemData.count() - 1)); + else if (clickedIndex) + tab_A_behind_B(source, tabId(clickedIndex)); + else + tab_A_before_B(source, tabId(clickedIndex)); if( widget() == event->source() ) - { - - const int from = this->itemClicked( _dragPoint ); - int itemClicked( this->itemClicked( point, false ) ); - - if( itemClicked > from ) - { - itemClicked++; - if( itemClicked >= clientGroupItems().count() ) - { itemClicked = -1; } - } - - _itemData.setDirty( true ); - moveItemInClientGroup( from, itemClicked ); updateTitleRect(); - } else { - - setForceActive( true ); - const int itemClicked( this->itemClicked( point, true ) ); - const long source = QString( groupData->data( clientGroupItemDragMimeType() ) ).toLong(); - _itemData.setDirty( true ); - moveItemToClientGroup( source, itemClicked ); - - } - _titleAnimationData->reset(); return true; @@ -1881,7 +1869,7 @@ namespace Oxygen if( button == _itemData[i]._closeButton.data() ) { _itemData.setDirty( true ); - closeClientGroupItem( i ); + closeTab( tabId(i) ); return true; } } @@ -1892,7 +1880,7 @@ namespace Oxygen //________________________________________________________________ QPixmap Client::itemDragPixmap( int index, const QRect& geometry ) { - const bool itemValid( index >= 0 && index < clientGroupItems().count() ); + const bool itemValid( index >= 0 && index < tabCount() ); QPixmap pixmap( geometry.size() ); QPainter painter( &pixmap ); @@ -1904,7 +1892,7 @@ namespace Oxygen renderWindowBackground( &painter, geometry, widget(), widget()->palette() ); // darken background if item is inactive - const bool itemActive = !( itemValid && index != visibleClientGroupItem() ); + const bool itemActive = !( itemValid && tabId(index) != currentTabId() ); if( !itemActive ) { @@ -1924,7 +1912,8 @@ namespace Oxygen if( itemValid ) { textRect.adjust( layoutMetric( LM_TitleBorderLeft ), 0, -layoutMetric(LM_TitleBorderRight), 0 ); } - const QString caption( itemValid ? clientGroupItems()[index].title() : this->caption() ); + const QString caption( itemValid ? this->caption(index) : this->caption() ); + renderTitleText( &painter, textRect, caption, titlebarTextColor( widget()->palette(), isActive() && itemActive ), diff --git a/clients/oxygen/oxygenclient.h b/clients/oxygen/oxygenclient.h index adb7d37333..e1d1d0ab81 100644 --- a/clients/oxygen/oxygenclient.h +++ b/clients/oxygen/oxygenclient.h @@ -89,7 +89,7 @@ namespace Oxygen //! true when decoration is forced active bool isForcedActive( void ) const - { return _forceActive && clientGroupItems().count() > 1; } + { return _forceActive && tabCount() > 1; } //! true when separator is to be drawn bool drawSeparator( void ) const @@ -116,7 +116,7 @@ namespace Oxygen return configuration().hideTitleBar() && !isShade() && - clientGroupItems().count() == 1; + tabCount() == 1; } //@} @@ -333,7 +333,7 @@ namespace Oxygen virtual bool closeItem( const Button* ); //! index of item matching point - int itemClicked( const QPoint& position, bool between = false ) const + int tabIndexAt( const QPoint& position, bool between = false ) const { return _itemData.itemAt( position , between ); } //! return pixmap corresponding to a given tab, for dragging @@ -358,7 +358,7 @@ namespace Oxygen bool hasTitleOutline( void ) const { return - clientGroupItems().count() >= 2 || + tabCount() >= 2 || _itemData.isAnimated() || ( (isActive()||glowIsAnimated()) && configuration().drawTitleOutline() ); } diff --git a/clients/oxygen/oxygenclientgroupitemdata.cpp b/clients/oxygen/oxygenclientgroupitemdata.cpp index 57a5199664..3d8ef2248b 100644 --- a/clients/oxygen/oxygenclientgroupitemdata.cpp +++ b/clients/oxygen/oxygenclientgroupitemdata.cpp @@ -214,7 +214,7 @@ namespace Oxygen if( count() <= 2 ) { - item._endBoundingRect = _client.defaultTitleRect( index == _client.visibleClientGroupItem() ); + item._endBoundingRect = _client.defaultTitleRect( _client.tabId(index) == _client.currentTabId() ); } else { @@ -260,7 +260,7 @@ namespace Oxygen } //____________________________________________________________________________ - void ClientGroupItemDataList::updateButtonActivity( int visibleItem ) const + void ClientGroupItemDataList::updateButtonActivity( long visibleItem ) const { for( int index = 0; index < count(); index++ ) @@ -268,7 +268,7 @@ namespace Oxygen const ClientGroupItemData& item( at(index) ); if( item._closeButton ) - { item._closeButton.data()->setForceInactive( index != visibleItem ); } + { item._closeButton.data()->setForceInactive( _client.tabId(index) != visibleItem ); } } diff --git a/clients/oxygen/oxygenclientgroupitemdata.h b/clients/oxygen/oxygenclientgroupitemdata.h index 989920f8fc..76a6c04022 100644 --- a/clients/oxygen/oxygenclientgroupitemdata.h +++ b/clients/oxygen/oxygenclientgroupitemdata.h @@ -151,7 +151,7 @@ namespace Oxygen { return animation().data()->isRunning(); } //! update button activity - void updateButtonActivity( int visibleItem ) const; + void updateButtonActivity( long visibleItem ) const; //! update buttons void updateButtons( bool alsoUpdate ) const; diff --git a/clients/oxygen/oxygenfactory.cpp b/clients/oxygen/oxygenfactory.cpp index 790fdbc742..827aa59eec 100644 --- a/clients/oxygen/oxygenfactory.cpp +++ b/clients/oxygen/oxygenfactory.cpp @@ -171,7 +171,7 @@ namespace Oxygen return true; // tabs - case AbilityClientGrouping: + case AbilityTabbing: return true; // no colors supported at this time diff --git a/clients/tabstrip/CMakeLists.txt b/clients/tabstrip/CMakeLists.txt deleted file mode 100644 index 8d269b10ac..0000000000 --- a/clients/tabstrip/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -add_subdirectory( config ) - -set(kwin_tabstrip_SRCS - tabstripbutton.cpp - tabstripdecoration.cpp - tabstripfactory.cpp - ) - -kde4_add_plugin(kwin3_tabstrip ${kwin_tabstrip_SRCS}) - -target_link_libraries(kwin3_tabstrip kdecorations) - -install(TARGETS kwin3_tabstrip DESTINATION ${PLUGIN_INSTALL_DIR}) - -install( FILES tabstrip.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin ) diff --git a/clients/tabstrip/config/CMakeLists.txt b/clients/tabstrip/config/CMakeLists.txt deleted file mode 100644 index 3d78f838c7..0000000000 --- a/clients/tabstrip/config/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ - -set(kwin_tabstrip_config_SRCS tabstripconfig.cpp ) - -kde4_add_ui_files(kwin_tabstrip_config_SRCS tabstripconfig.ui ) - -kde4_add_plugin(kwin_tabstrip_config ${kwin_tabstrip_config_SRCS}) - -target_link_libraries(kwin_tabstrip_config ${KDE4_KDEUI_LIBS} ${QT_QTGUI_LIBRARY}) - -install(TARGETS kwin_tabstrip_config DESTINATION ${PLUGIN_INSTALL_DIR} ) diff --git a/clients/tabstrip/config/tabstripconfig.cpp b/clients/tabstrip/config/tabstripconfig.cpp deleted file mode 100644 index 4ddd8fdf56..0000000000 --- a/clients/tabstrip/config/tabstripconfig.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/******************************************************************** -Tabstrip KWin window decoration -This file is part of the KDE project. - -Copyright (C) 2009 Jorge Mata -Copyright (C) 2009 Lucas Murray - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#include "tabstripconfig.h" - -#include "tabstripconfig.moc" - -#include -#include -#include - -#include -#include - -extern "C" - { - KDE_EXPORT QObject* allocate_config( KConfig* conf, QWidget* parent ) - { - return new TabstripConfig( conf, parent ); - } - } - -TabstripConfig::TabstripConfig( KConfig *c, QWidget *parent ) - { - Q_UNUSED(c); - KGlobal::locale()->insertCatalog( "kwin_tabstrip_config" ); - config = new KConfig( "tabstriprc" ); - KConfigGroup cg( config, "General" ); - ui = new TabstripConfigDialog( parent ); - connect( ui->left, SIGNAL(clicked()), SIGNAL(changed()) ); - connect( ui->center, SIGNAL(clicked()), SIGNAL(changed()) ); - connect( ui->right, SIGNAL(clicked()), SIGNAL(changed()) ); - connect( ui->showIcon, SIGNAL(clicked()), SIGNAL(changed()) ); - connect( ui->outlineColor, SIGNAL(clicked()), SIGNAL(changed()) ); - load( cg ); - ui->show(); - } - -TabstripConfig::~TabstripConfig() - { - delete ui; - delete config; - } - -void TabstripConfig::load( KConfigGroup &c ) - { - c = KConfigGroup( config, "General" ); - QString align = c.readEntry( "TitleAlignment", "Center" ); - ui->left->setChecked( align == "Left" ); - ui->center->setChecked( align == "Center" ); - ui->right->setChecked( align == "Right" ); - ui->showIcon->setChecked( c.readEntry( "ShowIcon", true ) ); - ui->outlineColor->setColor( c.readEntry( "OutlineColor", QColor( Qt::white ) ) ); - } - -void TabstripConfig::save( KConfigGroup &c ) - { - c = KConfigGroup( config, "General" ); - if( ui->left->isChecked() ) - c.writeEntry( "TitleAlignment", "Left" ); - else if( ui->center->isChecked() ) - c.writeEntry( "TitleAlignment", "Center" ); - else - c.writeEntry( "TitleAlignment", "Right" ); - c.writeEntry( "ShowIcon", ui->showIcon->isChecked() ); - c.writeEntry( "OutlineColor", ui->outlineColor->color() ); - config->sync(); - } - -void TabstripConfig::defaults() - { - ui->left->setChecked( false ); - ui->center->setChecked( true ); - ui->right->setChecked( false ); - ui->showIcon->setChecked( true ); - ui->outlineColor->setColor( Qt::white ); - emit changed(); - } diff --git a/clients/tabstrip/config/tabstripconfig.h b/clients/tabstrip/config/tabstripconfig.h deleted file mode 100644 index 52e19897ed..0000000000 --- a/clients/tabstrip/config/tabstripconfig.h +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************** -Tabstrip KWin window decoration -This file is part of the KDE project. - -Copyright (C) 2009 Jorge Mata -Copyright (C) 2009 Lucas Murray - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#ifndef TABSTRIPCONFIG_H -#define TABSTRIPCONFIG_H - -#include "ui_tabstripconfig.h" - -#include -#include - -class TabstripConfigDialog : public QWidget, public Ui::TabstripConfigUi - { - public: - TabstripConfigDialog( QWidget *parent ) : QWidget( parent ) - { - setupUi( this ); - } - }; - -class TabstripConfig : public QObject - { - Q_OBJECT - public: - TabstripConfig( KConfig *c, QWidget *parent ); - ~TabstripConfig(); - signals: - void changed(); - public slots: - void load( KConfigGroup &c ); - void save( KConfigGroup &c ); - void defaults(); - private: - KConfig *config; - TabstripConfigDialog *ui; - }; - -#endif diff --git a/clients/tabstrip/config/tabstripconfig.ui b/clients/tabstrip/config/tabstripconfig.ui deleted file mode 100644 index 8927f9dec9..0000000000 --- a/clients/tabstrip/config/tabstripconfig.ui +++ /dev/null @@ -1,78 +0,0 @@ - - - TabstripConfigUi - - - - 0 - 0 - 276 - 98 - - - - Tabstrip - - - - - - Title &Alignment - - - - - - &Left - - - - - - - &Center - - - - - - - &Right - - - - - - - - - - Display window icons - - - - - - - - - O&utline Color: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - outlineColor - - - - - - - - - - - - - diff --git a/clients/tabstrip/tabstrip.desktop b/clients/tabstrip/tabstrip.desktop deleted file mode 100644 index 2047aa6b57..0000000000 --- a/clients/tabstrip/tabstrip.desktop +++ /dev/null @@ -1,63 +0,0 @@ -[Desktop Entry] -Name=Tabstrip -Name[ar]=شريط الألسنة -Name[ast]=Tira de llingüetes -Name[bs]=Traka jezičaka -Name[ca]=Barra de pestanyes -Name[ca@valencia]=Barra de pestanyes -Name[cs]=Pruh karet -Name[csb]=Tabstrip -Name[da]=Tabstrip -Name[de]=Tabstrip -Name[el]=Tabstrip -Name[en_GB]=Tabstrip -Name[es]=Tira de pestañas -Name[et]=Sakiriba -Name[eu]=Tabstrip -Name[fi]=Välilehtilista -Name[fr]=Tabstrip -Name[fy]=Ljepperstrip -Name[ga]=Tabstrip -Name[he]=רצועת לשוניות -Name[hi]=टैबपट्टी -Name[hr]=Kartični prikaz -Name[hu]=Lapsáv -Name[ia]=Banda de scheda (Tabstrip) -Name[id]=Tabstrip -Name[is]=Tabstrip -Name[it]=Linguette -Name[ja]=Tabstrip -Name[kk]=Қойынды жолағы -Name[km]=Tabstrip -Name[kn]=Tabstrip -Name[ko]=탭 표시줄 -Name[lt]=Tabstrip -Name[lv]=Tabstrip -Name[ml]=ടാബ്സ്ട്രിപ്പ് -Name[nb]=Fanestripe -Name[nds]=Tabstrip -Name[nl]=Strip met tabbladen -Name[nn]=Fanestripe -Name[pa]=ਟੈਬ-ਪੱਟੀ -Name[pl]=Tabstrip -Name[pt]=Barra de Páginas -Name[pt_BR]=Barra de abas -Name[ro]=Bandă cu file -Name[ru]=Tabstrip -Name[si]=ටැබ් ඉර -Name[sk]=Tabstrip -Name[sl]=Tabstrip -Name[sr]=Трака језичака -Name[sr@ijekavian]=Трака језичака -Name[sr@ijekavianlatin]=Traka jezičaka -Name[sr@latin]=Traka jezičaka -Name[sv]=Flikrad -Name[th]=รูปแบบ Tabstrip -Name[tr]=Tabstrip -Name[ug]=بەتكۈچ بالداق -Name[uk]=Смужка вкладок -Name[wa]=Binde di linwetes -Name[x-test]=xxTabstripxx -Name[zh_CN]=Tabstrip -Name[zh_TW]=Tabstrip -X-KDE-Library=kwin3_tabstrip diff --git a/clients/tabstrip/tabstripbutton.cpp b/clients/tabstrip/tabstripbutton.cpp deleted file mode 100644 index 0479d38965..0000000000 --- a/clients/tabstrip/tabstripbutton.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/******************************************************************** -Tabstrip KWin window decoration -This file is part of the KDE project. - -Copyright (C) 2009 Jorge Mata -Copyright (C) 2009 Lucas Murray - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#include -#include "tabstripbutton.h" -#include "tabstripdecoration.h" -#include "tabstripfactory.h" - -#include - -#include -#include -#include -#include - -TabstripButton::TabstripButton( ButtonType type, TabstripDecoration *parent, QString tip ) - : KCommonDecorationButton( type, parent ), SIZE( 16 ) - { - setAutoFillBackground( false ); - setFixedSize( SIZE, SIZE ); - setCursor( Qt::ArrowCursor ); - client = parent; - btype = type; - setToolTip( tip ); - active_item = true; - hovering = false; - } - -TabstripButton::~TabstripButton() - { - } - -void TabstripButton::reset( unsigned long ) - { - update(); - } - -QSize TabstripButton::sizeHint() const - { - return QSize( SIZE, SIZE ); - } - -void TabstripButton::paintEvent( QPaintEvent * ) - { - QPainter p( this ); - const bool active = client->isActive() && active_item; - - // Icon geometry - QRect geom = QRect( 3, 3, width() - 6, height() - 6 ); - - // Determine painting colors - QColor bgColor = client->options()->color( KDecoration::ColorTitleBar, active ); - QColor textColor = client->options()->color( KDecoration::ColorFont, active ); - if( hovering ) - { // Invert if the mouse cursor is hovering over the button - textColor.setRed( 255 - textColor.red() ); - textColor.setGreen( 255 - textColor.green() ); - textColor.setBlue( 255 - textColor.blue() ); - } - - // Slight optimization as we are drawing solid straight lines - p.setRenderHint( QPainter::Antialiasing, false ); - - // Background - p.fillRect( 0, 0, width(), height(), bgColor ); - //p.fillRect( 0, 0, width(), height(), QColor( 255, 0, 0 )); - - // Paint buttons with the text color - p.setPen( textColor ); - - switch( btype ) - { - case HelpButton: - { - QFont font; - font.setBold( true ); - p.setFont( font ); - p.drawText( geom.adjusted( 0, 1, 0, 0), Qt::AlignVCenter | Qt::AlignHCenter, "?" ); - } - break; - case MaxButton: - switch( client->maximizeMode() ) - { - case TabstripDecoration::MaximizeRestore: - case TabstripDecoration::MaximizeVertical: - case TabstripDecoration::MaximizeHorizontal: - // TL - p.drawLine( geom.x() + 3, geom.y(), - geom.x(), geom.y() ); - p.drawLine( geom.x(), geom.y() + 3, - geom.x(), geom.y() ); - p.drawLine( geom.x() + 3, geom.y() + 1, - geom.x(), geom.y() + 1 ); - p.drawLine( geom.x() + 1, geom.y() + 3, - geom.x(), geom.y() + 1 ); - // TR - p.drawLine( geom.x() + geom.width() - 3, geom.y(), - geom.x() + geom.width(), geom.y() ); - p.drawLine( geom.x() + geom.width(), geom.y() + 3, - geom.x() + geom.width(), geom.y() ); - p.drawLine( geom.x() + geom.width() - 3, geom.y() + 1, - geom.x() + geom.width(), geom.y() + 1 ); - p.drawLine( geom.x() + geom.width() - 1, geom.y() + 3, - geom.x() + geom.width() - 1, geom.y() ); - // BL - p.drawLine( geom.x() + 3, geom.y() + geom.height(), - geom.x(), geom.y() + geom.height() ); - p.drawLine( geom.x(), geom.y() + geom.height() - 3, - geom.x(), geom.y() + geom.height() ); - p.drawLine( geom.x() + 3, geom.y() + geom.height() - 1, - geom.x(), geom.y() + geom.height() - 1 ); - p.drawLine( geom.x() + 1, geom.y() + geom.height() - 3, - geom.x() + 1, geom.y() + geom.height() ); - // BR - p.drawLine( geom.x() + geom.width() - 3, geom.y() + geom.height(), - geom.x() + geom.width(), geom.y() + geom.height() ); - p.drawLine( geom.x() + geom.width(), geom.y() + geom.height() - 3, - geom.x() + geom.width(), geom.y() + geom.height() ); - p.drawLine( geom.x() + geom.width() - 3, geom.y() + geom.height() - 1, - geom.x() + geom.width(), geom.y() + geom.height() - 1 ); - p.drawLine( geom.x() + geom.width() - 1, geom.y() + geom.height() - 3, - geom.x() + geom.width() - 1, geom.y() + geom.height() ); - break; - case TabstripDecoration::MaximizeFull: - // TL - p.drawLine( geom.x() + 2, geom.y(), - geom.x() + 2, geom.y() + 2 ); - p.drawLine( geom.x(), geom.y() + 2, - geom.x() + 2, geom.y() + 2 ); - p.drawLine( geom.x() + 3, geom.y(), - geom.x() + 3, geom.y() + 3 ); - p.drawLine( geom.x(), geom.y() + 3, - geom.x() + 3, geom.y() + 3 ); - // TR - p.drawLine( geom.x() + geom.width() - 2, geom.y(), - geom.x() + geom.width() - 2, geom.y() + 2 ); - p.drawLine( geom.x() + geom.width(), geom.y() + 2, - geom.x() + geom.width() - 2, geom.y() + 2 ); - p.drawLine( geom.x() + geom.width() - 3, geom.y(), - geom.x() + geom.width() - 3, geom.y() + 3 ); - p.drawLine( geom.x() + geom.width(), geom.y() + 3, - geom.x() + geom.width() - 3, geom.y() + 3 ); - // BL - p.drawLine( geom.x() + 2, geom.y() + geom.height(), - geom.x() + 2, geom.y() + geom.height() - 2 ); - p.drawLine( geom.x(), geom.y() + geom.height() - 2, - geom.x() + 2, geom.y() + geom.height() - 2 ); - p.drawLine( geom.x() + 3, geom.y() + geom.height(), - geom.x() + 3, geom.y() + geom.height() - 3 ); - p.drawLine( geom.x(), geom.y() + geom.height() - 3, - geom.x() + 3, geom.y() + geom.height() - 3 ); - // BR - p.drawLine( geom.x() + geom.width() - 2, geom.y() + geom.height(), - geom.x() + geom.width() - 2, geom.y() + geom.height() - 2 ); - p.drawLine( geom.x() + geom.width(), geom.y() + geom.height() - 2, - geom.x() + geom.width() - 2, geom.y() + geom.height() - 2 ); - p.drawLine( geom.x() + geom.width() - 3, geom.y() + geom.height(), - geom.x() + geom.width() - 3, geom.y() + geom.height() - 3 ); - p.drawLine( geom.x() + geom.width(), geom.y() + geom.height() - 3, - geom.x() + geom.width() - 3, geom.y() + geom.height() - 3 ); - break; - } - break; - case MinButton: - // B - p.drawLine( geom.x(), geom.y() + geom.height(), - geom.x() + geom.width(), geom.y() + geom.height() ); - p.drawLine( geom.x(), geom.y() + geom.height() - 1, - geom.x() + geom.width(), geom.y() + geom.height() - 1 ); - // L - p.drawLine( geom.x(), geom.y() + geom.height() - 3, - geom.x(), geom.y() + geom.height() ); - p.drawLine( geom.x() + 1, geom.y() + geom.height() - 3, - geom.x() + 1, geom.y() + geom.height() ); - // R - p.drawLine( geom.x() + geom.width(), geom.y() + geom.height() - 3, - geom.x() + geom.width(), geom.y() + geom.height() ); - p.drawLine( geom.x() + geom.width() - 1, geom.y() + geom.height() - 3, - geom.x() + geom.width() - 1, geom.y() + geom.height() ); - break; - case CloseButton: - case ItemCloseButton: - // TL-BR - p.drawLine( geom.x() + 1, geom.y() + 1, - geom.x() + geom.width() - 1, geom.y() + geom.height() - 1 ); - p.drawLine( geom.x() + 2, geom.y() + 1, - geom.x() + geom.width() - 1, geom.y() + geom.height() - 2 ); - p.drawLine( geom.x() + 1, geom.y() + 2, - geom.x() + geom.width() - 2, geom.y() + geom.height() - 1 ); - // TR-BL - p.drawLine( geom.x() + 1, geom.y() + geom.height() - 1, - geom.x() + geom.width() - 1, geom.y() + 1 ); - p.drawLine( geom.x() + 2, geom.y() + geom.height() - 1, - geom.x() + geom.width() - 1, geom.y() + 2 ); - p.drawLine( geom.x() + 1, geom.y() + geom.height() - 2, - geom.x() + geom.width() - 2, geom.y() + 1 ); - break; - case MenuButton: - if( client->clientGroupItems().count() > 1 || !TabstripFactory::showIcon() ) - { - p.drawRect( geom.x(), geom.y() + geom.height() / 2 - 5, - 1, 1 ); - p.drawRect( geom.x(), geom.y() + geom.height() / 2 - 1, - 1, 1 ); - p.drawRect( geom.x(), geom.y() + geom.height() / 2 + 3, - 1, 1 ); - p.drawRect( geom.x() + 4, geom.y() + geom.height() / 2 - 5, - geom.width() - 5, 1 ); - p.drawRect( geom.x() + 4, geom.y() + geom.height() / 2 - 1, - geom.width() - 5, 1 ); - p.drawRect( geom.x() + 4, geom.y() + geom.height() / 2 + 3, - geom.width() - 5, 1 ); - } - else - p.drawPixmap( 0, 0, client->icon().pixmap( SIZE )); - break; - case OnAllDesktopsButton: - { - if( isChecked() ) - p.fillRect( geom.x() + geom.width() / 2 - 1, geom.y() + geom.height() / 2 - 1, - 3, 3, textColor ); - else - { - p.fillRect( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 - 4, - 3, 3, textColor ); - p.fillRect( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 + 2, - 3, 3, textColor ); - p.fillRect( geom.x() + geom.width() / 2 + 2, geom.y() + geom.height() / 2 - 4, - 3, 3, textColor ); - p.fillRect( geom.x() + geom.width() / 2 + 2, geom.y() + geom.height() / 2 + 2, - 3, 3, textColor ); - } - } - break; - case AboveButton: - { - int o = -2; - if( isChecked() ) - { - o = -4; - p.drawRect( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 + 3, - 8, 1 ); - } - p.drawPoint( geom.x() + geom.width() / 2, geom.y() + geom.height() / 2 + o ); - p.drawLine( geom.x() + geom.width() / 2 - 1, geom.y() + geom.height() / 2 + o + 1, - geom.x() + geom.width() / 2 + 1, geom.y() + geom.height() / 2 + o + 1 ); - p.drawLine( geom.x() + geom.width() / 2 - 2, geom.y() + geom.height() / 2 + o + 2, - geom.x() + geom.width() / 2 + 2, geom.y() + geom.height() / 2 + o + 2 ); - p.drawLine( geom.x() + geom.width() / 2 - 3, geom.y() + geom.height() / 2 + o + 3, - geom.x() + geom.width() / 2 + 3, geom.y() + geom.height() / 2 + o + 3 ); - p.drawLine( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 + o + 4, - geom.x() + geom.width() / 2 + 4, geom.y() + geom.height() / 2 + o + 4 ); - } - break; - case BelowButton: - { - int o = 1; - if( isChecked() ) - { - o = 3; - p.drawRect( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 - 5, - 8, 1 ); - } - p.drawPoint( geom.x() + geom.width() / 2, geom.y() + geom.height() / 2 + o ); - p.drawLine( geom.x() + geom.width() / 2 - 1, geom.y() + geom.height() / 2 + o - 1, - geom.x() + geom.width() / 2 + 1, geom.y() + geom.height() / 2 + o - 1 ); - p.drawLine( geom.x() + geom.width() / 2 - 2, geom.y() + geom.height() / 2 + o - 2, - geom.x() + geom.width() / 2 + 2, geom.y() + geom.height() / 2 + o - 2 ); - p.drawLine( geom.x() + geom.width() / 2 - 3, geom.y() + geom.height() / 2 + o - 3, - geom.x() + geom.width() / 2 + 3, geom.y() + geom.height() / 2 + o - 3 ); - p.drawLine( geom.x() + geom.width() / 2 - 4, geom.y() + geom.height() / 2 + o - 4, - geom.x() + geom.width() / 2 + 4, geom.y() + geom.height() / 2 + o - 4 ); - } - break; - case ShadeButton: - p.drawLine( geom.x(), geom.y(), - geom.x() + geom.width(), geom.y() ); - p.drawLine( geom.x(), geom.y() + 1, - geom.x() + geom.width(), geom.y() + 1 ); - break; - case NumButtons: - default: - break; - }; - } - -void TabstripButton::enterEvent( QEvent *e ) - { - hovering = true; - repaint(); - KCommonDecorationButton::enterEvent( e ); - } - -void TabstripButton::leaveEvent( QEvent *e ) - { - hovering = false; - repaint(); - KCommonDecorationButton::leaveEvent( e ); - } diff --git a/clients/tabstrip/tabstripbutton.h b/clients/tabstrip/tabstripbutton.h deleted file mode 100644 index ea062306b0..0000000000 --- a/clients/tabstrip/tabstripbutton.h +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************** -Tabstrip KWin window decoration -This file is part of the KDE project. - -Copyright (C) 2009 Jorge Mata -Copyright (C) 2009 Lucas Murray - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#ifndef TABSTRIPBUTTON_H -#define TABSTRIPBUTTON_H - -#include -#include -#include - -class TabstripDecoration; - -class TabstripButton : public KCommonDecorationButton - { - public: - TabstripButton( ButtonType type, TabstripDecoration *parent, QString tip ); - ~TabstripButton(); - void reset( unsigned long changed ); - QSize sizeHint() const; - void setActive( bool active ); - private: - void paintEvent( QPaintEvent *e ); - void leaveEvent( QEvent *e ); - void enterEvent( QEvent *e ); - TabstripDecoration *client; - ButtonType btype; - const int SIZE; - bool active_item; - bool hovering; - }; - -inline void TabstripButton::setActive( bool active ) - { - active_item = active; - } - -#endif diff --git a/clients/tabstrip/tabstripdecoration.cpp b/clients/tabstrip/tabstripdecoration.cpp deleted file mode 100644 index a159a96e4c..0000000000 --- a/clients/tabstrip/tabstripdecoration.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/******************************************************************** -Tabstrip KWin window decoration -This file is part of the KDE project. - -Copyright (C) 2009 Jorge Mata -Copyright (C) 2009 Lucas Murray - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#include "tabstripdecoration.h" -#include "tabstripbutton.h" -#include "tabstripfactory.h" - -#include - -#include - -TabstripDecoration::TabstripDecoration( KDecorationBridge *bridge, KDecorationFactory *factory ) - : KCommonDecorationUnstable( bridge, factory ) - { - click_in_progress = false; - drag_in_progress = false; - button = Qt::NoButton; - } - -KCommonDecorationButton *TabstripDecoration::createButton( ButtonType type ) - { - switch( type ) - { - case HelpButton: - return ( new TabstripButton( type, this, i18n("Help") ) ); - break; - case MaxButton: - return ( new TabstripButton( type, this, i18n("Maximize") ) ); - break; - case MinButton: - return ( new TabstripButton( type, this, i18n("Minimize") ) ); - break; - case CloseButton: - return ( new TabstripButton( type, this, i18n("Close") ) ); - break; - case MenuButton: - return ( new TabstripButton( type, this, i18n("Menu") ) ); - break; - case OnAllDesktopsButton: - return ( new TabstripButton( type, this, i18n("All Desktops") ) ); - break; - case AboveButton: - return ( new TabstripButton( type, this, i18n("Above") ) ); - break; - case BelowButton: - return ( new TabstripButton( type, this, i18n("Below") ) ); - break; - case ShadeButton: - return ( new TabstripButton( type, this, i18n("Shade") ) ); - break; - default: - break; - }; - return 0; - } - -void TabstripDecoration::paintTab( QPainter &painter, const QRect &geom, ClientGroupItem &item, bool active ) - { - // Determine painting colors - QColor bgColor = options()->color( ColorTitleBar, active ); - QColor textColor = options()->color( ColorFont, active ); - - // Draw border around the tab - painter.setPen( Qt::black ); - painter.drawRect( geom.adjusted( 0, 0, -1, -1 )); - painter.setPen( TabstripFactory::outlineColor() ); - painter.drawRect( geom.adjusted( 1, 1, -2, -2 )); - - // Background - painter.fillRect( geom.adjusted( 2, 2, -2, -2 ), bgColor ); - - // Window title and icon - painter.setPen( textColor ); - if( TabstripFactory::showIcon() ) - { - QRect rect( geom.x() + 25, geom.y(), geom.width() - 48, geom.height() ); - QRect text; - QFont font = options()->font( active ); - QFontMetrics metrics( font ); - QString string = metrics.elidedText( item.title(), Qt::ElideRight, rect.width() ); - painter.setFont( font ); - painter.drawText( rect, TabstripFactory::titleAlign() | Qt::AlignVCenter, string, &text ); - painter.drawPixmap( text.x() - 22, rect.y() + 3, item.icon().pixmap( 16 )); - } - else - { - QRect rect( geom.x() + 5, geom.y(), geom.width() - 28, geom.height() ); - QFont font = options()->font( active ); - QFontMetrics metrics( font ); - QString string = metrics.elidedText( item.title(), Qt::ElideRight, rect.width() ); - painter.setFont( font ); - painter.drawText( rect, TabstripFactory::titleAlign() | Qt::AlignVCenter, string ); - } - } - -void TabstripDecoration::paintEvent( QPaintEvent * ) - { - QPainter painter( widget() ); - - // Determine painting colors - QColor bgColor = options()->color( ColorTitleBar, isClientGroupActive() ); - QColor textColor = options()->color( ColorFont, isClientGroupActive() ); - - // Determine section geometry - QRect frame( QPoint( 0, 0 ), widget()->frameGeometry().size() ); - QRect titlebar( frame.topLeft(), QSize( frame.width(), - layoutMetric( LM_TitleEdgeTop ) + layoutMetric( LM_TitleHeight ) + - layoutMetric( LM_TitleEdgeBottom ) - 1 // Titlebar and main frame overlap by 1px - )); - - // Slight optimization as we are drawing solid straight lines - painter.setRenderHint( QPainter::Antialiasing, false ); - - // Draw black/white border around the main window - painter.setPen( Qt::black ); - painter.drawRect( 0, titlebar.height() - 1, frame.width() - 1, frame.height() - titlebar.height() ); - painter.setPen( TabstripFactory::outlineColor() ); - painter.drawRect( 1, titlebar.height(), frame.width() - 3, frame.height() - titlebar.height() - 2 ); - - QList< ClientGroupItem > tabList = clientGroupItems(); - const int tabCount = tabList.count(); - - // Delete unneeded tab close buttons - while( tabCount < closeButtons.size() || ( tabCount == 1 && closeButtons.size() > 0 )) - { - TabstripButton *btn = closeButtons.takeFirst(); - btn->hide(); - btn->deleteLater(); - } - - if( tabCount > 1 ) - { - QRect allTabGeom = titleRect().adjusted( -1, -layoutMetric( LM_TitleEdgeTop ), 1, 0 ); - QRect tabGeom = allTabGeom; - tabGeom.setWidth( tabGeom.width() / tabCount + 1 ); // Split titlebar evenly - for( int i = 0; i < tabCount; ++i ) - { - // Last tab may have a different width due to rounding - if( i == tabCount - 1 ) - tabGeom.setWidth( allTabGeom.width() - tabGeom.width() * i + i - 1 ); - - // Actually paint the tab - paintTab( painter, tabGeom, tabList[i], isActive() && visibleClientGroupItem() == i ); - - // Create new close button if required - if( i >= closeButtons.size() ) - closeButtons.append( new TabstripButton( ItemCloseButton, this, i18n( "Close Item" ) ) ); - closeButtons[ i ]->setActive( isActive() && visibleClientGroupItem() == i ); - closeButtons[ i ]->move( tabGeom.right() - 18, tabGeom.bottom() - 18 ); - closeButtons[ i ]->installEventFilter( this ); - closeButtons[ i ]->show(); - - // Prepare for next iteration - tabGeom.translate( tabGeom.width() - 1, 0 ); - } - - // Draw border around the buttons - painter.setPen( Qt::black ); - painter.drawRect( 0, 0, allTabGeom.left(), allTabGeom.height() - 1 ); - painter.drawRect( allTabGeom.right() - 1, 0, frame.width() - allTabGeom.right(), allTabGeom.height() - 1 ); - painter.setPen( TabstripFactory::outlineColor() ); - painter.drawRect( 1, 1, allTabGeom.left() - 2, allTabGeom.height() - 3 ); - painter.drawRect( allTabGeom.right(), 1, frame.width() - allTabGeom.right() - 2, allTabGeom.height() - 3 ); - - // Background behind the buttons - painter.fillRect( 2, 2, allTabGeom.left() - 3, allTabGeom.height() - 4, bgColor ); - painter.fillRect( allTabGeom.right() + 1, 2, frame.width() - allTabGeom.right() - 3, allTabGeom.height() - 4, bgColor ); - } - else - { - // Draw border around the titlebar - painter.setPen( Qt::black ); - painter.drawRect( titlebar.adjusted( 0, 0, -1, -1 )); - painter.setPen( TabstripFactory::outlineColor() ); - painter.drawRect( titlebar.adjusted( 1, 1, -2, -2 )); - - // Background - painter.fillRect( titlebar.adjusted( 2, 2, -2, -2 ), bgColor ); - - // Window title - painter.setPen( textColor ); - QRect rect( titleRect().x() + 2, titleRect().y(), - titleRect().width() - 6, titleRect().height() - 3 ); - QFont font = options()->font( isActive() ); - QFontMetrics metrics( font ); - QString string = metrics.elidedText( caption(), Qt::ElideRight, rect.width() ); - painter.setFont( font ); - painter.drawText( rect, TabstripFactory::titleAlign() | Qt::AlignVCenter, string ); - } - } - -QString TabstripDecoration::visibleName() const - { - return i18n("Tabstrip"); - } - -void TabstripDecoration::init() - { - KCommonDecoration::init(); - widget()->setAutoFillBackground( false ); - widget()->setAttribute( Qt::WA_OpaquePaintEvent ); - widget()->setAcceptDrops( true ); - } - - -bool TabstripDecoration::eventFilter( QObject* o, QEvent* e ) - { - if( TabstripButton *btn = dynamic_cast< TabstripButton* >( o )) - { - if( e->type() == QEvent::MouseButtonPress ) - return true; // No-op - else if( e->type() == QEvent::MouseButtonRelease ) - { - const QMouseEvent* me = static_cast< QMouseEvent* >( e ); - if( me->button() == Qt::LeftButton && btn->rect().contains( me->pos() )) - closeClientGroupItem( closeButtons.indexOf( btn )); - return true; - } - } - - bool state = false; - if( e->type() == QEvent::MouseButtonPress ) - state = mouseButtonPressEvent( static_cast< QMouseEvent* >( e )); - else if( e->type() == QEvent::MouseButtonRelease && widget() == o ) - state = mouseButtonReleaseEvent( static_cast< QMouseEvent* >( e )); - else if( e->type() == QEvent::MouseMove ) - state = mouseMoveEvent( static_cast< QMouseEvent* >( e )); - else if( e->type() == QEvent::DragEnter && widget() == o ) - state = dragEnterEvent( static_cast< QDragEnterEvent* >( e )); - else if( e->type() == QEvent::DragMove && widget() == o ) - state = dragMoveEvent( static_cast< QDragMoveEvent* >( e )); - else if( e->type() == QEvent::DragLeave && widget() == o ) - state = dragLeaveEvent( static_cast< QDragLeaveEvent* >( e )); - else if( e->type() == QEvent::Drop && widget() == o ) - state = dropEvent( static_cast< QDropEvent* >( e )); - - return state || KCommonDecorationUnstable::eventFilter( o, e ); - } - -bool TabstripDecoration::mouseButtonPressEvent( QMouseEvent* e ) - { - click = widget()->mapToParent( e->pos() ); - int item = itemClicked( click ); - if( buttonToWindowOperation( e->button() ) == OperationsOp ) - { - displayClientMenu( item, widget()->mapToGlobal( click )); - return true; - } - if( item >= 0 ) - { - click_in_progress = true; - button = e->button(); - return true; - } - click_in_progress = false; - return false; - } - -bool TabstripDecoration::mouseButtonReleaseEvent( QMouseEvent* e ) - { - release = e->pos(); - int item = itemClicked( release ); - if( click_in_progress && item >= 0 ) - { - click_in_progress = false; - setVisibleClientGroupItem( item ); - return true; - } - click_in_progress = false; - return false; - } - -bool TabstripDecoration::mouseMoveEvent( QMouseEvent* e ) - { - QPoint c = e->pos(); - int item = itemClicked( c ); - if( item >= 0 && click_in_progress && buttonToWindowOperation( button ) == ClientGroupDragOp && - ( c - click ).manhattanLength() >= 4 ) - { - click_in_progress = false; - drag_in_progress = true; - QDrag *drag = new QDrag( widget() ); - QMimeData *group_data = new QMimeData(); - group_data->setData( clientGroupItemDragMimeType(), QString().setNum( itemId( item )).toAscii() ); - drag->setMimeData( group_data ); - - // Create draggable tab pixmap - QList< ClientGroupItem > tabList = clientGroupItems(); - const int tabCount = tabList.count(); - QRect frame( QPoint( 0, 0 ), widget()->frameGeometry().size() ); - QRect titlebar( frame.topLeft(), QSize( frame.width(), - layoutMetric( LM_TitleEdgeTop ) + layoutMetric( LM_TitleHeight ) + - layoutMetric( LM_TitleEdgeBottom ) - 1 // Titlebar and main frame overlap by 1px - )); - QRect geom = titleRect().adjusted( -1, -layoutMetric( LM_TitleEdgeTop ), 1, 0 ); - geom.setWidth( geom.width() / tabCount + 1 ); // Split titlebar evenly - geom.translate( geom.width() * item - item, 0 ); - QPixmap pix( geom.size() ); - QPainter painter( &pix ); - paintTab( painter, QRect( QPoint( 0, 0 ), geom.size() ), tabList[item], - isActive() && visibleClientGroupItem() == item ); - drag->setPixmap( pix ); - // If the cursor is on top of the pixmap then it makes the movement jerky on some systems - //drag->setHotSpot( QPoint( c.x() - geom.x(), c.y() - geom.y() )); - drag->setHotSpot( QPoint( c.x() - geom.x(), -1 )); - - drag->exec( Qt::MoveAction ); - drag_in_progress = false; - if( drag->target() == 0 && tabList.count() > 1 ) - { // Remove window from group and move to where the cursor is located - QPoint pos = QCursor::pos(); - frame.moveTo( pos.x() - c.x(), pos.y() - c.y() ); - removeFromClientGroup( itemClicked( click ), frame ); - } - return true; - } - return false; - } - -bool TabstripDecoration::dragEnterEvent( QDragEnterEvent* e ) - { - if( e->source() != 0 && e->source()->objectName() == "decoration widget" ) - { - drag_in_progress = true; - e->acceptProposedAction(); - QPoint point = widget()->mapToParent( e->pos() ); - targetTab = itemClicked( point ); - widget()->update(); - return true; - } - return false; - } - -bool TabstripDecoration::dropEvent( QDropEvent* e ) - { - QPoint point = widget()->mapToParent( e->pos() ); - drag_in_progress = false; - int tabClick = itemClicked( point ); - if( tabClick >= 0 ) - { - const QMimeData *group_data = e->mimeData(); - if( group_data->hasFormat( clientGroupItemDragMimeType() ) ) - { - if( widget() == e->source() ) - { - int from = itemClicked( click ); - moveItemInClientGroup( from, itemClicked( point, true )); - } - else - { - long source = QString( group_data->data( clientGroupItemDragMimeType() ) ).toLong(); - moveItemToClientGroup( source, itemClicked( point, true )); - } - return true; - } - } - return false; - } - -bool TabstripDecoration::dragMoveEvent( QDragMoveEvent* ) - { - return false; - } - -bool TabstripDecoration::dragLeaveEvent( QDragLeaveEvent* ) - { - return false; - } - -int TabstripDecoration::layoutMetric(LayoutMetric lm, bool respectWindowState, const KCommonDecorationButton *button) const - { - switch ( lm ) - { - case LM_BorderBottom: - return 2; - case LM_BorderLeft: - case LM_BorderRight: - return 2; - case LM_TitleHeight: - return 17; - case LM_TitleBorderLeft: - return 3; - case LM_TitleBorderRight: - return 1; - case LM_TitleEdgeTop: - case LM_TitleEdgeBottom: - case LM_TitleEdgeLeft: - case LM_TitleEdgeRight: - return 3; - case LM_ButtonWidth: - case LM_ButtonHeight: - return 16; - case LM_ButtonSpacing: - return 6; - case LM_ExplicitButtonSpacer: - return -2; - default: - return KCommonDecoration::layoutMetric( lm, respectWindowState, button ); - break; - } - } - -int TabstripDecoration::itemClicked( const QPoint &point, bool between ) - { - QRect frame = widget()->frameGeometry(); - QList< ClientGroupItem > list = clientGroupItems(); - int tabs = list.count(); - int t_x = titleRect().x(); - int t_y = frame.y(); - int t_w = titleRect().width(); - int t_h = layoutMetric( LM_TitleEdgeTop ) + layoutMetric( LM_TitleHeight ) + layoutMetric( LM_TitleEdgeBottom ); - int tabWidth = t_w/tabs; - if( between ) // We are inserting a new tab between two existing ones - t_x -= tabWidth / 2; - int rem = t_w%tabs; - int tab_x = t_x; - for( int i = 0; i < tabs; ++i ) - { - QRect tabRect( tab_x, t_y, i -Copyright (C) 2009 Lucas Murray - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#ifndef TABSTRIPDECORATION_H -#define TABSTRIPDECORATION_H - -#include -#include -#include -#include - -class TabstripButton; - -class TabstripDecoration : public KCommonDecorationUnstable - { - public: - TabstripDecoration( KDecorationBridge *bridge, KDecorationFactory *factory ); - KCommonDecorationButton *createButton( ButtonType type ); - void init(); - QString visibleName() const; - virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton *button = 0) const; - virtual bool eventFilter( QObject* o, QEvent* e ); - private: - void paintTab( QPainter &painter, const QRect &geom, ClientGroupItem &item, bool active ); - void paintEvent( QPaintEvent *e ); - bool mouseSingleClickEvent( QMouseEvent* e ); - bool mouseMoveEvent( QMouseEvent* e ); - bool mouseButtonPressEvent( QMouseEvent* e ); - bool mouseButtonReleaseEvent( QMouseEvent* e ); - bool dragMoveEvent( QDragMoveEvent* e ); - bool dragLeaveEvent( QDragLeaveEvent* e ); - bool dragEnterEvent( QDragEnterEvent* e ); - bool dropEvent( QDropEvent* e ); - int itemClicked( const QPoint &point, bool between = false ); - QList< TabstripButton* > closeButtons; - QPoint click, release; - int targetTab; - bool click_in_progress, drag_in_progress; - Qt::MouseButton button; - }; - -#endif diff --git a/clients/tabstrip/tabstripfactory.cpp b/clients/tabstrip/tabstripfactory.cpp deleted file mode 100644 index 6b34c01562..0000000000 --- a/clients/tabstrip/tabstripfactory.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/******************************************************************** -Tabstrip KWin window decoration -This file is part of the KDE project. - -Copyright (C) 2009 Jorge Mata -Copyright (C) 2009 Lucas Murray - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#include "tabstripfactory.h" -#include "tabstripdecoration.h" - -#include -#include -#include - -extern "C" - { - KDE_EXPORT KDecorationFactory *create_factory() - { - return new TabstripFactory(); - } - } - -Qt::AlignmentFlag TabstripFactory::titlealign = Qt::AlignCenter; -bool TabstripFactory::show_icon = true; -QColor TabstripFactory::outline_color = Qt::white; - -TabstripFactory::TabstripFactory() - { - initialized = false; - readConfig(); - initialized = true; - } - -TabstripFactory::~TabstripFactory() - { - } - -KDecoration *TabstripFactory::createDecoration( KDecorationBridge *bridge ) - { - return ( new TabstripDecoration( bridge, this ) )->decoration(); - } - -bool TabstripFactory::supports( Ability ability ) const - { - switch( ability ) - { - case AbilityButtonMenu: - case AbilityAnnounceColors: - case AbilityButtonOnAllDesktops: - case AbilityButtonSpacer: - case AbilityButtonHelp: - case AbilityButtonMinimize: - case AbilityButtonMaximize: - case AbilityButtonClose: - case AbilityButtonAboveOthers: - case AbilityButtonBelowOthers: - case AbilityButtonShade: - case AbilityClientGrouping: - return true; - default: - return false; - }; - } - -bool TabstripFactory::readConfig() - { - KConfig config( "tabstriprc" ); - KConfigGroup cg = config.group( "General" ); - Qt::AlignmentFlag oldalign = titlealign; - QString align = cg.readEntry( "TitleAlignment", "Center" ); - if( align == "Left" ) - titlealign = Qt::AlignLeft; - else if( align == "Center" ) - titlealign = Qt::AlignHCenter; - else if( align == "Right" ) - titlealign = Qt::AlignRight; - show_icon = cg.readEntry( "ShowIcon", true ); - outline_color = cg.readEntry( "OutlineColor", QColor( Qt::white ) ); - return ( titlealign != oldalign ); - } - -bool TabstripFactory::reset( unsigned long changed ) - { - initialized = false; - bool c_change = readConfig(); - initialized = true; - if( c_change || ( changed & ( SettingDecoration | SettingButtons | SettingBorder ) ) ) - return true; - else - { - resetDecorations( changed ); - return false; - } - } - -QList< KDecorationDefines::BorderSize > TabstripFactory::borderSizes() const - { - return QList< BorderSize >() << BorderNormal; - } diff --git a/clients/tabstrip/tabstripfactory.h b/clients/tabstrip/tabstripfactory.h deleted file mode 100644 index 0b610c21d3..0000000000 --- a/clients/tabstrip/tabstripfactory.h +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************** -Tabstrip KWin window decoration -This file is part of the KDE project. - -Copyright (C) 2009 Jorge Mata -Copyright (C) 2009 Lucas Murray - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*********************************************************************/ - -#ifndef TABSTRIPFACTORY_H -#define TABSTRIPFACTORY_H - -#include -#include -#include - -class TabstripFactory : public KDecorationFactoryUnstable - { - public: - TabstripFactory(); - ~TabstripFactory(); - KDecoration *createDecoration( KDecorationBridge *bridge ); - bool supports( Ability ability ) const; - bool reset( unsigned long changed ); - QList< KDecorationDefines::BorderSize > borderSizes() const; - static Qt::AlignmentFlag titleAlign(); - static bool showIcon(); - static QColor &outlineColor(); - private: - bool readConfig(); - bool initialized; - static Qt::AlignmentFlag titlealign; - static bool show_icon; - static QColor outline_color; - }; - -inline Qt::AlignmentFlag TabstripFactory::titleAlign() - { - return titlealign; - } - -inline bool TabstripFactory::showIcon() - { - return show_icon; - } -inline QColor &TabstripFactory::outlineColor() - { - return outline_color; - } - -#endif diff --git a/effects.cpp b/effects.cpp index 4f55799b5c..9602df33c8 100644 --- a/effects.cpp +++ b/effects.cpp @@ -385,11 +385,13 @@ void EffectsHandlerImpl::slotUnmanagedAdded(Unmanaged *u) emit windowAdded(u->effectWindow()); } -void EffectsHandlerImpl::slotClientShown(KWin::Toplevel *c) +void EffectsHandlerImpl::slotClientShown(KWin::Toplevel *t) { - Q_ASSERT(dynamic_cast(c)); - setupClientConnections(static_cast(c)); - emit windowAdded(c->effectWindow()); + Q_ASSERT(dynamic_cast(t)); + Client *c = static_cast(t); + setupClientConnections(c); + if (!c->tabGroup()) // the "window" has already been there + emit windowAdded(c->effectWindow()); } void EffectsHandlerImpl::slotDeletedRemoved(KWin::Deleted *d) @@ -424,19 +426,19 @@ void EffectsHandlerImpl::slotClientUnminimized(Client* c, bool animate) } } -void EffectsHandlerImpl::slotClientGroupItemSwitched(EffectWindow* from, EffectWindow* to) +void EffectsHandlerImpl::slotCurrentTabAboutToChange(EffectWindow *from, EffectWindow *to) { - emit clientGroupItemSwitched(from, to); + emit currentTabAboutToChange(from, to); } -void EffectsHandlerImpl::slotClientGroupItemAdded(EffectWindow* from, EffectWindow* to) +void EffectsHandlerImpl::slotTabAdded(EffectWindow* w, EffectWindow* to) { - emit clientGroupItemAdded(from, to); + emit tabAdded(w, to); } -void EffectsHandlerImpl::slotClientGroupItemRemoved(EffectWindow* c, EffectWindow* group) +void EffectsHandlerImpl::slotTabRemoved(EffectWindow *w, EffectWindow* leaderOfFormerGroup) { - emit clientGroupItemRemoved(c, group); + emit tabRemoved(w, leaderOfFormerGroup); } void EffectsHandlerImpl::slotDesktopChanged(int old) diff --git a/effects.h b/effects.h index 28ab72c303..40f219cbb7 100644 --- a/effects.h +++ b/effects.h @@ -175,9 +175,9 @@ public: QStringList activeEffects() const; public Q_SLOTS: - void slotClientGroupItemSwitched(EffectWindow* from, EffectWindow* to); - void slotClientGroupItemAdded(EffectWindow* from, EffectWindow* to); - void slotClientGroupItemRemoved(EffectWindow* c, EffectWindow* group); + void slotCurrentTabAboutToChange(EffectWindow* from, EffectWindow* to); + void slotTabAdded(EffectWindow* from, EffectWindow* to); + void slotTabRemoved(EffectWindow* c, EffectWindow* newActiveWindow); void slotShowOutline(const QRect &geometry); void slotHideOutline(); diff --git a/effects/boxswitch/boxswitch.cpp b/effects/boxswitch/boxswitch.cpp index fac6b3f019..68a820c90d 100644 --- a/effects/boxswitch/boxswitch.cpp +++ b/effects/boxswitch/boxswitch.cpp @@ -96,7 +96,7 @@ void BoxSwitchEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, if (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) { if (windows.contains(w)) { if (w == selected_window) - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP); + w->enablePainting(EffectWindow::PAINT_DISABLED_BY_TAB_GROUP); else data.setTranslucent(); w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP); diff --git a/effects/desktopgrid/desktopgrid.cpp b/effects/desktopgrid/desktopgrid.cpp index 925d2f1136..e0beace1c0 100644 --- a/effects/desktopgrid/desktopgrid.cpp +++ b/effects/desktopgrid/desktopgrid.cpp @@ -383,7 +383,7 @@ void DesktopGridEffect::slotWindowAdded(EffectWindow* w) if (!activated) return; if (isUsingPresentWindows()) { - if (w->isDesktop() || w->isDock() || !w->visibleInClientGroup()) + if (w->isDesktop() || w->isDock() || !w->isCurrentTab()) return; // don't add if (w->isOnAllDesktops()) { for (int i = 0; i < effects->numberOfDesktops(); i++) { @@ -1103,7 +1103,7 @@ void DesktopGridEffect::setup() WindowMotionManager manager; foreach (EffectWindow * w, effects->stackingOrder()) { if (w->isOnDesktop(i) && w->screen() == j && !w->isDesktop() && !w->isDock() && - w->visibleInClientGroup() && !w->isSkipSwitcher() && w->isOnCurrentActivity()) { + w->isCurrentTab() && !w->isSkipSwitcher() && w->isOnCurrentActivity()) { manager.manage(w); } } @@ -1319,7 +1319,7 @@ void DesktopGridEffect::desktopsAdded(int old) WindowMotionManager manager; foreach (EffectWindow * w, effects->stackingOrder()) { if (w->isOnDesktop(i) && w->screen() == j && !w->isDesktop() && !w->isDock() && - w->visibleInClientGroup()) { + w->isCurrentTab()) { manager.manage(w); } } @@ -1358,7 +1358,7 @@ void DesktopGridEffect::desktopsRemoved(int old) WindowMotionManager& manager = m_managers[(desktop-1)*(effects->numScreens())+j ]; foreach (EffectWindow * w, effects->stackingOrder()) { if (!manager.isManaging(w) && w->isOnDesktop(desktop) && w->screen() == j && - !w->isDesktop() && !w->isDock() && w->visibleInClientGroup()) { + !w->isDesktop() && !w->isDock() && w->isCurrentTab()) { manager.manage(w); } } diff --git a/effects/flipswitch/flipswitch.cpp b/effects/flipswitch/flipswitch.cpp index f7f430728d..26036459c8 100644 --- a/effects/flipswitch/flipswitch.cpp +++ b/effects/flipswitch/flipswitch.cpp @@ -471,8 +471,8 @@ void FlipSwitchEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); if (w->isMinimized()) w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); - if (!w->visibleInClientGroup()) - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP); + if (!w->isCurrentTab()) + w->enablePainting(EffectWindow::PAINT_DISABLED_BY_TAB_GROUP); } else { if ((m_start || m_stop) && !w->isDesktop() && w->isOnCurrentDesktop()) data.setTranslucent(); diff --git a/effects/highlightwindow/highlightwindow.cpp b/effects/highlightwindow/highlightwindow.cpp index f048cfbe18..e57a6f9081 100644 --- a/effects/highlightwindow/highlightwindow.cpp +++ b/effects/highlightwindow/highlightwindow.cpp @@ -53,7 +53,7 @@ HighlightWindowEffect::~HighlightWindowEffect() static bool isInitiallyHidden(EffectWindow* w) { // Is the window initially hidden until it is highlighted? - return w->isMinimized() || !w->visibleInClientGroup() || !w->isOnCurrentDesktop(); + return w->isMinimized() || !w->isCurrentTab() || !w->isOnCurrentDesktop(); } void HighlightWindowEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) @@ -97,8 +97,8 @@ void HighlightWindowEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& if (opacity != m_windowOpacity.end() && *opacity > 0.01) { if (w->isMinimized()) w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); - if (!w->visibleInClientGroup()) - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP); + if (!w->isCurrentTab()) + w->enablePainting(EffectWindow::PAINT_DISABLED_BY_TAB_GROUP); if (!w->isOnCurrentDesktop()) w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); } diff --git a/effects/presentwindows/presentwindows.cpp b/effects/presentwindows/presentwindows.cpp index fc725d9ac8..86ab0f5077 100755 --- a/effects/presentwindows/presentwindows.cpp +++ b/effects/presentwindows/presentwindows.cpp @@ -277,7 +277,7 @@ void PresentWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &d w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); // Display always w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); if (winData->visible) - w->enablePainting(EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP); + w->enablePainting(EffectWindow::PAINT_DISABLED_BY_TAB_GROUP); // Calculate window's opacity // TODO: Minimized windows or windows not on the current desktop are only 75% visible? @@ -1711,7 +1711,7 @@ void PresentWindowsEffect::setActive(bool active, bool closingTab) DataHash::iterator winData = m_windowData.find(w); if (winData != m_windowData.end()) winData->visible = (w->isOnDesktop(desktop) || w->isOnAllDesktops()) && - !w->isMinimized() && (w->visibleInClientGroup() || winData->visible); + !w->isMinimized() && (w->isCurrentTab() || winData->visible); } delete m_closeView; m_closeView = 0; @@ -1766,7 +1766,7 @@ bool PresentWindowsEffect::isSelectableWindow(EffectWindow *w) return false; if (!w->acceptsFocus()) return false; - if (!w->visibleInClientGroup()) + if (!w->isCurrentTab()) return false; if (w->isSkipSwitcher()) return false; diff --git a/effects/slideback/slideback.cpp b/effects/slideback/slideback.cpp index 380b3d52af..74abcdd605 100644 --- a/effects/slideback/slideback.cpp +++ b/effects/slideback/slideback.cpp @@ -334,7 +334,7 @@ bool SlideBackEffect::isWindowOnTop(EffectWindow* w) bool SlideBackEffect::isWindowUsable(EffectWindow* w) { return w && (w->isNormalWindow() || w->isDialog()) && !w->keepAbove() && !w->isDeleted() && !w->isMinimized() - && w->visibleInClientGroup(); + && w->isCurrentTab(); } bool SlideBackEffect::intersects(EffectWindow* windowUnder, const QRect &windowOverGeometry) diff --git a/events.cpp b/events.cpp index 45d64116ca..e249eca122 100644 --- a/events.cpp +++ b/events.cpp @@ -1207,7 +1207,7 @@ bool Client::processDecorationButtonPress(int button, int /*state*/, int x, int if (button == Button1 && com != Options::MouseOperationsMenu // actions where it's not possible to get the matching && com != Options::MouseMinimize // mouse release event - && com != Options::MouseClientGroupDrag) { + && com != Options::MouseDragTab) { mode = mousePosition(QPoint(x, y)); buttonDown = true; moveOffset = QPoint(x - padding_left, y - padding_top); @@ -1227,7 +1227,7 @@ bool Client::processDecorationButtonPress(int button, int /*state*/, int x, int com == Options::MouseActivate || com == Options::MouseActivateRaiseAndPassClick || com == Options::MouseActivateAndPassClick || - com == Options::MouseClientGroupDrag || + com == Options::MouseDragTab || com == Options::MouseNothing); } @@ -1276,7 +1276,7 @@ bool Client::buttonReleaseEvent(Window w, int /*button*/, int state, int x, int // mouse position is still relative to old Client position, adjust it QPoint mousepos(x_root - x + padding_left, y_root - y + padding_top); mode = mousePosition(mousepos); - } else if (workspace()->decorationSupportsClientGrouping()) + } else if (workspace()->decorationSupportsTabbing()) return false; updateCursor(); } diff --git a/geometry.cpp b/geometry.cpp index f577e196c8..6d47078e95 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -416,7 +416,7 @@ QPoint Workspace::adjustClientPosition(Client* c, QPoint pos, bool unrestricted, if ((((*l)->isOnDesktop(c->desktop()) && !(*l)->isMinimized()) || (c->isOnDesktop(NET::OnAllDesktops) && (*l)->isOnDesktop(Workspace::currentDesktop()) && !(*l)->isMinimized())) - && (!(*l)->clientGroup() || (*l) == (*l)->clientGroup()->visible()) + && (!(*l)->tabGroup() || (*l) == (*l)->tabGroup()->current()) && (*l) != c) { lx = (*l)->x(); ly = (*l)->y(); @@ -1257,8 +1257,8 @@ QSize Client::sizeForClientSize(const QSize& wsize, Sizemode mode, bool noframe) // basesize, minsize, maxsize, paspect and resizeinc have all values defined, // even if they're not set in flags - see getWmNormalHints() - QSize min_size = clientGroup() ? clientGroup()->minSize() : minSize(); - QSize max_size = clientGroup() ? clientGroup()->maxSize() : maxSize(); + QSize min_size = tabGroup() ? tabGroup()->minSize() : minSize(); + QSize max_size = tabGroup() ? tabGroup()->maxSize() : maxSize(); if (decoration != NULL) { QSize decominsize = decoration->minimumSize(); QSize border_size(border_left + border_right, border_top + border_bottom); @@ -1458,8 +1458,8 @@ void Client::getWmNormalHints() xSizeHint.win_gravity = NorthWestGravity; // Update min/max size of this group - if (clientGroup()) - clientGroup()->updateMinMaxSize(); + if (tabGroup()) + tabGroup()->updateMinMaxSize(); if (isManaged()) { // update to match restrictions @@ -1803,8 +1803,8 @@ bool Client::isResizable() const if (rules()->checkSize(QSize()).isValid()) // forced size return false; - QSize min = clientGroup() ? clientGroup()->minSize() : minSize(); - QSize max = clientGroup() ? clientGroup()->maxSize() : maxSize(); + QSize min = tabGroup() ? tabGroup()->minSize() : minSize(); + QSize max = tabGroup() ? tabGroup()->maxSize() : maxSize(); return min.width() < max.width() || min.height() < max.height(); } @@ -1919,8 +1919,8 @@ void Client::setGeometry(int x, int y, int w, int h, ForceGeometry_t force) deco_rect_before_block = deco_rect; // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); // TODO: this signal is emitted too often emit geometryChanged(); @@ -1986,8 +1986,8 @@ void Client::plainResize(int w, int h, ForceGeometry_t force) deco_rect_before_block = deco_rect; // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); // TODO: this signal is emitted too often emit geometryChanged(); } @@ -2033,8 +2033,8 @@ void Client::move(int x, int y, ForceGeometry_t force) deco_rect_before_block = deco_rect; // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); } void Client::blockGeometryUpdates(bool block) @@ -2075,8 +2075,8 @@ void Client::setMaximize(bool vertically, bool horizontally) emit clientMaximizedStateChanged(this, vertically, horizontally); // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); } static bool changeMaximizeRecursion = false; diff --git a/kcmkwin/kwindecoration/preview.cpp b/kcmkwin/kwindecoration/preview.cpp index a3d425674d..fe802c7345 100644 --- a/kcmkwin/kwindecoration/preview.cpp +++ b/kcmkwin/kwindecoration/preview.cpp @@ -475,55 +475,60 @@ QRect KDecorationPreviewBridge::transparentRect() const // Window tabbing -bool KDecorationPreviewBridge::isClientGroupActive() +int KDecorationPreviewBridge::tabCount() const { - return active; + return 1; } -QList< ClientGroupItem > KDecorationPreviewBridge::clientGroupItems() const +QString KDecorationPreviewBridge::caption(int) const { - return QList< ClientGroupItem >() << ClientGroupItem( - active ? "Active Window" : "Inactive Window", icon()); + return active ? "Active Window" : "Inactive Window"; } -long KDecorationPreviewBridge::itemId(int) +QIcon KDecorationPreviewBridge::icon(int) const +{ + return icon(); +} + +long KDecorationPreviewBridge::tabId(int) const { return 0; } -int KDecorationPreviewBridge::visibleClientGroupItem() +long KDecorationPreviewBridge::currentTabId() const { return 0; } -void KDecorationPreviewBridge::setVisibleClientGroupItem(int) +void KDecorationPreviewBridge::setCurrentTab(long) { } -void KDecorationPreviewBridge::moveItemInClientGroup(int, int) +void KDecorationPreviewBridge::tab_A_before_B(long, long) { } -void KDecorationPreviewBridge::moveItemToClientGroup(long, int) +void KDecorationPreviewBridge::tab_A_behind_B(long, long) { } -void KDecorationPreviewBridge::removeFromClientGroup(int, const QRect&) +void KDecorationPreviewBridge::untab(long, const QRect&) { } -void KDecorationPreviewBridge::closeClientGroupItem(int) +void KDecorationPreviewBridge::closeTab(long) { } -void KDecorationPreviewBridge::closeAllInClientGroup() +void KDecorationPreviewBridge::closeTabGroup() { } -void KDecorationPreviewBridge::displayClientMenu(int, const QPoint&) +void KDecorationPreviewBridge::showWindowMenu(const QPoint &, long) { } + KDecoration::WindowOperation KDecorationPreviewBridge::buttonToWindowOperation(Qt::MouseButtons) { return KDecoration::NoOp; diff --git a/kcmkwin/kwindecoration/preview.h b/kcmkwin/kwindecoration/preview.h index 2679fead97..20ee869f9b 100644 --- a/kcmkwin/kwindecoration/preview.h +++ b/kcmkwin/kwindecoration/preview.h @@ -120,17 +120,18 @@ public: virtual QRect transparentRect() const; // Window tabbing - virtual bool isClientGroupActive(); - virtual QList< ClientGroupItem > clientGroupItems() const; - virtual long itemId(int index); - virtual int visibleClientGroupItem(); - virtual void setVisibleClientGroupItem(int index); - virtual void moveItemInClientGroup(int index, int before); - virtual void moveItemToClientGroup(long itemId, int before); - virtual void removeFromClientGroup(int index, const QRect& newGeom); - virtual void closeClientGroupItem(int index); - virtual void closeAllInClientGroup(); - virtual void displayClientMenu(int index, const QPoint& pos); + virtual QString caption(int idx) const; + virtual void closeTab(long id); + virtual void closeTabGroup(); + virtual long currentTabId() const; + virtual QIcon icon(int idx) const; + virtual void setCurrentTab(long id); + virtual void showWindowMenu(const QPoint &, long id); + virtual void tab_A_before_B(long A, long B); + virtual void tab_A_behind_B(long A, long B); + virtual int tabCount() const; + virtual long tabId(int idx) const; + virtual void untab(long id, const QRect& newGeom); virtual WindowOperation buttonToWindowOperation(Qt::MouseButtons button); private: diff --git a/kwinbindings.cpp b/kwinbindings.cpp index f75b2bac7d..3284cf0700 100644 --- a/kwinbindings.cpp +++ b/kwinbindings.cpp @@ -59,9 +59,9 @@ a->setText(i18n("System")); a = actionCollection->addAction("Group:Navigation"); a->setText(i18n("Navigation")); -DEF(I18N_NOOP("Walk Through Window Tabs"), 0, slotSwitchToTabRight()); -DEF(I18N_NOOP("Walk Through Window Tabs (Reverse)"), 0, slotSwitchToTabLeft()); -DEF(I18N_NOOP("Remove Window From Group"), 0, slotRemoveFromGroup()); +DEF(I18N_NOOP("Walk Through Window Tabs"), 0, slotActivateNextTab()); +DEF(I18N_NOOP("Walk Through Window Tabs (Reverse)"), 0, slotActivatePrevTab()); +DEF(I18N_NOOP("Remove Window From Group"), 0, slotUntab()); a = actionCollection->addAction("Group:Windows"); a->setText(i18n("Windows")); diff --git a/layers.cpp b/layers.cpp index 5cd0de280e..397ff6f1d5 100644 --- a/layers.cpp +++ b/layers.cpp @@ -782,8 +782,8 @@ void Client::setKeepAbove(bool b) updateWindowRules(Rules::Above); // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); emit keepAboveChanged(); } @@ -806,8 +806,8 @@ void Client::setKeepBelow(bool b) updateWindowRules(Rules::Below); // Update states of all other windows in this group - if (clientGroup()) - clientGroup()->updateStates(this); + if (tabGroup()) + tabGroup()->updateStates(this); emit keepBelowChanged(); } diff --git a/libkdecorations/kcommondecoration.cpp b/libkdecorations/kcommondecoration.cpp index e43cca4a27..480a43710c 100644 --- a/libkdecorations/kcommondecoration.cpp +++ b/libkdecorations/kcommondecoration.cpp @@ -1277,59 +1277,64 @@ bool KCommonDecorationUnstable::compositingActive() const // Window tabbing -bool KCommonDecorationUnstable::isClientGroupActive() +int KCommonDecorationUnstable::tabCount() const { - return static_cast(decoration())->isClientGroupActive(); + return static_cast(decoration())->tabCount(); } -QList< ClientGroupItem > KCommonDecorationUnstable::clientGroupItems() const +QString KCommonDecorationUnstable::caption(int idx) const { - return static_cast(decoration())->clientGroupItems(); + return static_cast(decoration())->caption(idx); } -long KCommonDecorationUnstable::itemId(int index) +QIcon KCommonDecorationUnstable::icon(int idx) const { - return static_cast(decoration())->itemId(index); + return static_cast(decoration())->icon(idx); } -int KCommonDecorationUnstable::visibleClientGroupItem() +long KCommonDecorationUnstable::tabId(int idx) const { - return static_cast(decoration())->visibleClientGroupItem(); + return static_cast(decoration())->tabId(idx); } -void KCommonDecorationUnstable::setVisibleClientGroupItem(int index) +long KCommonDecorationUnstable::currentTabId() const { - static_cast(decoration())->setVisibleClientGroupItem(index); + return static_cast(decoration())->currentTabId(); } -void KCommonDecorationUnstable::moveItemInClientGroup(int index, int before) +void KCommonDecorationUnstable::setCurrentTab(long id) { - static_cast(decoration())->moveItemInClientGroup(index, before); + static_cast(decoration())->setCurrentTab(id); } -void KCommonDecorationUnstable::moveItemToClientGroup(long itemId, int before) +void KCommonDecorationUnstable::tab_A_before_B(long A, long B) { - static_cast(decoration())->moveItemToClientGroup(itemId, before); + static_cast(decoration())->tab_A_before_B(A, B); } -void KCommonDecorationUnstable::removeFromClientGroup(int index, const QRect& newGeom) +void KCommonDecorationUnstable::tab_A_behind_B(long A, long B) { - static_cast(decoration())->removeFromClientGroup(index, newGeom); + static_cast(decoration())->tab_A_behind_B(A, B); } -void KCommonDecorationUnstable::closeClientGroupItem(int index) +void KCommonDecorationUnstable::untab(long id, const QRect& newGeom) { - static_cast(decoration())->closeClientGroupItem(index); + static_cast(decoration())->untab(id, newGeom); } -void KCommonDecorationUnstable::closeAllInClientGroup() +void KCommonDecorationUnstable::closeTab(long id) { - static_cast(decoration())->closeAllInClientGroup(); + static_cast(decoration())->closeTab(id); } -void KCommonDecorationUnstable::displayClientMenu(int index, const QPoint& pos) +void KCommonDecorationUnstable::closeTabGroup() { - static_cast(decoration())->displayClientMenu(index, pos); + static_cast(decoration())->closeTabGroup(); +} + +void KCommonDecorationUnstable::showWindowMenu(const QPoint &pos, long id) +{ + static_cast(decoration())->showWindowMenu(pos, id); } KDecoration::WindowOperation KCommonDecorationUnstable::buttonToWindowOperation(Qt::MouseButtons button) diff --git a/libkdecorations/kcommondecoration.h b/libkdecorations/kcommondecoration.h index 03c48618ac..d207da818c 100644 --- a/libkdecorations/kcommondecoration.h +++ b/libkdecorations/kcommondecoration.h @@ -395,17 +395,19 @@ public: bool compositingActive() const; // Window tabbing - bool isClientGroupActive(); - QList< ClientGroupItem > clientGroupItems() const; - long itemId(int index); - int visibleClientGroupItem(); - void setVisibleClientGroupItem(int index); - void moveItemInClientGroup(int index, int before); - void moveItemToClientGroup(long itemId, int before = -1); - void removeFromClientGroup(int index, const QRect& newGeom = QRect()); - void closeClientGroupItem(int index); - void closeAllInClientGroup(); - void displayClientMenu(int index, const QPoint& pos); + using KCommonDecoration::caption; + QString caption(int idx) const; + void closeTab(long id); + void closeTabGroup(); + long currentTabId() const; + QIcon icon(int idx = 0) const; + void setCurrentTab(long id); + void showWindowMenu(const QPoint &, long id); + void tab_A_before_B(long A, long B); + void tab_A_behind_B(long A, long B); + int tabCount() const; + long tabId(int idx) const; + void untab(long id, const QRect& newGeom); WindowOperation buttonToWindowOperation(Qt::MouseButtons button); virtual bool eventFilter(QObject* o, QEvent* e); diff --git a/libkdecorations/kdecoration.cpp b/libkdecorations/kdecoration.cpp index e53f55cecc..f26699a6c5 100644 --- a/libkdecorations/kdecoration.cpp +++ b/libkdecorations/kdecoration.cpp @@ -412,63 +412,70 @@ void KDecorationUnstable::padding(int &left, int &right, int &top, int &bottom) left = right = top = bottom = 0; } -// Window tabbing +//BEGIN Window tabbing -bool KDecorationUnstable::isClientGroupActive() +int KDecorationUnstable::tabCount() const { - return static_cast< KDecorationBridgeUnstable* >(bridge_)->isClientGroupActive(); + return static_cast< KDecorationBridgeUnstable* >(bridge_)->tabCount(); } -QList< ClientGroupItem > KDecorationUnstable::clientGroupItems() const +long KDecorationUnstable::tabId(int idx) const { - return static_cast< KDecorationBridgeUnstable* >(bridge_)->clientGroupItems(); + return static_cast< KDecorationBridgeUnstable* >(bridge_)->tabId(idx); } -long KDecorationUnstable::itemId(int index) +QString KDecorationUnstable::caption(int idx) const { - return static_cast< KDecorationBridgeUnstable* >(bridge_)->itemId(index); + return static_cast< KDecorationBridgeUnstable* >(bridge_)->caption(idx); } -int KDecorationUnstable::visibleClientGroupItem() +QIcon KDecorationUnstable::icon(int idx) const { - return static_cast< KDecorationBridgeUnstable* >(bridge_)->visibleClientGroupItem(); + return static_cast< KDecorationBridgeUnstable* >(bridge_)->icon(idx); } -void KDecorationUnstable::setVisibleClientGroupItem(int index) +long KDecorationUnstable::currentTabId() const { - static_cast< KDecorationBridgeUnstable* >(bridge_)->setVisibleClientGroupItem(index); + return static_cast< KDecorationBridgeUnstable* >(bridge_)->currentTabId(); } -void KDecorationUnstable::moveItemInClientGroup(int index, int before) +void KDecorationUnstable::setCurrentTab(long id) { - static_cast< KDecorationBridgeUnstable* >(bridge_)->moveItemInClientGroup(index, before); + static_cast< KDecorationBridgeUnstable* >(bridge_)->setCurrentTab(id); } -void KDecorationUnstable::moveItemToClientGroup(long itemId, int before) +void KDecorationUnstable::tab_A_before_B(long A, long B) { - static_cast< KDecorationBridgeUnstable* >(bridge_)->moveItemToClientGroup(itemId, before); + static_cast< KDecorationBridgeUnstable* >(bridge_)->tab_A_before_B(A, B); } -void KDecorationUnstable::removeFromClientGroup(int index, const QRect& newGeom) +void KDecorationUnstable::tab_A_behind_B(long A, long B) { - static_cast< KDecorationBridgeUnstable* >(bridge_)->removeFromClientGroup(index, newGeom); + static_cast< KDecorationBridgeUnstable* >(bridge_)->tab_A_behind_B(A, B); } -void KDecorationUnstable::closeClientGroupItem(int index) +void KDecorationUnstable::untab(long id, const QRect& newGeom) { - static_cast< KDecorationBridgeUnstable* >(bridge_)->closeClientGroupItem(index); + static_cast< KDecorationBridgeUnstable* >(bridge_)->untab(id, newGeom); } -void KDecorationUnstable::closeAllInClientGroup() +void KDecorationUnstable::closeTab(long id) { - static_cast< KDecorationBridgeUnstable* >(bridge_)->closeAllInClientGroup(); + static_cast< KDecorationBridgeUnstable* >(bridge_)->closeTab(id); } -void KDecorationUnstable::displayClientMenu(int index, const QPoint& pos) +void KDecorationUnstable::closeTabGroup() { - static_cast< KDecorationBridgeUnstable* >(bridge_)->displayClientMenu(index, pos); + static_cast< KDecorationBridgeUnstable* >(bridge_)->closeTabGroup(); } +void KDecorationUnstable::showWindowMenu(const QPoint &pos, long id) +{ + static_cast< KDecorationBridgeUnstable* >(bridge_)->showWindowMenu(pos, id); +} + +//END tabbing + KDecoration::WindowOperation KDecorationUnstable::buttonToWindowOperation(Qt::MouseButtons button) { return static_cast< KDecorationBridgeUnstable* >(bridge_)->buttonToWindowOperation(button); @@ -479,7 +486,7 @@ QRegion KDecorationUnstable::region(KDecorationDefines::Region) return QRegion(); } -QString KDecorationDefines::clientGroupItemDragMimeType() +QString KDecorationDefines::tabDragMimeType() { return "text/ClientGroupItem"; } diff --git a/libkdecorations/kdecoration.h b/libkdecorations/kdecoration.h index 030afa0bbb..442d0a1dc4 100644 --- a/libkdecorations/kdecoration.h +++ b/libkdecorations/kdecoration.h @@ -104,12 +104,12 @@ public: NoOp, SetupWindowShortcutOp, ApplicationRulesOp, - RemoveClientFromGroupOp, // Remove from group - CloseClientGroupOp, // Close the group - MoveClientInGroupLeftOp, // Move left in the group - MoveClientInGroupRightOp, // Move right in the group + RemoveTabFromGroupOp, // Remove from group + CloseTabGroupOp, // Close the group + ActivateNextTabOp, // Move left in the group + ActivatePreviousTabOp, // Move right in the group ToggleClientTiledStateOp, // put a floating client into tiling - ClientGroupDragOp + TabDragOp }; /** * Basic color types that should be recognized by all decoration styles. @@ -197,7 +197,7 @@ public: AbilityUsesBlurBehind = 3003, ///< The decoration wants the background to be blurred, when the blur plugin is enabled. /// @since 4.6 // Tabbing - AbilityClientGrouping = 4000, ///< The decoration supports tabbing + AbilityTabbing = 4000, ///< The decoration supports tabbing // TODO colors for individual button types ABILITY_DUMMY = 10000000 }; @@ -228,28 +228,10 @@ public: /** * Returns the mimeType used to drag and drop clientGroupItems */ - static QString clientGroupItemDragMimeType(); + static QString tabDragMimeType(); }; -class KWIN_EXPORT ClientGroupItem -{ -public: - ClientGroupItem(QString t, QIcon i) { - title_ = t; - icon_ = i; - } - inline QIcon icon() const { - return icon_; - } - inline QString title() const { - return title_; - } -private: - QString title_; - QIcon icon_; -}; - class KDecorationProvides : public KDecorationDefines { @@ -942,56 +924,67 @@ public: /** * Returns whether or not this client group contains the active client. */ - bool isClientGroupActive(); + bool isInActiveTabGroup(); /** - * Return a list of all the clients in the group that contains the client that this - * decoration is attached to. + * Return the amount of tabs in this group */ - QList< ClientGroupItem > clientGroupItems() const; + int tabCount() const; + /** - * Returns a unique identifier for the client at index \p index of the client group list. - * \see moveItemToClientGroup() + * Return the icon for the tab at index \p idx (\p idx must be smaller than tabCount()) */ - long itemId(int index); + QIcon icon(int idx) const; + /** - * Returns the list index of the currently visible client in this group. + * Return the caption for the tab at index \p idx (\p idx must be smaller than tabCount()) */ - int visibleClientGroupItem(); + QString caption(int idx) const; + /** - * Switch the currently visible client to the one at list index \p index. + * Return the unique id for the tab at index \p idx (\p idx must be smaller than tabCount()) */ - void setVisibleClientGroupItem(int index); + long tabId(int idx) const; /** - * Move the client at index \p index to the position before the client at index \p before. + * Returns the id of the currently active client in this group. */ - void moveItemInClientGroup(int index, int before); + long currentTabId() const; /** - * Move the client that's unique identifier is \p itemId to the position before the client - * at index \p before if set, otherwise the end of the list. This call is to move clients - * between two different groups, if moving in the same group then use - * moveItemInClientGroup() instead. - * \see itemId() + * Activate tab for the window with the id \p id. */ - void moveItemToClientGroup(long itemId, int before = -1); + void setCurrentTab(long id); + /** - * Remove the client at index \p index from the group. If \p newGeom is set then the client - * will move and resize to the specified geometry, otherwise it will stay where the group - * is located. + * Entab windw with id \p A beFORE the window with the id \p B. */ - void removeFromClientGroup(int index, const QRect& newGeom = QRect()); + virtual void tab_A_before_B(long A, long B); /** - * Close the client at index \p index. + * Entab windw with id \p A beHIND the window with the id \p B. */ - void closeClientGroupItem(int index); + virtual void tab_A_behind_B(long A, long B); + /** + * Remove the window with the id \p id from its tabgroup and place it at \p newGeom + */ + virtual void untab(long id, const QRect& newGeom); + + /** + * Close the client with the id \p id. + */ + void closeTab(long id); /** * Close all windows in this group. */ - void closeAllInClientGroup(); + void closeTabGroup(); /** * Display the right-click client menu belonging to the client at index \p index at the * global coordinates specified by \p pos. */ - void displayClientMenu(int index, const QPoint& pos); + void showWindowMenu(const QPoint& pos, long id); + /** + * unshadow virtuals + */ + using KDecoration::caption; + using KDecoration::icon; + using KDecoration::showWindowMenu; /** * Determine which action the user has mapped \p button to. Useful for determining whether * a button press was for window tab dragging or for displaying the client menu. diff --git a/libkdecorations/kdecorationbridge.h b/libkdecorations/kdecorationbridge.h index f745ac7d2d..b7d061997d 100644 --- a/libkdecorations/kdecorationbridge.h +++ b/libkdecorations/kdecorationbridge.h @@ -97,17 +97,21 @@ public: virtual QRect transparentRect() const = 0; // Window tabbing - virtual bool isClientGroupActive() = 0; - virtual QList< ClientGroupItem > clientGroupItems() const = 0; - virtual long itemId(int index) = 0; - virtual int visibleClientGroupItem() = 0; - virtual void setVisibleClientGroupItem(int index) = 0; - virtual void moveItemInClientGroup(int index, int before) = 0; - virtual void moveItemToClientGroup(long itemId, int before) = 0; - virtual void removeFromClientGroup(int index, const QRect& newGeom) = 0; - virtual void closeClientGroupItem(int index) = 0; - virtual void closeAllInClientGroup() = 0; - virtual void displayClientMenu(int index, const QPoint& pos) = 0; + using KDecorationBridge::caption; + virtual QString caption(int idx) const = 0; + virtual void closeTab(long id) = 0; + virtual void closeTabGroup() = 0; + virtual long currentTabId() const = 0; + using KDecorationBridge::icon; + virtual QIcon icon(int idx) const = 0; + virtual void setCurrentTab(long id) = 0; + using KDecorationBridge::showWindowMenu; + virtual void showWindowMenu(const QPoint& pos, long id) = 0; + virtual void tab_A_before_B(long A, long B) = 0; + virtual void tab_A_behind_B(long A, long B) = 0; + virtual int tabCount() const = 0; + virtual long tabId(int idx) const = 0; + virtual void untab(long id, const QRect& newGeom) = 0; virtual WindowOperation buttonToWindowOperation(Qt::MouseButtons button) = 0; }; diff --git a/libkwineffects/kwineffects.cpp b/libkwineffects/kwineffects.cpp index 3f29062a17..b04c360576 100644 --- a/libkwineffects/kwineffects.cpp +++ b/libkwineffects/kwineffects.cpp @@ -380,7 +380,7 @@ WINDOW_HELPER_DEFAULT(bool, isSpecialWindow, "specialWindow", true) WINDOW_HELPER_DEFAULT(bool, acceptsFocus, "wantsInput", true) // We don't actually know... WINDOW_HELPER_DEFAULT(QPixmap, icon, "icon", QPixmap()) WINDOW_HELPER_DEFAULT(bool, isSkipSwitcher, "skipSwitcher", false) -WINDOW_HELPER_DEFAULT(bool, visibleInClientGroup, "visibleInClientGroup", false) +WINDOW_HELPER_DEFAULT(bool, isCurrentTab, "isCurrentTab", false) #undef WINDOW_HELPER_DEFAULT diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h index 6685ad2a3f..288dad825e 100644 --- a/libkwineffects/kwineffects.h +++ b/libkwineffects/kwineffects.h @@ -988,9 +988,9 @@ Q_SIGNALS: * @since 4.7 **/ void tabBoxKeyEvent(QKeyEvent* event); - void clientGroupItemSwitched(EffectWindow* from, EffectWindow* to); - void clientGroupItemAdded(EffectWindow* from, EffectWindow* to); // from merged with to - void clientGroupItemRemoved(EffectWindow* c, EffectWindow* group); // c removed from group + void currentTabAboutToChange(EffectWindow* from, EffectWindow* to); + void tabAdded(EffectWindow* from, EffectWindow* to); // from merged with to + void tabRemoved(EffectWindow* c, EffectWindow* group); // c removed from group /** * Signal emitted when mouse changed. * If an effect needs to get updated mouse positions, it needs to first call @link startMousePolling. @@ -1074,7 +1074,7 @@ public: /** Window will not be painted because it is minimized */ PAINT_DISABLED_BY_MINIMIZE = 1 << 3, /** Window will not be painted because it is not the active window in a client group */ - PAINT_DISABLED_BY_CLIENT_GROUP = 1 << 4, + PAINT_DISABLED_BY_TAB_GROUP = 1 << 4, /** Window will not be painted because it's not on the current activity */ PAINT_DISABLED_BY_ACTIVITY = 1 << 5 }; @@ -1265,7 +1265,7 @@ public: void unminimize(); void closeWindow() const; - bool visibleInClientGroup() const; + bool isCurrentTab() const; /** * Can be used to by effects to store arbitrary data in the EffectWindow. diff --git a/manage.cpp b/manage.cpp index 6f935ff457..e74c60797c 100644 --- a/manage.cpp +++ b/manage.cpp @@ -305,39 +305,47 @@ bool Client::manage(Window w, bool isMapped) // Create client group if the window will have a decoration bool dontKeepInArea = false; + setTabGroup(NULL); if (!noBorder()) { - setClientGroup(NULL); - bool autogrouping = rules()->checkAutogrouping(options->autogroupSimilarWindows); + const bool autogrouping = rules()->checkAutogrouping(options->autogroupSimilarWindows); + const bool autogroupInFg = rules()->checkAutogroupInForeground(options->autogroupInForeground); // Automatically add to previous groups on session restore - if (session && session->clientGroupClient && session->clientGroupClient != this && session->clientGroupClient->clientGroup()) - session->clientGroupClient->clientGroup()->add(this, -1, true); - else if (isMapped && autogrouping) + if (session && session->tabGroupClient && session->tabGroupClient != this) { + tabBehind(session->tabGroupClient, autogroupInFg); + } else if (isMapped && autogrouping) { // If the window is already mapped (Restarted KWin) add any windows that already have the // same geometry to the same client group. (May incorrectly handle maximized windows) - foreach (ClientGroup * group, workspace()->clientGroups) - if (geom == QRect(group->visible()->pos(), group->visible()->clientSize()) && - desk == group->visible()->desktop() && - activities() == group->visible()->activities() && - group->visible()->maximizeMode() != MaximizeFull) { - group->add(this, -1, true); - break; - } - if (!client_group && !isMapped && !session) { - // Attempt to automatically group similar windows - const Client* similar = workspace()->findSimilarClient(this); - if (similar && similar->clientGroup() && !similar->noBorder()) { - geom = QRect(similar->pos() + similar->clientPos(), similar->clientSize()); - updateDecoration(false); - similar->clientGroup()->add(this, -1, - rules()->checkAutogroupInForeground(options->autogroupInForeground)); - // Don't move entire group - geom = QRect(similar->pos() + similar->clientPos(), similar->clientSize()); - placementDone = true; - dontKeepInArea = true; + foreach (Client *other, workspace()->clientList()) { + if (other->maximizeMode() != MaximizeFull && + geom == QRect(other->pos(), other->clientSize()) && + desk == other->desktop() && activities() == other->activities()) { + + tabBehind(other, autogroupInFg); + break; + + } + } + } + if (autogrouping && !tab_group && !isMapped && !session) { + // Attempt to automatically group similar windows + Client* similar = findAutogroupCandidate(); + if (similar && !similar->noBorder()) { + if (autogroupInFg) { + similar->setDesktop(desk); // can happen when grouping by id. ... + similar->setMinimized(false); // ... or anyway - still group, but "here" and visible + } + if (!similar->isMinimized()) { // do not attempt to tab in background of a hidden group + geom = QRect(similar->pos() + similar->clientPos(), similar->clientSize()); + updateDecoration(false); + if (tabBehind(similar, autogroupInFg)) { + // Don't move entire group + geom = QRect(similar->pos() + similar->clientPos(), similar->clientSize()); + placementDone = true; + dontKeepInArea = true; + } + } } } - if (!client_group) - setClientGroup(new ClientGroup(this)); } updateDecoration(false); // Also gravitates @@ -658,4 +666,63 @@ void Client::embedClient(Window w, const XWindowAttributes& attr) updateMouseGrab(); } +// To accept "mainwindow#1" to "mainwindow#2" +static QByteArray truncatedWindowRole(QByteArray a) +{ + int i = a.indexOf('#'); + if (i == -1) + return a; + QByteArray b(a); + b.truncate(i); + return b; +} + +Client* Client::findAutogroupCandidate() const +{ + // Attempt to find a similar window to the input. If we find multiple possibilities that are in + // different groups then ignore all of them. This function is for automatic window grouping. + Client *found = NULL; + + // See if the window has a group ID to match with + QString wGId = rules()->checkAutogroupById(QString()); + if (!wGId.isEmpty()) { + foreach (Client *c, workspace()->clientList()) { + if (activities() != c->activities()) + continue; // don't cross activities + if (wGId == c->rules()->checkAutogroupById(QString())) { + if (found && found->tabGroup() != c->tabGroup()) { // We've found two, ignore both + found = NULL; + break; // Continue to the next test + } + found = c; + } + } + if (found) + return found; + } + + // If this is a transient window don't take a guess + if (isTransient()) + return NULL; + + // If we don't have an ID take a guess + if (rules()->checkAutogrouping(options->autogroupSimilarWindows)) { + QByteArray wRole = truncatedWindowRole(windowRole()); + foreach (Client *c, workspace()->clientList()) { + if (desktop() != c->desktop() || activities() != c->activities()) + continue; + QByteArray wRoleB = truncatedWindowRole(c->windowRole()); + if (resourceClass() == c->resourceClass() && // Same resource class + wRole == wRoleB && // Same window role + c->isNormalWindow()) { // Normal window TODO: Can modal windows be "normal"? + if (found && found->tabGroup() != c->tabGroup()) // We've found two, ignore both + return NULL; + found = c; + } + } + } + + return found; +} + } // namespace diff --git a/options.cpp b/options.cpp index 45e8152e20..f745ec45e4 100644 --- a/options.cpp +++ b/options.cpp @@ -389,7 +389,7 @@ Options::MouseCommand Options::mouseCommand(const QString &name, bool restricted if (lowerName == "resize") return restricted ? MouseResize : MouseUnrestrictedResize; if (lowerName == "shade") return MouseShade; if (lowerName == "minimize") return MouseMinimize; - if (lowerName == "start window tab drag") return MouseClientGroupDrag; + if (lowerName == "start window tab drag") return MouseDragTab; if (lowerName == "close") return MouseClose; if (lowerName == "increase opacity") return MouseOpacityMore; if (lowerName == "decrease opacity") return MouseOpacityLess; @@ -406,9 +406,9 @@ Options::MouseWheelCommand Options::mouseWheelCommand(const QString &name) if (lowerName == "above/below") return MouseWheelAboveBelow; if (lowerName == "previous/next desktop") return MouseWheelPreviousNextDesktop; if (lowerName == "change opacity") return MouseWheelChangeOpacity; - if (lowerName == "switch to window tab to the left/right") return MouseWheelChangeGroupWindow; + if (lowerName == "switch to window tab to the left/right") return MouseWheelChangeCurrentTab; if (lowerName == "nothing") return MouseWheelNothing; - return MouseWheelChangeGroupWindow; + return MouseWheelChangeCurrentTab; } bool Options::showGeometryTip() @@ -477,8 +477,8 @@ Options::MouseCommand Options::wheelToMouseCommand(MouseWheelCommand com, int de return delta > 0 ? MousePreviousDesktop : MouseNextDesktop; case MouseWheelChangeOpacity: return delta > 0 ? MouseOpacityMore : MouseOpacityLess; - case MouseWheelChangeGroupWindow: - return delta > 0 ? MouseLeftGroupWindow : MouseRightGroupWindow; + case MouseWheelChangeCurrentTab: + return delta > 0 ? MousePreviousTab : MouseNextTab; default: return MouseNothing; } diff --git a/options.h b/options.h index d3d158bfb0..67f225954e 100644 --- a/options.h +++ b/options.h @@ -197,14 +197,14 @@ public: MouseNextDesktop, MousePreviousDesktop, MouseAbove, MouseBelow, MouseOpacityMore, MouseOpacityLess, - MouseClose, MouseLeftGroupWindow, MouseRightGroupWindow, MouseClientGroupDrag, + MouseClose, MousePreviousTab, MouseNextTab, MouseDragTab, MouseNothing }; enum MouseWheelCommand { MouseWheelRaiseLower, MouseWheelShadeUnshade, MouseWheelMaximizeRestore, MouseWheelAboveBelow, MouseWheelPreviousNextDesktop, - MouseWheelChangeOpacity, MouseWheelChangeGroupWindow, + MouseWheelChangeOpacity, MouseWheelChangeCurrentTab, MouseWheelNothing }; diff --git a/scene.cpp b/scene.cpp index b41c8ee07d..2f30621d85 100644 --- a/scene.cpp +++ b/scene.cpp @@ -526,8 +526,8 @@ void Scene::Window::resetPaintingEnabled() if (Client* c = dynamic_cast< Client* >(toplevel)) { if (c->isMinimized()) disable_painting |= PAINT_DISABLED_BY_MINIMIZE; - if (c->clientGroup() && c != c->clientGroup()->visible()) - disable_painting |= PAINT_DISABLED_BY_CLIENT_GROUP; + if (c->tabGroup() && c != c->tabGroup()->current()) + disable_painting |= PAINT_DISABLED_BY_TAB_GROUP; else if (c->isHiddenInternal()) disable_painting |= PAINT_DISABLED; } diff --git a/scene.h b/scene.h index b1e438a064..dc426b979e 100644 --- a/scene.h +++ b/scene.h @@ -195,7 +195,7 @@ public: // Window will not be painted because it is minimized PAINT_DISABLED_BY_MINIMIZE = 1 << 3, // Window will not be painted because it is not the active window in a client group - PAINT_DISABLED_BY_CLIENT_GROUP = 1 << 4, + PAINT_DISABLED_BY_TAB_GROUP = 1 << 4, // Window will not be painted because it's not on the current activity PAINT_DISABLED_BY_ACTIVITY = 1 << 5 }; diff --git a/scripting/meta.cpp b/scripting/meta.cpp index 4f770385d5..b72eefa763 100644 --- a/scripting/meta.cpp +++ b/scripting/meta.cpp @@ -20,25 +20,12 @@ along with this program. If not, see . #include "meta.h" #include "client.h" -#include "clientgroup.h" +#include "tabgroup.h" #include using namespace KWin::MetaScripting; -// Meta for KWin::ClientGroup* objects -QScriptValue ClientGroup::toScriptValue(QScriptEngine* eng, const KClientGroupRef& cGrp) -{ - return eng->newQObject(cGrp, QScriptEngine::QtOwnership, - QScriptEngine::ExcludeChildObjects | QScriptEngine::ExcludeDeleteLater | QScriptEngine::PreferExistingWrapperObject); -} - -void ClientGroup::fromScriptValue(const QScriptValue& obj, KWin::ClientGroup*& cGrp) -{ - cGrp = qobject_cast(obj.toQObject()); -} -// End of metas for KWin::ClientGroup* objects - // Meta for QPoint object QScriptValue Point::toScriptValue(QScriptEngine* eng, const QPoint& point) { @@ -128,10 +115,8 @@ void KWin::MetaScripting::registration(QScriptEngine* eng) qScriptRegisterMetaType(eng, Size::toScriptValue, Size::fromScriptValue); qScriptRegisterMetaType(eng, Rect::toScriptValue, Rect::fromScriptValue); qScriptRegisterMetaType(eng, Client::toScriptValue, Client::fromScriptValue); - qScriptRegisterMetaType(eng, ClientGroup::toScriptValue, ClientGroup::fromScriptValue); qScriptRegisterSequenceMetaType(eng); - qScriptRegisterSequenceMetaType< QList >(eng); qScriptRegisterSequenceMetaType< QList >(eng); } diff --git a/scripting/meta.h b/scripting/meta.h index e781727128..aa0ca7beab 100644 --- a/scripting/meta.h +++ b/scripting/meta.h @@ -31,26 +31,15 @@ class QSize; namespace KWin { class Client; -class ClientGroup; } typedef KWin::Client* KClientRef; -typedef KWin::ClientGroup* KClientGroupRef; namespace KWin { namespace MetaScripting { -/** - * The toScriptValue and fromScriptValue functions used in qScriptRegisterMetaType. - * Conversion functions for KWin::ClientGroup* - */ -namespace ClientGroup -{ -QScriptValue toScriptValue(QScriptEngine*, const KClientGroupRef&); -void fromScriptValue(const QScriptValue&, KClientGroupRef&); -} /** * The toScriptValue and fromScriptValue functions used in qScriptRegisterMetaType. diff --git a/scripting/workspace_wrapper.cpp b/scripting/workspace_wrapper.cpp index e8a2c4e722..da84eb1a39 100644 --- a/scripting/workspace_wrapper.cpp +++ b/scripting/workspace_wrapper.cpp @@ -131,10 +131,6 @@ SLOTWRAPPER(slotWindowToDesktopLeft) SLOTWRAPPER(slotWindowToDesktopUp) SLOTWRAPPER(slotWindowToDesktopDown) -SLOTWRAPPER(slotSwitchToTabLeft) -SLOTWRAPPER(slotSwitchToTabRight) -SLOTWRAPPER(slotRemoveFromGroup) - #undef SLOTWRAPPER void WorkspaceWrapper::setActiveClient(KWin::Client* client) diff --git a/scripting/workspace_wrapper.h b/scripting/workspace_wrapper.h index e0392d8812..8c502a92cf 100644 --- a/scripting/workspace_wrapper.h +++ b/scripting/workspace_wrapper.h @@ -215,10 +215,6 @@ public Q_SLOTS: void slotWindowToDesktopUp(); void slotWindowToDesktopDown(); - void slotSwitchToTabLeft(); // Slot to move left the active Client. - void slotSwitchToTabRight(); // Slot to move right the active Client. - void slotRemoveFromGroup(); // Slot to remove the active client from its group. - private Q_SLOTS: void setupClientConnections(KWin::Client* client); }; diff --git a/sm.cpp b/sm.cpp index 2e41f61723..aa14fe9ade 100644 --- a/sm.cpp +++ b/sm.cpp @@ -163,12 +163,8 @@ void Workspace::storeClient(KConfigGroup &cg, int num, Client *c) cg.writeEntry(QString("windowType") + n, windowTypeToTxt(c->windowType())); cg.writeEntry(QString("shortcut") + n, c->shortcut().toString()); cg.writeEntry(QString("stackingOrder") + n, unconstrained_stacking_order.indexOf(c)); - int group = 0; - if (c->clientGroup()) - group = c->clientGroup()->clients().count() > 1 ? - // KConfig doesn't support long so we need to live with less precision on 64-bit systems - static_cast(reinterpret_cast(c->clientGroup())) : 0; - cg.writeEntry(QString("clientGroup") + n, group); + // KConfig doesn't support long so we need to live with less precision on 64-bit systems + cg.writeEntry(QString("tabGroup") + n, static_cast(reinterpret_cast(c->tabGroup()))); cg.writeEntry(QString("activities") + n, c->activities()); } @@ -322,8 +318,8 @@ void Workspace::addSessionInfo(KConfigGroup &cg) info->shortcut = cg.readEntry(QString("shortcut") + n, QString()); info->active = (active_client == i); info->stackingOrder = cg.readEntry(QString("stackingOrder") + n, -1); - info->clientGroup = cg.readEntry(QString("clientGroup") + n, 0); - info->clientGroupClient = NULL; + info->tabGroup = cg.readEntry(QString("tabGroup") + n, 0); + info->tabGroupClient = NULL; info->activities = cg.readEntry(QString("activities") + n, QStringList()); } } @@ -414,11 +410,13 @@ SessionInfo* Workspace::takeSessionInfo(Client* c) } } - // Set clientGroupClient for other clients in the same group - if (realInfo && realInfo->clientGroup) - foreach (SessionInfo * info, session) - if (!info->clientGroupClient && info->clientGroup == realInfo->clientGroup) - info->clientGroupClient = c; + // Set tabGroupClient for other clients in the same group + if (realInfo && realInfo->tabGroup) { + foreach (SessionInfo * info, session) { + if (!info->tabGroupClient && info->tabGroup == realInfo->tabGroup) + info->tabGroupClient = c; + } + } return realInfo; } diff --git a/sm.h b/sm.h index 803e14ad93..9e5c53b5ac 100644 --- a/sm.h +++ b/sm.h @@ -66,9 +66,9 @@ struct SessionInfo { bool active; // means 'was active in the saved session' int stackingOrder; float opacity; - int clientGroup; // Unique identifier for the client group that this window is in + int tabGroup; // Unique identifier for the client group that this window is in - Client* clientGroupClient; // The first client created that has an identical identifier + Client* tabGroupClient; // The first client created that has an identical identifier QStringList activities; }; diff --git a/tabgroup.cpp b/tabgroup.cpp new file mode 100644 index 0000000000..355c13928d --- /dev/null +++ b/tabgroup.cpp @@ -0,0 +1,295 @@ +/******************************************************************************* +KWin - the KDE window manager +This file is part of the KDE project. + +Copyright (C) 2011/2012 The KWin team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*******************************************************************************/ + +#include "tabgroup.h" + +#include "client.h" +#include "effects.h" + +namespace KWin +{ + +TabGroup::TabGroup(Client *c) + : m_clients() + , m_current(c) + , m_minSize(c->minSize()) + , m_maxSize(c->maxSize()) +{ + QIcon icon(c->icon()); + icon.addPixmap(c->miniIcon()); + m_clients << c; + c->setTabGroup(this); + c->setClientShown(true); +} + +TabGroup::~TabGroup() +{ +} + + +void TabGroup::activateNext() +{ + int index = m_clients.indexOf(m_current); + setCurrent(m_clients.at((index < m_clients.count() - 1) ? index + 1 : 0)); +} + +void TabGroup::activatePrev() +{ + int index = m_clients.indexOf(m_current); + setCurrent(m_clients.at((index > 0) ? index - 1 : m_clients.count() - 1)); +} + +bool TabGroup::add(Client* c, Client *other, bool after, bool becomeVisible) +{ + Q_ASSERT(!c->tabGroup()); + + if (!c->workspace()->decorationSupportsTabbing() || contains(c) || !contains(other)) + return false; + + // Tabbed windows MUST have a decoration + c->setNoBorder(false); + if (c->noBorder()) + return false; + + // If it's not possible to have the same states then ungroup them, TODO: Check all states + // We do this here as the ungroup code in updateStates() cannot be called until add() completes + + bool cannotTab = false; + ShadeMode oldShadeMode = c->shadeMode(); + QRect oldGeom = c->geometry(); + int oldDesktop = c->desktop(); + + c->setShade(m_current->shadeMode()); + cannotTab = c->shadeMode() != m_current->shadeMode(); + if (!cannotTab) { + c->setDesktop(m_current->desktop()); + cannotTab = c->desktop() != m_current->desktop(); + } + if (!cannotTab) { + c->setGeometry(m_current->geometry()); + cannotTab = c->geometry() != m_current->geometry(); + } + + if (cannotTab) { + c->setShade(oldShadeMode); + c->setDesktop(oldDesktop); + c->setGeometry(oldGeom); + // trigger decoration repaint on the group to make sure that hover animations are properly reset. + m_current->triggerDecorationRepaint(); + return false; // cannot tab + } + + // Actually add to new group ---------------------------------------- + + // Notify effects of merge + if (effects) + static_cast(effects)->slotTabAdded(c->effectWindow(), other->effectWindow()); + + int index = other ? m_clients.indexOf(other) : m_clients.size(); + index += after; + if (index > m_clients.size()) + index = m_clients.size(); + + m_clients.insert(index, c); + + c->setTabGroup(this); // Let the client know which group it belongs to + + updateMinMaxSize(); + updateStates(m_current, c); + + if (!becomeVisible) + c->setClientShown(false); + else { + c->setClientShown(true); + if (!effects || c->readyForPainting()) { + setCurrent(c); + if (options->focusPolicyIsReasonable()) + m_current->workspace()->requestFocus( c ); + } + else { + if (options->focusPolicyIsReasonable()) + m_current->workspace()->requestFocus( m_current ); + m_current = c; // setCurrent will be called by Toplevel::setReadyForPainting() + } + } + + m_current->triggerDecorationRepaint(); + return true; +} + +bool TabGroup::remove(Client* c, const QRect& newGeom) +{ + if (!c) + return false; + + int index = m_clients.indexOf(c); + if (index < 0) + return false; + + c->setTabGroup(NULL); + + m_clients.removeAt(index); + updateMinMaxSize(); + + if (c == m_current) { + m_current = index < m_clients.count() ? m_clients.at(index) : m_clients.last(); + m_current->setClientShown(true); + + if (effects) // "c -> m_current" because c was m_current + static_cast(effects)->slotCurrentTabAboutToChange(c->effectWindow(), m_current->effectWindow()); + } + + if (newGeom.isValid()) { + c->maximize(Client::MaximizeRestore); // explicitly calling for a geometry -> unmaximize - in doubt + c->setGeometry(newGeom); + } + + // Notify effects of removal + if (effects) + static_cast(effects)->slotTabRemoved(c->effectWindow(), m_current->effectWindow()); + + m_current->triggerDecorationRepaint(); + return true; +} + +void TabGroup::closeAll() +{ + // NOTICE - in theory it's OK to use the list because closing sends an event to the client and + // due to the async X11 nature, the client would be released and thus removed from m_clients + // after this function exits. + // However later Wayland support or similar might not share this bahaviour - and we really had + // enough trouble with a polluted client list around the tabbing code .... + ClientList list(m_clients); + for (ClientList::const_iterator i = list.constBegin(), end = list.constEnd(); i != end; ++i) + if (*i != m_current) + (*i)->closeWindow(); + + m_current->closeWindow(); +} + +void TabGroup::move(Client *c, Client *other, bool after) +{ + if (c == other) + return; + + int from = m_clients.indexOf(c); + if (from < 0) + return; + + int to = other ? m_clients.indexOf(other) : m_clients.size() - 1; + if (to < 0) + return; + to += after; + if (to >= m_clients.size()) + to = m_clients.size() - 1; + + if (from == to) + return; + + m_clients.move(from, to); + m_current->triggerDecorationRepaint(); +} + +bool TabGroup::isActive() const +{ + return contains(Workspace::self()->activeClient()); +} + +void TabGroup::setCurrent(Client* c, bool force) +{ + if ((c == m_current && !force) || !contains(c)) + return; + + // Notify effects of switch + if (effects) + static_cast(effects)->slotCurrentTabAboutToChange(m_current->effectWindow(), c->effectWindow()); + + m_current = c; + c->setClientShown(true); // reduce flicker? + for (ClientList::const_iterator i = m_clients.constBegin(), end = m_clients.constEnd(); i != end; ++i) + (*i)->setClientShown((*i) == m_current); +} + +void TabGroup::updateMinMaxSize() +{ + // Determine entire group's minimum and maximum sizes + // TODO this used to be signalled out but i didn't find a receiver - or got an idea what this would be good for + // find purpose & solution or kick it +// QSize oldMin = m_minSize; +// QSize oldMax = m_maxSize; + m_minSize = QSize(0, 0); + m_maxSize = QSize(INT_MAX, INT_MAX); + + for (ClientList::const_iterator i = m_clients.constBegin(); i != m_clients.constEnd(); ++i) { + m_minSize = m_minSize.expandedTo((*i)->minSize()); + m_maxSize = m_maxSize.boundedTo((*i)->maxSize()); + } + + // TODO: this actually resolves a conflict that should be catched when adding? + m_maxSize = m_maxSize.expandedTo(m_minSize); + + // calculate this _once_ to get a common size. + // TODO this leaves another unresolved conflict about the base increment (luckily not used too often) + const QSize size = m_current->clientSize().expandedTo(m_minSize).boundedTo(m_maxSize); + if (size != m_current->clientSize()) { + const QRect r(m_current->pos(), m_current->sizeForClientSize(size)); + for (ClientList::const_iterator i = m_clients.constBegin(), end = m_clients.constEnd(); i != end; ++i) + (*i)->setGeometry(r); + } +} + +void TabGroup::updateStates(Client* main, Client* only) +{ + ClientList toBeRemoved; + for (ClientList::const_iterator i = m_clients.constBegin(), end = m_clients.constEnd(); i != end; ++i) { + Client *c = (*i); + if (c != main && (!only || c == only)) { + if (c->isMinimized() != main->isMinimized()) { + if (main->isMinimized()) + c->minimize(true); + else + c->unminimize(true); + } + if (c->isShade() != main->isShade()) + c->setShade(main->isShade() ? ShadeNormal : ShadeNone); + if (c->geometry() != main->geometry()) + c->setGeometry(main->geometry()); + if (c->isOnAllDesktops() != main->isOnAllDesktops()) + c->setOnAllDesktops(main->isOnAllDesktops()); + if (c->desktop() != main->desktop()) + c->setDesktop(main->desktop()); + if (c->activities() != main->activities()) + c->setOnActivities(main->activities()); + if (c->keepAbove() != main->keepAbove()) + c->setKeepAbove(main->keepAbove()); + if (c->keepBelow() != main->keepBelow()) + c->setKeepBelow(main->keepBelow()); + + // If it's not possible to have the same states then ungroup them, TODO: Check all states + if (c->geometry() != main->geometry() || c->desktop() != main->desktop()) + toBeRemoved << c; + } + } + + for (ClientList::const_iterator i = toBeRemoved.constBegin(), end = toBeRemoved.constEnd(); i != end; ++i) + remove(*i); +} + +} diff --git a/tabgroup.h b/tabgroup.h new file mode 100644 index 0000000000..c02e1a27f7 --- /dev/null +++ b/tabgroup.h @@ -0,0 +1,186 @@ +/******************************************************************************* +KWin - the KDE window manager +This file is part of the KDE project. + +Copyright (C) 2011/2012 The KWin team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*******************************************************************************/ + +#ifndef KWIN_TABGROUP_H +#define KWIN_TABGROUP_H + +#include + +#include "kdecoration.h" +#include "utils.h" + +namespace KWin +{ + +class Client; + +/** + * This class represents a group of clients for use in window tabbing. All + * clients in the group share the same geometry and state information; I.e if + * one client changes then all others should also be changed. + * + * A group contains at least one client and DOES NOT contain multiple + * copies of the same client. A client MUST NOT be in two groups at the same + * time. All decorated clients SHOULD be in a group, even if it's a group of + * one client. + * + * rohanp: Had to convert this object to a QObject to make it easier for adding + * scripting interface to TabGroup. + * + * If a group contains multiple clients then only one will ever be mapped at + * any given time. + */ +class TabGroup +{ +public: + /** + * Creates a new group containing \p c. + */ + TabGroup(Client* c); + ~TabGroup(); + + /** + * Activate next tab (flips) + */ + void activateNext(); + + /** + * Activate previous tab (flips) + */ + void activatePrev(); + + /** + * Close all clients in this group. + */ + void closeAll(); + + /** + * Whether client \p c is member of this group + */ + bool contains(Client* c) const; + + /** + * The amount of clients in this group + */ + int count() const; + + /** + * Returns whether or not this group contains the active client. + */ + bool isActive() const; + + /** + * Returns whether this group is empty (used by workspace to remove it) + */ + bool isEmpty() const; + + /** + * Returns the list of all the clients contained in this group in their current order. + */ + const ClientList &clients() const; + + /** + * Returns the currently visible client. + */ + Client* current() const; + /** + * Makes \p c the visible client in the group - force is only used when the window becomes ready for painting. + * Any other usage just causes pointless action + */ + void setCurrent(Client* c, bool force = false); + + /** + * Returns combined minimum size of all clients in the group. + */ + QSize minSize() const; + /** + * Returns combined maximum size of all clients in the group. + */ + QSize maxSize() const; + + /** + * Ensures that all the clients in the group have identical geometries and states using + * \p main as the primary client to copy the settings off. If \p only is set then only + * that client is updated to match \p main. + */ + void updateStates(Client* main, Client* only = NULL); + + /** + * updates geometry restrictions of this group, basically called from Client::getWmNormalHints(), otherwise rather private + */ + void updateMinMaxSize(); + +signals: + void minSizeChanged(); + void maxSizeChanged(); + +private: + friend class Client; +// friend bool Client::tabTo(Client*, bool, bool); + bool add(KWin::Client *c, Client *other, bool behind, bool activateC); + void move(KWin::Client* c, KWin::Client* before, bool behind); + +// friend bool Client::untab(const QRect&); + bool remove(KWin::Client *c, const QRect &newGeom = QRect()); + + ClientList m_clients; + Client *m_current; + QSize m_minSize; + QSize m_maxSize; +}; + +inline bool TabGroup::contains(Client* c) const +{ + return c && m_clients.contains(c); +} + +inline int TabGroup::count() const +{ + return m_clients.count(); +} + +inline const ClientList &TabGroup::clients() const +{ + return m_clients; +} + +inline bool TabGroup::isEmpty() const +{ + return m_clients.isEmpty(); +} + +inline Client* TabGroup::current() const +{ + return m_current; +} + +inline QSize TabGroup::minSize() const +{ + return m_minSize; +} + +inline QSize TabGroup::maxSize() const +{ + return m_maxSize; +} + +} + +#endif diff --git a/toplevel.cpp b/toplevel.cpp index 4453396c61..f3902ea097 100644 --- a/toplevel.cpp +++ b/toplevel.cpp @@ -340,6 +340,10 @@ void Toplevel::setReadyForPainting() if (compositing()) { addRepaintFull(); emit windowShown(this); + if (Client *cl = dynamic_cast(this)) { + if (cl->tabGroup() && cl->tabGroup()->current() == cl) + cl->tabGroup()->setCurrent(cl, true); + } } } } diff --git a/useractions.cpp b/useractions.cpp index b310a3929f..1eaf3e217f 100644 --- a/useractions.cpp +++ b/useractions.cpp @@ -160,19 +160,19 @@ QMenu* Workspace::clientPopup() popup->addSeparator(); // Actions for window tabbing - if (decorationSupportsClientGrouping()) { - mRemoveTabGroup = popup->addAction(i18n("Remove &From Group")); - kaction = qobject_cast(keys->action("Remove TabGroup")); + if (decorationSupportsTabbing()) { + mRemoveFromTabGroup = popup->addAction(i18n("&Untab")); + kaction = qobject_cast(keys->action("Untab")); if (kaction != 0) - mRemoveTabGroup->setShortcut(kaction->globalShortcut().primary()); - mRemoveTabGroup->setData(Options::RemoveClientFromGroupOp); + mRemoveFromTabGroup->setShortcut(kaction->globalShortcut().primary()); + mRemoveFromTabGroup->setData(Options::RemoveTabFromGroupOp); - mCloseGroup = popup->addAction(i18n("Close Entire &Group")); - mCloseGroup->setIcon(KIcon("window-close")); + mCloseTabGroup = popup->addAction(i18n("Close Entire &Group")); + mCloseTabGroup->setIcon(KIcon("window-close")); kaction = qobject_cast(keys->action("Close TabGroup")); if (kaction != 0) - mCloseGroup->setShortcut(kaction->globalShortcut().primary()); - mCloseGroup->setData(Options::CloseClientGroupOp); + mCloseTabGroup->setShortcut(kaction->globalShortcut().primary()); + mCloseTabGroup->setData(Options::CloseTabGroupOp); popup->addSeparator(); } @@ -294,124 +294,115 @@ void Workspace::clientPopupAboutToShow() } mTilingStateOpAction->setVisible(m_tiling->isEnabled()); #endif - delete switch_to_tab_popup; - switch_to_tab_popup = 0; - delete add_tabs_popup; - add_tabs_popup = 0; - if (decorationSupportsClientGrouping()) { - const int tabGroupSize = active_popup_client->clientGroup() ? - active_popup_client->clientGroup()->items().count() : 1; - if (tabGroupSize > 1) - initSwitchToTab(); - initAddToTabGroup(); - mRemoveTabGroup->setVisible(tabGroupSize > 1); - mCloseGroup->setVisible(tabGroupSize > 1); + if (decorationSupportsTabbing()) { + initTabbingPopups(); + } else { + delete add_tabs_popup; + add_tabs_popup = 0; } } -void Workspace::initSwitchToTab() +void Workspace::selectPopupClientTab(QAction* action) { - if (switch_to_tab_popup) + if (!(active_popup_client && active_popup_client->tabGroup()) || !action->data().isValid()) return; - switch_to_tab_popup = new QMenu(popup); - switch_to_tab_popup->setFont(KGlobalSettings::menuFont()); - connect(switch_to_tab_popup, SIGNAL(triggered(QAction*)), - this, SLOT(slotSwitchToTab(QAction*))); - connect(switch_to_tab_popup, SIGNAL(aboutToShow()), - this, SLOT(switchToTabPopupAboutToShow())); - QAction* action = switch_to_tab_popup->menuAction(); - popup->insertAction(mRemoveTabGroup, action); - action->setText(i18n("Switch to Window Tab")); -} - -void Workspace::slotSwitchToTab(QAction* action) -{ - int side = action->data().toInt(); - int c_id = active_popup_client->clientGroup()->indexOfVisibleClient(); - int size = active_popup_client->clientGroup()->clients().count(); - if (side == 0) { // Left - if (c_id > 0) - active_popup_client->clientGroup()->setVisible(c_id - 1); - else - active_popup_client->clientGroup()->setVisible(size - 1); - } else if (side == 1) { // Right - if (c_id < size - 1) - active_popup_client->clientGroup()->setVisible(c_id + 1); - else - active_popup_client->clientGroup()->setVisible(0); - } else { // Find the client - side -= 2; - for (QList::const_iterator i = clientGroups.constBegin(); i != clientGroups.constEnd(); ++i) { - if ((*i)->contains(active_popup_client)) { - (*i)->setVisible(side); - break; - } - } + if (Client *other = action->data().value()) { + active_popup_client->tabGroup()->setCurrent(other); + return; } + + // failed conversion, try "1" & "2", being prev and next + int direction = action->data().toInt(); + if (direction == 1) + active_popup_client->tabGroup()->activatePrev(); + else if (direction == 2) + active_popup_client->tabGroup()->activateNext(); } -void Workspace::switchToTabPopupAboutToShow() +static QString shortCaption(const QString &s) { - if (!switch_to_tab_popup) - return; + if (s.length() < 64) + return s; + QString ss = s; + return ss.replace(32,s.length()-64,"..."); +} + +void Workspace::rebuildTabListPopup() +{ + Q_ASSERT(switch_to_tab_popup); + switch_to_tab_popup->clear(); - QAction* action = switch_to_tab_popup->addAction(i18n("To the Left")); - action->setData(0); - action = switch_to_tab_popup->addAction(i18n("To the Right")); - action->setData(1); + // whatever happens "0x1" and "0x2" are no heap positions ;-) + switch_to_tab_popup->addAction(i18nc("Switch to tab -> Previous", "Previous"))->setData(1); + switch_to_tab_popup->addAction(i18nc("Switch to tab -> Next", "Next"))->setData(2); + switch_to_tab_popup->addSeparator(); - int index = 2; - foreach (Client * c, active_popup_client->clientGroup()->clients()) { - if (c != active_popup_client->clientGroup()->visible()) { - action = switch_to_tab_popup->addAction(c->caption()); - action->setData(index); - } - index++; + + for (QList::const_iterator i = active_popup_client->tabGroup()->clients().constBegin(), + end = active_popup_client->tabGroup()->clients().constEnd(); i != end; ++i) { + if ((*i)->noBorder() || *i == active_popup_client->tabGroup()->current()) + continue; // cannot tab there anyway + switch_to_tab_popup->addAction(shortCaption((*i)->caption()))->setData(QVariant::fromValue(*i)); } } -void Workspace::initAddToTabGroup() +void Workspace::entabPopupClient(QAction* action) { - if (add_tabs_popup) + if (!active_popup_client || !action->data().isValid()) return; - add_tabs_popup = new QMenu(popup); - add_tabs_popup->setFont(KGlobalSettings::menuFont()); - connect(add_tabs_popup, SIGNAL(triggered(QAction*)), - this, SLOT(slotAddToTabGroup(QAction*))); // Merge to a group - connect(add_tabs_popup, SIGNAL(aboutToShow()), - this, SLOT(groupTabPopupAboutToShow())); // Show the possible groups to add - - QAction* action = add_tabs_popup->menuAction(); - popup->insertAction(mRemoveTabGroup, action); - action->setText(i18n("Move Window to Group")); + Client *other = action->data().value(); + if (!clients.contains(other)) // might have been lost betwenn pop-up and selection + return; + active_popup_client->tabBehind(other, true); + if (options->focusPolicyIsReasonable()) + requestFocus(active_popup_client); } -void Workspace::slotAddToTabGroup(QAction* action) +void Workspace::rebuildTabGroupPopup() { - if (!action->data().isValid() || !active_popup_client->clientGroup()) - return; - moveItemToClientGroup(active_popup_client->clientGroup(), - active_popup_client->clientGroup()->indexOfClient(active_popup_client), - clientGroups[action->data().toInt()], -1); -} + Q_ASSERT(add_tabs_popup); -void Workspace::groupTabPopupAboutToShow() -{ - if (!add_tabs_popup) - return; add_tabs_popup->clear(); - int index = 0; - for (QList::const_iterator i = clientGroups.constBegin(); i != clientGroups.constEnd(); ++i, index++) { - if (!(*i)->contains(active_popup_client)) { - QAction* action = add_tabs_popup->addAction((*i)->visible()->caption()); - action->setData(index); - } + QList handled; + for (QList::const_iterator i = clientList().constBegin(), end = clientList().constEnd(); i != end; ++i) { + if (*i == active_popup_client || (*i)->noBorder()) + continue; + add_tabs_popup->addAction(shortCaption((*i)->caption()))->setData(QVariant::fromValue(*i)); } } +void Workspace::initTabbingPopups() +{ + bool needTabManagers = false; + if (active_popup_client->tabGroup() && active_popup_client->tabGroup()->count() > 1) { + needTabManagers = true; + if (!switch_to_tab_popup) { + switch_to_tab_popup = new QMenu(i18n("Switch to Tab"), popup); + switch_to_tab_popup->setFont(KGlobalSettings::menuFont()); + connect(switch_to_tab_popup, SIGNAL(triggered(QAction*)), SLOT(selectPopupClientTab(QAction*))); + connect(switch_to_tab_popup, SIGNAL(aboutToShow()), SLOT(rebuildTabListPopup())); + popup->insertMenu(mRemoveFromTabGroup, switch_to_tab_popup); + } + } else { + delete switch_to_tab_popup; + switch_to_tab_popup = 0; + } + + if (!add_tabs_popup) { + add_tabs_popup = new QMenu(i18n("Tab behind..."), popup); + add_tabs_popup->setFont(KGlobalSettings::menuFont()); + connect(add_tabs_popup, SIGNAL(triggered(QAction*)), SLOT(entabPopupClient(QAction*))); + connect(add_tabs_popup, SIGNAL(aboutToShow()), SLOT(rebuildTabGroupPopup())); + popup->insertMenu(mRemoveFromTabGroup, add_tabs_popup); + } + + mRemoveFromTabGroup->setVisible(needTabManagers); + mCloseTabGroup->setVisible(needTabManagers); +} + void Workspace::initDesktopPopup() { if (desk_popup) @@ -739,36 +730,24 @@ void Workspace::performWindowOperation(Client* c, Options::WindowOperation op) case Options::LowerOp: lowerClient(c); break; - case Options::ClientGroupDragOp: // Handled by decoration itself + case Options::TabDragOp: // Handled by decoration itself case Options::NoOp: break; - case Options::RemoveClientFromGroupOp: - c->clientGroup()->remove(c); + case Options::RemoveTabFromGroupOp: + if (c->untab()) + if (options->focusPolicyIsReasonable()) + takeActivity(c, ActivityFocus | ActivityRaise, true); break; - case Options::MoveClientInGroupLeftOp: { - if (c->clientGroup()) { - int c_id = c->clientGroup()->indexOfClient(c); - int size = c->clientGroup()->clients().count(); - if (c_id > 0) - c->clientGroup()->setVisible(c_id - 1); - else - c->clientGroup()->setVisible(size - 1); - } + case Options::ActivateNextTabOp: + if (c->tabGroup()) + c->tabGroup()->activateNext(); break; - } - case Options::MoveClientInGroupRightOp: { - if (c->clientGroup()) { - int c_id = c->clientGroup()->indexOfClient(c); - int size = c->clientGroup()->clients().count(); - if (c_id < size - 1) - c->clientGroup()->setVisible(c_id + 1); - else - c->clientGroup()->setVisible(0); - } + case Options::ActivatePreviousTabOp: + if (c->tabGroup()) + c->tabGroup()->activatePrev(); break; - } - case Options::CloseClientGroupOp: - c->clientGroup()->closeAll(); + case Options::CloseTabGroupOp: + c->tabGroup()->closeAll(); case Options::ToggleClientTiledStateOp: { #ifdef KWIN_BUILD_TILING int desktop = c->desktop(); @@ -799,8 +778,8 @@ Options::WindowOperation Client::mouseButtonToWindowOperation(Qt::MouseButtons b com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3(); // TODO: Complete the list - if (com == Options::MouseClientGroupDrag) - return Options::ClientGroupDragOp; + if (com == Options::MouseDragTab) + return Options::TabDragOp; if (com == Options::MouseOperationsMenu) return Options::OperationsOp; return Options::NoOp; @@ -970,28 +949,18 @@ bool Client::performMouseCommand(Options::MouseCommand command, const QPoint &gl if (!isDesktop()) // No point in changing the opacity of the desktop setOpacity(qMax(opacity() - 0.1, 0.1)); break; - case Options::MouseLeftGroupWindow: { - int c_id = clientGroup()->indexOfClient(this); - int size = clientGroup()->clients().count(); - if (c_id > 0) - clientGroup()->setVisible(c_id - 1); - else - clientGroup()->setVisible(size - 1); - } + case Options::MousePreviousTab: + if (tabGroup()) + tabGroup()->activatePrev(); break; - case Options::MouseRightGroupWindow: { - int c_id = clientGroup()->indexOfClient(this); - int size = clientGroup()->clients().count(); - if (c_id < size - 1) - clientGroup()->setVisible(c_id + 1); - else - clientGroup()->setVisible(0); - } + case Options::MouseNextTab: + if (tabGroup()) + tabGroup()->activateNext(); break; case Options::MouseClose: closeWindow(); break; - case Options::MouseClientGroupDrag: + case Options::MouseDragTab: case Options::MouseNothing: replay = true; break; @@ -1405,35 +1374,22 @@ void Workspace::slotWindowToDesktopDown() } } -void Workspace::slotSwitchToTabRight() +void Workspace::slotActivateNextTab() { - if (!active_client || !active_client->clientGroup()) - return; - int c_id = active_client->clientGroup()->indexOfClient(active_client); - int size = active_client->clientGroup()->clients().count(); - if (c_id < size - 1) - active_client->clientGroup()->setVisible(c_id + 1); - else - active_client->clientGroup()->setVisible(0); + if (active_client && active_client->tabGroup()) + active_client->tabGroup()->activateNext(); } -void Workspace::slotSwitchToTabLeft() +void Workspace::slotActivatePrevTab() { - if (!active_client || !active_client->clientGroup()) - return; - int c_id = active_client->clientGroup()->indexOfClient(active_client); - int size = active_client->clientGroup()->clients().count(); - if (c_id > 0) - active_client->clientGroup()->setVisible(c_id - 1); - else - active_client->clientGroup()->setVisible(size - 1); + if (active_client && active_client->tabGroup()) + active_client->tabGroup()->activatePrev(); } -void Workspace::slotRemoveFromGroup() +void Workspace::slotUntab() { - if (!active_client || !active_client->clientGroup()) - return; - active_client->clientGroup()->remove(active_client); + if (active_client) + active_client->untab(); } /*! diff --git a/workspace.cpp b/workspace.cpp index 6c7465eb01..4f9ee18ffd 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -632,6 +632,8 @@ void Workspace::removeClient(Client* c, allowed_t) if (c == active_popup_client) closeActivePopup(); + c->untab(); + if (client_keys_client == c) setupWindowShortcutDone(false); if (!c->shortcut().isEmpty()) { @@ -782,7 +784,7 @@ void Workspace::updateToolWindows(bool also_hide) // TODO: What if Client's transiency/group changes? should this be called too? (I'm paranoid, am I not?) if (!options->hideUtilityWindowsForInactive) { for (ClientList::ConstIterator it = clients.constBegin(); it != clients.constEnd(); ++it) - if (!(*it)->clientGroup() || (*it)->clientGroup()->visible() == *it) + if (!(*it)->tabGroup() || (*it)->tabGroup()->current() == *it) (*it)->hideClient(false); return; } @@ -952,21 +954,18 @@ void Workspace::slotReconfigure() //curtain.setGeometry( Kephal::ScreenUtils::desktopGeometry() ); //curtain.show(); - for (ClientList::ConstIterator it = clients.constBegin(); - it != clients.constEnd(); - ++it) + for (ClientList::ConstIterator it = clients.constBegin(); it != clients.constEnd(); ++it) (*it)->updateDecoration(true, true); // If the new decoration doesn't supports tabs then ungroup clients - if (!decorationSupportsClientGrouping()) { - QList tmpGroups = clientGroups; // Prevent crashing - for (QList::const_iterator i = tmpGroups.constBegin(); i != tmpGroups.constEnd(); ++i) - (*i)->removeAll(); + if (!decorationSupportsTabbing()) { + foreach (Client * c, clients) + c->untab(); } mgr->destroyPreviousPlugin(); } else { forEachClient(CheckBorderSizesProcedure()); foreach (Client * c, clients) - c->triggerDecorationRepaint(); + c->triggerDecorationRepaint(); } #ifdef KWIN_BUILD_SCREENEDGES @@ -2081,87 +2080,6 @@ void Workspace::checkCursorPos() } } -int Workspace::indexOfClientGroup(ClientGroup* group) -{ - return clientGroups.indexOf(group); -} - -void Workspace::moveItemToClientGroup(ClientGroup* oldGroup, int oldIndex, - ClientGroup* group, int index) -{ - Client* c = oldGroup->clients().at(oldIndex); - group->add(c, index, true); -} - -void Workspace::removeClientGroup(ClientGroup* group) -{ - int index = clientGroups.indexOf(group); - if (index == -1) { - return; - } - - clientGroups.removeAt(index); - for (; index < clientGroups.size(); index++) { - foreach (Client *c, clientGroups.at(index)->clients()) { - c->setClientGroup(c->clientGroup()); - } - } -} - -// To accept "mainwindow#1" to "mainwindow#2" -static QByteArray truncatedWindowRole(QByteArray a) -{ - int i = a.indexOf('#'); - if (i == -1) - return a; - QByteArray b(a); - b.truncate(i); - return b; -} - -Client* Workspace::findSimilarClient(Client* c) -{ - // Attempt to find a similar window to the input. If we find multiple possibilities that are in - // different groups then ignore all of them. This function is for automatic window grouping. - Client* found = NULL; - - // See if the window has a group ID to match with - QString wGId = c->rules()->checkAutogroupById(QString()); - if (!wGId.isEmpty()) { - foreach (Client * cl, clients) { - if (wGId == cl->rules()->checkAutogroupById(QString())) { - if (found && found->clientGroup() != cl->clientGroup()) { // We've found two, ignore both - found = NULL; - break; // Continue to the next test - } - found = cl; - } - } - if (found) - return found; - } - - // If this is a transient window don't take a guess - if (c->isTransient()) - return NULL; - - // If we don't have an ID take a guess - if (c->rules()->checkAutogrouping(options->autogroupSimilarWindows)) { - QByteArray wRole = truncatedWindowRole(c->windowRole()); - foreach (Client * cl, clients) { - QByteArray wRoleB = truncatedWindowRole(cl->windowRole()); - if (c->resourceClass() == cl->resourceClass() && // Same resource class - wRole == wRoleB && // Same window role - cl->isNormalWindow()) { // Normal window TODO: Can modal windows be "normal"? - if (found && found->clientGroup() != cl->clientGroup()) // We've found two, ignore both - return NULL; - found = cl; - } - } - } - - return found; -} Outline* Workspace::outline() { diff --git a/workspace.h b/workspace.h index 40562d4d47..d9a4ee37fa 100644 --- a/workspace.h +++ b/workspace.h @@ -78,7 +78,6 @@ class Tile; class Tiling; class TilingLayout; #endif -class ClientGroup; #ifdef KWIN_BUILD_DESKTOPCHANGEOSD class DesktopChangeOSD; #endif @@ -367,16 +366,6 @@ public: return client_keys; } - // Tabbing - void addClientGroup(ClientGroup* group); - void removeClientGroup(ClientGroup* group); - /// Returns the index of c in clientGroupList. - int indexOfClientGroup(ClientGroup* group); - /// Change the client c_id to the group with index g_id - void moveItemToClientGroup(ClientGroup* oldGroup, int oldIndex, ClientGroup* group, int index = -1); - Client* findSimilarClient(Client* c); - QList clientGroups; // List of existing clients groups with no special order - /** * Returns the list of clients sorted in stacking order, with topmost client * at the last position @@ -440,7 +429,7 @@ public: bool hasDecorationShadows() const; Qt::Corner decorationCloseButtonCorner(); bool decorationHasAlpha() const; - bool decorationSupportsClientGrouping() const; // Returns true if the decoration supports tabs. + bool decorationSupportsTabbing() const; // Returns true if the decoration supports tabs. bool decorationSupportsFrameOverlap() const; bool decorationSupportsBlurBehind() const; @@ -632,15 +621,15 @@ public slots: // NOTE: debug method void dumpTiles() const; - void slotSwitchToTabLeft(); // Slot to move left the active Client. - void slotSwitchToTabRight(); // Slot to move right the active Client. - void slotRemoveFromGroup(); // Slot to remove the active client from its group. + void slotActivateNextTab(); // Slot to move left the active Client. + void slotActivatePrevTab(); // Slot to move right the active Client. + void slotUntab(); // Slot to remove the active client from its group. private slots: - void groupTabPopupAboutToShow(); // Popup to add to another group - void switchToTabPopupAboutToShow(); // Popup to move in the group - void slotAddToTabGroup(QAction*); // Add client to a group - void slotSwitchToTab(QAction*); // Change the tab + void rebuildTabGroupPopup(); + void rebuildTabListPopup(); + void entabPopupClient(QAction*); + void selectPopupClientTab(QAction*); void desktopPopupAboutToShow(); void activityPopupAboutToShow(); void clientPopupAboutToShow(); @@ -699,6 +688,7 @@ private: void initShortcuts(); void initDesktopPopup(); void initActivityPopup(); + void initTabbingPopups(); void restartKWin(const QString &reason); void discardPopup(); void setupWindowShortcut(Client* c); @@ -842,16 +832,13 @@ private: QAction* mNoBorderOpAction; QAction* mMinimizeOpAction; QAction* mCloseOpAction; - QAction* mRemoveTabGroup; // Remove client from group - QAction* mCloseGroup; // Close all clients in the group + QAction* mRemoveFromTabGroup; // Remove client from group + QAction* mCloseTabGroup; // Close all clients in the group ShortcutDialog* client_keys_dialog; Client* client_keys_client; bool global_shortcuts_disabled; bool global_shortcuts_disabled_for_client; - void initAddToTabGroup(); // Load options for menu add_tabs_popup - void initSwitchToTab(); // Load options for menu switch_to_tab_popup - PluginMgr* mgr; RootInfo* rootInfo; @@ -1194,12 +1181,12 @@ inline bool Workspace::decorationHasAlpha() const return mgr->factory()->supports(AbilityUsesAlphaChannel); } -inline bool Workspace::decorationSupportsClientGrouping() const +inline bool Workspace::decorationSupportsTabbing() const { if (!hasDecorationPlugin()) { return false; } - return mgr->factory()->supports(AbilityClientGrouping); + return mgr->factory()->supports(AbilityTabbing); } inline bool Workspace::decorationSupportsFrameOverlap() const @@ -1218,11 +1205,6 @@ inline bool Workspace::decorationSupportsBlurBehind() const return mgr->factory()->supports(AbilityUsesBlurBehind); } -inline void Workspace::addClientGroup(ClientGroup* group) -{ - clientGroups.append(group); -} - } // namespace #endif