diff --git a/geometry.cpp b/geometry.cpp
index dbfb41d8c8..be64c69804 100644
--- a/geometry.cpp
+++ b/geometry.cpp
@@ -2535,7 +2535,8 @@ bool Client::startMoveResize()
geom_restore = geometry(); // "restore" to current geometry
setMaximize(false, false);
}
- }
+ } else if (quick_tile_mode != QuickTileNone) // no longer now - we move, resize is handled below
+ setQuickTileMode(QuickTileNone); // otherwise we mess every second tile, bug #303937
} else if ((maximizeMode() == MaximizeFull && options->electricBorderMaximize()) ||
(quick_tile_mode != QuickTileNone && isMovable() && mode == PositionCenter)) {
// Exit quick tile mode when the user attempts to move a tiled window, cannot use isMove() yet
diff --git a/kcmkwin/kwindecoration/decorationmodel.cpp b/kcmkwin/kwindecoration/decorationmodel.cpp
index 3d3bb862f8..4915d10098 100644
--- a/kcmkwin/kwindecoration/decorationmodel.cpp
+++ b/kcmkwin/kwindecoration/decorationmodel.cpp
@@ -37,6 +37,18 @@ along with this program. If not, see .
#include
#include "kwindecoration.h"
+/* WARNING -------------------------------------------------------------------------
+* it is *ABSOLUTELY* mandatory to manage loadPlugin() and destroyPreviousPlugin()
+* using disablePreview()
+*
+* loadPlugin() moves the present factory pointer to "old_fact" which is then deleted
+* by the succeeding destroyPreviousPlugin()
+*
+* So if you loaded a new plugin and that changed the current factory, call disablePreview()
+* BEFORE the following destroyPreviousPlugin() destroys the factory for the current m_preview->deco->factory
+* (which is invoked on deco deconstruction)
+* WARNING ------------------------------------------------------------------------ */
+
namespace KWin
{
@@ -192,10 +204,12 @@ QVariant DecorationModel::data(const QModelIndex& index, int role) const
return static_cast< int >(m_decorations[ index.row()].borderSize);
case BorderSizesRole: {
QList< QVariant > sizes;
- if (m_plugins->loadPlugin(m_decorations[ index.row()].libraryName) &&
- m_plugins->factory() != NULL) {
+ const bool mustDisablePreview = m_plugins->factory() && m_plugins->factory() == m_preview->factory();
+ if (m_plugins->loadPlugin(m_decorations[index.row()].libraryName) && m_plugins->factory()) {
foreach (KDecorationDefines::BorderSize size, m_plugins->factory()->borderSizes()) // krazy:exclude=foreach
sizes << int(size);
+ if (mustDisablePreview) // it's nuked with destroyPreviousPlugin()
+ m_preview->disablePreview(); // so we need to get rid of m_preview->deco first
m_plugins->destroyPreviousPlugin();
}
return sizes;
@@ -312,6 +326,9 @@ void DecorationModel::regeneratePreview(const QModelIndex& index, const QSize& s
document.setHtml(html);
bool enabled = false;
bool loaded;
+ // m_preview->deco management is not required
+ // either the deco loads and the following recreateDecoration will sanitize decos (on new factory)
+ // or the deco does not load and destroyPreviousPlugin() is not called
if ((loaded = m_plugins->loadPlugin(data.libraryName)) && m_preview->recreateDecoration(m_plugins)) {
enabled = true;
m_preview->enablePreview();
diff --git a/kcmkwin/kwindecoration/preview.cpp b/kcmkwin/kwindecoration/preview.cpp
index fe802c7345..587df7c5b7 100644
--- a/kcmkwin/kwindecoration/preview.cpp
+++ b/kcmkwin/kwindecoration/preview.cpp
@@ -103,6 +103,11 @@ void KDecorationPreview::disablePreview()
no_preview->show();
}
+KDecorationFactory *KDecorationPreview::factory() const
+{
+ return deco[Active] ? deco[Active]->factory() : 0;
+}
+
void KDecorationPreview::paintEvent(QPaintEvent* e)
{
Q_UNUSED(e);
diff --git a/kcmkwin/kwindecoration/preview.h b/kcmkwin/kwindecoration/preview.h
index 20ee869f9b..52645fd767 100644
--- a/kcmkwin/kwindecoration/preview.h
+++ b/kcmkwin/kwindecoration/preview.h
@@ -50,6 +50,7 @@ public:
bool recreateDecoration(KDecorationPlugins* plugin);
void enablePreview();
void disablePreview();
+ KDecorationFactory *factory() const;
void setPreviewMask(const QRegion&, int, bool);
QRegion unobscuredRegion(bool, const QRegion&) const;
QRect windowGeometry(bool) const;
diff --git a/tabgroup.cpp b/tabgroup.cpp
index e7b133e8f1..771d789954 100644
--- a/tabgroup.cpp
+++ b/tabgroup.cpp
@@ -104,6 +104,15 @@ bool TabGroup::add(Client* c, Client *other, bool after, bool becomeVisible)
if (effects)
static_cast(effects)->slotTabAdded(c->effectWindow(), other->effectWindow());
+ // next: aling the client states BEFORE adding it to the group
+ // otherwise the caused indirect state changes would be taken as the dominating ones and break
+ // the main client
+ // example: QuickTiling is aligned to None, this restores the former QuickTiled size and alignes
+ // all other windows in the group - including the actual main client! - to this size and thus
+ // breaks the actually required alignment to the main windows geometry (because that now has the
+ // restored geometry of the formerly Q'tiled window) - bug #303937
+ updateStates(m_current, All, c);
+
int index = other ? m_clients.indexOf(other) : m_clients.size();
index += after;
if (index > m_clients.size())
@@ -114,7 +123,6 @@ bool TabGroup::add(Client* c, Client *other, bool after, bool becomeVisible)
c->setTabGroup(this); // Let the client know which group it belongs to
updateMinMaxSize();
- updateStates(m_current, All, c);
if (!becomeVisible)
c->setClientShown(false);
@@ -292,6 +300,8 @@ void TabGroup::blockStateUpdates(bool more) {
void TabGroup::updateStates(Client* main, States states, Client* only)
{
+ if (main == only)
+ return; // there's no need to only align "us" to "us"
if (m_stateUpdatesBlocked > 0) {
m_pendingUpdates |= states;
return;
@@ -300,10 +310,16 @@ void TabGroup::updateStates(Client* main, States states, Client* only)
states |= m_pendingUpdates;
m_pendingUpdates = TabGroup::None;
- ClientList toBeRemoved;
- for (ClientList::const_iterator i = m_clients.constBegin(), end = m_clients.constEnd(); i != end; ++i) {
+ ClientList toBeRemoved, onlyDummy;
+ ClientList *list = &m_clients;
+ if (only) {
+ onlyDummy << only;
+ list = &onlyDummy;
+ }
+
+ for (ClientList::const_iterator i = list->constBegin(), end = list->constEnd(); i != end; ++i) {
Client *c = (*i);
- if (c != main && (!only || c == only)) {
+ if (c != main) {
if ((states & Minimized) && c->isMinimized() != main->isMinimized()) {
if (main->isMinimized())
c->minimize(true);