summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mcompositemanager.cpp65
-rw-r--r--src/mcompositemanager_p.h5
-rw-r--r--src/mwindowpropertycache.h1
-rwxr-xr-xtests/functional/test20.py2
-rwxr-xr-xtests/functional/test21.py111
-rw-r--r--tests/functional/test21.py.testdata17
-rwxr-xr-xtests/functional/test8.py3
7 files changed, 175 insertions, 29 deletions
diff --git a/src/mcompositemanager.cpp b/src/mcompositemanager.cpp
index 5d3faa9..2023f10 100644
--- a/src/mcompositemanager.cpp
+++ b/src/mcompositemanager.cpp
@@ -905,12 +905,14 @@ void MCompositeManagerPrivate::propertyEvent(XPropertyEvent *e)
Window MCompositeManagerPrivate::getLastVisibleParent(MWindowPropertyCache *pc)
{
Window last = 0, parent;
+ MWindowPropertyCache *orig_pc = pc;
while (pc && (parent = pc->transientFor())) {
- MCompositeWindow *cw = COMPOSITE_WINDOW(parent);
- if (cw)
- pc = cw->propertyCache();
- else
- break; // no-good parent
+ pc = prop_caches.value(parent, 0);
+ if (pc == orig_pc) {
+ qWarning("%s(): window 0x%lx belongs to a transiency loop!",
+ __func__, orig_pc->winId());
+ break;
+ }
if (pc && pc->isMapped())
last = parent;
else // no-good parent, bail out
@@ -1480,16 +1482,24 @@ void MCompositeManagerPrivate::mapRequestEvent(XMapRequestEvent *e)
/* recursion is needed to handle transients that are transient for other
* transients */
void MCompositeManagerPrivate::raiseTransientsOf(MWindowPropertyCache *pc,
- int last_i)
+ int last_i, bool recursion)
{
+ static MWindowPropertyCache *orig_pc = 0;
+ if (!recursion)
+ orig_pc = pc;
for (QList<Window>::const_iterator it = pc->transientWindows().begin();
it != pc->transientWindows().end(); ++it) {
int i = stacking_list.indexOf(*it);
if (i != -1) {
stacking_list.move(i, last_i);
MWindowPropertyCache *p = prop_caches.value(*it, 0);
+ if (p == orig_pc && orig_pc) {
+ qWarning("%s(): window 0x%lx belongs to a transiency loop!",
+ __func__, orig_pc->winId());
+ break;
+ }
if (p && !p->transientWindows().isEmpty())
- raiseTransientsOf(p, last_i);
+ raiseTransientsOf(p, last_i, true);
}
}
}
@@ -1671,9 +1681,20 @@ void MCompositeManagerPrivate::setCurrentApp(Window w)
if (w == first_moved) break; \
MCompositeWindow *cw = COMPOSITE_WINDOW(w); \
if (cw && cw->propertyCache() && cw->isMapped() && (X)) { \
+ MCompositeWindow *orig_cw = cw; \
+ /* find the next window to move */ \
+ Window next = 0; \
+ for (int next_i = i + 1; next_i <= last_i; ++next_i) { \
+ next = stacking_list.at(next_i); \
+ cw = COMPOSITE_WINDOW(next); \
+ if (cw && cw->propertyCache() && cw->isMapped() && (X)) \
+ break; \
+ } \
stacking_list.move(i, last_i); \
- raiseTransientsOf(cw->propertyCache(), last_i); \
+ raiseTransientsOf(orig_cw->propertyCache(), last_i); \
if (!first_moved) first_moved = w; \
+ if (!next || (i = stacking_list.indexOf(next)) < 0) \
+ break; \
} else ++i; \
} }
@@ -1759,12 +1780,9 @@ void MCompositeManagerPrivate::checkStacking(bool force_visibility_check,
XMoveWindow(QX11Info::display(), deco->decoratorItem()->window(), 0, 0);
}
/* Meego layers 1-3: lock screen, ongoing call etc. */
- /* FIXME: we should check windowState() instead of iconifyState(), which
- is for animation purposes but that could lead to regressions with
- initial_state==IconicState windows */
for (unsigned int level = 1; level < 4; ++level)
RAISE_MATCHING(!getLastVisibleParent(cw->propertyCache()) &&
- cw->iconifyState() == MCompositeWindow::NoIconifyState
+ cw->propertyCache()->windowState() == NormalState
&& cw->propertyCache()->meegoStackingLayer() == level)
/* raise all system-modal dialogs */
RAISE_MATCHING(!getLastVisibleParent(cw->propertyCache())
@@ -2788,22 +2806,19 @@ bool MCompositeManagerPrivate::isRedirected(Window w)
return (COMPOSITE_WINDOW(w) != 0);
}
-bool MCompositeManagerPrivate::removeWindow(Window w)
+void MCompositeManagerPrivate::removeWindow(Window w)
{
// Item is already removed from scene when it is deleted
+ int removed = 0;
+
+ removed += windows_as_mapped.removeAll(w);
+ removed += windows.remove(w);
+ removed += stacking_list.removeAll(w);
- bool ret = true;
- windows_as_mapped.removeAll(w);
- if (windows.remove(w) == 0)
- ret = false;
-
- stacking_list.removeAll(w);
-
for (int i = 0; i < TOTAL_LAYERS; ++i)
if (stack[i] == w) stack[i] = 0;
- updateWinList();
- return ret;
+ if (removed > 0) updateWinList();
}
static QList<Window> orig_list;
@@ -3091,10 +3106,10 @@ void MCompositeManagerPrivate::enableRedirection()
((MTexturePixmapItem *)tp)->enableRedirectedRendering();
setWindowDebugProperties(it.key());
}
- XSync(QX11Info::display(), False);
-
+ XFlush(QX11Info::display());
compositing = true;
- QTimer::singleShot(100, this, SLOT(enablePaintedCompositing()));
+ // no delay: application does not need to redraw when maximizing it
+ enablePaintedCompositing();
}
void MCompositeManagerPrivate::enablePaintedCompositing()
diff --git a/src/mcompositemanager_p.h b/src/mcompositemanager_p.h
index cafbea8..f81a1f7 100644
--- a/src/mcompositemanager_p.h
+++ b/src/mcompositemanager_p.h
@@ -115,14 +115,15 @@ public:
bool isRedirected(Window window);
bool x11EventFilter(XEvent *event);
bool processX11EventFilters(XEvent *event);
- bool removeWindow(Window w);
+ void removeWindow(Window w);
bool needDecoration(Window w, MWindowPropertyCache *pc = 0);
MCompositeWindow *getHighestDecorated();
static bool compareWindows(Window w_a, Window w_b);
void roughSort();
void setCurrentApp(Window w);
- void raiseTransientsOf(MWindowPropertyCache *pc, int last_i);
+ void raiseTransientsOf(MWindowPropertyCache *pc, int last_i,
+ bool recursion = false);
MCompositeScene *watch;
Window localwin, localwin_parent;
diff --git a/src/mwindowpropertycache.h b/src/mwindowpropertycache.h
index 9f0caf3..2376243 100644
--- a/src/mwindowpropertycache.h
+++ b/src/mwindowpropertycache.h
@@ -94,6 +94,7 @@ public:
ShapeBounding);
}
+ Window winId() const { return window; }
Window parentWindow() const { return parent_window; }
void setParentWindow(Window w) { parent_window = w; }
diff --git a/tests/functional/test20.py b/tests/functional/test20.py
index e6d350a..7247c7d 100755
--- a/tests/functional/test20.py
+++ b/tests/functional/test20.py
@@ -60,7 +60,7 @@ time.sleep(1)
# simulate a phone call
fd = os.popen('windowctl P')
-time.sleep(10)
+time.sleep(15)
# create a fullscreen application window
fd = os.popen('windowctl fn')
diff --git a/tests/functional/test21.py b/tests/functional/test21.py
new file mode 100755
index 0000000..fc9bae1
--- /dev/null
+++ b/tests/functional/test21.py
@@ -0,0 +1,111 @@
+#!/usr/bin/python
+
+# Some tests for Meego stacking layer support.
+
+#* Test steps
+# * show an application window
+# * show an application window transient to the first one
+# * show an application window transient to the first transient
+# * show an application window transient to the second transient
+# * show an application window
+# * set the first non-transient application window to Meego level 1
+# * set the second non-transient application window to Meego level 1
+# * check correct stacking
+# * set the first non-transient application window to Meego level 2
+#* Post-conditions
+# * check correct stacking
+
+import os, re, sys, time
+
+if os.system('/sbin/mcetool --unblank-screen --set-tklock-mode=unlocked --set-inhibit-mode=stay-on'):
+ print 'mcetool is missing!'
+
+if os.system('pidof mcompositor'):
+ print 'mcompositor is not running'
+ sys.exit(1)
+
+# create application window
+fd = os.popen('windowctl kn')
+app1 = fd.readline().strip()
+time.sleep(1)
+
+# create transient application windows
+fd = os.popen('windowctl kn %s' % app1)
+trans1 = fd.readline().strip()
+fd = os.popen('windowctl kn %s' % trans1)
+trans2 = fd.readline().strip()
+fd = os.popen('windowctl kn %s' % trans2)
+trans3 = fd.readline().strip()
+time.sleep(1)
+
+# create application window
+fd = os.popen('windowctl kn')
+app2 = fd.readline().strip()
+time.sleep(1)
+
+# set the non-transient application windows to Meego level 1
+os.popen('windowctl E %s 1' % app1)
+os.popen('windowctl E %s 1' % app2)
+time.sleep(1)
+
+ret = app2_found = trans1_found = trans2_found = trans3_found = 0
+fd = os.popen('windowstack m')
+s = fd.read(5000)
+for l in s.splitlines():
+ if re.search("%s " % app2, l.strip()):
+ print app2, 'found'
+ app2_found = 1
+ elif re.search("%s " % trans3, l.strip()) and app2_found:
+ print trans3, 'found'
+ trans3_found = 1
+ elif re.search("%s " % trans2, l.strip()) and app2_found and trans3_found:
+ print trans2, 'found'
+ trans2_found = 1
+ elif re.search("%s " % trans1, l.strip()) and app2_found and trans3_found \
+ and trans2_found:
+ print trans1, 'found'
+ trans1_found = 1
+ elif re.search("%s " % app1, l.strip()) and app2_found and trans1_found \
+ and trans2_found and trans3_found:
+ print app1, 'found'
+ break
+ else:
+ print 'FAIL: stacking order is wrong'
+ print 'Failed stack:\n', s
+ ret = 1
+ break
+
+# set the first application window to Meego level 2
+os.popen('windowctl E %s 2' % app1)
+time.sleep(1)
+
+app2_found = trans1_found = trans2_found = trans3_found = 0
+fd = os.popen('windowstack m')
+s = fd.read(5000)
+for l in s.splitlines():
+ if re.search("%s " % trans3, l.strip()):
+ print trans3, 'found'
+ trans3_found = 1
+ elif re.search("%s " % trans2, l.strip()) and trans3_found:
+ print trans2, 'found'
+ trans2_found = 1
+ elif re.search("%s " % trans1, l.strip()) and trans3_found and trans2_found:
+ print trans1, 'found'
+ trans1_found = 1
+ elif re.search("%s " % app1, l.strip()) and trans1_found \
+ and trans2_found and trans3_found:
+ print app1, 'found'
+ break
+ elif re.search("%s " % app2, l.strip()):
+ print app2, 'found'
+ else:
+ print 'FAIL: stacking order is wrong'
+ print 'Failed stack:\n', s
+ ret = 1
+ break
+
+# cleanup
+os.popen('pkill windowctl')
+time.sleep(1)
+
+sys.exit(ret)
diff --git a/tests/functional/test21.py.testdata b/tests/functional/test21.py.testdata
new file mode 100644
index 0000000..014bfb3
--- /dev/null
+++ b/tests/functional/test21.py.testdata
@@ -0,0 +1,17 @@
+CaseName="Meego_stacking_layer_support"
+CaseRequirement="NONE"
+CaseTimeout="360"
+CaseDescription="Some tests for Meego stacking layer support.\n
+\n
+- Test steps\n
+\t- show an application window\n
+\t- show an application window transient to the first one\n
+\t- show an application window transient to the first transient\n
+\t- show an application window transient to the second transient\n
+\t- show an application window\n
+\t- set the first non-transient application window to Meego level 1\n
+\t- set the second non-transient application window to Meego level 1\n
+\t- check correct stacking\n
+\t- set the first non-transient application window to Meego level 2\n
+- Post-conditions\n
+\t- check correct stacking\n"
diff --git a/tests/functional/test8.py b/tests/functional/test8.py
index af13b5b..2421d10 100755
--- a/tests/functional/test8.py
+++ b/tests/functional/test8.py
@@ -154,8 +154,9 @@ for l in s.splitlines():
break
# swap the transiencies of the dialogs
-os.popen("windowctl t %s %s" % (new_dialog, old_win))
+# (this introduces a temporary transiency loop)
os.popen("windowctl t %s %s" % (new_win, new_dialog))
+os.popen("windowctl t %s %s" % (new_dialog, old_win))
time.sleep(1)
new_dialog_found = new_win_found = 0