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
This commit is contained in:
parent
bf88ec09ac
commit
85635dd485
65 changed files with 1252 additions and 2779 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
157
bridge.cpp
157
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,89 +219,118 @@ 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<Client*>(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<long>(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);
|
||||
if (!B) {
|
||||
if (c->tabGroup()) {
|
||||
if (Client *a = clientForId(A))
|
||||
a->untab();
|
||||
}
|
||||
|
||||
void Bridge::moveItemToClientGroup(long itemId, int before)
|
||||
{
|
||||
Client* item = reinterpret_cast<Client*>(itemId);
|
||||
if (!c->workspace()->hasClient(item)) {
|
||||
kWarning(1212) << "****** ARBITRARY CODE EXECUTION ATTEMPT DETECTED ******";
|
||||
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);
|
||||
if (!B) {
|
||||
if (c->tabGroup()) {
|
||||
if (Client *a = clientForId(A))
|
||||
a->untab();
|
||||
}
|
||||
|
||||
void Bridge::closeClientGroupItem(int index)
|
||||
{
|
||||
if (!c->clientGroup())
|
||||
return;
|
||||
const ClientList list = c->clientGroup()->clients();
|
||||
if (index >= 0 || index <= list.count())
|
||||
list.at(index)->closeWindow();
|
||||
}
|
||||
|
||||
void Bridge::closeAllInClientGroup()
|
||||
{
|
||||
if (c->clientGroup())
|
||||
c->clientGroup()->closeAll();
|
||||
if (Client *a = clientForId(A))
|
||||
if (Client *b = clientForId(B))
|
||||
a->tabBehind(b, true);
|
||||
}
|
||||
|
||||
void Bridge::displayClientMenu(int index, const QPoint& pos)
|
||||
|
||||
void Bridge::untab(long id, const QRect& newGeom)
|
||||
{
|
||||
if (c->clientGroup())
|
||||
c->clientGroup()->displayClientMenu(index, pos);
|
||||
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::closeTab(long id)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
28
bridge.h
28
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<long>(c);
|
||||
}
|
||||
Client* c;
|
||||
};
|
||||
|
||||
|
|
128
client.cpp
128
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) {
|
||||
map(Allowed);
|
||||
hidden = false;
|
||||
//updateVisibility();
|
||||
//updateAllowedActions();
|
||||
if (shown != hidden)
|
||||
return; // nothing to change
|
||||
hidden = !shown;
|
||||
if (options->inactiveTabsSkipTaskbar)
|
||||
setSkipTaskbar(false, false);
|
||||
setSkipTaskbar(hidden, false); // TODO: Causes reshuffle of the taskbar
|
||||
if (shown) {
|
||||
map(Allowed);
|
||||
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());
|
||||
}
|
||||
|
|
33
client.h
33
client.h
|
@ -41,7 +41,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "kdecoration.h"
|
||||
#include "rules.h"
|
||||
#include "toplevel.h"
|
||||
#include "clientgroup.h"
|
||||
#include "tabgroup.h"
|
||||
|
||||
#ifdef HAVE_XSYNC
|
||||
#include <X11/extensions/sync.h>
|
||||
|
@ -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
|
||||
|
|
357
clientgroup.cpp
357
clientgroup.cpp
|
@ -1,357 +0,0 @@
|
|||
/*******************************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
#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<EffectsHandlerImpl*>(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<EffectsHandlerImpl*>(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<EffectsHandlerImpl*>(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)));
|
||||
}
|
||||
|
||||
}
|
266
clientgroup.h
266
clientgroup.h
|
@ -1,266 +0,0 @@
|
|||
/*******************************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef KWIN_CLIENTGROUP_H
|
||||
#define KWIN_CLIENTGROUP_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#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<KWin::Client*> 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<KWin::ClientGroup*>)
|
||||
|
||||
#endif
|
|
@ -3,4 +3,3 @@ add_subdirectory( oxygen )
|
|||
add_subdirectory( plastik )
|
||||
add_subdirectory( b2 )
|
||||
add_subdirectory( laptop )
|
||||
add_subdirectory( tabstrip )
|
||||
|
|
|
@ -56,7 +56,7 @@ void AuroraeFactory::init()
|
|||
m_theme->loadTheme(themeName, config);
|
||||
m_theme->setBorderSize((KDecorationDefines::BorderSize)themeGroup.readEntry<int>("BorderSize", KDecorationDefines::BorderNormal));
|
||||
m_theme->setButtonSize((KDecorationDefines::BorderSize)themeGroup.readEntry<int>("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;
|
||||
|
|
|
@ -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 ),
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
|
|
|
@ -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 ); }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -171,7 +171,7 @@ namespace Oxygen
|
|||
return true;
|
||||
|
||||
// tabs
|
||||
case AbilityClientGrouping:
|
||||
case AbilityTabbing:
|
||||
return true;
|
||||
|
||||
// no colors supported at this time
|
||||
|
|
|
@ -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 )
|
|
@ -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} )
|
|
@ -1,96 +0,0 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "tabstripconfig.h"
|
||||
|
||||
#include "tabstripconfig.moc"
|
||||
|
||||
#include <KConfig>
|
||||
#include <KGlobal>
|
||||
#include <KLocale>
|
||||
|
||||
#include <QString>
|
||||
#include <QRadioButton>
|
||||
|
||||
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();
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef TABSTRIPCONFIG_H
|
||||
#define TABSTRIPCONFIG_H
|
||||
|
||||
#include "ui_tabstripconfig.h"
|
||||
|
||||
#include <KConfig>
|
||||
#include <QObject>
|
||||
|
||||
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
|
|
@ -1,78 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabstripConfigUi</class>
|
||||
<widget class="QWidget" name="TabstripConfigUi">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>276</width>
|
||||
<height>98</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Tabstrip</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Title &Alignment</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="left">
|
||||
<property name="text">
|
||||
<string>&Left</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="center">
|
||||
<property name="text">
|
||||
<string>&Center</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="right">
|
||||
<property name="text">
|
||||
<string>&Right</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showIcon">
|
||||
<property name="text">
|
||||
<string>Display window icons</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="outlineColorLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="outline">
|
||||
<property name="text">
|
||||
<string>O&utline Color:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>outlineColor</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="KColorButton" name="outlineColor"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -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
|
|
@ -1,317 +0,0 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include <kcommondecoration.h>
|
||||
#include "tabstripbutton.h"
|
||||
#include "tabstripdecoration.h"
|
||||
#include "tabstripfactory.h"
|
||||
|
||||
#include <KLocale>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPalette>
|
||||
#include <QPixmap>
|
||||
#include <QRect>
|
||||
|
||||
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 );
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef TABSTRIPBUTTON_H
|
||||
#define TABSTRIPBUTTON_H
|
||||
|
||||
#include <kcommondecoration.h>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
|
||||
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
|
|
@ -1,443 +0,0 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "tabstripdecoration.h"
|
||||
#include "tabstripbutton.h"
|
||||
#include "tabstripfactory.h"
|
||||
|
||||
#include <KLocale>
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
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<rem?tabWidth+1:tabWidth, t_h );
|
||||
if( tabRect.contains( point ) )
|
||||
return i;
|
||||
tab_x += tabRect.width();
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef TABSTRIPDECORATION_H
|
||||
#define TABSTRIPDECORATION_H
|
||||
|
||||
#include <kdecoration.h>
|
||||
#include <kcommondecoration.h>
|
||||
#include <QPaintEvent>
|
||||
#include <kdebug.h>
|
||||
|
||||
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
|
|
@ -1,113 +0,0 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "tabstripfactory.h"
|
||||
#include "tabstripdecoration.h"
|
||||
|
||||
#include <KConfig>
|
||||
#include <KConfigGroup>
|
||||
#include <KDebug>
|
||||
|
||||
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;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/********************************************************************
|
||||
Tabstrip KWin window decoration
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2009 Jorge Mata <matamax123@gmail.com>
|
||||
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef TABSTRIPFACTORY_H
|
||||
#define TABSTRIPFACTORY_H
|
||||
|
||||
#include <kdecorationfactory.h>
|
||||
#include <kdecoration.h>
|
||||
#include <kdecorationbridge.h>
|
||||
|
||||
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
|
20
effects.cpp
20
effects.cpp
|
@ -385,10 +385,12 @@ 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<Client*>(c));
|
||||
setupClientConnections(static_cast<Client*>(c));
|
||||
Q_ASSERT(dynamic_cast<Client*>(t));
|
||||
Client *c = static_cast<Client*>(t);
|
||||
setupClientConnections(c);
|
||||
if (!c->tabGroup()) // the "window" has already been there
|
||||
emit windowAdded(c->effectWindow());
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
30
geometry.cpp
30
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -1277,59 +1277,64 @@ bool KCommonDecorationUnstable::compositingActive() const
|
|||
|
||||
// Window tabbing
|
||||
|
||||
bool KCommonDecorationUnstable::isClientGroupActive()
|
||||
int KCommonDecorationUnstable::tabCount() const
|
||||
{
|
||||
return static_cast<KDecorationUnstable*>(decoration())->isClientGroupActive();
|
||||
return static_cast<const KDecorationUnstable*>(decoration())->tabCount();
|
||||
}
|
||||
|
||||
QList< ClientGroupItem > KCommonDecorationUnstable::clientGroupItems() const
|
||||
QString KCommonDecorationUnstable::caption(int idx) const
|
||||
{
|
||||
return static_cast<const KDecorationUnstable*>(decoration())->clientGroupItems();
|
||||
return static_cast<const KDecorationUnstable*>(decoration())->caption(idx);
|
||||
}
|
||||
|
||||
long KCommonDecorationUnstable::itemId(int index)
|
||||
QIcon KCommonDecorationUnstable::icon(int idx) const
|
||||
{
|
||||
return static_cast<KDecorationUnstable*>(decoration())->itemId(index);
|
||||
return static_cast<const KDecorationUnstable*>(decoration())->icon(idx);
|
||||
}
|
||||
|
||||
int KCommonDecorationUnstable::visibleClientGroupItem()
|
||||
long KCommonDecorationUnstable::tabId(int idx) const
|
||||
{
|
||||
return static_cast<KDecorationUnstable*>(decoration())->visibleClientGroupItem();
|
||||
return static_cast<const KDecorationUnstable*>(decoration())->tabId(idx);
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::setVisibleClientGroupItem(int index)
|
||||
long KCommonDecorationUnstable::currentTabId() const
|
||||
{
|
||||
static_cast<KDecorationUnstable*>(decoration())->setVisibleClientGroupItem(index);
|
||||
return static_cast<const KDecorationUnstable*>(decoration())->currentTabId();
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::moveItemInClientGroup(int index, int before)
|
||||
void KCommonDecorationUnstable::setCurrentTab(long id)
|
||||
{
|
||||
static_cast<KDecorationUnstable*>(decoration())->moveItemInClientGroup(index, before);
|
||||
static_cast<KDecorationUnstable*>(decoration())->setCurrentTab(id);
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::moveItemToClientGroup(long itemId, int before)
|
||||
void KCommonDecorationUnstable::tab_A_before_B(long A, long B)
|
||||
{
|
||||
static_cast<KDecorationUnstable*>(decoration())->moveItemToClientGroup(itemId, before);
|
||||
static_cast<KDecorationUnstable*>(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<KDecorationUnstable*>(decoration())->removeFromClientGroup(index, newGeom);
|
||||
static_cast<KDecorationUnstable*>(decoration())->tab_A_behind_B(A, B);
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::closeClientGroupItem(int index)
|
||||
void KCommonDecorationUnstable::untab(long id, const QRect& newGeom)
|
||||
{
|
||||
static_cast<KDecorationUnstable*>(decoration())->closeClientGroupItem(index);
|
||||
static_cast<KDecorationUnstable*>(decoration())->untab(id, newGeom);
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::closeAllInClientGroup()
|
||||
void KCommonDecorationUnstable::closeTab(long id)
|
||||
{
|
||||
static_cast<KDecorationUnstable*>(decoration())->closeAllInClientGroup();
|
||||
static_cast<KDecorationUnstable*>(decoration())->closeTab(id);
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::displayClientMenu(int index, const QPoint& pos)
|
||||
void KCommonDecorationUnstable::closeTabGroup()
|
||||
{
|
||||
static_cast<KDecorationUnstable*>(decoration())->displayClientMenu(index, pos);
|
||||
static_cast<KDecorationUnstable*>(decoration())->closeTabGroup();
|
||||
}
|
||||
|
||||
void KCommonDecorationUnstable::showWindowMenu(const QPoint &pos, long id)
|
||||
{
|
||||
static_cast<KDecorationUnstable*>(decoration())->showWindowMenu(pos, id);
|
||||
}
|
||||
|
||||
KDecoration::WindowOperation KCommonDecorationUnstable::buttonToWindowOperation(Qt::MouseButtons button)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
103
manage.cpp
103
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);
|
||||
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 (!client_group && !isMapped && !session) {
|
||||
}
|
||||
}
|
||||
if (autogrouping && !tab_group && !isMapped && !session) {
|
||||
// Attempt to automatically group similar windows
|
||||
const Client* similar = workspace()->findSimilarClient(this);
|
||||
if (similar && similar->clientGroup() && !similar->noBorder()) {
|
||||
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);
|
||||
similar->clientGroup()->add(this, -1,
|
||||
rules()->checkAutogroupInForeground(options->autogroupInForeground));
|
||||
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
|
||||
|
|
10
options.cpp
10
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
2
scene.h
2
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
|
||||
};
|
||||
|
|
|
@ -20,25 +20,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#include "meta.h"
|
||||
#include "client.h"
|
||||
#include "clientgroup.h"
|
||||
#include "tabgroup.h"
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
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<KWin::ClientGroup*>(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<QSize>(eng, Size::toScriptValue, Size::fromScriptValue);
|
||||
qScriptRegisterMetaType<QRect>(eng, Rect::toScriptValue, Rect::fromScriptValue);
|
||||
qScriptRegisterMetaType<KClientRef>(eng, Client::toScriptValue, Client::fromScriptValue);
|
||||
qScriptRegisterMetaType<KClientGroupRef>(eng, ClientGroup::toScriptValue, ClientGroup::fromScriptValue);
|
||||
|
||||
qScriptRegisterSequenceMetaType<QStringList>(eng);
|
||||
qScriptRegisterSequenceMetaType< QList<KWin::ClientGroup*> >(eng);
|
||||
qScriptRegisterSequenceMetaType< QList<KWin::Client*> >(eng);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -131,10 +131,6 @@ SLOTWRAPPER(slotWindowToDesktopLeft)
|
|||
SLOTWRAPPER(slotWindowToDesktopUp)
|
||||
SLOTWRAPPER(slotWindowToDesktopDown)
|
||||
|
||||
SLOTWRAPPER(slotSwitchToTabLeft)
|
||||
SLOTWRAPPER(slotSwitchToTabRight)
|
||||
SLOTWRAPPER(slotRemoveFromGroup)
|
||||
|
||||
#undef SLOTWRAPPER
|
||||
|
||||
void WorkspaceWrapper::setActiveClient(KWin::Client* client)
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
22
sm.cpp
22
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<int>(reinterpret_cast<long>(c->clientGroup())) : 0;
|
||||
cg.writeEntry(QString("clientGroup") + n, group);
|
||||
cg.writeEntry(QString("tabGroup") + n, static_cast<int>(reinterpret_cast<long>(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;
|
||||
}
|
||||
|
|
4
sm.h
4
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;
|
||||
};
|
||||
|
||||
|
|
295
tabgroup.cpp
Normal file
295
tabgroup.cpp
Normal file
|
@ -0,0 +1,295 @@
|
|||
/*******************************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2011/2012 The KWin team <kwin@kde.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as 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 <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
#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<EffectsHandlerImpl*>(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<EffectsHandlerImpl*>(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<EffectsHandlerImpl*>(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<EffectsHandlerImpl*>(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);
|
||||
}
|
||||
|
||||
}
|
186
tabgroup.h
Normal file
186
tabgroup.h
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*******************************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2011/2012 The KWin team <kwin@kde.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as 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 <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef KWIN_TABGROUP_H
|
||||
#define KWIN_TABGROUP_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#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
|
|
@ -340,6 +340,10 @@ void Toplevel::setReadyForPainting()
|
|||
if (compositing()) {
|
||||
addRepaintFull();
|
||||
emit windowShown(this);
|
||||
if (Client *cl = dynamic_cast<Client*>(this)) {
|
||||
if (cl->tabGroup() && cl->tabGroup()->current() == cl)
|
||||
cl->tabGroup()->setCurrent(cl, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
290
useractions.cpp
290
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<KAction*>(keys->action("Remove TabGroup"));
|
||||
if (decorationSupportsTabbing()) {
|
||||
mRemoveFromTabGroup = popup->addAction(i18n("&Untab"));
|
||||
kaction = qobject_cast<KAction*>(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<KAction*>(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,122 +294,113 @@ void Workspace::clientPopupAboutToShow()
|
|||
}
|
||||
mTilingStateOpAction->setVisible(m_tiling->isEnabled());
|
||||
#endif
|
||||
delete switch_to_tab_popup;
|
||||
switch_to_tab_popup = 0;
|
||||
|
||||
if (decorationSupportsTabbing()) {
|
||||
initTabbingPopups();
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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<ClientGroup*>::const_iterator i = clientGroups.constBegin(); i != clientGroups.constEnd(); ++i) {
|
||||
if ((*i)->contains(active_popup_client)) {
|
||||
(*i)->setVisible(side);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::switchToTabPopupAboutToShow()
|
||||
{
|
||||
if (!switch_to_tab_popup)
|
||||
if (Client *other = action->data().value<Client*>()) {
|
||||
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();
|
||||
}
|
||||
|
||||
static QString shortCaption(const QString &s)
|
||||
{
|
||||
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<Client*>::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<Client*>();
|
||||
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<ClientGroup*>::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<Client*> handled;
|
||||
for (QList<Client*>::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()
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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,15 +954,12 @@ 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<ClientGroup*> tmpGroups = clientGroups; // Prevent crashing
|
||||
for (QList<ClientGroup*>::const_iterator i = tmpGroups.constBegin(); i != tmpGroups.constEnd(); ++i)
|
||||
(*i)->removeAll();
|
||||
if (!decorationSupportsTabbing()) {
|
||||
foreach (Client * c, clients)
|
||||
c->untab();
|
||||
}
|
||||
mgr->destroyPreviousPlugin();
|
||||
} else {
|
||||
|
@ -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()
|
||||
{
|
||||
|
|
44
workspace.h
44
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<ClientGroup*> 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
|
||||
|
|
Loading…
Reference in a new issue