summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mcompositemanager.cpp15
-rw-r--r--src/mcompositescene.cpp44
-rw-r--r--src/mtexturepixmapitem_p.cpp7
-rw-r--r--src/mwindowpropertycache.cpp10
-rw-r--r--src/mwindowpropertycache.h2
-rwxr-xr-xtests/functional/test16.py54
-rw-r--r--tests/functional/test16.py.testdata9
-rw-r--r--tests/windowctl/windowctl.cpp21
8 files changed, 133 insertions, 29 deletions
diff --git a/src/mcompositemanager.cpp b/src/mcompositemanager.cpp
index 4901b4b..668407d 100644
--- a/src/mcompositemanager.cpp
+++ b/src/mcompositemanager.cpp
@@ -1818,7 +1818,12 @@ void MCompositeManagerPrivate::mapEvent(XMapEvent *e)
else
item->saveBackingStore(true);
item->setVisible(true);
- item->fadeIn();
+ // TODO: don't show the animation if the window is not stacked on top
+ const XWMHints &h = pc->getWMHints();
+ if (!(h.flags & StateHint) || h.initial_state != IconicState)
+ item->fadeIn();
+ else
+ item->setNewlyMapped(false);
goto stack_and_return;
}
@@ -1836,10 +1841,14 @@ void MCompositeManagerPrivate::mapEvent(XMapEvent *e)
qDebug() << "Composition overhead (new pixmap):"
<< overhead_measure.elapsed();
#endif
- if (item->isAppWindow())
+ const XWMHints &h = pc->getWMHints();
+ if ((!(h.flags & StateHint) || h.initial_state != IconicState)
+ && item->isAppWindow())
item->fadeIn();
- else
+ else {
item->setVisible(true);
+ item->setNewlyMapped(false);
+ }
// the current decorated window got mapped
if (e->window == MDecoratorFrame::instance()->managedWindow() &&
diff --git a/src/mcompositescene.cpp b/src/mcompositescene.cpp
index 36cb017..a2a437c 100644
--- a/src/mcompositescene.cpp
+++ b/src/mcompositescene.cpp
@@ -98,21 +98,41 @@ void MCompositeScene::setupOverlay(Window window, const QRect &geom,
void MCompositeScene::drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[], QWidget *widget)
{
- for (int i = 0; i < numItems; ++i) {
- MCompositeWindow *window = (MCompositeWindow *) items[i];
+ QRegion visible(sceneRect().toRect());
+ QList<QGraphicsItem*> to_paint;
+ QList<QStyleOptionGraphicsItem> paint_opts;
+ // visibility is determined from top to bottom
+ for (int i = numItems - 1; i >= 0; --i) {
+ MCompositeWindow *cw = (MCompositeWindow *) items[i];
- // Redraw only textures which don't have opaque textures above it
- if (((i < numItems - 1)
- && (items[i+1]->sceneMatrix().mapRect(items[i]->boundingRect()) ==
- items[i]->boundingRect())
- && (!((MCompositeWindow *)items[i+1])->propertyCache()->hasAlpha())
- && (((MCompositeWindow *)items[i+1])->opacity() == 1.0))
- || window->isIconified())
- continue;
+ if (visible.isEmpty())
+ // nothing below is visible anymore
+ break;
+
+ // FIXME: this region is always the same as the window's shape,
+ // some transformations would be needed...
+ QRegion r(cw->sceneMatrix().map(cw->propertyCache()->shapeRegion()));
+ // transitioning window can be smaller than shapeRegion(), so paint
+ // all transitioning windows
+ if (cw->isWindowTransitioning() || visible.intersects(r)) {
+ to_paint.prepend(cw);
+ paint_opts.prepend(options[i]);
+ }
+
+ // subtract opaque regions
+ if (!cw->isWindowTransitioning()
+ && !cw->propertyCache()->hasAlpha() && cw->opacity() == 1.0)
+ visible -= r;
+ }
+ // paint from bottom to top so that blending works
+ while (!to_paint.isEmpty()) {
+ // TODO: paint only the intersected region (glScissor?)
+ MCompositeWindow *cw = (MCompositeWindow*)to_paint.takeFirst();
painter->save();
- painter->setMatrix(items[i]->sceneMatrix(), true);
- items[i]->paint(painter, &options[i], widget);
+ painter->setMatrix(cw->sceneMatrix(), true);
+ QStyleOptionGraphicsItem opts = paint_opts.takeFirst();
+ cw->paint(painter, &opts, widget);
painter->restore();
}
}
diff --git a/src/mtexturepixmapitem_p.cpp b/src/mtexturepixmapitem_p.cpp
index 223b442..4343a82 100644
--- a/src/mtexturepixmapitem_p.cpp
+++ b/src/mtexturepixmapitem_p.cpp
@@ -255,12 +255,7 @@ void MTexturePixmapPrivate::damageTracking(bool enabled)
void MTexturePixmapPrivate::saveBackingStore(bool renew)
{
- XWindowAttributes a;
- if (!XGetWindowAttributes(QX11Info::display(), item->window(), &a)) {
- qWarning("%s: invalid window 0x%lx", __func__, item->window());
- return;
- }
- if (a.map_state != IsViewable)
+ if (item->propertyCache()->is_valid && !item->propertyCache()->isMapped())
return;
if (windowp)
diff --git a/src/mwindowpropertycache.cpp b/src/mwindowpropertycache.cpp
index a11f82c..764d896 100644
--- a/src/mwindowpropertycache.cpp
+++ b/src/mwindowpropertycache.cpp
@@ -218,19 +218,19 @@ bool MWindowPropertyCache::hasAlpha()
return has_alpha ? true : false;
}
-const QRegion MWindowPropertyCache::shapeRegion()
+const QRegion &MWindowPropertyCache::shapeRegion()
{
if (shape_rects_valid) {
if (shape_region.isEmpty())
- return QRegion(realGeometry());
- else
- return shape_region;
+ shape_region = QRegion(realGeometry());
+ return shape_region;
}
xcb_shape_get_rectangles_reply_t *r;
r = xcb_shape_get_rectangles_reply(xcb_conn, xcb_shape_rects_cookie, 0);
if (!r) {
shape_rects_valid = true;
- return QRegion(realGeometry());
+ shape_region = QRegion(realGeometry());
+ return shape_region;
}
xcb_rectangle_iterator_t i;
i = xcb_shape_get_rectangles_rectangles_iterator(r);
diff --git a/src/mwindowpropertycache.h b/src/mwindowpropertycache.h
index 5f049a0..e75a5d0 100644
--- a/src/mwindowpropertycache.h
+++ b/src/mwindowpropertycache.h
@@ -80,7 +80,7 @@ public:
}
return real_geom;
}
- const QRegion shapeRegion();
+ const QRegion &shapeRegion();
void shapeRefresh() {
if (!shape_rects_valid)
shapeRegion();
diff --git a/tests/functional/test16.py b/tests/functional/test16.py
new file mode 100755
index 0000000..80cefdd
--- /dev/null
+++ b/tests/functional/test16.py
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+
+# Check that initial_state=IconicState is respected in WM_HINTS
+
+#* Test steps
+# * show an application window with initial_state=IconicState
+#* Post-conditions
+# * application is stacked under the desktop window
+
+import os, re, sys, time
+
+if os.system('/sbin/mcetool --unblank-screen --set-inhibit-mode=stay-on'):
+ print 'mcetool is missing!'
+
+if os.system('pidof mcompositor'):
+ print 'mcompositor is not running'
+ sys.exit(1)
+
+fd = os.popen('windowstack m')
+s = fd.read(5000)
+win_re = re.compile('^0x[0-9a-f]+')
+home_win = 0
+for l in s.splitlines():
+ if re.search(' DESKTOP viewable ', l.strip()):
+ home_win = win_re.match(l.strip()).group()
+ break
+
+if home_win == 0:
+ print 'FAIL: desktop not found'
+ sys.exit(1)
+
+# create initially iconic application window
+fd = os.popen('windowctl In')
+old_win = fd.readline().strip()
+time.sleep(2)
+
+ret = 0
+fd = os.popen('windowstack m')
+s = fd.read(5000)
+for l in s.splitlines():
+ if re.search("%s " % home_win, l.strip()):
+ print home_win, 'found'
+ break
+ elif re.search("%s " % old_win, l.strip()):
+ print 'FAIL: application window is not iconic'
+ print 'Failed stack:\n', s
+ ret = 1
+ break
+
+# cleanup
+os.popen('pkill windowctl')
+time.sleep(1)
+
+sys.exit(ret)
diff --git a/tests/functional/test16.py.testdata b/tests/functional/test16.py.testdata
new file mode 100644
index 0000000..827057f
--- /dev/null
+++ b/tests/functional/test16.py.testdata
@@ -0,0 +1,9 @@
+CaseName="initial_state_iconic_is_respected"
+CaseRequirement="NONE"
+CaseTimeout="360"
+CaseDescription="Check that initial_state=IconicState is respected in WM_HINTS.\n
+\n
+- Test steps\n
+\t- show an application window with initial_state=IconicState\n
+- Post-conditions\n
+\t- application is stacked under the desktop window\n"
diff --git a/tests/windowctl/windowctl.cpp b/tests/windowctl/windowctl.cpp
index b4d3ad6..9580d41 100644
--- a/tests/windowctl/windowctl.cpp
+++ b/tests/windowctl/windowctl.cpp
@@ -308,7 +308,7 @@ static void wait_for_mapnotify(Display *dpy, Window w)
static void print_usage_and_exit(QString& stdOut)
{
#define PROG "windowctl"
- stdOut = "Usage 1: " PROG " [afoemks](n|d|i|b) [transient for <XID>]\n"
+ stdOut = "Usage 1: " PROG " [afoemksI](n|d|i|b) [transient for <XID>]\n"
"a - ARGB (32-bit) window, otherwise 16-bit is used\n"
"f - fullscreen window\n"
"o - override-redirect window\n"
@@ -316,6 +316,7 @@ static void print_usage_and_exit(QString& stdOut)
"m - set _NET_WM_STATE_MODAL (makes sense for dialogs only)\n"
"k - set _KDE_NET_WM_WINDOW_TYPE_OVERRIDE\n"
"s - make the window shaped\n"
+ "I - use initial_state = IconicState in WM_HINTS\n"
"h - set _MEEGOTOUCH_DECORATOR_BUTTONS for home and close buttons\n"
"n - WM_TYPE_NORMAL window (if 'k' is given, that is the first type)\n"
"d - WM_TYPE_DIALOG window\n"
@@ -378,6 +379,17 @@ static void set_group (Display *dpy, char *first, char *second)
XSync(dpy, False);
}
+static void set_initial_state_iconic (Display *dpy, Window w)
+{
+ XWMHints h;
+ memset(&h, 0, sizeof(h));
+
+ h.flags = StateHint;
+ h.initial_state = IconicState;
+ XSetWMHints(dpy, w, &h);
+ XSync(dpy, False);
+}
+
static void do_command (Display *dpy, char command, Window window,
Window target, QString& stdOut)
{
@@ -546,7 +558,7 @@ static bool old_main(QStringList& args, QString& stdOut)
time_t last_time;
int argb = 0, fullscreen = 0, override_redirect = 0, decor_buttons = 0,
exit_on_unmap = 1, modal = 0, kde_override = 0, meego_layer = -1,
- shaped = 0;
+ shaped = 0, initial_iconic = 0;
WindowType windowtype = TYPE_INVALID;
if (args.count() < 1 || args.count() > 4) {
@@ -594,6 +606,10 @@ static bool old_main(QStringList& args, QString& stdOut)
shaped = 1;
continue;
}
+ if (*p == 'I') {
+ initial_iconic = 1;
+ continue;
+ }
if (*p == 'h') {
decor_buttons = 1;
continue;
@@ -724,6 +740,7 @@ static bool old_main(QStringList& args, QString& stdOut)
if (decor_buttons) set_decorator_buttons(dpy, w);
if (shaped) set_shaped(dpy, w);
+ if (initial_iconic) set_initial_state_iconic(dpy, w);
green_gc = XCreateGC (dpy, w, 0, NULL);
XParseColor (dpy, colormap, green, &green_col);