diff options
-rw-r--r-- | src/mcompositemanager.cpp | 65 | ||||
-rw-r--r-- | src/mcompositemanager_p.h | 5 | ||||
-rw-r--r-- | src/mwindowpropertycache.h | 1 | ||||
-rwxr-xr-x | tests/functional/test20.py | 2 | ||||
-rwxr-xr-x | tests/functional/test21.py | 111 | ||||
-rw-r--r-- | tests/functional/test21.py.testdata | 17 | ||||
-rwxr-xr-x | tests/functional/test8.py | 3 |
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 |