Move TabGroup functionality from Client to AbstractClient
Only setClientShown remains in Client. This might need a dedicated implementation for ShellClient.
This commit is contained in:
parent
7defd93047
commit
46d8b87646
6 changed files with 129 additions and 149 deletions
|
@ -114,14 +114,10 @@ bool AbstractClient::isTransient() const
|
|||
return false;
|
||||
}
|
||||
|
||||
TabGroup *AbstractClient::tabGroup() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AbstractClient::setTabGroup(TabGroup* group)
|
||||
{
|
||||
Q_UNUSED(group)
|
||||
tab_group = group;
|
||||
emit tabGroupChanged();
|
||||
}
|
||||
|
||||
void AbstractClient::setClientShown(bool shown)
|
||||
|
@ -131,14 +127,81 @@ void AbstractClient::setClientShown(bool shown)
|
|||
|
||||
bool AbstractClient::untab(const QRect &toGeometry, bool clientRemoved)
|
||||
{
|
||||
Q_UNUSED(toGeometry)
|
||||
Q_UNUSED(clientRemoved)
|
||||
TabGroup *group = tab_group;
|
||||
if (group && group->remove(this)) { // remove sets the tabgroup to "0", therefore the pointer is cached
|
||||
if (group->isEmpty()) {
|
||||
delete group;
|
||||
}
|
||||
if (clientRemoved)
|
||||
return true; // there's been a broadcast signal that this client is now removed - don't touch it
|
||||
setClientShown(!(isMinimized() || isShade()));
|
||||
bool keepSize = toGeometry.size() == size();
|
||||
bool changedSize = false;
|
||||
if (quickTileMode() != QuickTileMode(QuickTileFlag::None)) {
|
||||
changedSize = true;
|
||||
setQuickTileMode(QuickTileFlag::None); // if we leave a quicktiled group, assume that the user wants to untile
|
||||
}
|
||||
if (toGeometry.isValid()) {
|
||||
if (maximizeMode() != MaximizeRestore) {
|
||||
changedSize = true;
|
||||
maximize(MaximizeRestore); // explicitly calling for a geometry -> unmaximize
|
||||
}
|
||||
if (keepSize && changedSize) {
|
||||
setGeometryRestore(geometry()); // checkWorkspacePosition() invokes it
|
||||
QPoint cpoint = Cursor::pos();
|
||||
QPoint point = cpoint;
|
||||
point.setX((point.x() - toGeometry.x()) * geometryRestore().width() / toGeometry.width());
|
||||
point.setY((point.y() - toGeometry.y()) * geometryRestore().height() / toGeometry.height());
|
||||
auto geometry_restore = geometryRestore();
|
||||
geometry_restore.moveTo(cpoint-point);
|
||||
setGeometryRestore(geometry_restore);
|
||||
} else {
|
||||
setGeometryRestore(toGeometry); // checkWorkspacePosition() invokes it
|
||||
}
|
||||
setGeometry(geometryRestore());
|
||||
checkWorkspacePosition();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AbstractClient::tabTo(AbstractClient *other, bool behind, bool activate)
|
||||
{
|
||||
Q_ASSERT(other && other != this);
|
||||
|
||||
if (tab_group && tab_group == other->tabGroup()) { // special case: move inside group
|
||||
tab_group->move(this, other, behind);
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void AbstractClient::syncTabGroupFor(QString property, bool fromThisClient)
|
||||
{
|
||||
if (tab_group)
|
||||
tab_group->sync(property.toAscii().data(), fromThisClient ? this : tab_group->current());
|
||||
}
|
||||
|
||||
bool AbstractClient::isCurrentTab() const
|
||||
{
|
||||
return true;
|
||||
return !tab_group || tab_group->current() == this;
|
||||
}
|
||||
|
||||
xcb_timestamp_t AbstractClient::userTime() const
|
||||
|
|
|
@ -272,6 +272,10 @@ class KWIN_EXPORT AbstractClient : public Toplevel
|
|||
* considered unresponsive. This usually indicates that the application froze or crashed.
|
||||
*/
|
||||
Q_PROPERTY(bool unresponsive READ unresponsive NOTIFY unresponsiveChanged)
|
||||
/**
|
||||
* The "Window Tabs" Group this Client belongs to.
|
||||
**/
|
||||
Q_PROPERTY(KWin::TabGroup* tabGroup READ tabGroup NOTIFY tabGroupChanged SCRIPTABLE false)
|
||||
|
||||
public:
|
||||
virtual ~AbstractClient();
|
||||
|
@ -422,11 +426,34 @@ public:
|
|||
return m_minimized;
|
||||
}
|
||||
virtual void setFullScreen(bool set, bool user = true) = 0;
|
||||
virtual TabGroup *tabGroup() const;
|
||||
virtual void setTabGroup(TabGroup* group);
|
||||
// Tabbing functions
|
||||
Q_INVOKABLE inline bool tabBefore(AbstractClient *other, bool activate) { return tabTo(other, false, activate); }
|
||||
Q_INVOKABLE inline bool tabBehind(AbstractClient *other, bool activate) { return tabTo(other, true, activate); }
|
||||
/**
|
||||
* Syncs the *dynamic* @param property @param fromThisClient or the @link currentTab() to
|
||||
* all members of the @link tabGroup() (if there is one)
|
||||
*
|
||||
* eg. if you call:
|
||||
* client->setProperty("kwin_tiling_floats", true);
|
||||
* client->syncTabGroupFor("kwin_tiling_floats", true)
|
||||
* all clients in this tabGroup will have ::property("kwin_tiling_floats").toBool() == true
|
||||
*
|
||||
* WARNING: non dynamic properties are ignored - you're not supposed to alter/update such explicitly
|
||||
*/
|
||||
Q_INVOKABLE void syncTabGroupFor(QString property, bool fromThisClient = false);
|
||||
TabGroup *tabGroup() const;
|
||||
/**
|
||||
* Set tab group - this is to be invoked by TabGroup::add/remove(client) and NO ONE ELSE
|
||||
*/
|
||||
void setTabGroup(TabGroup* group);
|
||||
virtual void setClientShown(bool shown);
|
||||
Q_INVOKABLE virtual bool untab(const QRect &toGeometry = QRect(), bool clientRemoved = false);
|
||||
virtual bool isCurrentTab() const;
|
||||
Q_INVOKABLE bool untab(const QRect &toGeometry = QRect(), bool clientRemoved = false);
|
||||
/*
|
||||
* When a click is done in the decoration and it calls the group
|
||||
* to change the visible client it starts to move-resize the new
|
||||
* client, this function stops it.
|
||||
*/
|
||||
bool isCurrentTab() const;
|
||||
virtual QRect geometryRestore() const = 0;
|
||||
virtual MaximizeMode maximizeMode() const = 0;
|
||||
void maximize(MaximizeMode);
|
||||
|
@ -732,6 +759,11 @@ Q_SIGNALS:
|
|||
void hasApplicationMenuChanged(bool);
|
||||
void applicationMenuActiveChanged(bool);
|
||||
void unresponsiveChanged(bool);
|
||||
/**
|
||||
* 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 tabGroupChanged();
|
||||
|
||||
protected:
|
||||
AbstractClient();
|
||||
|
@ -1031,6 +1063,8 @@ protected:
|
|||
void finishWindowRules();
|
||||
void discardTemporaryRules();
|
||||
|
||||
bool tabTo(AbstractClient *other, bool behind, bool activate);
|
||||
|
||||
private:
|
||||
void handlePaletteChange();
|
||||
QSharedPointer<TabBox::TabBoxClientImpl> m_tabBoxClient;
|
||||
|
@ -1108,6 +1142,7 @@ private:
|
|||
QKeySequence _shortcut;
|
||||
|
||||
WindowRules m_rules;
|
||||
TabGroup* tab_group = nullptr;
|
||||
|
||||
static bool s_haveResizeEffect;
|
||||
};
|
||||
|
@ -1175,6 +1210,11 @@ inline void AbstractClient::setPendingGeometryUpdate(PendingGeometry_t update)
|
|||
m_pendingGeometryUpdate = update;
|
||||
}
|
||||
|
||||
inline TabGroup* AbstractClient::tabGroup() const
|
||||
{
|
||||
return tab_group;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWin::AbstractClient*)
|
||||
|
|
101
client.cpp
101
client.cpp
|
@ -108,7 +108,6 @@ Client::Client()
|
|||
, shadeHoverTimer(NULL)
|
||||
, m_colormap(XCB_COLORMAP_NONE)
|
||||
, in_group(NULL)
|
||||
, tab_group(NULL)
|
||||
, ping_timer(NULL)
|
||||
, m_killHelperPID(0)
|
||||
, m_pingTimestamp(XCB_TIME_CURRENT_TIME)
|
||||
|
@ -167,6 +166,17 @@ Client::Client()
|
|||
}
|
||||
});
|
||||
|
||||
connect(this, &Client::tabGroupChanged, this,
|
||||
[this] {
|
||||
auto group = tabGroup();
|
||||
if (group) {
|
||||
unsigned long data[] = {qHash(group)}; //->id();
|
||||
m_client.changeProperty(atoms->kde_net_wm_tab_group, XCB_ATOM_CARDINAL, 32, 1, data);
|
||||
}
|
||||
else
|
||||
m_client.deleteProperty(atoms->kde_net_wm_tab_group);
|
||||
});
|
||||
|
||||
// SELI TODO: Initialize xsizehints??
|
||||
}
|
||||
|
||||
|
@ -1506,95 +1516,6 @@ void Client::fetchIconicName()
|
|||
}
|
||||
}
|
||||
|
||||
bool Client::tabTo(Client *other, bool behind, bool activate)
|
||||
{
|
||||
Q_ASSERT(other && other != this);
|
||||
|
||||
if (tab_group && tab_group == other->tabGroup()) { // special case: move inside group
|
||||
tab_group->move(this, other, behind);
|
||||
return true;
|
||||
}
|
||||
|
||||
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, bool clientRemoved)
|
||||
{
|
||||
TabGroup *group = tab_group;
|
||||
if (group && group->remove(this)) { // remove sets the tabgroup to "0", therefore the pointer is cached
|
||||
if (group->isEmpty()) {
|
||||
delete group;
|
||||
}
|
||||
if (clientRemoved)
|
||||
return true; // there's been a broadcast signal that this client is now removed - don't touch it
|
||||
setClientShown(!(isMinimized() || isShade()));
|
||||
bool keepSize = toGeometry.size() == size();
|
||||
bool changedSize = false;
|
||||
if (quickTileMode() != QuickTileMode(QuickTileFlag::None)) {
|
||||
changedSize = true;
|
||||
setQuickTileMode(QuickTileFlag::None); // if we leave a quicktiled group, assume that the user wants to untile
|
||||
}
|
||||
if (toGeometry.isValid()) {
|
||||
if (maximizeMode() != MaximizeRestore) {
|
||||
changedSize = true;
|
||||
maximize(MaximizeRestore); // explicitly calling for a geometry -> unmaximize
|
||||
}
|
||||
if (keepSize && changedSize) {
|
||||
geom_restore = geometry(); // checkWorkspacePosition() invokes it
|
||||
QPoint cpoint = Cursor::pos();
|
||||
QPoint point = cpoint;
|
||||
point.setX((point.x() - toGeometry.x()) * geom_restore.width() / toGeometry.width());
|
||||
point.setY((point.y() - toGeometry.y()) * geom_restore.height() / toGeometry.height());
|
||||
geom_restore.moveTo(cpoint-point);
|
||||
} else {
|
||||
geom_restore = toGeometry; // checkWorkspacePosition() invokes it
|
||||
}
|
||||
setGeometry(geom_restore);
|
||||
checkWorkspacePosition();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Client::setTabGroup(TabGroup *group)
|
||||
{
|
||||
tab_group = group;
|
||||
if (group) {
|
||||
unsigned long data[] = {qHash(group)}; //->id();
|
||||
m_client.changeProperty(atoms->kde_net_wm_tab_group, XCB_ATOM_CARDINAL, 32, 1, data);
|
||||
}
|
||||
else
|
||||
m_client.deleteProperty(atoms->kde_net_wm_tab_group);
|
||||
emit tabGroupChanged();
|
||||
}
|
||||
|
||||
bool Client::isCurrentTab() const
|
||||
{
|
||||
return !tab_group || tab_group->current() == this;
|
||||
}
|
||||
|
||||
void Client::syncTabGroupFor(QString property, bool fromThisClient)
|
||||
{
|
||||
if (tab_group)
|
||||
tab_group->sync(property.toAscii().data(), fromThisClient ? this : tab_group->current());
|
||||
}
|
||||
|
||||
void Client::setClientShown(bool shown)
|
||||
{
|
||||
if (deleting)
|
||||
|
|
45
client.h
45
client.h
|
@ -70,10 +70,6 @@ class KWIN_EXPORT Client
|
|||
* Because of that no changed signal is provided.
|
||||
*/
|
||||
Q_PROPERTY(QSize basicUnit READ basicUnit)
|
||||
/**
|
||||
* The "Window Tabs" Group this Client belongs to.
|
||||
**/
|
||||
Q_PROPERTY(KWin::TabGroup* tabGroup READ tabGroup NOTIFY tabGroupChanged SCRIPTABLE false)
|
||||
/**
|
||||
* A client can block compositing. That is while the Client is alive and the state is set,
|
||||
* Compositing is suspended and is resumed when there are no Clients blocking compositing any
|
||||
|
@ -250,27 +246,6 @@ public:
|
|||
StrutRects strutRects() const;
|
||||
bool hasStrut() const override;
|
||||
|
||||
// Tabbing functions
|
||||
TabGroup* tabGroup() const override; // 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); }
|
||||
/**
|
||||
* Syncs the *dynamic* @param property @param fromThisClient or the @link currentTab() to
|
||||
* all members of the @link tabGroup() (if there is one)
|
||||
*
|
||||
* eg. if you call:
|
||||
* client->setProperty("kwin_tiling_floats", true);
|
||||
* client->syncTabGroupFor("kwin_tiling_floats", true)
|
||||
* all clients in this tabGroup will have ::property("kwin_tiling_floats").toBool() == true
|
||||
*
|
||||
* WARNING: non dynamic properties are ignored - you're not supposed to alter/update such explicitly
|
||||
*/
|
||||
Q_INVOKABLE void syncTabGroupFor(QString property, bool fromThisClient = false);
|
||||
Q_INVOKABLE bool untab(const QRect &toGeometry = QRect(), bool clientRemoved = false) override;
|
||||
/**
|
||||
* Set tab group - this is to be invoked by TabGroup::add/remove(client) and NO ONE ELSE
|
||||
*/
|
||||
void setTabGroup(TabGroup* group) override;
|
||||
/*
|
||||
* If shown is true the client is mapped and raised, if false
|
||||
* the client is unmapped and hidden, this function is called
|
||||
|
@ -278,12 +253,6 @@ public:
|
|||
* client.
|
||||
*/
|
||||
void setClientShown(bool shown) override;
|
||||
/*
|
||||
* When a click is done in the decoration and it calls the group
|
||||
* to change the visible client it starts to move-resize the new
|
||||
* client, this function stops it.
|
||||
*/
|
||||
bool isCurrentTab() const override;
|
||||
|
||||
/**
|
||||
* Whether or not the window has a strut that expands through the invisible area of
|
||||
|
@ -407,12 +376,6 @@ Q_SIGNALS:
|
|||
void clientManaging(KWin::Client*);
|
||||
void clientFullScreenSet(KWin::Client*, bool, bool);
|
||||
|
||||
/**
|
||||
* 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 tabGroupChanged();
|
||||
|
||||
/**
|
||||
* Emitted whenever the Client want to show it menu
|
||||
*/
|
||||
|
@ -497,8 +460,6 @@ private:
|
|||
|
||||
void updateInputWindow();
|
||||
|
||||
bool tabTo(Client *other, bool behind, bool activate);
|
||||
|
||||
Xcb::Property fetchShowOnScreenEdge() const;
|
||||
void readShowOnScreenEdge(Xcb::Property &property);
|
||||
/**
|
||||
|
@ -562,7 +523,6 @@ private:
|
|||
xcb_colormap_t m_colormap;
|
||||
QString cap_normal, cap_iconic, cap_suffix;
|
||||
Group* in_group;
|
||||
TabGroup* tab_group;
|
||||
QTimer* ping_timer;
|
||||
qint64 m_killHelperPID;
|
||||
xcb_timestamp_t m_pingTimestamp;
|
||||
|
@ -634,11 +594,6 @@ inline Group* Client::group()
|
|||
return in_group;
|
||||
}
|
||||
|
||||
inline TabGroup* Client::tabGroup() const
|
||||
{
|
||||
return tab_group;
|
||||
}
|
||||
|
||||
inline bool Client::isShown(bool shaded_is_shown) const
|
||||
{
|
||||
return !isMinimized() && (!isShade() || shaded_is_shown) && !hidden &&
|
||||
|
|
|
@ -370,7 +370,7 @@ bool Client::manage(xcb_window_t w, bool isMapped)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!(tab_group || isMapped || session)) {
|
||||
if (!(tabGroup() || isMapped || session)) {
|
||||
// Attempt to automatically group similar windows
|
||||
Client* similar = findAutogroupCandidate();
|
||||
if (similar && !similar->noBorder()) {
|
||||
|
|
|
@ -150,6 +150,7 @@ Q_SIGNALS:
|
|||
void maxSizeChanged();
|
||||
|
||||
private:
|
||||
friend class AbstractClient;
|
||||
friend class Client;
|
||||
// friend bool Client::tabTo(Client*, bool, bool);
|
||||
bool add(KWin::AbstractClient *c, AbstractClient *other, bool behind, bool activateC);
|
||||
|
|
Loading…
Reference in a new issue