[meego-commits] 10763: Changes to Trunk:Testing/meegotouch-compositor

Fathi Boudra no_reply at build.meego.com
Thu Dec 9 10:17:08 UTC 2010


Hi,
I have made the following changes to meegotouch-compositor in project Trunk:Testing. Please review and accept ASAP.

Thank You,
Fathi Boudra

[This message was auto-generated]

---

Request #10763:

  submit:   devel:qt-mtf/meegotouch-compositor(r49) -> Trunk:Testing/meegotouch-compositor


Message:
    * Thu Dec 09 2010 Fathi Boudra <fathi.boudra at nokia.com> - 0.8.0
- Update to 0.8.0-2 (BMC#11090)
* Wed Nov 09 2010 Fathi Boudra <fathi.boudra at nokia.com> - 0.7.8
- Remove gl build requirement
* Wed Nov 09 2010 Miroslav Safr <miroslav.safr at tieto.com> - 0.7.8
- BMC#8957: - mcompositor 0.7.6 core dumps on netbook
 -fixed and tested on netbook
* Tue Nov 03 2010 Miroslav Safr <miroslav.safr at tieto.com> - 0.7.8
- updated to release 0.7.8~1
- added pkgconfig(xrandr), build requires it
* Tue Nov 03 2010 Miroslav Safr <miroslav.safr at tieto.com> - 0.7.7
- updated to release 0.7.7-1
* Tue Oct 26 2010 Miroslav Safr <miroslav.safr at tieto.com> - 0.7.6
- updated to release 0.7.6-1
- removed obsolete plankton theme
* Tue Oct 19 2010 Miroslav Safr <mirsolav.safr at tieto.com> - 0.7.5
- updated to 0.7.5-1 (with build fix)
- updated initialize_EGL_library.patch
* Fri Oct 08 2010 Miroslav Safr <mirsolav.safr at tieto.com> - 0.7.3
- Update to 0.7.3
- removed integrated patches:
  mcompositor-black-screen-gtk.patch
  re-add_fallback_when_Image_extension_is_not_available.patch
- added %{_libdir}/libmcompositor.so* and includes

State:   new          2010-12-09T02:17:06 boudra
Comment: None



changes files:
--------------
--- meegotouch-compositor.changes
+++ meegotouch-compositor.changes
@@ -0,0 +1,33 @@
+* Thu Dec 09 2010 Fathi Boudra <fathi.boudra at nokia.com> - 0.8.0
+- Update to 0.8.0-2 (BMC#11090)
+
+* Wed Nov 09 2010 Fathi Boudra <fathi.boudra at nokia.com> - 0.7.8
+- Remove gl build requirement
+
+* Wed Nov 09 2010 Miroslav Safr <miroslav.safr at tieto.com> - 0.7.8
+- BMC#8957: - mcompositor 0.7.6 core dumps on netbook
+ -fixed and tested on netbook
+
+* Tue Nov 03 2010 Miroslav Safr <miroslav.safr at tieto.com> - 0.7.8
+- updated to release 0.7.8~1
+- added pkgconfig(xrandr), build requires it
+
+* Tue Nov 03 2010 Miroslav Safr <miroslav.safr at tieto.com> - 0.7.7
+- updated to release 0.7.7-1
+
+* Tue Oct 26 2010 Miroslav Safr <miroslav.safr at tieto.com> - 0.7.6
+- updated to release 0.7.6-1
+- removed obsolete plankton theme
+
+* Tue Oct 19 2010 Miroslav Safr <mirsolav.safr at tieto.com> - 0.7.5
+- updated to 0.7.5-1 (with build fix)
+- updated initialize_EGL_library.patch
+
+* Fri Oct 08 2010 Miroslav Safr <mirsolav.safr at tieto.com> - 0.7.3
+- Update to 0.7.3
+- removed integrated patches:
+  mcompositor-black-screen-gtk.patch
+  re-add_fallback_when_Image_extension_is_not_available.patch
+- added %{_libdir}/libmcompositor.so* and includes
+
+

old:
----
  mcompositor-black-screen-gtk.patch
  meegotouch-compositor-0.5.8.tar.bz2
  re-add_fallback_when_Image_extension_is_not_available.patch

new:
----
  meegotouch-compositor-0.8.0.tar.gz

spec files:
-----------
--- meegotouch-compositor.spec
+++ meegotouch-compositor.spec
@@ -1,39 +1,37 @@
 # 
 # Do NOT Edit the Auto-generated Part!
-# Generated by: spectacle version 0.20
+# Generated by: spectacle version 0.21
 # 
 # >> macros
 # << macros
 
 Name:       meegotouch-compositor
 Summary:    MeeGo UI Compositing Window Manager
-Version:    0.5.8
+Version:    0.8.0
 Release:    1
 Group:      System/Desktop
 License:    LGPLv2.1
 URL:        http://meego.gitorious.org/meegotouch/meegotouch-compositor
-Source0:    %{name}-%{version}.tar.bz2
+Source0:    %{name}-%{version}.tar.gz
 Source1:    mdecorator.desktop
 Source100:  meegotouch-compositor.yaml
 Patch0:     add_Xext_lib_to_windowctl.patch
 Patch1:     fix_test_compile_issues.patch
 Patch2:     fix_build_on_ARM.patch
 Patch3:     initialize_EGL_library.patch
-Patch4:     mcompositor-black-screen-gtk.patch
-Patch5:     re-add_fallback_when_Image_extension_is_not_available.patch
 Requires(post): /sbin/ldconfig
 Requires(postun): /sbin/ldconfig
 BuildRequires:  pkgconfig(QtDBus)
 BuildRequires:  pkgconfig(QtNetwork)
 BuildRequires:  pkgconfig(QtOpenGL)
 BuildRequires:  pkgconfig(contextprovider-1.0)
-BuildRequires:  pkgconfig(gl)
 BuildRequires:  pkgconfig(meegotouch)
 BuildRequires:  pkgconfig(x11)
 BuildRequires:  pkgconfig(xcomposite)
 BuildRequires:  pkgconfig(xdamage)
 BuildRequires:  pkgconfig(xext)
 BuildRequires:  pkgconfig(xrender)
+BuildRequires:  pkgconfig(xrandr)
 Provides:   duicompositor >= 0.3.9
 Provides:   mcompositor >= 0.4.6
 Obsoletes:   duicompositor < 0.3.9
@@ -67,10 +65,6 @@
 %patch2 -p1
 # initialize_EGL_library.patch
 %patch3 -p1
-# mcompositor-black-screen-gtk.patch
-%patch4 -p1
-# re-add_fallback_when_Image_extension_is_not_available.patch
-%patch5 -p1
 # >> setup
 # << setup
 
@@ -89,10 +83,11 @@
 # >> install pre
 # << install pre
 %qmake_install
+mkdir -p %{buildroot}%{_sysconfdir}/xdg/autostart
+cp -a %{SOURCE1} %{buildroot}%{_sysconfdir}/xdg/autostart
+
 
 # >> install post
-mkdir -p %{buildroot}%{_sysconfdir}/xdg/autostart/
-cp %{SOURCE1} %{buildroot}%{_sysconfdir}/xdg/autostart/
 # << install post
 
 
@@ -112,6 +107,7 @@
 %{_bindir}/mcompositor
 %{_bindir}/mdecorator
 %{_libdir}/libdecorator.so.*
+%{_libdir}/libmcompositor.so.*
 # << files
 
 
@@ -122,5 +118,14 @@
 %{_bindir}/windowctl
 %{_bindir}/windowstack
 %{_libdir}/libdecorator.so
+%{_libdir}/libmcompositor.so
+%{_includedir}/meegotouch/mcompositor/mcompatoms_p.h
+%{_includedir}/meegotouch/mcompositor/mcompmgrextensionfactory.h
+%{_includedir}/meegotouch/mcompositor/mcompositemanager.h
+%{_includedir}/meegotouch/mcompositor/mcompositemanagerextension.h
+%{_includedir}/meegotouch/mcompositor/mcompositewindow.h
+%{_includedir}/meegotouch/mcompositor/mcompositewindowgroup.h
+%{_includedir}/meegotouch/mcompositor/mcompositewindowshadereffect.h
+%{_includedir}/meegotouch/mcompositor/mwindowpropertycache.h
 # << files devel
 

other changes:
--------------

++++++ initialize_EGL_library.patch
--- initialize_EGL_library.patch
+++ initialize_EGL_library.patch
@@ -5,12 +5,9 @@
 
 More correct, and needed on some platforms.
 ---
- src/mtexturepixmapitem_egl.cpp |    8 ++++++--
- 1 files changed, 6 insertions(+), 2 deletions(-)
-
 --- a/src/mtexturepixmapitem_egl.cpp
 +++ b/src/mtexturepixmapitem_egl.cpp
-@@ -85,8 +85,11 @@ class EglResourceManager
+@@ -86,8 +86,11 @@ class EglResourceManager
  public:
      EglResourceManager()
          : has_tfp(false) {
@@ -23,11 +20,11 @@
  
          QString exts = QLatin1String(eglQueryString(dpy, EGL_EXTENSIONS));
          if ((exts.contains("EGL_KHR_image") &&
-@@ -97,6 +100,7 @@ public:
+@@ -98,6 +101,7 @@ public:
              eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR"); 
              glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES"); 
          } else {
-+            qCritical("EGL version: %d.%d\n", maj, min);
-             qCritical() << "EGL extensions:" << exts;
-             qFatal("no EGL tfp support, aborting\n");
++            qDebug("EGL version: %d.%d\n", maj, min);
+             qDebug("No EGL tfp support.\n");
          }
+         texman = new EglTextureManager();

++++++ meegotouch-compositor-0.5.8.tar.bz2 -> meegotouch-compositor-0.8.0.tar.gz
--- .git
+++ .git
-(directory)
--- .git/HEAD
+++ .git/HEAD
-4c90d59ca5d13bcdc1f62e4fb4d2d36fb6547a4a
--- .git/branches
+++ .git/branches
-(directory)
--- .git/config
+++ .git/config
-[core]
-	repositoryformatversion = 0
-	filemode = true
-	bare = false
-	logallrefupdates = true
-[remote "origin"]
-	fetch = +refs/heads/*:refs/remotes/origin/*
-	url = git://gitorious.org/meegotouch/meegotouch-compositor.git
-[branch "master"]
-	remote = origin
-	merge = refs/heads/master
--- .git/description
+++ .git/description
-Unnamed repository; edit this file 'description' to name the repository.
--- .git/hooks
+++ .git/hooks
-(directory)
--- .git/hooks/applypatch-msg.sample
+++ .git/hooks/applypatch-msg.sample
-#!/bin/sh
-#
-# An example hook script to check the commit log message taken by
-# applypatch from an e-mail message.
-#
-# The hook should exit with non-zero status after issuing an
-# appropriate message if it wants to stop the commit.  The hook is
-# allowed to edit the commit message file.
-#
-# To enable this hook, rename this file to "applypatch-msg".
-
-. git-sh-setup
-test -x "$GIT_DIR/hooks/commit-msg" &&
-	exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
-:
--- .git/hooks/commit-msg.sample
+++ .git/hooks/commit-msg.sample
-#!/bin/sh
-#
-# An example hook script to check the commit log message.
-# Called by "git commit" with one argument, the name of the file
-# that has the commit message.  The hook should exit with non-zero
-# status after issuing an appropriate message if it wants to stop the
-# commit.  The hook is allowed to edit the commit message file.
-#
-# To enable this hook, rename this file to "commit-msg".
-
-# Uncomment the below to add a Signed-off-by line to the message.
-# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
-# hook is more suited to it.
-#
-# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
-# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
-
-# This example catches duplicate Signed-off-by lines.
-
-test "" = "$(grep '^Signed-off-by: ' "$1" |
-	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
-	echo >&2 Duplicate Signed-off-by lines.
-	exit 1
-}
--- .git/hooks/post-commit.sample
+++ .git/hooks/post-commit.sample
-#!/bin/sh
-#
-# An example hook script that is called after a successful
-# commit is made.
-#
-# To enable this hook, rename this file to "post-commit".
-
-: Nothing
--- .git/hooks/post-receive.sample
+++ .git/hooks/post-receive.sample
-#!/bin/sh
-#
-# An example hook script for the "post-receive" event.
-#
-# The "post-receive" script is run after receive-pack has accepted a pack
-# and the repository has been updated.  It is passed arguments in through
-# stdin in the form
-#  <oldrev> <newrev> <refname>
-# For example:
-#  aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
-#
-# see contrib/hooks/ for a sample, or uncomment the next line and
-# rename the file to "post-receive".
-
-#. /usr/share/git-core/contrib/hooks/post-receive-email
--- .git/hooks/post-update.sample
+++ .git/hooks/post-update.sample
-#!/bin/sh
-#
-# An example hook script to prepare a packed repository for use over
-# dumb transports.
-#
-# To enable this hook, rename this file to "post-update".
-
-exec git update-server-info
--- .git/hooks/pre-applypatch.sample
+++ .git/hooks/pre-applypatch.sample
-#!/bin/sh
-#
-# An example hook script to verify what is about to be committed
-# by applypatch from an e-mail message.
-#
-# The hook should exit with non-zero status after issuing an
-# appropriate message if it wants to stop the commit.
-#
-# To enable this hook, rename this file to "pre-applypatch".
-
-. git-sh-setup
-test -x "$GIT_DIR/hooks/pre-commit" &&
-	exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
-:
--- .git/hooks/pre-commit.sample
+++ .git/hooks/pre-commit.sample
-#!/bin/sh
-#
-# An example hook script to verify what is about to be committed.
-# Called by "git commit" with no arguments.  The hook should
-# exit with non-zero status after issuing an appropriate message if
-# it wants to stop the commit.
-#
-# To enable this hook, rename this file to "pre-commit".
-
-if git rev-parse --verify HEAD >/dev/null 2>&1
-then
-	against=HEAD
-else
-	# Initial commit: diff against an empty tree object
-	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
-fi
-
-# If you want to allow non-ascii filenames set this variable to true.
-allownonascii=$(git config hooks.allownonascii)
-
-# Cross platform projects tend to avoid non-ascii filenames; prevent
-# them from being added to the repository. We exploit the fact that the
-# printable range starts at the space character and ends with tilde.
-if [ "$allownonascii" != "true" ] &&
-	# Note that the use of brackets around a tr range is ok here, (it's
-	# even required, for portability to Solaris 10's /usr/bin/tr), since
-	# the square bracket bytes happen to fall in the designated range.
-	test "$(git diff --cached --name-only --diff-filter=A -z $against |
-	  LC_ALL=C tr -d '[ -~]\0')"
-then
-	echo "Error: Attempt to add a non-ascii file name."
-	echo
-	echo "This can cause problems if you want to work"
-	echo "with people on other platforms."
-	echo
-	echo "To be portable it is advisable to rename the file ..."
-	echo
-	echo "If you know what you are doing you can disable this"
-	echo "check using:"
-	echo
-	echo "  git config hooks.allownonascii true"
-	echo
-	exit 1
-fi
-
-exec git diff-index --check --cached $against --
--- .git/hooks/pre-rebase.sample
+++ .git/hooks/pre-rebase.sample
-#!/bin/sh
-#
-# Copyright (c) 2006, 2008 Junio C Hamano
-#
-# The "pre-rebase" hook is run just before "git rebase" starts doing
-# its job, and can prevent the command from running by exiting with
-# non-zero status.
-#
-# The hook is called with the following parameters:
-#
-# $1 -- the upstream the series was forked from.
-# $2 -- the branch being rebased (or empty when rebasing the current branch).
-#
-# This sample shows how to prevent topic branches that are already
-# merged to 'next' branch from getting rebased, because allowing it
-# would result in rebasing already published history.
-
-publish=next
-basebranch="$1"
-if test "$#" = 2
-then
-	topic="refs/heads/$2"
-else
-	topic=`git symbolic-ref HEAD` ||
-	exit 0 ;# we do not interrupt rebasing detached HEAD
-fi
-
-case "$topic" in
-refs/heads/??/*)
-	;;
-*)
-	exit 0 ;# we do not interrupt others.
-	;;
-esac
-
-# Now we are dealing with a topic branch being rebased
-# on top of master.  Is it OK to rebase it?
-
-# Does the topic really exist?
-git show-ref -q "$topic" || {
-	echo >&2 "No such branch $topic"
-	exit 1
-}
-
-# Is topic fully merged to master?
-not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
-if test -z "$not_in_master"
-then
-	echo >&2 "$topic is fully merged to master; better remove it."
-	exit 1 ;# we could allow it, but there is no point.
-fi
-
-# Is topic ever merged to next?  If so you should not be rebasing it.
-only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
-only_next_2=`git rev-list ^master           ${publish} | sort`
-if test "$only_next_1" = "$only_next_2"
-then
-	not_in_topic=`git rev-list "^$topic" master`
-	if test -z "$not_in_topic"
-	then
-		echo >&2 "$topic is already up-to-date with master"
-		exit 1 ;# we could allow it, but there is no point.
-	else
-		exit 0
-	fi
-else
-	not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
-	/usr/bin/perl -e '
-		my $topic = $ARGV[0];
-		my $msg = "* $topic has commits already merged to public branch:\n";
-		my (%not_in_next) = map {
-			/^([0-9a-f]+) /;
-			($1 => 1);
-		} split(/\n/, $ARGV[1]);
-		for my $elem (map {
-				/^([0-9a-f]+) (.*)$/;
-				[$1 => $2];
-			} split(/\n/, $ARGV[2])) {
-			if (!exists $not_in_next{$elem->[0]}) {
-				if ($msg) {
-					print STDERR $msg;
-					undef $msg;
-				}
-				print STDERR " $elem->[1]\n";
-			}
-		}
-	' "$topic" "$not_in_next" "$not_in_master"
-	exit 1
-fi
-
-exit 0
-
-################################################################
-
-This sample hook safeguards topic branches that have been
-published from being rewound.
-
-The workflow assumed here is:
-
- * Once a topic branch forks from "master", "master" is never
-   merged into it again (either directly or indirectly).
-
- * Once a topic branch is fully cooked and merged into "master",
-   it is deleted.  If you need to build on top of it to correct
-   earlier mistakes, a new topic branch is created by forking at
-   the tip of the "master".  This is not strictly necessary, but
-   it makes it easier to keep your history simple.
-
- * Whenever you need to test or publish your changes to topic
-   branches, merge them into "next" branch.
-
-The script, being an example, hardcodes the publish branch name
-to be "next", but it is trivial to make it configurable via
-$GIT_DIR/config mechanism.
-
-With this workflow, you would want to know:
-
-(1) ... if a topic branch has ever been merged to "next".  Young
-    topic branches can have stupid mistakes you would rather
-    clean up before publishing, and things that have not been
-    merged into other branches can be easily rebased without
-    affecting other people.  But once it is published, you would
-    not want to rewind it.
-
-(2) ... if a topic branch has been fully merged to "master".
-    Then you can delete it.  More importantly, you should not
-    build on top of it -- other people may already want to
-    change things related to the topic as patches against your
-    "master", so if you need further changes, it is better to
-    fork the topic (perhaps with the same name) afresh from the
-    tip of "master".
-
-Let's look at this example:
-
-		   o---o---o---o---o---o---o---o---o---o "next"
-		  /       /           /           /
-		 /   a---a---b A     /           /
-		/   /               /           /
-	       /   /   c---c---c---c B         /
-	      /   /   /             \         /
-	     /   /   /   b---b C     \       /
-	    /   /   /   /             \     /
-    ---o---o---o---o---o---o---o---o---o---o---o "master"
-
-
-A, B and C are topic branches.
-
- * A has one fix since it was merged up to "next".
-
- * B has finished.  It has been fully merged up to "master" and "next",
-   and is ready to be deleted.
-
- * C has not merged to "next" at all.
-
-We would want to allow C to be rebased, refuse A, and encourage
-B to be deleted.
-
-To compute (1):
-
-	git rev-list ^master ^topic next
-	git rev-list ^master        next
-
-	if these match, topic has not merged in next at all.
-
-To compute (2):
-
-	git rev-list master..topic
-
-	if this is empty, it is fully merged to "master".
--- .git/hooks/prepare-commit-msg.sample
+++ .git/hooks/prepare-commit-msg.sample
-#!/bin/sh
-#
-# An example hook script to prepare the commit log message.
-# Called by "git commit" with the name of the file that has the
-# commit message, followed by the description of the commit
-# message's source.  The hook's purpose is to edit the commit
-# message file.  If the hook fails with a non-zero status,
-# the commit is aborted.
-#
-# To enable this hook, rename this file to "prepare-commit-msg".
-
-# This hook includes three examples.  The first comments out the
-# "Conflicts:" part of a merge commit.
-#
-# The second includes the output of "git diff --name-status -r"
-# into the message, just before the "git status" output.  It is
-# commented because it doesn't cope with --amend or with squashed
-# commits.
-#
-# The third example adds a Signed-off-by line to the message, that can
-# still be edited.  This is rarely a good idea.
-
-case "$2,$3" in
-  merge,)
-    /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
-
-# ,|template,)
-#   /usr/bin/perl -i.bak -pe '
-#      print "\n" . `git diff --cached --name-status -r`
-#	 if /^#/ && $first++ == 0' "$1" ;;
-
-  *) ;;
-esac
-
-# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
-# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
--- .git/hooks/update.sample
+++ .git/hooks/update.sample
-#!/bin/sh
-#
-# An example hook script to blocks unannotated tags from entering.
-# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
-#
-# To enable this hook, rename this file to "update".
-#
-# Config
-# ------
-# hooks.allowunannotated
-#   This boolean sets whether unannotated tags will be allowed into the
-#   repository.  By default they won't be.
-# hooks.allowdeletetag
-#   This boolean sets whether deleting tags will be allowed in the
-#   repository.  By default they won't be.
-# hooks.allowmodifytag
-#   This boolean sets whether a tag may be modified after creation. By default
-#   it won't be.
-# hooks.allowdeletebranch
-#   This boolean sets whether deleting branches will be allowed in the
-#   repository.  By default they won't be.
-# hooks.denycreatebranch
-#   This boolean sets whether remotely creating branches will be denied
-#   in the repository.  By default this is allowed.
-#
-
-# --- Command line
-refname="$1"
-oldrev="$2"
-newrev="$3"
-
-# --- Safety check
-if [ -z "$GIT_DIR" ]; then
-	echo "Don't run this script from the command line." >&2
-	echo " (if you want, you could supply GIT_DIR then run" >&2
-	echo "  $0 <ref> <oldrev> <newrev>)" >&2
-	exit 1
-fi
-
-if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
-	echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
-	exit 1
-fi
-
-# --- Config
-allowunannotated=$(git config --bool hooks.allowunannotated)
-allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
-denycreatebranch=$(git config --bool hooks.denycreatebranch)
-allowdeletetag=$(git config --bool hooks.allowdeletetag)
-allowmodifytag=$(git config --bool hooks.allowmodifytag)
-
-# check for no description
-projectdesc=$(sed -e '1q' "$GIT_DIR/description")
-case "$projectdesc" in
-"Unnamed repository"* | "")
-	echo "*** Project description file hasn't been set" >&2
-	exit 1
-	;;
-esac
-
-# --- Check types
-# if $newrev is 0000...0000, it's a commit to delete a ref.
-zero="0000000000000000000000000000000000000000"
-if [ "$newrev" = "$zero" ]; then
-	newrev_type=delete
-else
-	newrev_type=$(git cat-file -t $newrev)
-fi
-
-case "$refname","$newrev_type" in
-	refs/tags/*,commit)
-		# un-annotated tag
-		short_refname=${refname##refs/tags/}
-		if [ "$allowunannotated" != "true" ]; then
-			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
-			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
-			exit 1
-		fi
-		;;
-	refs/tags/*,delete)
-		# delete tag
-		if [ "$allowdeletetag" != "true" ]; then
-			echo "*** Deleting a tag is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	refs/tags/*,tag)
-		# annotated tag
-		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
-		then
-			echo "*** Tag '$refname' already exists." >&2
-			echo "*** Modifying a tag is not allowed in this repository." >&2
-			exit 1
-		fi
-		;;
-	refs/heads/*,commit)
-		# branch
-		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
-			echo "*** Creating a branch is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	refs/heads/*,delete)
-		# delete branch
-		if [ "$allowdeletebranch" != "true" ]; then
-			echo "*** Deleting a branch is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	refs/remotes/*,commit)
-		# tracking branch
-		;;
-	refs/remotes/*,delete)
-		# delete tracking branch
-		if [ "$allowdeletebranch" != "true" ]; then
-			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	*)
-		# Anything else (is there anything else?)
-		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
-		exit 1
-		;;
-esac
-
-# --- Finished
-exit 0
--- .git/info
+++ .git/info
-(directory)
--- .git/info/exclude
+++ .git/info/exclude
-# git ls-files --others --exclude-from=.git/info/exclude
-# Lines that start with '#' are comments.
-# For a project mostly in C, the following would be a good set of
-# exclude patterns (uncomment them if you want to use them):
-# *.[oa]
-# *~
--- .git/logs
+++ .git/logs
-(directory)
--- .git/logs/HEAD
+++ .git/logs/HEAD
-0000000000000000000000000000000000000000 485277ebf58de88f908f2a4103f3c5c2b79bd3de kaitlin <kaitlin at usagi.intel.com> 1286232856 -0700	clone: from git://gitorious.org/meegotouch/meegotouch-compositor.git
-485277ebf58de88f908f2a4103f3c5c2b79bd3de 679b0a07b8e6c81af549ea7191c75963f90b7262 kaitlin <kaitlin at usagi.intel.com> 1286232904 -0700	checkout: moving from master to 0.7.0-1
-679b0a07b8e6c81af549ea7191c75963f90b7262 e7bd46b423eeef5e2a2611175f2f8b29796358a7 kaitlin <kaitlin at usagi.intel.com> 1286233241 -0700	checkout: moving from 679b0a07b8e6c81af549ea7191c75963f90b7262 to 0.6.1-1
-e7bd46b423eeef5e2a2611175f2f8b29796358a7 d4f20c59ecb1bfa85f0c868886f8a96311449ab9 kaitlin <kaitlin at usagi.intel.com> 1286233593 -0700	checkout: moving from e7bd46b423eeef5e2a2611175f2f8b29796358a7 to 0.6.0-1
-d4f20c59ecb1bfa85f0c868886f8a96311449ab9 90748c32f931cfc208b5349bff11c9f8868dd60c kaitlin <kaitlin at usagi.intel.com> 1286233686 -0700	checkout: moving from d4f20c59ecb1bfa85f0c868886f8a96311449ab9 to 0.5.9-1
-90748c32f931cfc208b5349bff11c9f8868dd60c 4c90d59ca5d13bcdc1f62e4fb4d2d36fb6547a4a kaitlin <kaitlin at usagi.intel.com> 1286233995 -0700	checkout: moving from 90748c32f931cfc208b5349bff11c9f8868dd60c to 0.5.8-1
--- .git/logs/refs
+++ .git/logs/refs
-(directory)
--- .git/logs/refs/heads
+++ .git/logs/refs/heads
-(directory)
--- .git/logs/refs/heads/master
+++ .git/logs/refs/heads/master
-0000000000000000000000000000000000000000 485277ebf58de88f908f2a4103f3c5c2b79bd3de kaitlin <kaitlin at usagi.intel.com> 1286232856 -0700	clone: from git://gitorious.org/meegotouch/meegotouch-compositor.git
--- .git/objects
+++ .git/objects
-(directory)
--- .git/objects/info
+++ .git/objects/info
-(directory)
--- .git/objects/pack
+++ .git/objects/pack
-(directory)
--- .git/packed-refs
+++ .git/packed-refs
-# pack-refs with: peeled 
-14848d7259baf2fd17ce80f09c5c86253bea1a75 refs/tags/0.7.2-1
-3291ca1b25e17119d15b447c301e0170a42ce085 refs/tags/0.7.1-1
-b6da94318069f4c47ff2401cbd34b43b9c134b40 refs/tags/0.7.0rc1
-679b0a07b8e6c81af549ea7191c75963f90b7262 refs/tags/0.7.0-1
-e7bd46b423eeef5e2a2611175f2f8b29796358a7 refs/tags/0.6.1-1
-d4f20c59ecb1bfa85f0c868886f8a96311449ab9 refs/tags/0.6.0-1
-90748c32f931cfc208b5349bff11c9f8868dd60c refs/tags/0.5.9-1
-4c90d59ca5d13bcdc1f62e4fb4d2d36fb6547a4a refs/tags/0.5.8-1
-9632704aa2826c67d40a8c84f9d791f07cfe8523 refs/tags/0.5.7-1
-ff59edb1ac3f71ad40858ceb8358c613a8be635b refs/tags/0.5.6-1
-a821801116d593a4d26d7975c0484430d5b9db54 refs/tags/0.5.5-1
-82bbc3fcb086af573133fd586386e40579c635bd refs/tags/0.5.4-1
-5055e17c3ab1d5db31ff9b31f974966e8aa5763b refs/tags/0.5.3-1
-a9b4d70fe35b79de08c33053cb77f5866bc9a697 refs/tags/0.5.2-1
-^0c672622dcbd266ddfbde539066190462f7cd4e5
-0d410771a07a53477494edda276b0745325a4e81 refs/tags/0.5.10-1
-fcf50456b2cd4393e2fbcfed244574f6ecfd818b refs/tags/0.5.1-1
-6a48a397238e5a876d0d21516b6fd96e488b5053 refs/tags/0.5.0rc1
-d352d354e9d2a03212a06d3063bbd84273f5cfb0 refs/tags/0.5.0-1
-a355209ccf898b312cb8144e00385f9830dba4b0 refs/tags/0.4.9-1
-f374b5a447b9e8e105087ff2df93ff062a45a142 refs/tags/0.4.8-1
-af381a9aa0c006f7fc7dd8285a7c66f6f60abe76 refs/tags/0.4.7-2
-ebab152ae135d97a59bf39e770587defd3543c59 refs/tags/0.4.6rc2
-3bbabcf124c9d8b459ca3cb7ca4145536ee00b6f refs/tags/0.4.6rc1
-c25e85ff48783a7a6c88e268bd8d85207829e323 refs/tags/0.4.6-1
-a678fd43629913d0c560e8972416994d7eccdfde refs/tags/0.4.5-1
-efc9cf8109dadff7c33e34439675593c5633b70f refs/tags/0.4.4-1
-8c9889176e50c312c93f10b9973363462140f19d refs/tags/0.4.3-1
-c9f781e93a8a2aa0f1c7c83749901b39ccb1e53d refs/tags/0.4.2-1
-b6f79410aa6479073cc95d00bbd5767417d1d353 refs/tags/0.4.10rc2
-ccc240d5f2319bfac94bd0226865b3a0f341db3d refs/tags/0.4.10rc1
-499cfd5896e17f26eb6f5aa835dd8d10a433c622 refs/tags/0.4.10-4
-ea10f32a47bd09120c7793c7109a9a2457794029 refs/tags/0.4.10-3
-d45828000f3fcad9495f8de48dbacd128725e044 refs/tags/0.4.10-2
-cdd3d26e6ac987a47e80d04d3b80225746838a40 refs/tags/0.4.10-1
-90c59d05a7899d025a1034aa1dbc07c1a1e80183 refs/tags/0.4.1-2
-a403a71e1bcb6494962a9dd21cc652d315a3f9d9 refs/tags/0.4.1-1
-d431904e0c085c0372f8a9d141d11ba500ac3d35 refs/tags/0.4.0-1
-e50192f4ec19a836b35555d9ca4b3f568e6093f8 refs/tags/0.3.9-1
-77f0b3891e4f8c261472bc73d6b1e8c5bed355aa refs/tags/0.3.8-1
-f2eda9878b9b7b56eb3fe706efeb3e490989dc9c refs/tags/0.3.7-1
-543666894aaa754950cb8644c0802871116c4bb3 refs/tags/0.3.6rc2
-b36080c6ee501e49f620054a878042e2dfb91f60 refs/tags/0.3.6rc1
-98de0ceaed24896b9069b384c9f59dbf93fd3f71 refs/tags/0.3.6-1
-98013b6bb838017364369893061869dc289af8c5 refs/tags/0.3.5-1
-77c2bb2e45bf5959a8380eca0b6bf0967a397552 refs/tags/0.3.4rc1
-77c2bb2e45bf5959a8380eca0b6bf0967a397552 refs/tags/0.3.4rc
-b04fb347bddfe081267abcb1c0dfdf3796de78c9 refs/tags/0.3.3rc1
-c2a0774e52a3107bf7d1c0bf013d74aa6dd41adb refs/tags/0.3.10-2
-0f7845c6f23f0a47f23a3aafd8382b6a4025670e refs/tags/0.3.10-1
-485277ebf58de88f908f2a4103f3c5c2b79bd3de refs/remotes/origin/master
--- .git/refs
+++ .git/refs
-(directory)
--- .git/refs/heads
+++ .git/refs/heads
-(directory)
--- .git/refs/heads/master
+++ .git/refs/heads/master
-485277ebf58de88f908f2a4103f3c5c2b79bd3de
--- .git/refs/remotes
+++ .git/refs/remotes
-(directory)
--- .git/refs/remotes/origin
+++ .git/refs/remotes/origin
-(directory)
--- .git/refs/remotes/origin/HEAD
+++ .git/refs/remotes/origin/HEAD
-ref: refs/remotes/origin/master
--- .git/refs/tags
+++ .git/refs/tags
-(directory)
--- .gitignore
+++ .gitignore
@@ -11,6 +11,7 @@
 debian/duicompositor
 debian/duicompositor-dbg
 debian/duicompositor-tests
+debian/mcompositor-dev/
 debian/mcompositor-dbg/
 debian/mcompositor-functional-tests/
 debian/mcompositor/
@@ -23,6 +24,8 @@
 *-stamp
 tests.xml
 decorators/mdecorator/mdecorator
-src/mcompositor
+mcompositor/mcompositor
 tests/windowctl/windowctl
 tests/windowstack/windowstack
+tests/GLES2/test-gles2
+tests/focus-tracker/focus-tracker
--- debian/changelog
+++ debian/changelog
@@ -1,3 +1,151 @@
+mcompositor (0.8.0-2) unstable; urgency=low
+
+  * rebuild mcompositor-dev for all architectures
+
+ -- Adam Endrodi <ext-adam.endrodi at nokia.com>  Wed, 08 Dec 2010 15:01:17 +0200
+
+mcompositor (0.8.0-1) unstable; urgency=low
+
+  * New: MCompositeWindowGroup to render several windows in one texture.
+  * Fixes: NB#206365 - Device freeze if Application Crash
+  * Remove a bunch of deprecated functions
+  * Fixes: NB#202713 - New implementation for fullscreen switching
+  * more fixes for NB#202713 + fix status menu stacking issue
+  * Limit xoverlay changes for NB#202713 to the EGL backend only
+  * Fixes: NB#202667 - Search application launches automatically
+  * fix transiency detection for the decorator
+  * add MCompositeManagerPrivate::changed_properties to signify when we should
+    check stacking/focus/etc
+  * Fixes: NB#206347 - Status indicator menu is opened on top of home, not the topmost 
+  * Fixes: NB#207947 - System dialog opens in wrong orientation
+  * Fixes: NB#208395 - Lock ui is revealing another copy of it
+  * don't set_as_current_app !isMapped() windows
+  * delete bogus "compositing not enabled!" warning
+  * debugging enhancements for stacking
+  * make test13.py and test14.py pass
+  * try to make test20.py pass
+  * tighten package dependencies
+  * Fixes: NB#202389 - mcompositor is wasting time printing stuff to console
+  * exposee desktop in checkStacking()
+  * die if plugins are unloadable
+  * delete rootWindow::_NET_SUPPORTING_WM_CHECK on exit
+  * set right decoratorRect in case it's too large
+
+ -- Adam Endrodi <ext-adam.endrodi at nokia.com>  Tue, 07 Dec 2010 13:54:46 +0200
+
+mcompositor (0.7.9-1) unstable; urgency=low
+
+  * Fixes: NB#205707 - System dialogs are not shown
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Wed, 17 Nov 2010 14:54:49 +0200
+
+mcompositor (0.7.8-1) unstable; urgency=low
+
+  * Fixes: NB#203276 - Show unmap animation on UnmapNotify, not on _NET_CLOSE_WINDOW
+  * Fixes: http://bugs.meego.com/show_bug.cgi?id=8957
+  * Fixes: NB#199378 - Only Input Method toolbar is visible after reopening Conversational View - Move all redirection of windows to MTexturePi
+  * Fixes: NB#199856 - Application catches tap from screen unblanking when Status Menu fails to open - allow setting NormalState when a window
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Thu, 28 Oct 2010 16:19:02 +0300
+
+mcompositor (0.7.7-1) unstable; urgency=low
+
+  * Fixes: NB#196487 - display doesn't become dimmed
+  * Various optimizations and fixes	
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Thu, 28 Oct 2010 00:31:43 +0300
+
+mcompositor (0.7.6-1) unstable; urgency=low
+
+  * Fixes: NB#198346 - Not able to answer coming calls when device lock...
+  * Fixes: NB#187502 - Fn+Backspace works simultaneously as a task switcher...
+
+ -- Kimmo Hämäläinen <kimmo.hamalainen at nokia.com>  Fri, 22 Oct 2010 10:31:05 +0300
+
+mcompositor (0.7.5-1) unstable; urgency=low
+
+  * Fixes: NB#189364 - Same properties are changed multiple times for all bg apps..
+  * Fixes: NB#189519 - compositor calls eglSwapBuffers without rendering anything	
+  * Fixes: NB#196385 - Display is not updated correctly after screen blank on-off sequence, take two
+  * New interface: custom window animation handler
+  * New interface: stacking list 	
+	
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Tue, 12 Oct 2010 14:14:43 +0300
+
+mcompositor (0.7.4-1) unstable; urgency=low
+
+  * Fixes: NB#196316 - Ugly flicker during startup-animation
+  * New: Changes: testing binaries into own package
+  * New: Restored texture from pixmap functionality software rendering	
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Tue, 05 Oct 2010 16:46:41 +0300
+
+mcompositor (0.7.3-1) unstable; urgency=low
+
+  * Fixes: NB#196194 - MCOMPOSITOR titlebar misalignment causes Toast to be unusable
+  * Fixes: NB#195550 - Status Menu opens in background of application
+  * Fixes: NB#187120 - Flicker when opening the dialer page	
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Thu, 30 Sep 2010 03:29:48 +0300
+
+mcompositor (0.7.2-1) unstable; urgency=low
+
+  * Fixes: NB#194203 - MCompositor slows down application start from the grid by 0,8s
+  * Fixes: NB#182860 - Pin query appears..., 
+  * Fixes: NB#192454 - Devicelock UI flickers...
+  * Fixes: NB#188373 Global alpha being reset when running omapxvsink	
+  * New: Improvements and texture getter for shader effects API
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Fri, 24 Sep 2010 12:58:13 +0300
+
+mcompositor (0.7.1-1) unstable; urgency=low
+
+  * Fixes: NB#193821 - leaking pixmap references
+  * Fixes: NB#188336 - setVideoGlobalAlpha does not work
+  * Fixes: NB#193948 - application state is reported incorrectly to tdriver
+  * Fixes: NB#186732 - Reaction times for switching from Home Screen to fullscreen are above target for many applications
+  * New development package	
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Fri, 17 Sep 2010 12:37:43 +0300
+
+mcompositor (0.7.0-1) unstable; urgency=low
+
+  * Fixes: NB#191286 - mcompositor is eating CPU from the background in basic panning use cases
+  * Fixes: NB#189756 - COREWEB: /usr/bin/mcompositor 'MWindowPropertyCache::isDecorator MCompositeManagerPrivate::compareWindows MCompositeManagerPrivate::roughSort MCompositeManagerPrivate::bindWindow'
+  * New: Modularized compositing framework with support for extensions and custom window effects using shaders	
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Wed, 15 Sep 2010 00:11:28 +0300
+
+mcompositor (0.6.1-1) unstable; urgency=low
+
+  * Fixes: NB#180786 - QWidget::show() does not fire subsequent X11 window map requests
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Tue, 14 Sep 2010 13:29:10 +0300
+
+mcompositor (0.6.0-1) unstable; urgency=low
+
+  * Fixes: NB#186402 - The application is getting minimized on clicking close button
+  * Improvements: beginAnimation() and endAnimation() API
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Thu, 09 Sep 2010 23:42:14 +0300
+
+mcompositor (0.5.10-1) unstable; urgency=low
+
+  * Fixes: NB#184226 - PIN code dialog uses initial_state==IconicState when it shows itself
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Wed, 08 Sep 2010 17:06:40 +0300
+
+mcompositor (0.5.9-1) unstable; urgency=low
+
+  * Fixes: NB#184773 - Application dialog gets stucked when left metakey + backspace buttons are pressed
+  * Fixes: NB#181749 - Window animations feel 'cheap' compared to Fremantle
+  * Fixes: NB#183538 - Blue screen displays for ~2 secs while booting the device
+  * Fixes: NB#180628 - visibility notification coming late
+  * Fixes: NB#186827 - mcompositor causes device freezing
+  * Fixes: NB#186832 - MCompositor crashes at app termination	
+
+ -- Abdiel Janulgue <abj at codefuassasin.research.nokia.com>  Wed, 18 Aug 2010 19:43:31 +0300
+
 mcompositor (0.5.8-1) unstable; urgency=low
 
   * Fixes: NB#185979 - Managing separate child window causing mcompositor to crash
--- debian/control
+++ debian/control
@@ -2,7 +2,7 @@
 Section: x11
 Priority: extra
 Maintainer: Abdiel Janulgue <abdiel.janulgue at nokia.com>
-Build-Depends: debhelper (>= 5), libqt4-dev, libmeegotouch-dev, libgles2-sgx-img-dev [arm armel], opengles-sgx-img-common-dev [arm armel], libgl-dev [i386], libgl1 [i386], libqt4-opengl-dev, libxrender-dev, libxcomposite-dev, libxdamage-dev, libxtst-dev, libxi-dev, mce-dev [arm armel], libcontextsubscriber-dev, pkg-config, aegis-builder (>= 1.4), libxml2-utils, test-definition, libx11-xcb-dev, libxcb-render0-dev, libxext-dev, libxcb-shape0-dev
+Build-Depends: debhelper (>= 5), libqt4-dev, libmeegotouch-dev, libgles2-sgx-img-dev [arm armel], opengles-sgx-img-common-dev [arm armel], libgl-dev [i386], libgl1 [i386], libqt4-opengl-dev, libxrender-dev, libxcomposite-dev, libxdamage-dev, libxtst-dev, libxi-dev, mce-dev [arm armel], libcontextsubscriber-dev, pkg-config, aegis-builder (>= 1.4), libxml2-utils, test-definition, libx11-xcb-dev, libxcb-render0-dev, libxext-dev, libxcb-shape0-dev, libxrandr-dev
 Standards-Version: 3.7.2
 
 Package: mcompositor
@@ -19,9 +19,22 @@
 Description: MeeGo Touch UI Compositing Window Manager debug symbols
  MeeGo Touch UI Compositor debug symbols
 
+Package: mcompositor-dev
+Architecture: any
+Depends: mcompositor (=${Source-Version})
+Description: MeeGo Touch UI Compositing Window Manager header files
+ MeeGo Touch UI Compositor header files for plugins.
+
+Package: mcompositor-utils
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: commandline tools for testing mcompositor
+ . 
+
+
 Package: mcompositor-functional-tests
 Architecture: any
-Depends: libmeegotouchcore0, ci-testing, meego-env-dimming, meego-env-behave, python, contextkit-utils, ${shlibs:Depends}
+Depends: libmeegotouchcore0, ci-testing, meego-env-dimming, meego-env-behave, python, contextkit-utils, aegis-dss-tools [arm armel], x11-utils, mcompositor-utils, ${shlibs:Depends}
 XB-Maemo-CI-Packages:  mcompositor
 XB-Maemo-CI-Stage: fast
 Description: mcompositor functional testcases
--- debian/mcompositor-dev.install
+++ debian/mcompositor-dev.install
+usr/include
--- debian/mcompositor-functional-tests.install
+++ debian/mcompositor-functional-tests.install
@@ -1,5 +1,3 @@
 usr/share/mcompositor-functional-tests
 usr/share/meegotouch/testscripts
-usr/bin/windowctl
-usr/bin/windowstack
-usr/bin/focus-tracker
+usr/bin/mcompositor-test-init.py
--- debian/mcompositor-utils.install
+++ debian/mcompositor-utils.install
+usr/bin/windowctl
+usr/bin/windowstack
+usr/bin/focus-tracker
--- debian/mcompositor.install
+++ debian/mcompositor.install
@@ -1,3 +1,4 @@
 usr/bin/mcompositor
 usr/bin/mdecorator
 usr/lib/libdecorator.so*
+usr/lib/libmcompositor.so*
--- debian/rules
+++ debian/rules
@@ -120,7 +120,7 @@
 	dh_fixperms
 #	dh_perl
 #	dh_python
-	dh_makeshlibs
+	dh_makeshlibs -V
 	dh_installdeb
 	dh_shlibdeps
 	dh_gencontrol
--- decorators/mdecorator/mdecoratorwindow.cpp
+++ decorators/mdecorator/mdecoratorwindow.cpp
@@ -73,10 +73,10 @@
     virtual void activateEvent() {
     }
 
-    virtual void setAutoRotation(bool mode) {
-        decorwindow->setOrientationAngleLocked(!mode);
-        if (!mode)
-            decorwindow->setOrientationAngle(M::Angle0);
+    virtual void setAutoRotation(bool mode)
+    {
+        Q_UNUSED(mode)
+        // we follow the orientation of the topmost app
     }
 
     virtual void setOnlyStatusbar(bool mode) 
@@ -106,16 +106,11 @@
 MDecoratorWindow::MDecoratorWindow(QWidget *parent)
     : MWindow(parent)
 {
-    XSelectInput(QX11Info::display(), winId(), PropertyChangeMask);
     onlyStatusbarAtom = XInternAtom(QX11Info::display(),
                                     "_MDECORATOR_ONLY_STATUSBAR", False);
     managedWindowAtom = XInternAtom(QX11Info::display(),
                                     "_MDECORATOR_MANAGED_WINDOW", False);
 
-    // default setting is not to rotate automatically
-    setOrientationAngle(M::Angle0);
-    setOrientationAngleLocked(true);
-
     homeButtonPanel = new MHomeButtonPanel();
     escapeButtonPanel = new MEscapeButtonPanel();
     navigationBar = new MNavigationBar();
@@ -142,6 +137,7 @@
     setMDecoratorWindowProperty();
 
     setInputRegion();
+    setProperty("followsCurrentApplicationWindowOrientation", true);
 }
 
 void MDecoratorWindow::setWindowTitle(const QString& title)
@@ -250,21 +246,33 @@
 {
     static XRectangle prev_rect = {0, 0, 0, 0};
     QRegion region;
-    QRect r = statusBar->boundingRect().toRect();
-    region += r;
+    QRect r_tmp(statusBar->geometry().toRect());
+    region += statusBar->mapToScene(r_tmp).boundingRect().toRect();
     if (!only_statusbar) {
-        QRect r2 = navigationBar->boundingRect().toRect();
-        QRegion tmp(0, r.height(), r2.width(), r2.height());
-        region += tmp;
-        r2 = homeButtonPanel->boundingRect().toRect();
-        tmp = QRegion(0, r.height(), r2.width(), r2.height());
-        region += tmp;
-        r2 = escapeButtonPanel->boundingRect().toRect();
-        tmp = QRegion(0, r.height(), r2.width(), r2.height());
-        region += tmp;
+        r_tmp = QRect(navigationBar->geometry().toRect());
+        region += navigationBar->mapToScene(r_tmp).boundingRect().toRect();
+        r_tmp = QRect(homeButtonPanel->geometry().toRect());
+        region += homeButtonPanel->mapToScene(r_tmp).boundingRect().toRect();
+        r_tmp = QRect(escapeButtonPanel->geometry().toRect());
+        region += escapeButtonPanel->mapToScene(r_tmp).boundingRect().toRect();
     }
-    decoratorRect = region.boundingRect();
 
+    const QRect fs(QApplication::desktop()->screenGeometry());
+    decoratorRect = region.boundingRect();
+    // crop it to fullscreen to work around a weird issue
+    if (decoratorRect.width() > fs.width())
+        decoratorRect.setWidth(fs.width());
+    if (decoratorRect.height() > fs.height())
+        decoratorRect.setHeight(fs.height());
+
+    if (!only_statusbar && decoratorRect.width() > fs.width() / 2
+        && decoratorRect.height() > fs.height() / 2) {
+        // decorator is so big that it is probably in more than one part
+        // (which is not yet supported)
+        setOnlyStatusbar(true);
+        r_tmp = statusBar->geometry().toRect();
+        region = decoratorRect = statusBar->mapToScene(r_tmp).boundingRect().toRect();
+    }
     XRectangle rect = itemRectToScreenRect(decoratorRect);
     if (memcmp(&prev_rect, &rect, sizeof(XRectangle))) {
         Display *dpy = QX11Info::display();
--- mcompositor
+++ mcompositor
+(directory)
--- mcompositor.pro
+++ mcompositor.pro
@@ -3,6 +3,7 @@
 SUBDIRS = \
     decorators \
     src \
+    mcompositor\
     tests \
 
 src.depends=decorators
--- mcompositor/main.cpp
+++ mcompositor/main.cpp
+/***************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (directui at nokia.com)
+**
+** This file is part of mcompositor.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at directui at nokia.com.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation
+** and appearing in the file LICENSE.LGPL included in the packaging
+** of this file.
+**
+****************************************************************************/
+
+#include <QtGui>
+#include <QGLWidget>
+#include "mcompositescene.h"
+#include "mcompositemanager.h"
+
+int main(int argc, char *argv[])
+{
+    // We don't need meego graphics system
+    setenv("QT_GRAPHICSSYSTEM", "raster", 1);
+
+#ifdef WINDOW_DEBUG
+    // React to context-commander's fake events; required by test20.py
+    // to be able to fake a phone call.
+    setenv("CONTEXT_COMMANDING", "1", 1);
+#endif
+    
+    // Don't load any Qt plugins
+    QCoreApplication::setLibraryPaths(QStringList());
+    MCompositeManager app(argc, argv);
+
+    QGraphicsScene *scene = app.scene();
+    QGraphicsView view(scene);
+    
+    view.setProperty("NoMStyle", true);
+    view.setUpdatesEnabled(false);
+    view.setAutoFillBackground(false);
+    view.setBackgroundBrush(Qt::NoBrush);
+    view.setForegroundBrush(Qt::NoBrush);
+    view.setFrameShadow(QFrame::Plain);
+
+    view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+    view.setAttribute(Qt::WA_NoSystemBackground);
+#if QT_VERSION >= 0x040600
+    view.move(-2, -2);
+    view.setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
+    view.setOptimizationFlags(QGraphicsView::IndirectPainting);
+#endif
+    app.setSurfaceWindow(view.winId());
+
+    view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+    view.setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+    view.setMinimumSize(QApplication::desktop()->width() + 2,
+                        QApplication::desktop()->height() + 2);
+    view.setMaximumSize(QApplication::desktop()->width() + 2,
+                        QApplication::desktop()->height() + 2);
+
+    QGLFormat fmt;
+    fmt.setSamples(0);
+    fmt.setSampleBuffers(false);
+
+    QGLWidget *w = new QGLWidget(fmt);
+    w->setAttribute(Qt::WA_PaintOutsidePaintEvent);
+#ifndef GLES2_VERSION
+    QPalette p = w->palette();
+    p.setColor(QPalette::Background, QColor(Qt::black));
+    w->setPalette(p);
+    w->update();
+#endif
+    
+    w->setAutoFillBackground(false);
+    w->setMinimumSize(QApplication::desktop()->width(),
+                      QApplication::desktop()->height());
+    w->setMaximumSize(QApplication::desktop()->width(),
+                      QApplication::desktop()->height());
+    app.setGLWidget(w);
+    view.setViewport(w);
+    w->makeCurrent();
+    view.show();
+
+    app.prepareEvents();
+    app.redirectWindows();
+    app.loadPlugins();
+
+    return app.exec();
+}
--- mcompositor/mcompositor.pro
+++ mcompositor/mcompositor.pro
+include(../meegotouch_config.pri)
+
+TEMPLATE = app
+TARGET = 
+DEPENDPATH += .
+INCLUDEPATH += ../src
+
+LIBS += ../src/libmcompositor.so ../decorators/libdecorator/libdecorator.so
+
+target.path += $$M_INSTALL_BIN
+INSTALLS += target 
+
+# Input
+SOURCES += main.cpp
+
+contains(DEFINES, WINDOW_DEBUG_ALOT) {
+    HEADERS += xserverpinger.h
+    SOURCES += xserverpinger.cpp
+}
+
+QT = core gui opengl
--- mcompositor/xserverpinger.cpp
+++ mcompositor/xserverpinger.cpp
+// Instances of XServerPinger send some simple X requests periodically
+// and warn no reply arrives until the next ping.
+#include "xserverpinger.h"
+
+#include <QCoreApplication>
+#include <QSocketNotifier>
+#include <QtDebug>
+
+#include <X11/Xlib.h>
+#include <X11/Xlib-xcb.h>
+
+#include <xcb/xcb.h>
+#include <xcb/xcbext.h>
+
+#include <signal.h>
+#include <sys/prctl.h>
+#include <sys/signalfd.h>
+
+// Ping X in @pingInterval miliseconds.
+XServerPinger::XServerPinger(int pingInterval)
+{
+    Display *dpy;
+    sigset_t sigs;
+
+    // Open a separate connection to X.
+    dpy = XOpenDisplay(NULL);
+    xcb = XGetXCBConnection(dpy);
+    connect(new QSocketNotifier(ConnectionNumber(dpy), QSocketNotifier::Read),
+            SIGNAL(activated(int)), SLOT(xInput(int)));
+
+    // XGetInputFocus() is our ping request.
+    request = xcb_get_input_focus(xcb);
+    xcb_flush(xcb);
+
+    timer = new QTimer();
+    connect(timer, SIGNAL(timeout()), SLOT(tick()));
+    timer->start(pingInterval);
+
+    // die() if we get SIGINT or SIGTERM.
+    sigemptyset(&sigs);
+    sigaddset(&sigs, SIGINT);
+    sigaddset(&sigs, SIGTERM);
+    connect(new QSocketNotifier(signalfd(-1, &sigs, 0),
+                                QSocketNotifier::Read),
+            SIGNAL(activated(int)), SLOT(die(int)));
+    sigprocmask(SIG_BLOCK, &sigs, NULL);
+}
+
+void XServerPinger::xInput(int)
+{
+    void *reply;
+    xcb_generic_error_t *error;
+    xcb_generic_event_t *event;
+
+    // X has sent us something, read it.
+    if ((event = xcb_poll_for_event(xcb)) != NULL)
+        // Some event, ignore it
+        free(event);
+
+    if (request.sequence
+        && xcb_poll_for_reply(xcb, request.sequence, &reply, &error)) {
+        if (reply) {
+            free(reply);
+            request.sequence = 0;
+        } else if (error)
+            // Ignore
+            free(error);
+    }
+}
+
+void XServerPinger::tick()
+{
+    if (!request.sequence) {
+        // Last ping was successful, keep pinging.
+        request = xcb_get_input_focus(xcb);
+        xcb_flush(xcb);
+    } else
+        // Ping timed out
+        qWarning("X is on holidays");
+}
+
+void XServerPinger::die(int)
+{
+    const char *wmcheck = "_NET_SUPPORTING_WM_CHECK";
+
+    xcb_delete_property(xcb,
+                        xcb_setup_roots_iterator(xcb_get_setup(xcb)).data->root,
+                        xcb_intern_atom_reply(xcb,
+                                              xcb_intern_atom(xcb,
+                                                              False,
+                                                              strlen(wmcheck),
+                                                              wmcheck),
+                                              NULL)->atom);
+    xcb_flush(xcb);
+    QCoreApplication::quit();
+}
+
+// Start XServerPinger in a separate process if it's not running yet.
+static void altmain() __attribute__((constructor));
+static void altmain()
+{
+    // Don't run again if the parent restarted.
+    if (getenv("XSERVERPINGER"))
+        return;
+    putenv("XSERVERPINGER=1");
+
+    // Start a new process and let our parent (the real mcompositor) go.
+    if (fork())
+        return;
+
+    // Die with the parent.
+    prctl(PR_SET_PDEATHSIG, SIGTERM);
+
+    int meh = 0;
+    QCoreApplication app(meh, 0);
+
+    XServerPinger pinger(2500);
+    app.exec();
+    exit(0);
+}
--- mcompositor/xserverpinger.h
+++ mcompositor/xserverpinger.h
+#ifndef XSERVERPINGER_H
+#define XSERVERPINGER_H
+
+#include <QObject>
+#include <QTimer>
+
+#include <xcb/xcb.h>
+
+class XServerPinger: public QObject
+{
+    Q_OBJECT
+
+public:
+    XServerPinger(int pingInterval);
+protected:
+    xcb_connection_t *xcb;
+    xcb_get_input_focus_cookie_t request;
+    QTimer *timer;
+
+public slots:
+    void xInput(int);
+    void tick();
+    void die(int);
+};
+
+#endif // ! XSERVERPINGER_H
--- meegotouch_config.pri
+++ meegotouch_config.pri
@@ -19,5 +19,19 @@
     }
 }
 
+contains(QT_CONFIG, opengles2) {
+     DEFINES += GLES2_VERSION
+} else {
+     # Qt wasn't built with EGL/GLES2 support but EGL is present
+     # ensure we still use the EGL back-end 
+     exists($$QMAKE_INCDIR_OPENGL/EGL) {
+         DEFINES += GLES2_VERSION
+     } 
+     # Otherwise use GLX backend
+     else {
+         DEFINES += DESKTOP_VERSION
+     }
+} 
+
 # Compositor components only
-VERSION = 0.5.5
+VERSION = 0.7.9
--- src/main.cpp
+++ src/main.cpp
-/***************************************************************************
-**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (directui at nokia.com)
-**
-** This file is part of mcompositor.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at directui at nokia.com.
-**
-** This library is free software; you can redistribute it and/or
-** modify it under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation
-** and appearing in the file LICENSE.LGPL included in the packaging
-** of this file.
-**
-****************************************************************************/
-
-#include <QtGui>
-#include <QGLWidget>
-#include "mcompositescene.h"
-#include "mcompositemanager.h"
-
-int main(int argc, char *argv[])
-{
-    // We don't need meego graphics system
-    setenv("QT_GRAPHICSSYSTEM", "raster", 1);
-    
-    // Don't load any Qt plugins
-    QCoreApplication::setLibraryPaths(QStringList());
-    MCompositeManager app(argc, argv);
-
-    QGraphicsScene *scene = app.scene();
-    QGraphicsView view(scene);
-    
-    view.setProperty("NoMStyle", true);
-    view.setUpdatesEnabled(false);
-    view.setAutoFillBackground(false);
-    view.setBackgroundBrush(Qt::NoBrush);
-    view.setForegroundBrush(Qt::NoBrush);
-    view.setFrameShadow(QFrame::Plain);
-
-    view.setWindowFlags(Qt::X11BypassWindowManagerHint);
-    view.setAttribute(Qt::WA_NoSystemBackground);
-#if QT_VERSION >= 0x040600
-    view.move(-2, -2);
-    view.setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
-    view.setOptimizationFlags(QGraphicsView::IndirectPainting);
-#endif
-    app.setSurfaceWindow(view.winId());
-
-    view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-    view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-    view.setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
-    view.setMinimumSize(QApplication::desktop()->width() + 2,
-                        QApplication::desktop()->height() + 2);
-    view.setMaximumSize(QApplication::desktop()->width() + 2,
-                        QApplication::desktop()->height() + 2);
-
-    QGLFormat fmt;
-    fmt.setSamples(0);
-    fmt.setSampleBuffers(false);
-
-    QGLWidget *w = new QGLWidget(fmt);
-    w->setAttribute(Qt::WA_PaintOutsidePaintEvent);
-    QPalette p = w->palette();
-    p.setColor(QPalette::Background, QColor(Qt::black));
-    w->setPalette(p);
-    w->update();
-    
-    w->setAutoFillBackground(false);
-    w->setMinimumSize(QApplication::desktop()->width(),
-                      QApplication::desktop()->height());
-    w->setMaximumSize(QApplication::desktop()->width(),
-                      QApplication::desktop()->height());
-    app.setGLWidget(w);
-    view.setViewport(w);
-    w->makeCurrent();
-    view.show();
-
-    app.prepareEvents();
-    app.redirectWindows();
-
-    return app.exec();
-}
--- src/mcompatoms_p.h
+++ src/mcompatoms_p.h
@@ -20,8 +20,6 @@
 #ifndef MCOMPATOMS_P_H
 #define MCOMPATOMS_P_H
 
-#include <QRectF>
-
 class MCompAtoms
 {
 public:
@@ -44,6 +42,7 @@
     };
 
     enum Atoms {
+        // The following atoms are added to the _NET_SUPPORTED list.
         // window manager
         WM_PROTOCOLS,
         WM_DELETE_WINDOW,
@@ -73,6 +72,7 @@
         _NET_WM_WINDOW_OPACITY,
         _NET_WM_STATE,
         _NET_WM_ICON_GEOMETRY,
+        _NET_WM_USER_TIME_WINDOW,
         WM_STATE,
 
         // misc
@@ -94,6 +94,11 @@
         _MEEGO_STACKING_LAYER,
         _MEEGOTOUCH_DECORATOR_BUTTONS,
         _MEEGOTOUCH_CURRENT_APP_WINDOW,
+        _MEEGOTOUCH_ALWAYS_MAPPED,
+        _MEEGOTOUCH_DESKTOP_VIEW,
+        _MEEGOTOUCH_CANNOT_MINIMIZE,
+        _MEEGOTOUCH_MSTATUSBAR_GEOMETRY,
+        _MEEGOTOUCH_CUSTOM_REGION,
 
 #ifdef WINDOW_DEBUG
         _M_WM_INFO,
@@ -104,6 +109,16 @@
         _M_WM_WINDOW_DIRECT_INVISIBLE,
 #endif
 
+        // The rest of the atoms are not added to _NET_SUPPORTED.
+        END_OF_NET_SUPPORTED,
+
+        // RROutput properties
+        RROUTPUT_CTYPE = END_OF_NET_SUPPORTED,
+        RROUTPUT_PANEL,
+        RROUTPUT_ALPHA_MODE,
+        RROUTPUT_GRAPHICS_ALPHA,
+        RROUTPUT_VIDEO_ALPHA,
+
         ATOMS_TOTAL
     };
     static MCompAtoms *instance();
--- src/mcompmgrextensionfactory.h
+++ src/mcompmgrextensionfactory.h
+/***************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (directui at nokia.com)
+**
+** This file is part of mcompositor.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at directui at nokia.com.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation
+** and appearing in the file LICENSE.LGPL included in the packaging
+** of this file.
+**
+****************************************************************************/
+
+#ifndef MCOMPMGREXTENSIONFACTORY_H
+#define MCOMPMGREXTENSIONFACTORY_H
+
+#include <QtPlugin>
+
+class MCompmgrExtensionFactory
+{
+ public:
+    virtual ~MCompmgrExtensionFactory() {}
+
+    virtual MCompositeManagerExtension* create() = 0;
+    virtual QString extensionName() = 0;
+};
+
+Q_DECLARE_INTERFACE(MCompmgrExtensionFactory,
+                    "com.nokia.mCompositor.MCompmgrExtensionFactory/1.0");
+
+#endif //MCOMPMGREXTENSIONFACTORY_H
--- src/mcompositemanager.cpp
+++ src/mcompositemanager.cpp
@@ -25,24 +25,33 @@
 #include "msimplewindowframe.h"
 #include "mdecoratorframe.h"
 #include "mdevicestate.h"
+#include "mcompositemanagerextension.h"
+#include "mcompmgrextensionfactory.h"
 #include <mrmiserver.h>
 
 #include <QX11Info>
 #include <QByteArray>
 #include <QVector>
+#include <QtPlugin>
 
 #include <X11/Xutil.h>
 #include <X11/extensions/Xcomposite.h>
 #include <X11/extensions/Xfixes.h>
 #include <X11/extensions/shape.h>
+#include <X11/extensions/Xrandr.h>
 #include <X11/Xatom.h>
 #include <X11/Xmd.h>
 #include <X11/XKBlib.h>
+#include <X11/Xproto.h>
 #include "mcompatoms_p.h"
 
-#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
 #include <signal.h>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #define TRANSLUCENT 0xe0000000
 #define OPAQUE      0xffffffff
 
@@ -83,6 +92,32 @@
 
 #ifdef WINDOW_DEBUG
 static QTime overhead_measure;
+// this can be toggled with SIGUSR1
+static bool debug_mode = false;
+#endif
+
+// Enable to see the decisions of the stacker.
+#if 0
+# define STACKING_DEBUGGING
+# define STACKING(fmt, args...)                     \
+    qDebug("line:%u: " fmt, __LINE__ ,##args)
+# define STACKING_MOVE(from, to)                    \
+    STACKING("moving %d (0x%lx) -> %d in stack",    \
+           from,                                    \
+           0 <= from && from < stacking_list.size() \
+              ? stacking_list[from] : 0,            \
+           to)
+#else
+# define STACKING(...)                              /* NOP */
+# define STACKING_MOVE(...)                         /* NOP */
+#endif
+
+// Enable to see what and why getTopmostApp() chooses
+// as a toplevel window.
+#if 0
+# define GTA(...)   qDebug("getTopmostApp: " __VA_ARGS__)
+#else
+# define GTA(...)                                   /* NOP */
 #endif
 
 MCompAtoms *MCompAtoms::instance()
@@ -94,7 +129,7 @@
 
 MCompAtoms::MCompAtoms()
 {
-    const char *atom_names[] = {
+    static const char *atom_names[] = {
         "WM_PROTOCOLS",
         "WM_DELETE_WINDOW",
         "WM_TAKE_FOCUS",
@@ -124,6 +159,7 @@
         "_NET_WM_WINDOW_OPACITY",
         "_NET_WM_STATE",
         "_NET_WM_ICON_GEOMETRY",
+        "_NET_WM_USER_TIME_WINDOW",
         "WM_STATE",
 
         // misc
@@ -145,6 +181,11 @@
         "_MEEGO_STACKING_LAYER",
         "_MEEGOTOUCH_DECORATOR_BUTTONS",
         "_MEEGOTOUCH_CURRENT_APP_WINDOW",
+        "_MEEGOTOUCH_ALWAYS_MAPPED",
+        "_MEEGOTOUCH_DESKTOP_VIEW",
+        "_MEEGOTOUCH_CANNOT_MINIMIZE",
+        "_MEEGOTOUCH_MSTATUSBAR_GEOMETRY",
+        "_MEEGOTOUCH_CUSTOM_REGION",
 
 #ifdef WINDOW_DEBUG
         // custom properties for CITA
@@ -155,6 +196,14 @@
         "_M_WM_WINDOW_DIRECT_VISIBLE",
         "_M_WM_WINDOW_DIRECT_INVISIBLE",
 #endif
+
+        // Add atoms you don't want to be in rootWindow::_NET_SUPPORTED below.
+        // RROutput properties
+        RR_PROPERTY_CONNECTOR_TYPE,
+        "Panel",
+        "AlphaMode",
+        "GraphicsAlpha",
+        "VideoAlpha",
     };
 
     Q_ASSERT((sizeof(atom_names) / sizeof(atom_names[0])) == ATOMS_TOTAL);
@@ -166,7 +215,7 @@
 
     XChangeProperty(dpy, QX11Info::appRootWindow(), atoms[_NET_SUPPORTED],
                     XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms,
-                    ATOMS_TOTAL);
+                    END_OF_NET_SUPPORTED);
 }
 
 MCompAtoms::Type MCompAtoms::windowType(Window w)
@@ -333,49 +382,6 @@
     return 0;
 }
 
-class MapRequesterPrivate: public QObject
-{
-    Q_OBJECT
-public:
-    static MapRequesterPrivate* instance(QObject* parent = 0)
-    {
-        if (!d)
-            d = new MapRequesterPrivate(parent);
-        return d;
-    }
-    
-    void requestMap(Window window)
-    {
-        if (!((MCompositeManager *) qApp)->isCompositing()
-            // if something is already queueing, add to the queue, otherwise
-            // the mapping order goes wrong
-            || !map_requests.isEmpty())
-            map_requests.push_back(window);
-        else
-            XMapWindow(QX11Info::display(), window);
-    }
-
-public slots:
-    void grantMapRequests()
-    {
-        while (!map_requests.isEmpty()) {
-            // first come first served
-            Window w = map_requests.takeFirst();
-            XMapWindow(QX11Info::display(), w);
-        }
-    }
-    
-private:
-    QList<Window> map_requests;
-    explicit MapRequesterPrivate(QObject* parent = 0)
-        :QObject(parent)
-    {}
-    
-    static MapRequesterPrivate *d;
-};
-
-MapRequesterPrivate* MapRequesterPrivate::d = 0;
-
 static Window transient_for(Window window)
 {
     Window transient_for = 0;
@@ -489,7 +495,8 @@
             QRect r = availScreenRect;
             XMoveResizeWindow(dpy, window, r.x(), r.y(), r.width(), r.height());
         }
-        priv->dirtyStacking(false);
+        if (win && win->propertyCache()->isMapped())
+            priv->dirtyStacking(false);
     } break;
     case 1: /* add */ {
         if (i == -1) {
@@ -513,7 +520,8 @@
             MDecoratorFrame::instance()->lower();
             MDecoratorFrame::instance()->setManagedWindow(0);
         }
-        priv->dirtyStacking(false);
+        if (win && win->propertyCache()->isMapped())
+            priv->dirtyStacking(false);
     } break;
     case 2: /* toggle */ {
         if (i == -1)
@@ -525,48 +533,131 @@
     }
 }
 
-#ifdef GLES2_VERSION
-// This is a Harmattan hardware-specific feature to maniplute the graphics overlay
-static void toggle_global_alpha_blend(unsigned int state, int manager = 0)
-{
-    FILE *out;
-    char path[256];
+/* Finds, caches and returns the primary (Panel) RROutput.
+ * Returns None if it cannot be found or it doesn't support
+ * alpha blending. */
+static RROutput find_primary_output()
+{
+    static bool been_here = false;
+    static RROutput primary = None;
+    int i;
+    Display *dpy;
+    int major, minor;
+    bool has_alpha_mode;
+    XRRScreenResources *scres;
+
+    /* Initialize only once. */
+    if (been_here != None)
+        return primary;
+    been_here = true;
 
-    snprintf(path, 256, "/sys/devices/platform/omapdss/manager%d/alpha_blending_enabled", manager);
+    /* Check RandR, who knows what kind of X server we ride. */
+    dpy = QX11Info::display();
+    if (!XRRQueryVersion(dpy, &major, &minor)
+        || !(major > 1 || (major == 1 && minor >= 3)))
+      return None;
+
+    /* Enumerate all the outputs X knows about and find the one
+     * whose connector type is "Panel". */
+    if (!(scres = XRRGetScreenResources(dpy, DefaultRootWindow(dpy))))
+        return None;
+
+    has_alpha_mode = false;
+    for (i = 0, primary = None; i < scres->noutput && primary == None; i++) {
+        Atom t;
+        int fmt;
+        unsigned char *contype;
+        unsigned long nitems, rem;
+
+        if (XRRGetOutputProperty(dpy, scres->outputs[i], ATOM(RROUTPUT_CTYPE),
+                                 0, 1, False, False, AnyPropertyType, &t,
+                                 &fmt, &nitems, &rem, &contype) == Success) {
+            if (t == XA_ATOM && fmt == 32 && nitems == 1
+                && *(Atom *)contype == ATOM(RROUTPUT_PANEL)) {
+                unsigned char *alpha_mode;
+
+                /* Does the primary output support alpha blending? */
+                primary = scres->outputs[i];
+                if (XRRGetOutputProperty(dpy, primary,
+                          ATOM(RROUTPUT_ALPHA_MODE), 0, 1, False, False,
+                          AnyPropertyType, &t, &fmt, &nitems, &rem,
+                          &alpha_mode) == Success) {
+                    has_alpha_mode = t == XA_INTEGER && fmt == 32
+                      && nitems == 1;
+                    XFree(alpha_mode);
+                }
+            }
+            XFree(contype);
+        }
+    }
+    XRRFreeScreenResources(scres);
 
-    out = fopen(path, "w");
+    /* If the primary output doesn't support alpha blending, don't bother. */
+    if (!has_alpha_mode)
+        primary = None;
 
-    if (out) {
-        fprintf(out, "%d", state);
-        fclose(out);
-    }
+    return primary;
 }
 
-static void set_global_alpha(unsigned int plane, unsigned int level)
+/* Set GraphicsAlpha and/or VideoAlpha of the primary output
+ * and enable/disable alpha blending if necessary. */
+static void set_global_alpha(int new_gralpha, int new_vidalpha)
 {
-    FILE *out;
-    char path[256];
+    static int blending = -1, gralpha = -1, vidalpha = -1;
+    RROutput output;
+    Display *dpy;
+    int blend;
 
-    snprintf(path, 256, "/sys/devices/platform/omapdss/overlay%d/global_alpha", plane);
+    Q_ASSERT(-1 <= new_gralpha  && new_gralpha  <= 255);
+    Q_ASSERT(-1 <= new_vidalpha && new_vidalpha <= 255);
+    if ((output = find_primary_output()) == None)
+        return;
+    dpy = QX11Info::display();
 
-    out = fopen(path, "w");
+    /* Only set changed properties. */
+    if (new_gralpha < 0)
+        new_gralpha = gralpha;
+    if (new_vidalpha < 0)
+        new_vidalpha = vidalpha;
+    if (new_gralpha < 0 && new_vidalpha < 0)
+        /* There must have been an error getting the properties. */
+        return;
 
-    if (out) {
-        fprintf(out, "%d", level);
-        fclose(out);
-    }
+    blend = new_gralpha < 255 || new_vidalpha < 255;
+    if (blend != blending && !blend)
+        /* Disable blending first. */
+        XRRChangeOutputProperty(dpy, output, ATOM(RROUTPUT_ALPHA_MODE),
+                                XA_INTEGER, 32, PropModeReplace,
+                                (unsigned char *)&blend, 1);
+
+    if (new_gralpha >= 0 && new_gralpha != gralpha) {
+        /* Change or reset graphics alpha. */
+        XRRChangeOutputProperty(dpy, output, ATOM(RROUTPUT_GRAPHICS_ALPHA),
+                                XA_INTEGER, 32, PropModeReplace,
+                                (unsigned char *)&new_gralpha, 1);
+        gralpha = new_gralpha;
+    }
+    if (new_vidalpha >= 0 && new_vidalpha != vidalpha) {
+        /* Change or reset video alpha. */
+        XRRChangeOutputProperty(dpy, output, ATOM(RROUTPUT_VIDEO_ALPHA),
+                                XA_INTEGER, 32, PropModeReplace,
+                                (unsigned char *)&new_vidalpha, 1);
+        vidalpha = new_vidalpha;
+    }
+
+    if (blend != blending && blend)
+        /* Enable blending last. */
+        XRRChangeOutputProperty(dpy, output, ATOM(RROUTPUT_ALPHA_MODE),
+                                XA_INTEGER, 32, PropModeReplace,
+                                (unsigned char *)&blend, 1);
+    blending = blend;
 }
 
-static void set_alpha_onplane(int plane, int value)
+/* Turn off global alpha blending on both planes. */
+static void reset_global_alpha()
 {
-    if (value == 255)
-        toggle_global_alpha_blend(0, plane);
-    else if (value < 255)
-        toggle_global_alpha_blend(1, plane);
-    
-    set_global_alpha(plane, value);
+    set_global_alpha(255, 255);
 }
-#endif
 
 static Bool map_predicate(Display *display, XEvent *xevent, XPointer arg)
 {
@@ -620,7 +711,10 @@
       buttoned_win(0),
       glwidget(0),
       compositing(true),
-      stacking_timeout_check_visibility(false)
+      changed_properties(false),
+      prepared(false),
+      stacking_timeout_check_visibility(false),
+      stacking_timeout_timestamp(CurrentTime)
 {
     xcb_conn = XGetXCBConnection(QX11Info::display());
     MWindowPropertyCache::set_xcb_connection(xcb_conn);
@@ -635,13 +729,17 @@
             this, SLOT(callOngoing(bool)));
     stacking_timer.setSingleShot(true);
     connect(&stacking_timer, SIGNAL(timeout()), this, SLOT(stackingTimeout()));
-    connect(this, SIGNAL(compositingEnabled()), MapRequesterPrivate::instance(this),
-            SLOT(grantMapRequests()));
-
+    connect(this, SIGNAL(currentAppChanged(Window)), this,
+            SLOT(setupButtonWindows(Window)));
 }
 
 MCompositeManagerPrivate::~MCompositeManagerPrivate()
 {
+    if (prepared)
+        // Advertise the world we're gone.
+        XDeleteProperty(QX11Info::display(), QX11Info::appRootWindow(),
+                        ATOM(_NET_SUPPORTING_WM_CHECK));
+
     delete watch;
     delete atom;
     watch   = 0;
@@ -659,20 +757,6 @@
     return p;
 }
 
-void MCompositeManagerPrivate::disableInput()
-{
-    watch->setupOverlay(xoverlay, QRect(0, 0, 0, 0), true);
-    watch->setupOverlay(localwin, QRect(0, 0, 0, 0), true);
-}
-
-void MCompositeManagerPrivate::enableInput()
-{
-    watch->setupOverlay(xoverlay, QRect(0, 0, 0, 0));
-    watch->setupOverlay(localwin, QRect(0, 0, 0, 0));
-
-    emit inputEnabled();
-}
-
 static void setup_key_grabs()
 {
     Display* dpy = QX11Info::display();
@@ -681,7 +765,10 @@
         switcher_key = XKeysymToKeycode(dpy, XStringToKeysym("BackSpace"));
         XGrabKey(dpy, switcher_key, Mod5Mask,
                  RootWindow(QX11Info::display(), 0), True,
-                 GrabModeSync, GrabModeSync);
+                 GrabModeAsync, GrabModeAsync);
+        XGrabKey(dpy, switcher_key, Mod5Mask | LockMask,
+                 RootWindow(QX11Info::display(), 0), True,
+                 GrabModeAsync, GrabModeAsync);
     }
     
     if (!ignored_mod) {
@@ -695,6 +782,7 @@
                                  0, 0);    
         XkbFreeControls(xkb_t, 0, True);
         ignored_mod = true;
+        free(xkb_t);
     }
 }
 
@@ -731,7 +819,7 @@
     overlay_mapped = false; // make sure we try to map it in startup
     XReparentWindow(QX11Info::display(), localwin, xoverlay, 0, 0);
     localwin_parent = xoverlay;
-    enableInput();
+    XMoveWindow(QX11Info::display(), localwin, -2, -2);
 
     XDamageQueryExtension(QX11Info::display(), &damage_event, &damage_error);
 
@@ -740,6 +828,7 @@
                                      RootWindow(QX11Info::display(), 0),
                                      -1, -1, 1, 1, 0, CopyFromParent,
                                      InputOnly, CopyFromParent, 0, 0);
+    XStoreName(QX11Info::display(), close_button_win, "MCompositor close button");
     XSelectInput(QX11Info::display(), close_button_win,
                  ButtonReleaseMask | ButtonPressMask);
     XMapWindow(QX11Info::display(), close_button_win);
@@ -747,9 +836,34 @@
                                     RootWindow(QX11Info::display(), 0),
                                     -1, -1, 1, 1, 0, CopyFromParent,
                                     InputOnly, CopyFromParent, 0, 0);
+    XStoreName(QX11Info::display(), home_button_win, "MCompositor home button");
     XSelectInput(QX11Info::display(), home_button_win,
                  ButtonReleaseMask | ButtonPressMask);
     XMapWindow(QX11Info::display(), home_button_win);
+
+    prepared = true;
+}
+
+void MCompositeManagerPrivate::loadPlugins()
+{
+    // hard-coded for now. move this to plugindir later
+#define PDIR "/usr/lib/mcompositor"
+    QDir pluginsDir = QDir(PDIR);
+   
+    foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
+        QObject *plugin;
+        MCompmgrExtensionFactory* factory;
+
+        QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
+        if (!(plugin = loader.instance()))
+            qFatal("couldn't load %s: %s",
+                   loader.fileName().toLatin1().constData(),
+                   loader.errorString().toLatin1().constData());
+        if (!(factory = qobject_cast<MCompmgrExtensionFactory *>(plugin)))
+            qFatal("%s is not a MCompmgrExtensionFactory",
+                   loader.fileName().toLatin1().constData());
+        factory->create();
+     }
 }
 
 bool MCompositeManagerPrivate::needDecoration(Window window,
@@ -801,8 +915,6 @@
 
 void MCompositeManagerPrivate::damageEvent(XDamageNotifyEvent *e)
 {
-    if (device_state->displayOff())
-        return;
     XserverRegion r = XFixesCreateRegion(QX11Info::display(), 0, 0);
     int num;
     XDamageSubtract(QX11Info::display(), e->damage, None, r);
@@ -811,8 +923,11 @@
     XFixesDestroyRegion(QX11Info::display(), r);
 
     MCompositeWindow *item = COMPOSITE_WINDOW(e->drawable);
-    if (item && rects)
-        item->updateWindowPixmap(rects, num);
+    if (item && rects) {
+        item->updateWindowPixmap(rects, num, e->timestamp);
+        if (item->waitingForDamage())
+            item->damageReceived(false);
+    }
 
     if (rects)
         XFree(rects);
@@ -831,8 +946,9 @@
 
     MCompositeWindow *item = COMPOSITE_WINDOW(e->window);
     if (item) {
-        if (!item->isClosing())
-            item->deleteLater();
+        item->deleteLater();
+        removeWindow(item->window());
+        // PC deleted with the MCompositeWindow
     } else {
         // We got a destroy event from a framed window (or a window that was
         // never mapped)
@@ -841,48 +957,55 @@
             framed_windows.remove(e->window);
             delete fd.frame;
         }
-    }
-    
-    if (prop_caches.contains(e->window) && (!item || (item && !item->isClosing()))) {
-        delete prop_caches.value(e->window);
-        prop_caches.remove(e->window);
+        if (prop_caches.contains(e->window)) {
+            delete prop_caches.value(e->window);
+            prop_caches.remove(e->window);
+        }
     }
 }
 
 void MCompositeManagerPrivate::propertyEvent(XPropertyEvent *e)
 {
-    MWindowPropertyCache *pc = 0;
-    if (prop_caches.contains(e->window))
-        pc = prop_caches.value(e->window);
-    if (pc && pc->propertyEvent(e) && pc->isMapped()) {
-        dirtyStacking(false);
+    MWindowPropertyCache *pc;
+
+    if (!prop_caches.contains(e->window))
+        return;
+    pc = prop_caches.value(e->window);
+
+    if (pc->propertyEvent(e) && pc->isMapped()) {
+        changed_properties = true; // property change can affect stacking order
+        if (pc->isDecorator())
+            // in case decorator's transiency changes, make us update the value
+            pc->transientFor();
+        dirtyStacking(false, e->time);
         MCompositeWindow *cw = COMPOSITE_WINDOW(e->window);
         if (cw && !cw->isNewlyMapped()) {
-            checkStacking(false);
+            checkStacking(false, e->time);
             // window on top could have changed
             if (!possiblyUnredirectTopmostWindow())
                 enableCompositing(false);
         }
     }
-#ifdef GLES2_VERSION
+
     // global alpha events here. TODO: property cache class could handle this
     // but it is straightforward to manipulate it from here
-    if (pc && e->atom == ATOM(_MEEGOTOUCH_GLOBAL_ALPHA))
-        set_alpha_onplane(0, pc->globalAlpha());
-    if (pc && e->atom == ATOM(_MEEGOTOUCH_VIDEO_ALPHA))
-        set_alpha_onplane(1, pc->videoGlobalAlpha());
-#endif
+    if (e->atom == ATOM(_MEEGOTOUCH_GLOBAL_ALPHA))
+        set_global_alpha(pc->globalAlpha(), -1);
+    else if (e->atom == ATOM(_MEEGOTOUCH_VIDEO_ALPHA))
+        set_global_alpha(-1, pc->videoGlobalAlpha());
 }
 
 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
@@ -892,27 +1015,60 @@
 }
 
 Window MCompositeManagerPrivate::getTopmostApp(int *index_in_stacking_list,
-                                               Window ignore_window)
+                                               Window ignore_window,
+                                               bool skip_always_mapped)
 {
     for (int i = stacking_list.size() - 1; i >= 0; --i) {
         Window w = stacking_list.at(i);        
-        if (w == ignore_window || !w) continue;
-        if (w == stack[DESKTOP_LAYER])
+        GTA("considering 0x%lx", w);
+        if (w == ignore_window || !w) {
+            GTA("ignoring");
+            continue;
+        }
+        if (w == stack[DESKTOP_LAYER]) {
             /* desktop is above all applications */
+            GTA("  desktop layer reached");
             return 0;
+        }
+
         MCompositeWindow *cw = COMPOSITE_WINDOW(w);
         MWindowPropertyCache *pc;
-        if (cw && cw->isMapped() && (pc = cw->propertyCache()) &&
-            (cw->isAppWindow(true) ||
-            /* non-transient TYPE_MENU is on the same stacking layer */
-            (!getLastVisibleParent(pc) &&
-            pc->windowTypeAtom() == ATOM(_NET_WM_WINDOW_TYPE_MENU))) &&
-            pc->windowState() == NormalState && !cw->isWindowTransitioning()) {
-            if (index_in_stacking_list)
-                *index_in_stacking_list = i;
-            return w;
+        if (!cw) {
+            GTA("  has no MCompositeWindow");
+            continue;
+        } else if (!cw->isMapped()) {
+            GTA("  not mapped");
+            continue;
+        } else if (!(pc = cw->propertyCache())) {
+            GTA("  has no property cache");
+            continue;
+        } else if (skip_always_mapped && pc->alwaysMapped()) {
+            GTA("  has _MEEGOTOUCH_ALWAYS_MAPPED");
+            continue;
+        }
+        // NOTE: this WILL pass transient application window and non-transient
+        // menu (this is intended!)
+        if ((pc->windowTypeAtom() == ATOM(_NET_WM_WINDOW_TYPE_MENU)
+             && getLastVisibleParent(pc))
+            || (pc->windowTypeAtom() != ATOM(_NET_WM_WINDOW_TYPE_MENU)
+                && !cw->isAppWindow(true))) {
+            GTA("  not an application window (or non-transient menu)");
+            continue;
+        }
+        if (pc->windowState() != NormalState) {
+            GTA("  not in normal state");
+            continue;
+        } else if (cw->isWindowTransitioning()) {
+            GTA("  is transitioning");
+            continue;
         }
+
+        GTA("  suitable");
+        if (index_in_stacking_list)
+            *index_in_stacking_list = i;
+        return w;
     }
+    GTA("no suitable window found");
     return 0;
 }
 
@@ -936,6 +1092,17 @@
     return 0;
 }
 
+bool MCompositeManagerPrivate::haveMappedWindow() const
+{
+    for (int i = stacking_list.size() - 1; i >= 0; --i) {
+        Window w = stacking_list.at(i);        
+        MWindowPropertyCache *pc = prop_caches.value(w, 0);
+        if (pc && pc->is_valid && pc->isMapped())
+            return true;
+    }
+    return false;
+}
+
 // TODO: merge this with disableCompositing() so that in the end we have
 // stacking order sensitive logic
 bool MCompositeManagerPrivate::possiblyUnredirectTopmostWindow()
@@ -958,6 +1125,9 @@
             win_i = i;
             break;
         }
+        if (cw->isClosing())
+            // this window is unmapped and has unmap animation going on
+            return false;
         if (cw->isMapped() && (cw->propertyCache()->hasAlpha()
                                || cw->needDecoration()
                                || cw->propertyCache()->isDecorator()
@@ -965,17 +1135,35 @@
             || !fs_r.subtracted(cw->propertyCache()->shapeRegion()).isEmpty()))
             // this window prevents direct rendering
             return false;
-        if (cw->isMapped() && cw->isAppWindow(true)) {
+        // it is a fullscreen, non-transparent window of any type
+        if (cw->isMapped()) {
             top = w;
             win_i = i;
             break;
         }
     }
-    
-    // compositing is always assumed when a window gets mapped because of our
-    // MapRequester class
-    
+
+    // this code prevents us disabling compositing when we have a window
+    // that has XMapWindow() called but we have not yet received the MapNotify
+    for (int i = stacking_list.size() - 1; i >= 0; --i) {
+        Window w = stacking_list.at(i);        
+        if (w == stack[DESKTOP_LAYER]) break;
+        MWindowPropertyCache *pc = prop_caches.value(w, 0);
+        if (pc && pc->is_valid && pc->beingMapped())
+            return false;
+    }
+    if (!haveMappedWindow()) {
+        disableCompositing(FORCED);
+        return true;
+    }
+
     if (top && cw && !MCompositeWindow::hasTransitioningWindow()) {
+#ifdef GLES2_VERSION
+        if (compositing) {
+            showOverlayWindow(false);
+            compositing = false;
+        }
+#endif
         // unredirect the chosen window and any docks and OR windows above it
         // TODO: what else should be unredirected?
         if (!((MTexturePixmapItem *)cw)->isDirectRendered()) {
@@ -994,11 +1182,12 @@
                 }
             }
         }
+#ifndef GLES2_VERSION
         if (compositing) {
-            scene()->views()[0]->setUpdatesEnabled(false);
-            XUnmapWindow(QX11Info::display(), xoverlay);
+            showOverlayWindow(false);
             compositing = false;
         }
+#endif
         ret = true;
     }
     return ret;
@@ -1006,6 +1195,9 @@
 
 void MCompositeManagerPrivate::unmapEvent(XUnmapEvent *e)
 {
+    if (e->event != QX11Info::appRootWindow())
+        // handle root's SubstructureNotifys (top-levels) only
+        return;
     if (configure_reqs.contains(e->window)) {
         QList<XConfigureRequestEvent*> l = configure_reqs.value(e->window);
         while (!l.isEmpty()) {
@@ -1019,6 +1211,8 @@
         wpc = prop_caches.value(e->window);
         wpc->setBeingMapped(false);
         wpc->setIsMapped(false);
+        if (!wpc->isInputOnly())
+            XRemoveFromSaveSet(QX11Info::display(), e->window);
     }
 
     // do not keep unmapped windows in windows_as_mapped list
@@ -1031,15 +1225,12 @@
 
     MCompositeWindow *item = COMPOSITE_WINDOW(e->window);
     if (item) {
+        item->closeWindowAnimation();
         item->stopPing();
         item->setIsMapped(false);
-        setWindowState(e->window, IconicState);
+        setWindowState(e->window, WithdrawnState);
         if (item->isVisible() && !item->isClosing())
             item->setVisible(false);
-        if (!item->isClosing())
-            // mark it direct-rendered so we create damage object etc.
-            // in case it is re-mapped
-            ((MTexturePixmapItem *)item)->enableDirectFbRendering();
 
         if (MDecoratorFrame::instance()->managedWindow() == e->window) {
             // decorate next window in the stack if any
@@ -1047,8 +1238,7 @@
             if (!cw) {
                 MDecoratorFrame::instance()->lower();
                 MDecoratorFrame::instance()->setManagedWindow(0);
-                positionWindow(MDecoratorFrame::instance()->winId(),
-                               STACK_BOTTOM);
+                positionWindow(MDecoratorFrame::instance()->winId(), false);
             } else {
                 if (cw->status() == MCompositeWindow::Hung) {
                     MDecoratorFrame::instance()->setManagedWindow(cw, true);
@@ -1072,7 +1262,6 @@
         XReparentWindow(QX11Info::display(), e->window,
                         RootWindow(QX11Info::display(), 0), 0, 0);
         setWindowState(e->window, IconicState);
-        XRemoveFromSaveSet(QX11Info::display(), e->window);
         framed_windows.remove(e->window);
         XUngrabServer(QX11Info::display());
         delete fd.frame;
@@ -1084,18 +1273,14 @@
 
     dirtyStacking(false);
 
-#ifdef GLES2_VERSION
     // Set the global alpha if the window beneath this window has one
-    Window newtop = getTopmostApp(0, e->window);
-    MCompositeWindow *c_newtop = MCompositeWindow::compositeWindow(newtop);
-    if(c_newtop) {
-        set_alpha_onplane(0, c_newtop->propertyCache()->globalAlpha());
-        set_alpha_onplane(1, c_newtop->propertyCache()->videoGlobalAlpha());
-    } else {
-        set_alpha_onplane(0, 255);
-        set_alpha_onplane(1, 255);
-    }    
-#endif        
+    MCompositeWindow *newtop = MCompositeWindow::compositeWindow(
+                                         getTopmostApp(0, e->window));
+    if (newtop)
+        set_global_alpha(newtop->propertyCache()->globalAlpha(),
+                         newtop->propertyCache()->videoGlobalAlpha());
+    else
+        reset_global_alpha();
 }
 
 void MCompositeManagerPrivate::configureEvent(XConfigureEvent *e)
@@ -1114,8 +1299,10 @@
             item->propertyCache()->setRealGeometry(r);
             check_visibility = true;
         }
-        item->setPos(e->x, e->y);
-        item->resize(e->width, e->height);
+        if (item->propertyCache()->windowState() != IconicState) {
+            item->setPos(e->x, e->y);
+            item->resize(e->width, e->height);
+        }
         if (e->override_redirect == True) {
             if (check_visibility)
                 dirtyStacking(true);
@@ -1141,12 +1328,13 @@
                 item->update();
                 dirtyStacking(check_visibility);
                 check_visibility = false;
-            }
+            } else
+                dirtyStacking(check_visibility);
         } else {
             // FIXME: seems that this branch is never executed?
             if (e->window == MDecoratorFrame::instance()->managedWindow())
                 MDecoratorFrame::instance()->lower();
-            item->setIconified(true);
+            // item->setIconified(true);
             // ensure ZValue is set only after the animation is done
             item->requestZValue(0);
 
@@ -1193,36 +1381,42 @@
         if (e->value_mask & CWSibling) {
             int above_i = stacking_list.indexOf(e->above);
             if (above_i >= 0) {
-                if (above_i > win_i)
+                if (above_i > win_i) {
+                    STACKING_MOVE(win_i, above_i);
                     safe_move(stacking_list, win_i, above_i);
-                else
+                } else {
+                    STACKING_MOVE(win_i, above_i+1);
                     safe_move(stacking_list, win_i, above_i + 1);
+                }
                 dirtyStacking(false);
             }
         } else {
             Window parent = transient_for(e->window);
             if (parent)
-                positionWindow(parent, STACK_TOP);
+                positionWindow(parent, true);
             else
-                positionWindow(e->window, STACK_TOP);
+                positionWindow(e->window, true);
         }
     } else if (win_i >= 0 && e->detail == Below
                && (e->value_mask & CWStackMode)) {
         if (e->value_mask & CWSibling) {
             int above_i = stacking_list.indexOf(e->above);
             if (above_i >= 0) {
-                if (above_i > win_i)
+                if (above_i > win_i) {
+                    STACKING_MOVE(win_i, above_i-1);
                     safe_move(stacking_list, win_i, above_i - 1);
-                else
+                } else {
+                    STACKING_MOVE(win_i, above_i);
                     safe_move(stacking_list, win_i, above_i);
+                }
                 dirtyStacking(false);
             }
         } else {
             Window parent = transient_for(e->window);
             if (parent)
-                positionWindow(parent, STACK_BOTTOM);
+                positionWindow(parent, false);
             else
-                positionWindow(e->window, STACK_BOTTOM);
+                positionWindow(e->window, false);
         }
     }
 
@@ -1320,6 +1514,8 @@
         // we know the parent due to SubstructureRedirectMask on root window
         pc->setParentWindow(RootWindow(dpy, 0));
     }
+    if(!pc->isInputOnly())
+        XAddToSaveSet(QX11Info::display(), e->window);
 
     MCompAtoms::Type wtype = pc->windowType();
     QRect a = pc->realGeometry();
@@ -1365,7 +1561,7 @@
     }
 
 #ifdef WINDOW_DEBUG
-    overhead_measure.start();
+    if (debug_mode) overhead_measure.start();
 #endif
 
     const QList<Atom> &states = pc->netWmState();
@@ -1374,17 +1570,20 @@
         fullscreen_wm_state(this, 1, e->window, &v);
     }
 
-    pc->setBeingMapped(true);
+    pc->setBeingMapped(true); // don't disable compositing & allow setting state
+    const XWMHints &h = pc->getWMHints();
+    if ((h.flags & StateHint) && (h.initial_state == IconicState))
+        setWindowState(e->window, IconicState);
+    else
+        setWindowState(e->window, NormalState);
     if (needDecoration(e->window, pc)) {
-        XAddToSaveSet(QX11Info::display(), e->window);
-
         if (MDecoratorFrame::instance()->decoratorItem()) {
-            enableCompositing();
-            MapRequesterPrivate::instance()->requestMap(e->window);
             // initially visualize decorator item so selective compositing
             // checks won't disable compositing
             MDecoratorFrame::instance()->decoratorItem()->setVisible(true);
         } else {
+#if 0 /* FIXME/TODO: this does NOT work when mdecorator starts after the first
+         decorated window is shown. See NB#196194 */
             // it will be non-toplevel, so mask needs to be set here
             XSelectInput(dpy, e->window,
                          StructureNotifyMask | ColormapChangeMask |
@@ -1425,53 +1624,54 @@
 
             XReparentWindow(QX11Info::display(), e->window,
                             frame->windowArea(), 0, 0);
-            setWindowState(e->window, NormalState);     
-            MapRequesterPrivate::instance()->requestMap(e->window);
+            MapRequesterPrivate::instance()->requestMap(pc);
             frame->show();
 
             XSync(QX11Info::display(), False);
+#else
+            qWarning("%s: mdecorator hasn't started yet", __func__);
+#endif
         }
-    } else {
-        const XWMHints &h = pc->getWMHints();
-        if ((h.flags & StateHint) && (h.initial_state == IconicState))
-            setWindowState(e->window, IconicState);
-        else
-            setWindowState(e->window, NormalState);
-        MapRequesterPrivate::instance()->requestMap(e->window);
     }
+    // create the damage object before mapping to get 'em all
+    if (!device_state->displayOff())
+        pc->damageTracking(true);
+    XMapWindow(QX11Info::display(), e->window);
 }
 
 /* recursion is needed to handle transients that are transient for other
  * transients */
-static void raise_transients(QList<Window>& winlist, Window w, int last_i)
+void MCompositeManagerPrivate::raiseTransientsOf(MWindowPropertyCache *pc,
+                                                 int last_i, bool recursion)
 {
-    Window first_moved = 0;
-    for (int i = 0; i < last_i;) {
-        Window iw = winlist.at(i);
-        if (iw == first_moved)
-            /* each window is only considered once */
-            break;
-        MCompositeWindow *cw = MCompositeWindow::compositeWindow(iw);
-        if (cw && cw->propertyCache()->transientFor() == w) {
-            safe_move(winlist, i, last_i);
-            if (!first_moved) first_moved = iw;
-            raise_transients(winlist, iw, last_i);
-        } else ++i;
+    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_MOVE(i, last_i);
+            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, true);
+        }
     }
 }
 
-#if 0 // disabled due to bugs in applications (e.g. widgetsgallery)
-static Bool
-timestamp_predicate(Display *display,
-                    XEvent  *xevent,
-                    XPointer arg)
+static Bool timestamp_predicate(Display *display, XEvent *xevent, XPointer arg)
 {
     Q_UNUSED(arg);
     if (xevent->type == PropertyNotify &&
             xevent->xproperty.window == RootWindow(display, 0) &&
             xevent->xproperty.atom == ATOM(_NET_CLIENT_LIST))
         return True;
-
     return False;
 }
 
@@ -1479,18 +1679,14 @@
 {
     XEvent xevent;
     long data = 0;
-
     /* zero-length append to get timestamp in the PropertyNotify */
     XChangeProperty(QX11Info::display(), RootWindow(QX11Info::display(), 0),
                     ATOM(_NET_CLIENT_LIST),
                     XA_WINDOW, 32, PropModeAppend,
                     (unsigned char *)&data, 0);
-
     XIfEvent(QX11Info::display(), &xevent, timestamp_predicate, NULL);
-
     return xevent.xproperty.time;
 }
-#endif
 
 /* NOTE: this assumes that stacking is correct */
 void MCompositeManagerPrivate::checkInputFocus(Time timestamp)
@@ -1500,10 +1696,8 @@
     /* find topmost window wanting the input focus */
     for (int i = stacking_list.size() - 1; i >= 0; --i) {
         Window iw = stacking_list.at(i);
-        MCompositeWindow *cw = COMPOSITE_WINDOW(iw);
-        MWindowPropertyCache *pc;
-        if (cw) pc = cw->propertyCache();
-        if (!cw || !cw->isMapped() || !pc->wantsFocus() || pc->isDecorator()
+        MWindowPropertyCache *pc = prop_caches.value(iw, 0);
+        if (!pc || !pc->isMapped() || !pc->wantsFocus() || pc->isDecorator()
             || pc->windowTypeAtom() == ATOM(_NET_WM_WINDOW_TYPE_DOCK))
             continue;
         if (!pc->isOverrideRedirect() &&
@@ -1523,6 +1717,10 @@
         return;
     prev_focus = w;
 
+    // timestamp is needed because Qt could set the focus some cases (i.e.
+    // startup and XEmbed)
+    if (timestamp == CurrentTime)
+        timestamp = get_server_time();
 #if 0 // disabled due to bugs in applications (e.g. widgetsgallery)
     MCompositeWindow *cw = windows.value(w);
     if (cw && cw->supportedProtocols().indexOf(ATOM(WM_TAKE_FOCUS)) != -1) {
@@ -1543,15 +1741,18 @@
         XSendEvent(QX11Info::display(), w, False, NoEventMask, &ev);
     } else
 #endif
-        XSetInputFocus(QX11Info::display(), w, RevertToPointerRoot, timestamp);
+    XSetInputFocus(QX11Info::display(), w, RevertToPointerRoot, timestamp);
 
     XChangeProperty(QX11Info::display(), RootWindow(QX11Info::display(), 0),
                     ATOM(_NET_ACTIVE_WINDOW),
                     XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
 }
 
-void MCompositeManagerPrivate::dirtyStacking(bool force_visibility_check)
+void MCompositeManagerPrivate::dirtyStacking(bool force_visibility_check,
+                                             Time timestamp)
 {
+    if (timestamp != CurrentTime)
+        stacking_timeout_timestamp = timestamp;
     if (force_visibility_check)
         stacking_timeout_check_visibility = true;
     if (!stacking_timer.isActive())
@@ -1580,10 +1781,25 @@
     }
 }
 
-// TODO: make this know when the property changed, to avoid X calls
-void MCompositeManagerPrivate::setupButtonWindows(MCompositeWindow *topmost)
+void MCompositeManagerPrivate::setupButtonWindows(Window curr_app)
 {
+    Q_UNUSED(curr_app);
+    MCompositeWindow *topmost = 0;
+    // find out highest application window
+    for (int i = stacking_list.size() - 1; i >= 0; --i) {
+         MCompositeWindow *cw;
+         Window w = stacking_list.at(i);
+         if (w == stack[DESKTOP_LAYER])
+             break;
+         if (!(cw = COMPOSITE_WINDOW(w)))
+             continue;
+         if (cw->isMapped() && cw->isAppWindow(true)) {
+             topmost = cw;
+             break;
+         }
+    }
     bool home_set = false, close_set = false;
+    static bool home_lowered = true, close_lowered = true;
     if (topmost) {
         XWindowChanges wc = {0, 0, 0, 0, 0, topmost->window(), Above};
         int mask = CWX | CWY | CWWidth | CWHeight | CWSibling | CWStackMode;
@@ -1594,6 +1810,7 @@
             XConfigureWindow(QX11Info::display(), home_button_win, mask, &wc);
             home_button_geom = h;
             home_set = true;
+            home_lowered = false;
         }
         const QRect &c = topmost->propertyCache()->closeButtonGeometry();
         if (c.width() > 1 && c.height() > 1) {
@@ -1602,42 +1819,86 @@
             XConfigureWindow(QX11Info::display(), close_button_win, mask, &wc);
             close_button_geom = c;
             close_set = true;
+            close_lowered = false;
         }
     }
     if ((home_set || close_set) && topmost) {
         buttoned_win = topmost->window();
-        if (!home_set)
+        if (!home_set && !home_lowered) {
             XLowerWindow(QX11Info::display(), home_button_win);
-        if (!close_set)
+            home_lowered = true;
+        }
+        if (!close_set && !close_lowered) {
             XLowerWindow(QX11Info::display(), close_button_win);
+            close_lowered = true;
+        }
     } else if (buttoned_win) {
         buttoned_win = 0;
-        XLowerWindow(QX11Info::display(), close_button_win);
-        XLowerWindow(QX11Info::display(), home_button_win);
+        if (!close_lowered) {
+            XLowerWindow(QX11Info::display(), close_button_win);
+            close_lowered = true;
+        }
+        if (!home_lowered) {
+            XLowerWindow(QX11Info::display(), home_button_win);
+            home_lowered = true;
+        }
     }
 }
 
-void MCompositeManagerPrivate::setCurrentApp(Window w)
+void MCompositeManagerPrivate::setCurrentApp(Window w,
+                                             bool stacking_order_changed)
 {
     static Window prev = (Window)-1;
-    if (prev == w)
+    if (prev == w) {
+        if (stacking_order_changed)
+            // signal listener could be interested in transients of
+            // the current application (could be also different signal?)
+            emit currentAppChanged(current_app);
         return;
+    }
     XChangeProperty(QX11Info::display(), RootWindow(QX11Info::display(), 0),
                     ATOM(_MEEGOTOUCH_CURRENT_APP_WINDOW),
                     XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
+    current_app = w;
+    emit currentAppChanged(current_app);
     prev = w;
 }
 
+// XSetErrorHandler() function, used exclusively to catch errors
+// with XRestackWindows().
+static bool xrestackwindows_error;
+static int xrestackwindows_error_handler(Display *dpy, XErrorEvent *err)
+{
+    Q_UNUSED(dpy);
+
+    // XRestackWindows() is actually a series of XConfigureWindow()s.
+    if (err->request_code == X_ConfigureWindow)
+        xrestackwindows_error = true;
+    return 0;
+}
+
 #define RAISE_MATCHING(X) { \
     first_moved = 0; \
     for (int i = 0; i < last_i;) { \
         Window w = stacking_list.at(i); \
         if (w == first_moved) break; \
         MCompositeWindow *cw = COMPOSITE_WINDOW(w); \
-        if (cw && (X)) { \
-            safe_move(stacking_list, i, last_i); \
-	    raise_transients(stacking_list, w, last_i); \
+        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_MOVE(i, last_i); \
+            stacking_list.move(i, 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; \
     } }
 
@@ -1654,9 +1915,9 @@
             stacking_timeout_check_visibility = false;
         }
         stacking_timer.stop();
+        stacking_timeout_timestamp = CurrentTime;
     }
-    Window active_app = 0, duihome = stack[DESKTOP_LAYER], first_moved,
-           set_as_current_app = 0;
+    Window active_app = 0, duihome = stack[DESKTOP_LAYER], first_moved;
     int last_i = stacking_list.size() - 1;    
     bool desktop_up = false, fs_app = false;
     int app_i = -1;
@@ -1666,11 +1927,8 @@
     active_app = getTopmostApp(&app_i);
     if (!active_app || app_i < 0) {
         desktop_up = true;
-        if (duihome)
-            set_as_current_app = duihome;
     } else {
         aw = COMPOSITE_WINDOW(active_app);
-        set_as_current_app = active_app;
         if (aw) {
             // getTopmostApp() can return a transient now
             Window parent = getLastVisibleParent(aw->propertyCache());
@@ -1684,6 +1942,9 @@
 
     /* raise active app with its transients, or duihome if
      * there is no active application */
+    STACKING("checkStacking: desktop_up: %d, active_app: 0x%lx, app_i: %d",
+             desktop_up, active_app, app_i);
+    setExposeDesktop(desktop_up);
     if (!desktop_up && active_app && app_i >= 0 && aw) {
 	/* raise application windows belonging to the same group */
 	XID group;
@@ -1693,6 +1954,7 @@
             if (cw->propertyCache()->windowState() == NormalState
                 && cw->isAppWindow()
                 && cw->propertyCache()->windowGroup() == group) {
+                STACKING_MOVE(i, last_i);
                 safe_move(stacking_list, i, last_i);
 	             /* active_app was moved, update the index */
 	             app_i = stacking_list.indexOf(active_app);
@@ -1701,11 +1963,14 @@
 	    }
 	}
     
+        STACKING_MOVE(app_i, last_i);
 	safe_move(stacking_list, app_i, last_i);
 	/* raise transients recursively */
-	raise_transients(stacking_list, active_app, last_i);
+        if (aw->propertyCache())
+	    raiseTransientsOf(aw->propertyCache(), last_i);
     } else if (duihome) {
         //qDebug() << "raising home window" << duihome;
+        STACKING_MOVE(stacking_list.indexOf(duihome), last_i);
         safe_move(stacking_list, stacking_list.indexOf(duihome), last_i);
     }
 
@@ -1716,18 +1981,14 @@
                 cw->propertyCache()->windowTypeAtom()
                                         == ATOM(_NET_WM_WINDOW_TYPE_DOCK))
     else if (active_app && aw && deco->decoratorItem() &&
-               deco->managedWindow() == active_app &&
-               (fs_app || aw->status() == MCompositeWindow::Hung)) {
+             deco->managedWindow() == active_app) {
         // no dock => decorator starts from (0,0)
         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())
@@ -1764,11 +2025,11 @@
     for (int i = stacking_list.size() - 1; i >= 0; --i) {
          MCompositeWindow *cw;
          Window w = stacking_list.at(i);
-         if (w == stack[DESKTOP_LAYER])
+         if (w == duihome)
              break;
          if (!(cw = COMPOSITE_WINDOW(w)))
              continue;
-         if (cw->isMapped() && cw->isAppWindow(true)) {
+         if (cw->propertyCache() && cw->isMapped() && cw->isAppWindow(true)) {
              topmost = cw;
              top_i = i;
              break;
@@ -1783,10 +2044,13 @@
         Window deco_w = deco->decoratorItem()->window();
         int deco_i = stacking_list.indexOf(deco_w);
         if (deco_i >= 0) {
-            if (deco_i < top_i)
+            if (deco_i < top_i) {
+                STACKING_MOVE(deco_i, top_i);
                 safe_move(stacking_list, deco_i, top_i);
-            else
+            } else {
+                STACKING_MOVE(deco_i, top_i+1);
                 safe_move(stacking_list, deco_i, top_i + 1);
+            }
             if (!compositing)
                 // decor requires compositing
                 enableCompositing(true);
@@ -1808,23 +2072,48 @@
              only_mapped.append(stacking_list.at(i));
     }
     static QList<Window> prev_only_mapped;
-    bool order_changed = prev_only_mapped != only_mapped;
-    if (order_changed) {
-        /* fix Z-values */
-        for (int i = 0; i <= last_i; ++i) {
-            MCompositeWindow *witem = COMPOSITE_WINDOW(stacking_list.at(i));
-            if (witem && witem->hasTransitioningWindow())
-                // don't change Z values until animation is over
-                break;
-            if (witem)
-                witem->requestZValue(i);
-        }
 
+    // fix Z-values always to make sure we do it after an animation
+    for (int i = 0; i <= last_i; ++i) {
+         MCompositeWindow *witem = COMPOSITE_WINDOW(stacking_list.at(i));
+         if (witem && witem->hasTransitioningWindow())
+             // don't change Z values until animation is over
+             break;
+         if (witem)
+             witem->requestZValue(i);
+    }
+    bool order_changed = prev_only_mapped != only_mapped;
+    if (xrestackwindows_error || order_changed) {
         QList<Window> reverse;
         for (int i = last_i; i >= 0; --i)
             reverse.append(stacking_list.at(i));
+
+#ifdef STACKING_DEBUGGING
+        // Log the actual arguments of XRestackWindows().
+        QList<Window>::const_iterator winit;
+        QString line;
+        for (winit = reverse.constBegin(); winit != reverse.constEnd();
+             ++winit) {
+            if (winit != reverse.constBegin())
+                line += ", ";
+            line += QString().sprintf("0x%lx", *winit);
+        }
+        STACKING("XRestackWindows([%s])", line.toLatin1().constData());
+#endif
+
+        // Watch out for errors, there may be BadWin:s in @reverse.
+        XSync(QX11Info::display(), False);
+        int (*xerr)(Display *dpy, XErrorEvent *);
+        xrestackwindows_error = false;
+        xerr = XSetErrorHandler(xrestackwindows_error_handler);
         XRestackWindows(QX11Info::display(), reverse.toVector().data(),
                         reverse.size());
+        XSync(QX11Info::display(), False);
+        XSetErrorHandler(xerr);
+        if (xrestackwindows_error) {
+            STACKING("XRestackWindows() failed, retry later");
+            dirtyStacking(false);
+        }
 
         // decorator and OR windows are not included to the property
         QList<Window> no_decors = only_mapped;
@@ -1842,13 +2131,12 @@
                         (unsigned char *)no_decors.toVector().data(),
                         no_decors.size());
         prev_only_mapped = QList<Window>(only_mapped);
-
-        checkInputFocus(timestamp);
+    }
+    if (order_changed || changed_properties) {
         if (!device_state->displayOff())
             pingTopmost();
+        checkInputFocus(timestamp);
     }
-    // possibly set up InputOnly windows for close and home buttons
-    setupButtonWindows(topmost);
     if (order_changed || force_visibility_check) {
         static int xres = ScreenOfDisplay(QX11Info::display(),
                                    DefaultScreen(QX11Info::display()))->width;
@@ -1863,7 +2151,7 @@
                  break;
              }
              MCompositeWindow *cw = COMPOSITE_WINDOW(w);
-             MWindowPropertyCache *pc;
+             MWindowPropertyCache *pc = 0;
              if (cw && cw->isMapped())
                  pc = cw->propertyCache();
              if (cw && cw->isMapped() && !pc->hasAlpha() &&
@@ -1906,13 +2194,34 @@
                 setWindowState(cw->window(), NormalState);
         }
     }
-    setCurrentApp(set_as_current_app);
+    // current app has different semantics from getTopmostApp and pure isAppWindow
+    Window set_as_current_app = duihome;
+    for (int i = stacking_list.size() - 1; i >= 0; --i) {
+        Window w = stacking_list.at(i);        
+        if (!w) continue;
+        MCompositeWindow *cw = COMPOSITE_WINDOW(w);
+        if (!cw || !cw->propertyCache() || !cw->propertyCache()->is_valid)
+            continue;
+        if (cw->propertyCache()->winId() == duihome)
+            break;
+        Atom type = cw->propertyCache()->windowTypeAtom();
+        if (type != ATOM(_NET_WM_WINDOW_TYPE_DIALOG) &&
+            type != ATOM(_NET_WM_WINDOW_TYPE_MENU) &&
+            cw->isMapped() && cw->isAppWindow(true)) {
+            set_as_current_app = w;
+            break;
+        }
+    }
+    setCurrentApp(set_as_current_app, order_changed || changed_properties);
+    changed_properties = false;
 }
 
 void MCompositeManagerPrivate::stackingTimeout()
 {
-    checkStacking(stacking_timeout_check_visibility);
+    checkStacking(stacking_timeout_check_visibility,
+                  stacking_timeout_timestamp);
     stacking_timeout_check_visibility = false;
+    stacking_timeout_timestamp = CurrentTime;
     if (!device_state->displayOff() && !possiblyUnredirectTopmostWindow()) 
         enableCompositing(true);
 }
@@ -1922,8 +2231,7 @@
     Window win = e->window;
 
     if (win == xoverlay) {
-        overlay_mapped = true;
-        enableRedirection();
+        showOverlayWindow(true);
         return;
     }
     if (win == localwin || win == localwin_parent || win == close_button_win
@@ -1942,6 +2250,7 @@
         prop_caches[win] = wpc;
     }
     wpc->setBeingMapped(false);
+    wpc->setIsMapped(true);
 
     FrameData fd = framed_windows.value(win);
     if (fd.frame) {
@@ -1981,50 +2290,54 @@
         }
     }
 
-#ifdef GLES2_VERSION
-    int g_alpha = wpc->globalAlpha();
-    int v_alpha = wpc->videoGlobalAlpha();
-    set_alpha_onplane(0, g_alpha);
-    set_alpha_onplane(1, v_alpha);
-#endif
+    set_global_alpha(wpc->globalAlpha(), wpc->videoGlobalAlpha());
 
     MWindowPropertyCache *pc = 0;
     MCompositeWindow *item = COMPOSITE_WINDOW(win);
     if (item) {
         item->setIsMapped(true);
-        if (windows_as_mapped.indexOf(win) == -1)
-            windows_as_mapped.append(win);
         pc = item->propertyCache();
         if (!pc) return;
+        if (!pc->isDecorator() && !pc->isOverrideRedirect()
+            && windows_as_mapped.indexOf(win) == -1)
+            windows_as_mapped.append(win);
     }
-    // Compositing is assumed to be enabled at this point if a window
+    // Compositing is always assumed to be enabled at this point if a window
     // has alpha channels
-    if (!compositing && (pc && pc->hasAlpha())) {
-        qWarning("mapEvent(): compositing not enabled!");
-        return;
-    }
+    if (!compositing && (pc && pc->hasAlpha()))
+        enableCompositing(true);
+
     if (item && pc) {
         if (wtype == MCompAtoms::NORMAL)
             pc->setWindowTypeAtom(ATOM(_NET_WM_WINDOW_TYPE_NORMAL));
         else
             pc->setWindowTypeAtom(atom->getType(win));
 #ifdef WINDOW_DEBUG
-        qDebug() << "Composition overhead (existing pixmap):" 
-                 << overhead_measure.elapsed();
+        if (debug_mode)
+            qDebug() << "Composition overhead (existing pixmap):" 
+                     << overhead_measure.elapsed();
 #endif
         if (((MTexturePixmapItem *)item)->isDirectRendered()) {
             ((MTexturePixmapItem *)item)->enableRedirectedRendering();
             setWindowDebugProperties(item->window());
         } else
-            item->saveBackingStore(true);
+            item->saveBackingStore();
         // 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)
-            && !pc->isInputOnly())
-            item->showWindow();
-        else {
-            item->setVisible(true);
+            && !pc->alwaysMapped() && e->send_event == False
+            && !pc->isInputOnly()) {
+            // remapped/prestarted apps should also have startup animation
+            // FIXME: assumes this window is on top
+            item->requestZValue(scene()->items().count() + 1);
+            item->setNewlyMapped(true);
+            if (!item->showWindow()) {
+                item->setNewlyMapped(false);
+                item->setVisible(true);
+            }
+        } else {
             item->setNewlyMapped(false);
+            item->setVisible(true);
         }
         goto stack_and_return;
     }
@@ -2037,17 +2350,21 @@
             return;
         pc = item->propertyCache();
 #ifdef WINDOW_DEBUG
-        if (pc->hasAlpha())
+        if (debug_mode && pc->hasAlpha())
             qDebug() << "Composition overhead (new pixmap):"
                      << overhead_measure.elapsed();
 #endif
         const XWMHints &h = pc->getWMHints();
         if ((!(h.flags & StateHint) || h.initial_state != IconicState)
-            && !pc->isInputOnly() && item->isAppWindow())
-            item->showWindow();
-        else {
-            item->setVisible(true);
+            && !pc->alwaysMapped() && e->send_event == False
+            && !pc->isInputOnly() && item->isAppWindow()) {
+            if (!item->showWindow()) {
+                item->setNewlyMapped(false);
+                item->setVisible(true);
+            }
+        } else {
             item->setNewlyMapped(false);
+            item->setVisible(true);
         }
         
         // the current decorated window got mapped
@@ -2087,11 +2404,11 @@
 
     /* do this after bindWindow() so that the window is in stacking_list */
     if (pc->windowState() == NormalState &&
-        (stack[DESKTOP_LAYER] != win || !getTopmostApp(0, win)))
+        (stack[DESKTOP_LAYER] != win || !getTopmostApp(0, win, true)))
         activateWindow(win, CurrentTime, false);
     else
         // desktop is stacked below the active application
-        positionWindow(win, STACK_BOTTOM);
+        positionWindow(win, false);
     
     dirtyStacking(false);
 }
@@ -2100,6 +2417,7 @@
 {
     MWindowPropertyCache *pc = cw->propertyCache();
     if (pc->supportedProtocols().indexOf(ATOM(_NET_WM_PING)) != -1
+        && pc->windowTypeAtom() != ATOM(_NET_WM_WINDOW_TYPE_NOTIFICATION)
         && pc->windowTypeAtom() != ATOM(_NET_WM_WINDOW_TYPE_DOCK)
         && pc->windowTypeAtom() != ATOM(_NET_WM_WINDOW_TYPE_MENU)
         && !pc->isDecorator() && !pc->isOverrideRedirect()
@@ -2119,27 +2437,25 @@
         if (event->window != stack[DESKTOP_LAYER])
             setExposeDesktop(false);
 
-        Window raise = event->window;
-        MCompositeWindow *d_item = COMPOSITE_WINDOW(stack[DESKTOP_LAYER]);
-        bool needComp = false;
-        if (d_item && d_item->isDirectRendered()
-            && raise != stack[DESKTOP_LAYER]) {
-            needComp = true;
-            enableCompositing(true);
-        }
-        if (i && i->propertyCache()->windowState() == IconicState) {
-            i->setZValue(windows.size() + 1);
-            QRectF iconGeometry = i->propertyCache()->iconGeometry();
-            i->restore(iconGeometry, needComp);
-#ifdef GLES2_VERSION
-            int g_alpha = i->propertyCache()->globalAlpha();
-            if (g_alpha < 255)
-                set_alpha_onplane(0, g_alpha);
-            int v_alpha = i->propertyCache()->videoGlobalAlpha();
-            if (v_alpha < 255)
-                set_alpha_onplane(1, v_alpha);
-#endif
+        if (!getTopmostApp()) {
+            // Not necessary to animate if not in desktop view.
+            Window raise = event->window;
+            MCompositeWindow *d_item = COMPOSITE_WINDOW(stack[DESKTOP_LAYER]);
+            bool needComp = false;
+            if (d_item && d_item->isDirectRendered()
+                && raise != stack[DESKTOP_LAYER]) {
+                needComp = true;
+                enableCompositing(true);
+            }
+            if (i && i->propertyCache()->windowState() == IconicState) {
+                i->setZValue(windows.size() + 1);
+                QRectF iconGeometry = i->propertyCache()->iconGeometry();
+                i->restore(iconGeometry, needComp);
+                set_global_alpha(i->propertyCache()->globalAlpha(),
+                                 i->propertyCache()->videoGlobalAlpha());
+            }
         }
+
         if (fd.frame)
             setWindowState(fd.frame->managedWindow(), NormalState);
         else
@@ -2147,26 +2463,14 @@
         if (event->window == stack[DESKTOP_LAYER]) {
             // Mark normal applications on top of home Iconic to make our
             // qsort() function to work
-            for (int wi = stacking_list.size() - 1; wi >= 0; --wi) {
-                 Window w = stacking_list.at(wi);
-                 if (w == stack[DESKTOP_LAYER])
-                     break;
-                 MCompositeWindow *cw = COMPOSITE_WINDOW(w);
-                 if (cw && cw->isMapped() &&
-                     !cw->propertyCache()->meegoStackingLayer()
-                     && cw->isAppWindow(true))
-                     setWindowState(cw->window(), IconicState);
-            }
+            iconifyApps();
             activateWindow(event->window, CurrentTime, true);
         } else
             // use composition due to the transition effect
             activateWindow(event->window, CurrentTime, false);
     } else if (i && event->message_type == ATOM(_NET_CLOSE_WINDOW)) {
-        
-        i->closeWindow();
-        // update stacking lit to remove window from switcher
-        checkStacking(false);
-        
+        // save pixmap and delete or kill this window
+        i->closeWindowRequest();
     } else if (event->message_type == ATOM(WM_PROTOCOLS)) {
         if (event->data.l[0] == (long) ATOM(_NET_WM_PING)) {
             MCompositeWindow *ping_source = COMPOSITE_WINDOW(event->data.l[2]);
@@ -2215,6 +2519,13 @@
                 d_item->setZValue(i->zValue() - 1);
 
                 Window lower, topmost = getTopmostApp();
+                if (i->window() != topmost) {
+                    /* Request from a background app.  Don't do anything,
+                     * just make sure the states are not screwed. */
+                    i->stopPing();
+                    setWindowState(i->window(), IconicState);
+                    return;
+                }
                 if (topmost)
                     lower = topmost;
                 else
@@ -2224,7 +2535,6 @@
                 bool needComp = false;
                 if (i->isDirectRendered() || d_item->isDirectRendered()) {
                     d_item->setVisible(true);
-                    enableCompositing(true);
                     needComp = true;
                 }
 
@@ -2244,13 +2554,19 @@
                     if (w == stack[DESKTOP_LAYER])
                         break;
                     MCompositeWindow *cw = COMPOSITE_WINDOW(w);
-                    if (cw && cw->isMapped() && cw->isAppWindow(true) &&
+                    if (cw && cw->isMapped() && (cw->isAppWindow(true)
+                        // mark transient dialogs Iconic too, so that
+                        // restoreHandler() is called when they are maximised
+                        || (cw->propertyCache()->windowTypeAtom()
+                               == ATOM(_NET_WM_WINDOW_TYPE_DIALOG)
+                            && getLastVisibleParent(cw->propertyCache()))) &&
                         // skip devicelock and screenlock windows
-                        (cw->propertyCache()->meegoStackingLayer() > 2 ||
-                         cw->propertyCache()->meegoStackingLayer() == 0))
+                        !cw->propertyCache()->dontIconify())
                         setWindowState(cw->window(), IconicState);
                 }
                 Q_ASSERT(lower_i > 0);
+                STACKING_MOVE(stacking_list.indexOf(stack[DESKTOP_LAYER]),
+                              lower_i-1);
                 safe_move(stacking_list, stacking_list.indexOf(stack[DESKTOP_LAYER]),
                                    lower_i - 1);
 
@@ -2258,6 +2574,8 @@
                 // that have selective compositing. This is triggered
                 // when windows are rendered off-screen
                 i->iconify(i->propertyCache()->iconGeometry(), needComp);
+                if (needComp)
+                    enableCompositing(true);
                 if (i->needDecoration())
                     i->startTransition();
                 i->stopPing();
@@ -2294,16 +2612,19 @@
     
     if ((!delete_sent || window->status() == MCompositeWindow::Hung)) {
         kill_window(window->window());
-        MDecoratorFrame::instance()->lower();
+        if (MDecoratorFrame::instance()->managedWindow() == window->window())
+            MDecoratorFrame::instance()->lower();
     }
-    window->deleteLater(); 
+    /* DO NOT deleteLater() this window yet because
+       a) it can remove a mapped window from stacking_list
+       b) delete can be ignored (e.g. "Do you want to exit?" dialog)
+       c) _NET_WM_PID could be wrong (i.e. the window does not go away)
+       d) we get UnmapNotify/DestroyNotify anyway when it _really_ closes */
 }
 
+// window iconified or unmapping animation ended
 void MCompositeManagerPrivate::lowerHandler(MCompositeWindow *window)
-{
-    if (window->iconifyState() != MCompositeWindow::TransitionIconifyState)
-        return;
-
+{    
     // TODO: (work for more)
     // Handle minimize request coming from a managed window itself,
     // if there are any
@@ -2314,20 +2635,16 @@
         if (i)
             i->iconify();
     }
-    // set for roughSort() before raising duihome 
-    setWindowState(window->window(), IconicState);
-
-    if (stack[DESKTOP_LAYER]) {
-        // redirect windows for the switcher
-        enableCompositing();
-        positionWindow(stack[DESKTOP_LAYER], STACK_TOP);
-        dirtyStacking(false);
+    if (window->isMapped()) {
+        // set for roughSort()
+        setWindowState(window->window(), IconicState);
+        roughSort();
     }
-#ifdef GLES2_VERSION
+    // checkStacking() will redirect windows for the switcher
+    dirtyStacking(false);
+
     // Reset the global alpha on minimize
-    set_alpha_onplane(0, 255);
-    set_alpha_onplane(1, 255);
-#endif
+    reset_global_alpha();
 }
 
 void MCompositeManagerPrivate::restoreHandler(MCompositeWindow *window)
@@ -2339,11 +2656,16 @@
     else
         to_stack = window;
     setWindowState(to_stack->window(), NormalState);
-    
-    if (window->isNewlyMapped())
-        window->setNewlyMapped(false);
 
-    positionWindow(to_stack->window(), STACK_TOP);
+    // FIXME: call these for the whole transiency chain
+    window->setNewlyMapped(false);
+    if (to_stack != window)
+        to_stack->setNewlyMapped(false);
+    window->setUntransformed();
+    if (window != to_stack)
+        to_stack->setUntransformed();
+
+    positionWindow(to_stack->window(), true);
 
     /* the animation is finished, compositing needs to be reconsidered */
     dirtyStacking(false);
@@ -2403,7 +2725,7 @@
         MCompositeWindow *to_stack = cw;
         if (last) to_stack = COMPOSITE_WINDOW(last);
         // move it to the correct position in the stack
-        positionWindow(to_stack->window(), STACK_TOP);
+        positionWindow(to_stack->window(), true);
         // possibly set decorator
         if (cw == getHighestDecorated() || cw->status() == MCompositeWindow::Hung) {
             if (FULLSCREEN_WINDOW(cw)) {
@@ -2424,10 +2746,10 @@
         }
     } else if (pc->isDecorator()) {
         // if decorator crashes and reappears, stack it to bottom, raise later
-        positionWindow(w, STACK_BOTTOM);
+        positionWindow(w, false);
     } else if (w == stack[DESKTOP_LAYER]) {
         setExposeDesktop(true);
-        positionWindow(w, STACK_TOP);
+        positionWindow(w, true);
     } else
         checkInputFocus(timestamp);
 
@@ -2440,20 +2762,31 @@
 {
     if (display_off) {
         // keep compositing to have synthetic events to obscure all windows
-        enableCompositing(true);
+        if (!haveMappedWindow())
+            enableCompositing(true);
         scene()->views()[0]->setUpdatesEnabled(false);
         /* stop pinging to save some battery */
         for (QHash<Window, MCompositeWindow *>::iterator it = windows.begin();
              it != windows.end(); ++it) {
-             MCompositeWindow *i  = it.value();
+             MCompositeWindow *i = it.value();
              i->stopPing();
+             // stop damage tracking while the display is off
+             if (i->propertyCache())
+                 i->propertyCache()->damageTracking(false);
         }
     } else {
-        scene()->views()[0]->setUpdatesEnabled(true);
         if (!possiblyUnredirectTopmostWindow())
             enableCompositing(false);
         /* start pinging again */
         pingTopmost();
+        // restart damage tracking
+        for (QHash<Window, MCompositeWindow *>::iterator it = windows.begin();
+             it != windows.end(); ++it) {
+             MCompositeWindow *i = it.value();
+             if (i->propertyCache() && (i->propertyCache()->isMapped() ||
+                                        i->propertyCache()->beingMapped()))
+                 i->propertyCache()->damageTracking(true);
+        }
     }
     dirtyStacking(true);  // VisibilityNotify generation
 }
@@ -2484,12 +2817,16 @@
 
 void MCompositeManagerPrivate::setWindowState(Window w, int state)
 {
-    MCompositeWindow* i = COMPOSITE_WINDOW(w);
-    if(i && i->propertyCache()->windowState() == state)
+    MWindowPropertyCache *pc = prop_caches.value(w, 0);
+    if (pc && pc->windowState() == state)
+        return;
+    else if (pc && (!pc->isMapped() && !pc->beingMapped())
+             && (state == NormalState || state == IconicState)) {
+        // qWarning("%s: window 0x%lx is in wrong state", __func__, w);
         return;
-    else if (i)
+    } else if (pc)
         // cannot wait for the property change notification
-        i->propertyCache()->setWindowState(state);
+        pc->setWindowState(state);
 
     CARD32 d[2];
     d[0] = state;
@@ -2498,9 +2835,15 @@
                     32, PropModeReplace, (unsigned char *)d, 2);
 }
 
+void MCompositeManager::setWindowState(Window w, int state)
+{
+   d->setWindowState(w, state);
+}
+
 void MCompositeManagerPrivate::setWindowDebugProperties(Window w)
 {
 #ifdef WINDOW_DEBUG
+    if (!debug_mode) return;
     MCompositeWindow *i = COMPOSITE_WINDOW(w);
     if (!i)
         return;
@@ -2526,6 +2869,7 @@
 
 bool MCompositeManagerPrivate::x11EventFilter(XEvent *event)
 {
+    // Core non-subclassable events
     static const int damage_ev = damage_event + XDamageNotify;
     static int shape_event_base = 0;
     if (!shape_event_base) {
@@ -2549,8 +2893,22 @@
         }
         return true;
     }
+    
+    if (processX11EventFilters(event, false))
+        return true;
+    
+    bool ret = true;
     switch (event->type) {
-
+    case FocusIn: {
+        XFocusChangeEvent *e = (XFocusChangeEvent*)event;
+        // make sure we focus right window on reverting the focus to root
+        if (e->window == RootWindow(QX11Info::display(), 0)
+            && e->mode == NotifyNormal) {
+            prev_focus = e->window;
+            checkInputFocus(CurrentTime);
+        }
+        break;
+    }
     case DestroyNotify:
         destroyEvent(&event->xdestroywindow); break;
     case PropertyNotify:
@@ -2568,10 +2926,11 @@
     case ClientMessage:
         clientMessageEvent(&event->xclient); break;
     case ButtonRelease:
-    case ButtonPress:
+    case ButtonPress: 
         buttonEvent(&event->xbutton);
         // Qt needs to handle this event for the window frame buttons
-        return false;
+        ret = false;
+        break;
     case KeyPress:
     case KeyRelease:
         XAllowEvents(QX11Info::display(), ReplayKeyboard, event->xkey.time);
@@ -2588,9 +2947,28 @@
         }
         break;
     default:
-        return false;
+        ret = false;
+        break;
     }
-    return true;
+    processX11EventFilters(event, true);
+    return ret;
+}
+
+bool MCompositeManagerPrivate::processX11EventFilters(XEvent *event, bool after)
+{
+    if (!m_extensions.contains(event->type))
+        return false;
+    
+    QList<MCompositeManagerExtension*> evlist = m_extensions.values(event->type);
+    bool processed = false;
+    if (after)
+        for (int i = 0; i < evlist.size(); ++i) 
+            evlist[i]->afterX11Event(event);
+    else
+        for (int i = 0; i < evlist.size(); ++i) 
+            processed = evlist[i]->x11Event(event);
+    
+    return processed;
 }
 
 void MCompositeManagerPrivate::keyEvent(XKeyEvent* e)
@@ -2613,8 +2991,13 @@
         memset(&ev, 0, sizeof(ev));
         ev.type = ClientMessage;
         ev.window = buttoned_win;
-        ev.message_type = ATOM(_NET_CLOSE_WINDOW);
-        rootMessageEvent(&ev);
+        ev.message_type = ATOM(WM_PROTOCOLS);
+        ev.format = 32;
+        ev.data.l[0] = ATOM(WM_DELETE_WINDOW);
+        ev.data.l[1] = CurrentTime;
+        XSendEvent(QX11Info::display(), buttoned_win, False, NoEventMask,
+                   (XEvent*)&ev);
+        return;
     }
     if (buttoned_win) {
         XButtonEvent ev = *e;
@@ -2652,13 +3035,17 @@
         xcb_get_window_attributes_reply_t *attr;
         attr = xcb_get_window_attributes_reply(xcb_conn,
                      xcb_get_window_attributes(xcb_conn, kids[i]), 0);
-        if (!attr)
+        if (!attr || attr->_class == XCB_WINDOW_CLASS_INPUT_ONLY) {
+            if (attr) free(attr);
             continue;
+        }
         xcb_get_geometry_reply_t *geom;
         geom = xcb_get_geometry_reply(xcb_conn,
                         xcb_get_geometry(xcb_conn, kids[i]), 0);
-        if (!geom)
+        if (!geom) {
+            free(attr);
             continue;
+        }
         // Pre-create MWindowPropertyCache for likely application windows
         if (localwin != kids[i] && (attr->map_state == XCB_MAP_STATE_VIEWABLE
             || (geom->width == xres && geom->height == yres))
@@ -2668,6 +3055,8 @@
                                                                attr, geom);
             if (!p->is_valid) {
                 delete p;
+                free(attr);
+                free(geom);
                 continue;
             }
             prop_caches[kids[i]] = p;
@@ -2679,33 +3068,33 @@
         if (attr && attr->map_state == XCB_MAP_STATE_VIEWABLE &&
             localwin != kids[i] && geom &&
             (geom->width > 1 && geom->height > 1)) {
+            // TODO: remove this bindWindow call -- shouldn't be needed
             MCompositeWindow* window = bindWindow(kids[i]);
             if (window) {
                 window->setNewlyMapped(false);
                 window->setVisible(true);
+                // synthetise MapNotify, to use the usual code path for plugins
+                XMapEvent e;
+                e.type = MapNotify;
+                e.serial = 0;
+                e.send_event = True;
+                e.event = RootWindow(QX11Info::display(), 0);
+                e.window = kids[i];
+                e.override_redirect = False;
+                XSendEvent(QX11Info::display(),
+                           RootWindow(QX11Info::display(), 0),
+                           False, SubstructureNotifyMask, (XEvent*)&e);
             }
         }
     }
     if (kids)
         XFree(kids);
-    scene()->views()[0]->setUpdatesEnabled(true);
-    checkStacking(false);
-
-    MCompositeWindow *item = getHighestDecorated();
-    if (item && FULLSCREEN_WINDOW(item)) {
-        // fullscreen window has decorator above it during ongoing call
-        MDecoratorFrame::instance()->setManagedWindow(item, true);
-        MDecoratorFrame::instance()->setOnlyStatusbar(true);
-    } else if (item) {
-        MDecoratorFrame::instance()->setManagedWindow(item);
-        MDecoratorFrame::instance()->setOnlyStatusbar(false);
-    }
 
     // Wait for the MapNotify for the overlay (show() of the graphicsview
     // in main() causes it even if we don't map it explicitly)
     XEvent xevent;
     XIfEvent(QX11Info::display(), &xevent, map_predicate, (XPointer)xoverlay);
-    XUnmapWindow(QX11Info::display(), xoverlay);
+    showOverlayWindow(false);
     if (!possiblyUnredirectTopmostWindow())
         enableCompositing(true);
 }
@@ -2715,22 +3104,20 @@
     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;
+
+    STACKING("remove 0x%lx from stack", w);
+    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;
@@ -2744,6 +3131,11 @@
     MCompositeWindow *cw_b = MCompositeWindow::compositeWindow(w_b);
     MDecoratorFrame *deco = MDecoratorFrame::instance();
     
+    if (!cw_a->propertyCache()) // a is already destroyed
+        return true;
+    if (!cw_b->propertyCache()) // b is already destroyed
+        return false;
+
     // a is unused decorator?
     if (cw_a->propertyCache()->isDecorator() &&
         (!deco->managedClient() ||
@@ -2808,6 +3200,7 @@
 
 void MCompositeManagerPrivate::roughSort()
 {
+    STACKING("sorting stack");
     orig_list = stacking_list;
     qSort(stacking_list.begin(), stacking_list.end(), compareWindows);
 }
@@ -2819,7 +3212,6 @@
     // no need for StructureNotifyMask because of root's SubstructureNotifyMask
     XSelectInput(display, window, PropertyChangeMask);
     XShapeSelectInput(display, window, ShapeNotifyMask);
-    XCompositeRedirectWindow(display, window, CompositeRedirectManual);
 
     MWindowPropertyCache *wpc;
     if (prop_caches.contains(window)) {
@@ -2833,7 +3225,7 @@
         prop_caches[window] = wpc;
     }
     wpc->setIsMapped(true);
-    MCompositeWindow *item = new MTexturePixmapItem(window, wpc, glwidget);
+    MCompositeWindow *item = new MTexturePixmapItem(window, wpc);
     if (!item->isValid()) {
         item->deleteLater();
         return 0;
@@ -2872,10 +3264,13 @@
     item->updateWindowPixmap();
 
     int i = stacking_list.indexOf(window);
-    if (i == -1)
+    if (i == -1) {
+        STACKING("adding 0x%lx to stack", window);
         stacking_list.append(window);
-    else
+    } else {
+        STACKING_MOVE(i, stacking_list.size()-1);
         safe_move(stacking_list, i, stacking_list.size() - 1);
+    }
     roughSort();
 
     addItem(item);
@@ -2886,14 +3281,10 @@
     } else if (pc->windowType() == MCompAtoms::DESKTOP) {
         // just in case startup sequence changes
         stack[DESKTOP_LAYER] = window;
-        connect(this, SIGNAL(inputEnabled()), item,
-                SLOT(setUnBlurred()));
         dirtyStacking(false);
         return item;
     }
 
-    item->manipulationEnabled(true);
-
     // the decorator got mapped. this is here because the compositor
     // could be restarted at any point
     if (pc->isDecorator() && !MDecoratorFrame::instance()->decoratorItem()) {
@@ -2913,7 +3304,6 @@
     watch->addItem(item);    
     updateWinList();
     setWindowDebugProperties(item->window());
-    connect(item, SIGNAL(acceptingInput()), SLOT(enableInput()));
 
     if (atom->windowType(item->window()) == MCompAtoms::DESKTOP) {
         connect(item, SIGNAL(desktopActivated(MCompositeWindow *)),
@@ -2925,7 +3315,8 @@
     connect(this, SIGNAL(compositingEnabled()), item, SLOT(startTransition()));
     connect(item, SIGNAL(itemRestored(MCompositeWindow *)), SLOT(restoreHandler(MCompositeWindow *)));
     connect(item, SIGNAL(itemIconified(MCompositeWindow *)), SLOT(lowerHandler(MCompositeWindow *)));
-    connect(item, SIGNAL(windowClosed(MCompositeWindow *)), SLOT(closeHandler(MCompositeWindow *)));
+    connect(item, SIGNAL(closeWindowRequest(MCompositeWindow *)),
+            SLOT(closeHandler(MCompositeWindow *)));
 
 
     // ping protocol
@@ -2949,13 +3340,25 @@
     dirtyStacking(false);
 }
 
+// mark application windows iconic (except those that shouldn't be)
+void MCompositeManagerPrivate::iconifyApps()
+{
+    for (int wi = stacking_list.size() - 1; wi >= 0; --wi) {
+        Window w = stacking_list.at(wi);
+        MCompositeWindow *cw = COMPOSITE_WINDOW(w);
+        if (cw && cw->propertyCache() && cw->propertyCache()->isMapped()
+            && !cw->propertyCache()->dontIconify()
+            && !cw->propertyCache()->meegoStackingLayer()
+            && cw->isAppWindow(true))
+            setWindowState(cw->window(), IconicState);
+    }
+}
+
 /*!
    Helper function to arrange arrange the order of the windows
    in the _NET_CLIENT_LIST_STACKING
 */
-void
-MCompositeManagerPrivate::positionWindow(Window w,
-        MCompositeManagerPrivate::StackPosition pos)
+void MCompositeManagerPrivate::positionWindow(Window w, bool on_top)
 {
     if (stacking_list.isEmpty())
         return;
@@ -2964,67 +3367,112 @@
     if (wp == -1 || wp >= stacking_list.size())
         return;
 
-    switch (pos) {
-    case STACK_BOTTOM: {
-        //qDebug() << __func__ << "to bottom:" << w;
-        safe_move(stacking_list, wp, 0);
-        break;
-    }
-    case STACK_TOP: {
+    if (on_top) {
         //qDebug() << __func__ << "to top:" << w;
         setWindowState(w, NormalState);
+        if (w == stack[DESKTOP_LAYER])
+            // iconify apps for roughSort()
+            iconifyApps();
+        STACKING_MOVE(wp, stacking_list.size()-1);
         safe_move(stacking_list, wp, stacking_list.size() - 1);
         // needed so that checkStacking() finds the current application
         roughSort();
-        break;
-    }
-    default:
-        break;
-
+    } else {
+        //qDebug() << __func__ << "to bottom:" << w;
+        STACKING_MOVE(wp, 0);
+        safe_move(stacking_list, wp, 0);
     }
     updateWinList();
 }
 
+void MCompositeManager::positionWindow(Window w,
+                                       MCompositeManager::StackPosition pos)
+{
+    d->positionWindow(w, pos == MCompositeManager::STACK_TOP ? true : false);
+}
+
+const QRect &MCompositeManager::decoratorRect() const
+{
+    return MDecoratorFrame::instance()->decoratorRect();
+}
+
+const QList<Window> &MCompositeManager::stackingList() const
+{
+    return d->stacking_list;
+}
+
 void MCompositeManagerPrivate::enableCompositing(bool forced)
 {
     if (compositing && !forced)
         return;
 
     if (!overlay_mapped)
-        mapOverlayWindow();
+        showOverlayWindow(true);
     else
-        enableRedirection();
+        enableRedirection(true);
 }
 
-void MCompositeManagerPrivate::mapOverlayWindow()
+void MCompositeManagerPrivate::showOverlayWindow(bool show)
 {
-    // Freeze painting of framebuffer as of this point
-    scene()->views()[0]->setUpdatesEnabled(false);
-    XMoveWindow(QX11Info::display(), localwin, -2, -2);
-    XMapWindow(QX11Info::display(), xoverlay);
+    static bool first_call = true;
+    static XRectangle empty = {0, 0, 0, 0},
+                      fs = {0, 0,
+                            ScreenOfDisplay(QX11Info::display(),
+                                DefaultScreen(QX11Info::display()))->width + 2,
+                            ScreenOfDisplay(QX11Info::display(),
+                                DefaultScreen(QX11Info::display()))->height + 2};
+    if (!show && (overlay_mapped || first_call)) {
+        scene()->views()[0]->setUpdatesEnabled(false);
+        XShapeCombineRectangles(QX11Info::display(), xoverlay,
+                                ShapeBounding, 0, 0, &empty, 1,
+                                ShapeSet, Unsorted);
+        XShapeCombineRectangles(QX11Info::display(), localwin,
+                                ShapeBounding, 0, 0, &empty, 1,
+                                ShapeSet, Unsorted);
+        overlay_mapped = false;
+    } else if (show && (!overlay_mapped || first_call)) {
+#ifdef GLES2_VERSION
+        enableRedirection(false);
+#endif
+        XShapeCombineRectangles(QX11Info::display(), xoverlay,
+                                ShapeBounding, 0, 0, &fs, 1,
+                                ShapeSet, Unsorted);
+        XShapeCombineRectangles(QX11Info::display(), localwin,
+                                ShapeBounding, 0, 0, &fs, 1,
+                                ShapeSet, Unsorted);
+        XserverRegion r = XFixesCreateRegion(QX11Info::display(), &empty, 1);
+        XFixesSetWindowShapeRegion(QX11Info::display(), xoverlay,
+                                   ShapeInput, 0, 0, r);
+        XFixesSetWindowShapeRegion(QX11Info::display(), localwin,
+                                   ShapeInput, 0, 0, r);
+        XFixesDestroyRegion(QX11Info::display(), r);
+        overlay_mapped = true;
+#ifndef GLES2_VERSION
+        enableRedirection(false);
+#endif
+        emit compositingEnabled();
+    }
+    first_call = false;
 }
 
-void MCompositeManagerPrivate::enableRedirection()
+void MCompositeManagerPrivate::enableRedirection(bool emit_signal)
 {
     for (QHash<Window, MCompositeWindow *>::iterator it = windows.begin();
             it != windows.end(); ++it) {
-        MCompositeWindow *tp  = it.value();
-        if (tp->windowVisible())
+        MCompositeWindow *tp = it.value();
+        if (tp->isValid() && tp->isDirectRendered() && tp->propertyCache()
+            && (tp->propertyCache()->isMapped()
+                || tp->propertyCache()->beingMapped()))
             ((MTexturePixmapItem *)tp)->enableRedirectedRendering();
         setWindowDebugProperties(it.key());
     }
-    XSync(QX11Info::display(), False);
-    
     compositing = true;
-    QTimer::singleShot(100, this, SLOT(enablePaintedCompositing()));
-}
-
-void MCompositeManagerPrivate::enablePaintedCompositing()
-{
+    // no delay: application does not need to redraw when maximizing it
     scene()->views()[0]->setUpdatesEnabled(true);
-    glwidget->update();
-    // At this point everything should be rendered off-screen
-    emit compositingEnabled();
+    // NOTE: enableRedirectedRendering() calls glwidget->update() if needed
+    if (emit_signal)
+        // At this point everything should be rendered off-screen
+        emit compositingEnabled();
 }
 
 void MCompositeManagerPrivate::disableCompositing(ForcingLevel forced)
@@ -3046,7 +3494,9 @@
             return;
     }
 
-    scene()->views()[0]->setUpdatesEnabled(false);
+#ifdef GLES2_VERSION  
+    showOverlayWindow(false);
+#endif
 
     for (QHash<Window, MCompositeWindow *>::iterator it = windows.begin();
             it != windows.end(); ++it) {
@@ -3058,8 +3508,9 @@
         setWindowDebugProperties(it.key());
     }
 
-    XUnmapWindow(QX11Info::display(), xoverlay);
-    XFlush(QX11Info::display());
+#ifndef GLES2_VERSION  
+    showOverlayWindow(false);
+#endif
 
     if (MDecoratorFrame::instance()->decoratorItem())
         MDecoratorFrame::instance()->lower();
@@ -3097,8 +3548,7 @@
         if (!i->isAppWindow(true) ||
             i->propertyCache()->windowState() == IconicState ||
             // skip devicelock and screenlock windows
-            i->propertyCache()->meegoStackingLayer() == 1 ||
-            i->propertyCache()->meegoStackingLayer() == 2 ||
+            i->propertyCache()->dontIconify() ||
 
             i->propertyCache()->windowTypeAtom() == ATOM(_NET_WM_WINDOW_TYPE_DESKTOP))
             continue;
@@ -3119,6 +3569,12 @@
     }
 }
 
+void MCompositeManagerPrivate::installX11EventFilter(long xevent, 
+                                                     MCompositeManagerExtension* extension)
+{  
+    m_extensions.insert(xevent, extension);
+}
+
 void MCompositeManagerPrivate::showLaunchIndicator(int timeout)
 {
     if (!launchIndicator) {
@@ -3139,17 +3595,458 @@
         launchIndicator->hide();
 }
 
+static void sigusr1_handler(int signo)
+{
+    Q_UNUSED(signo)
+#ifdef WINDOW_DEBUG
+    debug_mode = !debug_mode;
+#endif
+}
+
+#ifdef WINDOW_DEBUG
+void MCompositeManager::dumpState(const char *heading)
+{
+    static const char *tf[] = { "false", "true" };
+    static const char *yn[] = { "no", "yes" };
+    int i;
+    QString line;
+    const QRect *r;
+    MCompositeWindow *cw;
+    QHash<const MCompositeManagerExtension*, QList<int> > extensions;
+
+    if (heading)
+      qDebug("%s: ", heading);
+
+    qDebug(    "display:          %s",
+               d->device_state->displayOff() ? "off" : "on");
+    qDebug(    "call state:       %s",
+               d->device_state->ongoingCall() ? "ongoing" : "idle");
+
+    qDebug(    "composition:      %s", isCompositing() ? "on"  : "off");
+    qDebug(    "xoverlay:         0x%lx, %s", d->xoverlay,
+               d->overlay_mapped ? "mapped" : "unmapped");
+    qDebug(    "avail screen:     %dx%d%+d%+d",
+               availScreenRect.width(), availScreenRect.height(),
+               availScreenRect.x(), availScreenRect.y());
+
+    qDebug(    "current_app:      0x%lx", d->current_app);
+    qDebug(    "topmostApp:       0x%lx (index: %d)",
+               d->getTopmostApp(&i), i);
+    if ((cw = d->getHighestDecorated()) != NULL)
+        qDebug("highestDecorated: 0x%lx", cw->window());
+    else
+        qDebug("highestDecorated: None");
+
+    qDebug(    "local_win:        0x%lx, parent: 0x%lx",
+               d->localwin, d->localwin_parent);
+
+    qDebug(    "prev_focus:       0x%lx", d->prev_focus);
+    qDebug(    "buttoned_win:     0x%lx", d->buttoned_win);
+
+    // Decoration button geometries.
+    r = &d->home_button_geom;
+    qDebug(    "home button:      0x%lx (%dx%d%+d%+d)",
+               d->home_button_win,
+               r->width(), r->height(), r->x(), r->y());
+    r = &d->close_button_geom;
+    qDebug(    "close button:     0x%lx (%dx%d%+d%+d)",
+               d->close_button_win,
+               r->width(), r->height(), r->x(), r->y());
+
+    line = "dock_region:     ";
+    if (!d->dock_region.isEmpty()) {
+        foreach (const QRect &rect, d->dock_region.rects())
+            line += QString().sprintf(" %dx%d%+d%+d",
+                                      rect.width(), rect.height(),
+                                      rect.x(), rect.y());
+    } else
+        line += " <Empty>";
+    qDebug() << line.toLatin1().constData();
+
+    // Stacking
+    qDebug(    "stacking_timer:   %s",
+               d->stacking_timer.isActive() ? "active" : "idle");
+    qDebug(    "check_visibility: %s",
+               tf[d->stacking_timeout_check_visibility]);
+
+    // Top windows per stacking layer.
+    qDebug("stacking layers:");
+    qDebug("    input: 0x%lx", d->stack[INPUT_LAYER]);
+    qDebug("     dock: 0x%lx", d->stack[DOCK_LAYER]);
+    qDebug("   system: 0x%lx", d->stack[SYSTEM_LAYER]);
+    qDebug("      app: 0x%lx", d->stack[APPLICATION_LAYER]);
+    qDebug("  desktop: 0x%lx", d->stack[DESKTOP_LAYER]);
+
+    // Stacking order of mapped windows and mapping order of windows.
+    QList<Window>::const_iterator winit;
+    qDebug("window stack:");
+    for (winit = d->stacking_list.constEnd();
+         --winit != d->stacking_list.constBegin(); )
+        qDebug("  0x%lx", *winit);
+    qDebug("mapping order:");
+    for (winit = d->windows_as_mapped.constEnd();
+         --winit != d->windows_as_mapped.constBegin(); )
+        qDebug("  0x%lx", *winit);
+
+    // All MCompositeWindow:s we know about.
+    QHash<Window, MCompositeWindow *>::const_iterator cwit;
+    qDebug("windows:");
+    for (cwit = d->windows.constBegin(); cwit != d->windows.constEnd();
+         ++cwit) {
+        static const char *winstates[] = {
+            "normal", "hung", "minimizing", "closing"
+        };
+        static const char *iconstates[] = { "none", "manual", "transition" };
+        MCompositeWindow *cw, *behind;
+        char *name;
+
+        cw = *cwit;
+        Q_ASSERT(cwit.key() == cw->window());
+
+        // Determine the window's name.
+        name = NULL;
+        XFetchName(QX11Info::display(), cw->window(), &name);
+        if (!name) {
+            XClassHint cls;
+
+            cls.res_name = cls.res_class = NULL;
+            XGetClassHint(QX11Info::display(), cw->window(), &cls);
+            if (!(name = cls.res_name))
+                name = cls.res_class;
+            else if (cls.res_class)
+                XFree(cls.res_class);
+        }
+
+        qDebug("  ptr %p == xwin 0x%lx%s: %s", cw, cw->window(),
+               cw->isValid() ? "" : " (not valid anymore)",
+               name ? name : "[noname]");
+        qDebug("    mapped: %s, newly mapped: %s",
+               yn[cw->isMapped()], yn[cw->isNewlyMapped()]);
+        qDebug("    visible: %s, direct rendered: %s",
+               yn[cw->windowVisible()], yn[cw->isDirectRendered()]);
+        qDebug("    is app: %s, needs decoration: %s",
+               yn[cw->isAppWindow()], yn[cw->needDecoration()]);
+        qDebug("    status: %s, iconified: %s, iconification status: %s",
+               winstates[cw->status()], yn[cw->isIconified()],
+               iconstates[cw->iconifyState()]);
+        qDebug("    has transitioning windows: %s, transitioning: %s, "
+                   "closing: %s",
+                   yn[cw->hasTransitioningWindow()],
+                   yn[cw->isWindowTransitioning()],
+                   yn[cw->isClosing()]);
+        qDebug("    dimmed: %s, blurred: %s, scaled: %s",
+                    yn[cw->dimmedEffect()], yn[cw->blurred()],
+                    yn[cw->isScaled()]);
+        behind = cw->behind();
+        qDebug("    stack index: %d, behind window: 0x%lx, "
+                   "last visible parent: 0x%lx", cw->indexInStack(),
+                   behind ? behind->window() : 0, cw->lastVisibleParent());
+
+        // MWindowPropertyCache::transientFor() can change state,
+        // transientWindows() doesn't.
+        QList<Window> const &transients = cw->propertyCache()->transientWindows();
+        if (!transients.empty()) {
+            line = "    transients:";
+            QList<Window>::const_iterator trit;
+            for (trit = transients.constBegin();
+                 trit != transients.constEnd(); ++trit)
+                line += QString().sprintf(" 0x%lx", *trit);
+            qDebug() << line.toLatin1().constData();
+        }
+
+        if (name)
+            XFree(name);
+    }
+
+    if (!d->framed_windows.isEmpty()) {
+        QHash<Window, MCompositeManagerPrivate::FrameData>::const_iterator fwit;
+
+        qDebug("framed_windows:");
+        for (fwit = d->framed_windows.constBegin();
+             fwit != d->framed_windows.constEnd(); ++fwit)
+            qDebug("  0x%lx: parent=0x%lx, mapped=%s", fwit.key(),
+                   fwit->parentWindow, fwit->mapped ? "yes" : "no");
+    } else
+        qDebug("framed_windows: <None>");
+
+    // Which windows are in the property cache?
+    line = "with property cache:";
+    QHash<Window, MWindowPropertyCache*>::const_iterator pcit;
+    for (pcit = d->prop_caches.constBegin();
+         pcit != d->prop_caches.constEnd(); ++pcit)
+      line += QString().sprintf(" 0x%lx", pcit.key());
+    qDebug() << line.toLatin1().constData();
+
+    // Pending XConfigureRequestEvent:s.
+    if (!d->configure_reqs.isEmpty()) {
+        // Print each as "0x123456: 10x20+30+40 [XYWH] Above 0xABCDE"
+        QHash<Window, QList<XConfigureRequestEvent*> >::const_iterator it;
+        QList<XConfigureRequestEvent*>::const_iterator ot;
+
+        qDebug("configure_reqs:");
+        for (it = d->configure_reqs.constBegin();
+             it != d->configure_reqs.constEnd(); ++it) {
+            for (ot = it->constBegin(); ot != it->constEnd(); ++ot) {
+                const XConfigureRequestEvent *ev = *ot;
+
+                // The requested geometry
+                line = QString().sprintf("  0x%lx: %dx%d%+d%+d", it.key(),
+                                         ev->width, ev->height,
+                                         ev->x, ev->y);
+
+                // What is to be changed
+                if (ev->value_mask & (CWX|CWY|CWWidth|CWHeight)) {
+                    line += " [";
+                    if (ev->value_mask & CWX)
+                        line += 'X';
+                    if (ev->value_mask & CWY)
+                        line += 'Y';
+                    if (ev->value_mask & CWWidth)
+                        line += 'W';
+                    if (ev->value_mask & CWHeight)
+                        line += 'H';
+                    line += ']';
+                }
+
+                // Print the new stack mode and possibly the new sibling.
+                if (ev->value_mask & CWStackMode) {
+                    line += " stacking: ";
+                    if (ev->detail == Above)
+                      line += "above";
+                    else if (ev->detail == Below)
+                      line += "below";
+                    else if (ev->detail == TopIf)
+                      line += "topif";
+                    else if (ev->detail == BottomIf)
+                      line += "bottomif";
+                    else if (ev->detail == Opposite)
+                      line += "opposite";
+                    else
+                      line += QString().sprintf("%d", ev->detail);
+
+                    if (ev->value_mask & CWSibling)
+                      line += QString().sprintf(" 0x%lx", ev->above);
+                }
+            }
+        }
+    } else
+        qDebug("configure_reqs: <None>");
+
+    // Dump the scene items from top to bottom.
+    qDebug("scene:");
+    foreach (const QGraphicsItem *gi, d->watch->items()) {
+        if (!gi) {
+            qDebug("  NULL (WTF?)");
+            continue;
+        }
+
+        const QRectF &r = gi->sceneBoundingRect();
+        const MCompositeWindow *cw = dynamic_cast<const MCompositeWindow *>(gi);
+        qDebug("  %p: %dx%d%+d%+d %s", cw ? (void *)cw : (void *)gi,
+                  (int)r.width(), (int)r.height(), (int)r.x(), (int)r.y(),
+                  gi->isVisible() ? "visible" : "hidden");
+    }
+
+    // Show the current state of extensions.
+    // @m_extenions is a QMultiHash of X events an extension reacts to
+    // pointing to the object.  Invert the hash so we can iterate over
+    // each extension once.
+    qDebug("plugins:");
+    for (QHash<int, MCompositeManagerExtension*>::const_iterator exit = d->m_extensions.constBegin(); exit != d->m_extensions.constEnd(); ++exit)
+        extensions[*exit].append(exit.key());
+    for (QHash<const MCompositeManagerExtension*, QList<int> >::const_iterator exit = extensions.constBegin(); exit != extensions.constEnd(); ++exit) {
+        int event;
+        bool first;
+        QString events;
+
+        // Print the extension's class name followed by its X events.
+        first = true;
+        foreach (event, *exit) {
+            if (first)
+                first = false;
+            else
+                events += ", ";
+
+            // Translate common event numbers to strings.
+            switch (event) {
+            case ButtonPress:     events += "ButtonPress";    break;
+            case ButtonRelease:   events += "ButtonRelease";  break;
+            case MotionNotify:    events += "Motion";         break;
+            case UnmapNotify:     events += "Unmap";          break;
+            case MapNotify:       events += "Map";            break;
+            case ConfigureNotify: events += "Configure";      break;
+            case PropertyNotify:  events += "Property";       break;
+            default:
+                events += QString().sprintf("%u", event);
+                break;
+            }
+        }
+        qDebug("-- %s for event(s) %s:",
+               exit.key()->metaObject()->className(),
+               events.toLatin1().constData());
+        exit.key()->dumpState();
+    }
+}
+
+// Called when the remote control pipe has got input.
+void MCompositeManager::remoteControl(int cmdfd)
+{
+    int lcmd;
+    char cmd[128];
+
+    if ((lcmd = ::read(cmdfd, cmd, sizeof(cmd)-1)) < 0)
+        return;
+    if (lcmd > 0 && cmd[lcmd-1] == '\n')
+        lcmd--;
+    cmd[lcmd] = '\0';
+
+    if (!strcmp(cmd, "state")) {
+        dumpState();
+    } else if (!strncmp(cmd, "state ", strlen("state "))) {
+        const char *space = &cmd[strlen("state")];
+        dumpState(space+strspn(space, " "));
+    } else if (!strcmp(cmd, "save")
+               || !strncmp(cmd, "save ", strlen("save "))) {
+        // dumpState() into a file
+        static unsigned cnt = 0;
+        int pos;
+        time_t now;
+        QString fname;
+        const char *cfname;
+        FILE *out, *saved_stderr;
+        QRegExp rex("%(\\.\\d+)?[diuxX]");
+
+        // Get the output file name.
+        if ((cfname = strchr(cmd, ' ')) != NULL)
+            cfname += strspn(cfname, " ");
+        fname = cfname && *cfname ? cfname : "mc.log.%.2u";
+
+        // Substitute @res with @cnt if necessary.
+        if ((pos = rex.indexIn(fname)) >= 0)
+            fname.replace(pos, rex.cap(0).length(),
+                          QString().sprintf(rex.cap(0).toLatin1().constData(),
+                                            cnt++));
+
+        // Open @out.
+        cfname = fname.toLatin1().constData();
+        if (!(out = fopen(cfname, "w"))) {
+            qDebug("couldn't open %s", cfname);
+            return;
+        }
+
+        // Temporarily replace @stderr, so qDebug() will output to @out.
+        saved_stderr = stderr;
+        stderr = out;
+        time(&now);
+        dumpState(ctime(&now));
+        stderr = saved_stderr;
+
+        fclose(out);
+        qDebug("state dumped into %s", fname.toLatin1().constData());
+    } else if (!strcmp(cmd, "restart")) {
+        QString me = qApp->applicationFilePath();
+        QStringList args = qApp->arguments();
+        const char **argv;
+        unsigned i;
+
+        delete d;
+        XFlush(QX11Info::display());
+
+        // Convert the QStringList of args into a char *[].
+        i = 0;
+        argv = new const char *[args.count()+1];
+        foreach (const QString &arg, args)
+            argv[i] = arg.toLatin1().constData();
+        argv[i] = NULL;
+
+        // Restart ourselves.
+        qDebug("Die, you son of a bitch!");
+        execv(me.toLatin1().constData(), (char **)argv);
+        qDebug("Gothca!");
+    } else if (!strcmp(cmd, "exit") || !strcmp(cmd, "quit")) {
+        // exit() deadlocks, go the fast route
+        delete d;
+        XFlush(QX11Info::display());
+        _exit(0);
+    } else if (!strcmp(cmd, "help")) {
+        qDebug("Commands i understand:");
+        qDebug("  state [<tag>]   dump MCompositeManager, MCompositeWindow:s ");
+        qDebug("                  and QGraphicsScene state information");
+        qDebug("  save [<fname>]  dump it into <fname>");
+        qDebug("  exit, quit      geez");
+        qDebug("  restart         re-execute mcompositor");
+    } else
+        qDebug("%s: unknown command", cmd);
+}
+
+void MCompositeManager::xtrace(const char *fun, const char *msg, int lmsg)
+{
+    MCompositeManager *p = static_cast<MCompositeManager *>(qApp);
+    char str[160];
+
+    // Normalize @fun and @msg so that @msg != NULL in the end,
+    // and turn synopsis [2] into MCompositor::xtrace(NULL, msg).
+    if (!msg) {
+        if (fun) {
+            msg = fun;
+            fun = NULL;
+        } else {
+            msg = "HERE";
+            lmsg = strlen("HERE");
+        }
+    }
+
+    // Fail if we don't have an X connection yet.
+    if (!p || !p->d || !p->d->xcb_conn) {
+        qWarning("cannot xtrace yet from %s", fun ? fun : msg);
+        return;
+    }
+
+    // Format @str to include both @fun and @msg if @fun was specified,
+    // and count the length of @str.
+    if (fun != NULL) {
+        lmsg = snprintf(str, sizeof(str), "%s from %s", msg, fun);
+        msg = str;
+    } else if (lmsg < 0)
+        lmsg = strlen(msg);
+
+    // Make @str visible in xtrace by sending it along with an innocent
+    // X request.  Unfortunately this makes this function a synchronisation
+    // point (it has to wait for the reply).  Use xcb rather than libx11
+    // because the latter maintains a hashtable of known Atom:s.
+    xcb_intern_atom_reply(p->d->xcb_conn,
+                          xcb_intern_atom(p->d->xcb_conn, False, lmsg, msg),
+                          NULL);
+}
+
+void MCompositeManager::xtracef(const char *fun, const char *fmt, ...)
+{
+    va_list printf_args;
+    char msg[160];
+    int lmsg;
+
+    va_start(printf_args, fmt);
+    lmsg = vsnprintf(msg, sizeof(msg), fmt, printf_args);
+    va_end(printf_args);
+    xtrace(fun, msg, lmsg);
+}
+#endif // WINDOW_DEBUG
+
 MCompositeManager::MCompositeManager(int &argc, char **argv)
     : QApplication(argc, argv)
 {
-    if (QX11Info::isCompositingManagerRunning()) {
-        qCritical("Compositing manager already running.");
-        ::exit(0);
-    }
+    signal(SIGUSR1, sigusr1_handler);
 
     d = new MCompositeManagerPrivate(this);
     MRmiServer *s = new MRmiServer(".mcompositor", this);
     s->exportObject(this);
+
+#ifdef WINDOW_DEBUG
+    // Open the remote control interface.
+    mknod("/tmp/mrc", S_IFIFO | 0666, 0);
+    connect(new QSocketNotifier(open("/tmp/mrc", O_RDWR), QSocketNotifier::Read),
+            SIGNAL(activated(int)), SLOT(remoteControl(int)));
+#endif
 }
 
 MCompositeManager::~MCompositeManager()
@@ -3158,21 +4055,41 @@
     d = 0;
 }
 
+const QHash<Window, MWindowPropertyCache*>& MCompositeManager::propCaches() const
+{
+    return d->prop_caches;
+}
+
 void MCompositeManager::setGLWidget(QGLWidget *glw)
 {
     d->glwidget = glw;
 }
 
+QGLWidget *MCompositeManager::glWidget() const
+{
+    return d->glwidget;
+}
+
 QGraphicsScene *MCompositeManager::scene()
 {
     return d->scene();
 }
 
 void MCompositeManager::prepareEvents()
-{
+{    
+    if (QX11Info::isCompositingManagerRunning()) {
+        qCritical("Compositing manager already running.");
+        ::exit(0);
+    }
+    
     d->prepare();
 }
 
+void MCompositeManager::loadPlugins()
+{
+    d->loadPlugins();
+}
+
 bool MCompositeManager::x11EventFilter(XEvent *event)
 {
     return d->x11EventFilter(event);
@@ -3193,9 +4110,9 @@
     return d->isRedirected(w);
 }
 
-void MCompositeManager::enableCompositing()
+void MCompositeManager::enableCompositing(bool forced)
 {
-    d->enableCompositing();
+    d->enableCompositing(forced);
 }
 
 void MCompositeManager::disableCompositing()
@@ -3218,4 +4135,23 @@
     return d->compositing;
 }
 
-#include "mcompositemanager.moc"
+void MCompositeManager::debug(const QString& d)
+{
+    const char* msg = d.toAscii();
+    _log("%s\n", msg);
+}
+
+bool MCompositeManager::displayOff()
+{
+    return d->device_state->displayOff();
+}
+
+bool MCompositeManager::possiblyUnredirectTopmostWindow()
+{
+    return d->possiblyUnredirectTopmostWindow();
+}
+
+void MCompositeManager::exposeSwitcher()
+{
+    d->exposeSwitcher();
+}
--- src/mcompositemanager.h
+++ src/mcompositemanager.h
@@ -22,6 +22,7 @@
 
 #include <QApplication>
 #include <QGLWidget>
+#include "mwindowpropertycache.h"
 
 class QGraphicsScene;
 class MCompositeManagerPrivate;
@@ -68,6 +69,9 @@
      */
     void setGLWidget(QGLWidget *glw);
 
+    /*! QGLWidget accessor for static initialisations. */
+    QGLWidget *glWidget() const;
+
     /*!
      * Reimplemented from QApplication::x11EventFilter() to catch X11 events
      */
@@ -94,6 +98,8 @@
      */
     void redirectWindows();
 
+    void loadPlugins();
+
     /*!
      * Returns whether a Window is redirected or not
      *
@@ -106,9 +112,51 @@
      * or not
      */
     bool isCompositing();
+
+    /*!
+     * Try to direct-render the topmost window
+     */
+    bool possiblyUnredirectTopmostWindow();
     
+    /*!
+     * Returns if the display is off
+     */
+    bool displayOff();
+
+    void debug(const QString& d);
+    const QHash<Window, MWindowPropertyCache*>& propCaches() const;
+
+    enum StackPosition {
+        STACK_BOTTOM = 0,
+        STACK_TOP
+    };
+    void positionWindow(Window w, StackPosition pos);
+    void setWindowState(Window, int);
+    const QList<Window> &stackingList() const;
+
+#ifdef WINDOW_DEBUG
+    // Dump the current state of MCompositeManager and MCompositeWindow:s
+    // to qDebug().  Only available if compiled with TESTABILITY=on
+    // (-DWINDOW_DEBUG).
+    void dumpState(const char *heading = 0);
+
+    // "Print" @msg in xtrace, to show you where your program's control was
+    // between the various X requests, responses and events.
+    // Synopsis:
+    // [1] MCompositeManager::xtrace();
+    // [2] MCompositeManager::xtrace("HEI");
+    // [3] MCompositeManager::xtrace(__PRETTY_FUNCTION__, "HEI");
+    //
+    // xtracef() is the same, except that it sends a formatted message.
+    // You can leave @fun NULL if you want.
+    static void xtrace (const char *fun = NULL, const char *msg = NULL,
+                        int lmsg = -1);
+    static void xtracef(const char *fun, const char *fmt, ...)
+        __attribute__((format(printf, 2, 3)));
+#endif
+
 public slots:
-    void enableCompositing();
+    void enableCompositing(bool forced = false);
     void disableCompositing();
 
     /*! Invoked remotely by MRmiClient to show a launch indicator
@@ -118,6 +166,20 @@
      */
     void showLaunchIndicator(int timeout);
     void hideLaunchIndicator();
+
+    /*!
+     * Invoke to show the desktop window, possibly with switcher contents
+     */
+    void exposeSwitcher();
+
+    /*!
+     * Area the decorator occupies.
+     */
+    const QRect &decoratorRect() const;
+
+#ifdef WINDOW_DEBUG
+    void remoteControl(int fd);
+#endif
      
 signals:
     void decoratorRectChanged(const QRect& rect);
@@ -127,6 +189,9 @@
 
     friend class MCompositeWindow;
     friend class MCompWindowAnimator;
+    friend class MCompositeManagerExtension;
+    friend class MTexturePixmapPrivate;
+    friend class MWindowPropertyCache;
 };
 
 #endif
--- src/mcompositemanager_p.h
+++ src/mcompositemanager_p.h
@@ -39,6 +39,7 @@
 class MCompositeWindow;
 class MDeviceState;
 class MWindowPropertyCache;
+class MCompositeManagerExtension;
 
 enum {
     INPUT_LAYER = 0,
@@ -57,10 +58,6 @@
 {
     Q_OBJECT
 public:
-    enum StackPosition {
-        STACK_BOTTOM = 0,
-        STACK_TOP
-    };
     enum ForcingLevel {
         NO_FORCED = 0,
         FORCED
@@ -74,12 +71,14 @@
     QGraphicsScene *scene();
 
     void prepare();
+    void loadPlugins();
     void activateWindow(Window w, Time timestamp,
 		        bool disableCompositing = true);
     void updateWinList();
     void setWindowState(Window , int);
     void setWindowDebugProperties(Window w);
-    void positionWindow(Window w, StackPosition pos);
+    void iconifyApps();
+    void positionWindow(Window w, bool on_top);
     void addItem(MCompositeWindow *item);
     void damageEvent(XDamageNotifyEvent *);
     void destroyEvent(XDestroyWindowEvent *);
@@ -93,10 +92,11 @@
     void clientMessageEvent(XClientMessageEvent *);
     void keyEvent(XKeyEvent*);
     void buttonEvent(XButtonEvent*);
+    void installX11EventFilter(long xevent, MCompositeManagerExtension* extension);
     
     void redirectWindows();
-    void mapOverlayWindow();
-    void enableRedirection();
+    void showOverlayWindow(bool show);
+    void enableRedirection(bool emit_signal);
     void setExposeDesktop(bool exposed);
     void checkStacking(bool force_visibility_check,
                        Time timestamp = CurrentTime);
@@ -104,26 +104,31 @@
     void configureWindow(MCompositeWindow *cw, XConfigureRequestEvent *e);
 
     Window getTopmostApp(int *index_in_stacking_list = 0,
-                         Window ignore_window = 0);
+                         Window ignore_window = 0,
+                         bool skip_always_mapped = false);
     Window getLastVisibleParent(MWindowPropertyCache *pc);
-    void setupButtonWindows(MCompositeWindow *topmost);
 
     bool possiblyUnredirectTopmostWindow();
+    bool haveMappedWindow() const;
     bool isRedirected(Window window);
     bool x11EventFilter(XEvent *event);
-    bool removeWindow(Window w);
+    bool processX11EventFilters(XEvent *event, bool after);
+    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 setCurrentApp(Window w, bool stacking_order_changed);
+    void raiseTransientsOf(MWindowPropertyCache *pc, int last_i,
+                           bool recursion = false);
 
     MCompositeScene *watch;
     Window localwin, localwin_parent;
     Window xoverlay;
     Window prev_focus;
     Window close_button_win, home_button_win, buttoned_win;
+    Window current_app;
     QRect home_button_geom, close_button_geom;
 
     static Window stack[TOTAL_LAYERS];
@@ -144,6 +149,7 @@
     QHash<Window, FrameData> framed_windows;
     QHash<Window, QList<XConfigureRequestEvent*> > configure_reqs;
     QHash<Window, MWindowPropertyCache*> prop_caches;
+    QMultiHash<int, MCompositeManagerExtension* > m_extensions;
     QRegion dock_region;
 
     int damage_event;
@@ -151,25 +157,29 @@
 
     bool compositing;
     bool overlay_mapped;
+    bool changed_properties;
     MDeviceState *device_state;
 
+    // Indicates whether MCompositeManager::prepare() has finished.
+    // Used by the destructor.
+    bool prepared;
+
     xcb_connection_t *xcb_conn;
 
     // mechanism for lazy stacking
     QTimer stacking_timer;
     bool stacking_timeout_check_visibility;
-    void dirtyStacking(bool force_visibility_check);
+    Time stacking_timeout_timestamp;
+    void dirtyStacking(bool force_visibility_check, Time t = CurrentTime);
     void pingTopmost();
 
 signals:
-    void inputEnabled();
     void compositingEnabled();
+    void currentAppChanged(Window w);
 
 public slots:
 
     void gotHungWindow(MCompositeWindow *window);
-    void enableInput();
-    void disableInput();
     void enableCompositing(bool forced = false);
     void disableCompositing(ForcingLevel forced = NO_FORCED);
     void showLaunchIndicator(int timeout);
@@ -181,12 +191,12 @@
     
     void onDesktopActivated(MCompositeWindow*);
     void exposeDesktop();
-    void enablePaintedCompositing();
     void exposeSwitcher();
     
     void displayOff(bool display_off);
     void callOngoing(bool call_ongoing);
     void stackingTimeout();
+    void setupButtonWindows(Window topmost);
 };
 
 #endif
--- src/mcompositemanagerextension.cpp
+++ src/mcompositemanagerextension.cpp
+/***************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (directui at nokia.com)
+**
+** This file is part of mcompositor.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at directui at nokia.com.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation
+** and appearing in the file LICENSE.LGPL included in the packaging
+** of this file.
+**
+****************************************************************************/
+
+#include "mcompositemanager.h"
+#include "mcompositemanager_p.h"
+#include "mcompositemanagerextension.h"
+
+MCompositeManagerExtension::MCompositeManagerExtension(QObject *parent)
+    :QObject(parent)
+{
+    MCompositeManager *p = (MCompositeManager *) qApp;
+    connect(p->d, SIGNAL(currentAppChanged(Window)), SLOT(q_currentAppChanged(Window)) );
+}
+
+MCompositeManagerExtension::~MCompositeManagerExtension()
+{
+}
+
+void MCompositeManagerExtension::q_currentAppChanged(Window window)
+{
+    emit currentAppChanged(window);
+}
+
+void MCompositeManagerExtension::listenXEventType(long XEventType)
+{
+    MCompositeManager *p = (MCompositeManager *) qApp;
+    p->d->installX11EventFilter(XEventType, this);
+}
+
+void MCompositeManagerExtension::dumpState() const
+{
+    /* NOP */
+}
+
+Qt::HANDLE MCompositeManagerExtension::desktopWindow()
+{    
+    MCompositeManager *p = (MCompositeManager *) qApp;
+    return p->d->stack[DESKTOP_LAYER];
+}
+
+Qt::HANDLE MCompositeManagerExtension::currentAppWindow()
+{
+    MCompositeManager *p = (MCompositeManager *) qApp;
+    return p->d->current_app;
+}
+
+bool MCompositeManagerExtension::windowIconified(MCompositeWindow* window, 
+                                                 bool deferred)
+{
+    Q_UNUSED(window)
+    Q_UNUSED(deferred)
+        
+    return false;
+}
+
+bool MCompositeManagerExtension::windowRestored(MCompositeWindow* window, 
+                                                bool deferred)
+{
+    Q_UNUSED(window)
+    Q_UNUSED(deferred)
+
+    return false;
+}
+
+bool MCompositeManagerExtension::windowShown(MCompositeWindow* window)
+{
+    Q_UNUSED(window)
+
+    return false;
+}
+
+bool MCompositeManagerExtension::windowClosed(MCompositeWindow* window)
+{
+    Q_UNUSED(window)
+
+    return false;
+}
--- src/mcompositemanagerextension.h
+++ src/mcompositemanagerextension.h
+/***************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (directui at nokia.com)
+**
+** This file is part of mcompositor.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at directui at nokia.com.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation
+** and appearing in the file LICENSE.LGPL included in the packaging
+** of this file.
+**
+****************************************************************************/
+
+#ifndef MCOMPOSITEMANAGEREXTENSION_H
+#define MCOMPOSITEMANAGEREXTENSION_H
+
+#include <QObject>
+#include <X11/Xlib.h>
+
+class MCompositeManagerPrivate;
+class MCompositeWindow;
+
+class MCompositeManagerExtension: public QObject
+{
+    Q_OBJECT
+
+ public:
+    MCompositeManagerExtension(QObject *parent = 0);
+    ~MCompositeManagerExtension();
+
+    void testFn();
+    
+    /*
+     * Returns the desktop window
+     */
+    Qt::HANDLE desktopWindow();
+
+    /*
+     * Returns the current application window
+     */
+    Qt::HANDLE currentAppWindow();
+    
+    /*! 
+     * Informs the composite manager that this extension is subscribed
+     * to an XEvent type and requests delivery of only the registered event to
+     * prevent it from being spammed by unwanted events. 
+     * Note: Do not combine the types in the same way as the
+     * event mask in XSelectInput. XEvent type is not a mask enum type and will 
+     * not work. Call this function once for each XEvent type you need to 
+     * register with.
+     *
+     * \param XEventType Specifies the XEvent type that this extension is 
+     * interested in listening
+     */
+    void listenXEventType(long XEventType);
+
+    //! qDebug() any state information indented by three spaces you want
+    //! to be included in MCompositeManager::dumpState()'s output.
+    virtual void dumpState() const;
+
+ signals:    
+    void currentAppChanged(Qt::HANDLE window);
+    
+ protected:
+    /*!
+     * Special event handler to receive native X11 events passed in the event
+     * parameter. Return true to stop the composite manager from handling
+     * the event, otherwise return false to try forwarding the native event to 
+     * the composite manager. 
+     * 
+     * If there are other extensions that are subscribed to the same event and 
+     * this function returns true, the event will still be blocked from 
+     * propagating to the composite manager even if this function 
+     * returns false. Be careful when returning true when there are other 
+     * extensions around and only use as a last resort to reimplement core 
+     * functionality.
+     */
+    virtual bool x11Event(XEvent *event) = 0;
+
+    /*!
+     * Called for each event after MCompositeManager's event handling.
+     */
+    virtual void afterX11Event(XEvent *event) = 0;
+
+    virtual bool windowIconified(MCompositeWindow* window, bool deferred);
+    virtual bool windowRestored(MCompositeWindow* window, bool deferred);
+    virtual bool windowShown(MCompositeWindow* window);
+    virtual bool windowClosed(MCompositeWindow* window);
+
+ private slots:
+    void q_currentAppChanged(Window window);
+
+ private:
+    friend class MCompositeManagerPrivate;
+    friend class MCompositeWindow;
+};
+
+#endif
--- src/mcompositescene.cpp
+++ src/mcompositescene.cpp
@@ -27,6 +27,7 @@
 
 #include "mcompositewindow.h"
 #include "mcompositescene.h"
+#include "mcompositewindowgroup.h"
 
 #include <X11/extensions/Xfixes.h>
 #ifdef HAVE_SHAPECONST
@@ -67,67 +68,71 @@
     XSetWindowAttributes sattr;
     sattr.event_mask =  SubstructureRedirectMask | SubstructureNotifyMask | StructureNotifyMask | PropertyChangeMask;
 
-    //XCompositeRedirectSubwindows (dpy, root, CompositeRedirectAutomatic);
+    // All newly mapped windows should be redirected to avoid double Expose
+    XCompositeRedirectSubwindows(dpy, root, CompositeRedirectManual);
 
     XChangeWindowAttributes(dpy, root, CWEventMask, &sattr);
-    XSelectInput(dpy, root, SubstructureNotifyMask | SubstructureRedirectMask | StructureNotifyMask | PropertyChangeMask);
+    XSelectInput(dpy, root, SubstructureNotifyMask | SubstructureRedirectMask
+                            | StructureNotifyMask | PropertyChangeMask
+                            | FocusChangeMask);
     XSetErrorHandler(error_handler);
 }
 
-
-void MCompositeScene::setupOverlay(Window window, const QRect &geom,
-                                     bool restoreInput)
-{
-    Display *dpy = QX11Info::display();
-    XRectangle rect;
-
-    rect.x      = geom.x();
-    rect.y      = geom.y();
-    rect.width  = geom.width();
-    rect.height = geom.height();
-    XserverRegion region = XFixesCreateRegion(dpy, &rect, 1);
-
-    XFixesSetWindowShapeRegion(dpy, window, ShapeBounding, 0, 0, 0);
-    if (!restoreInput)
-        XFixesSetWindowShapeRegion(dpy, window, ShapeInput, 0, 0, region);
-    else
-        XFixesSetWindowShapeRegion(dpy, window, ShapeInput, 0, 0, 0);
-
-    XFixesDestroyRegion(dpy, region);
-}
-
 void MCompositeScene::drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[], QWidget *widget)
 {
     QRegion visible(sceneRect().toRect());
     QVector<int> to_paint(10);
     int size = 0;
+    bool desktop_painted = false;
     // visibility is determined from top to bottom
     for (int i = numItems - 1; i >= 0; --i) {
         MCompositeWindow *cw = (MCompositeWindow *) items[i];
-        
-        if (cw->isDirectRendered() || !cw->isVisible()
-            || !cw->propertyCache()->isMapped()
-            || cw->propertyCache()->isInputOnly())
-            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()));
+
+#ifdef GLES2_VERSION
+        static int item_type = MCompositeWindowGroup::Type;
+#else
+        static int item_type = QGraphicsItem::Type + 2;
+#endif
+        if (cw->type() != item_type) {
+            if (!cw->propertyCache())  // this window is dead
+                continue;
+            if (cw->hasTransitioningWindow() && cw->propertyCache()->isDecorator())
+                // if we have a transition animation, don't draw the decorator
+                // lest we can have it drawn with the transition (especially
+                // when desktop window is not yet shown, NB#192454)
+                continue;
+            if (cw->isDirectRendered() || !cw->isVisible()
+                || !(cw->propertyCache()->isMapped() || cw->isWindowTransitioning())
+                || cw->propertyCache()->isInputOnly())
+                    continue;            
+            if (visible.isEmpty())
+                // nothing below is visible anymore
+                break;
+        }
+
+        // Ensure that intersects() still work, otherwise, painting a window
+        // is skipped when another window above it is scaled or moved to an 
+        // area that exposed the lower window and causes an ugly flicker.
+        // r reflects the applied transformation and position of the window
+        QRegion r = cw->sceneTransform().map(cw->propertyCache()->shapeRegion());
         
         // transitioning window can be smaller than shapeRegion(), so paint
         // all transitioning windows
-        if (cw->isWindowTransitioning() || visible.intersects(r)) {
+        if (cw->isWindowTransitioning() || visible.intersects(r)
+            || cw->type() == MCompositeWindowGroup::Type) {
             if (size >= 9)
                 to_paint.resize(to_paint.size()+1);
             to_paint[size++] = i;
+            if (cw->propertyCache()->windowTypeAtom()
+                                         == ATOM(_NET_WM_WINDOW_TYPE_DESKTOP))
+                desktop_painted = true;
         }
 
         // subtract opaque regions
         if (!cw->isWindowTransitioning()
-            && !cw->propertyCache()->hasAlpha() && cw->opacity() == 1.0)
+            && !cw->propertyCache()->hasAlpha() 
+            && cw->opacity() == 1.0
+            && !cw->group()) // window is not renderered off-screen)
             visible -= r;
     }
     if (size > 0) {
@@ -135,6 +140,20 @@
         for (int i = size - 1; i >= 0; --i) {
             int item_i = to_paint[i];
             painter->save();
+            if (!desktop_painted) {
+                // clear rubbish from the root window during startup when
+                // desktop window does not exist and we show zoom animations
+                glClearColor(0, 0, 0, 0);
+                glClear(GL_COLOR_BUFFER_BIT);
+                desktop_painted = true;
+                if (((MCompositeWindow*)items[item_i])->
+                                             propertyCache()->isDecorator()) {
+                    // don't paint decorator on top of plain black background
+                    // (see NB#182860, NB#192454)
+                    painter->restore();
+                    continue;
+                }
+            }
             // TODO: paint only the intersected region (glScissor?)
             painter->setMatrix(items[item_i]->sceneMatrix(), true);
             items[item_i]->paint(painter, &options[item_i], widget);
--- src/mcompositescene.h
+++ src/mcompositescene.h
@@ -52,16 +52,6 @@
      */
     void prepareRoot();
 
-    /*!
-     * Creates an event "hole" within the Window win so that events generated
-     * by win can pass through down to the Window below it.
-     *
-     * \param win Window id of the Window you intend to generate a pass-through
-     * area
-     * \param geom Geometry of the area within win used as a pass-through area
-     */
-    void setupOverlay(Window win, const QRect &geom,
-                      bool restoreInput = false);
 protected:
     void drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[], QWidget *widget);
 
--- src/mcompositewindow.cpp
+++ src/mcompositewindow.cpp
@@ -23,6 +23,8 @@
 #include "mcompositemanager_p.h"
 #include "mtexturepixmapitem.h"
 #include "mdecoratorframe.h"
+#include "mcompositemanagerextension.h"
+#include "mcompositewindowgroup.h"
 
 #include <QX11Info>
 #include <QGraphicsScene>
@@ -42,6 +44,8 @@
       scaleto(1),
       scaled(false),
       zval(1),
+      sent_ping_timestamp(0),
+      received_ping_timestamp(0),
       blur(false),
       iconified(false),
       iconified_final(false),
@@ -49,20 +53,18 @@
       destroyed(false),
       window_status(Normal),
       need_decor(false),
-      window_obscured(true), // true to synthesize initial visibility event
+      window_obscured(-1),
       is_transitioning(false),
       pinging_enabled(false),
       dimmed_effect(false),
+      waiting_for_damage(0),
       win_id(window)
 {
     thumb_mode = false;
-    if (!mpc->is_valid) {
+    if (!mpc || (mpc && !mpc->is_valid)) {
         is_valid = false;
-        pc = 0;
         anim = 0;
         newly_mapped = false;
-        sent_ping_timestamp = 0;
-        received_ping_timestamp = 0;
         t_ping = 0;
         window_visible = false;
         return;
@@ -70,11 +72,16 @@
         is_valid = true;
     anim = new MCompWindowAnimator(this);
     connect(anim, SIGNAL(transitionDone()),  SLOT(finalizeState()));
-    connect(anim, SIGNAL(transitionStart()), SLOT(windowTransitioning()));
+    connect(anim, SIGNAL(transitionStart()), SLOT(beginAnimation()));
+    connect(mpc, SIGNAL(iconGeometryUpdated()), SLOT(updateIconGeometry()));
     setAcceptHoverEvents(true);
 
     t_ping = new QTimer(this);
     connect(t_ping, SIGNAL(timeout()), SLOT(pingTimeout()));
+
+    damage_timer = new QTimer(this);
+    damage_timer->setSingleShot(true);
+    connect(damage_timer, SIGNAL(timeout()), SLOT(damageTimeout()));
     
     MCompAtoms* atoms = MCompAtoms::instance(); 
     if (pc->windowType() == MCompAtoms::NORMAL)
@@ -91,12 +98,13 @@
     // We initially prevent item visibility from compositor itself
     // or it's corresponding thumbnail rendered by the switcher
     bool is_app = isAppWindow();
+    newly_mapped = is_app;
     if (!pc->isInputOnly()) {
         // never paint InputOnly windows
         window_visible = !is_app;
-        setVisible(window_visible);
+        setVisible(window_visible); // newly_mapped used here
     }
-    newly_mapped = is_app;
+    origPosition = QPointF(pc->realGeometry().x(), pc->realGeometry().y());
 
     if (fadeRect.isEmpty()) {
         QRectF d = QApplication::desktop()->availableGeometry();
@@ -109,18 +117,14 @@
 MCompositeWindow::~MCompositeWindow()
 {
     MCompositeManager *p = (MCompositeManager *) qApp;
-    if (!p->d->removeWindow(window()))
-        qWarning("destroyEvent(): Error removing window");
+    p->d->removeWindow(window());
 
-    if (t_ping) {
+    if (window() && t_ping) {
         stopPing();
         t_ping = 0;
     }
-    if (is_transitioning) {
-        // we got destroyed during animation
-        --window_transitioning;
-        is_transitioning = false;
-    }
+    endAnimation();
+    
     anim = 0;
     
     if (pc) {
@@ -135,12 +139,6 @@
     update();
 }
 
-void MCompositeWindow::setUnBlurred()
-{
-    blur = false;
-    update();
-}
-
 bool MCompositeWindow::blurred()
 {
     return blur;
@@ -173,29 +171,54 @@
  */
 void MCompositeWindow::iconify(const QRectF &icongeometry, bool defer)
 {
+    if (iconify_state == ManualIconifyState) {
+        setIconified(true);
+        window_status = Normal;
+        return;
+    }
+
     if (window_status != MCompositeWindow::Closing)
         window_status = MCompositeWindow::Minimizing;
-
-    if (icongeometry.isEmpty())
-        this->iconGeometry = fadeRect;
-    else
-        this->iconGeometry = icongeometry;
+    
+    // Custom iconify handler
+    MCompositeManager *p = (MCompositeManager *) qApp;
+    QList<MCompositeManagerExtension*> evlist = p->d->m_extensions.values(MapNotify);
+    for (int i = 0; i < evlist.size(); ++i) { 
+        if (evlist[i]->windowIconified(this, defer)) {
+            iconified = true;
+            window_status = Normal;
+            return;
+        }
+    }
+    
+    this->iconGeometry = icongeometry;
     if (!iconified)
         origPosition = pos();
 
     // horizontal and vert. scaling factors
     qreal sx = iconGeometry.width() / boundingRect().width();
     qreal sy = iconGeometry.height() / boundingRect().height();
-
+    
     anim->deferAnimation(defer);
     anim->translateScale(qreal(1.0), qreal(1.0), sx, sy,
                          iconGeometry.topLeft());
     iconified = true;
     // do this to avoid stacking code disturbing Z values
-    if (!is_transitioning) {
-        ++window_transitioning;
-        is_transitioning = true;
-    }
+    beginAnimation();
+}
+
+void MCompositeWindow::setUntransformed()
+{
+    endAnimation();
+    
+    if (anim)
+        anim->stopAnimation(); // stop and restore the matrix
+    newly_mapped = false;
+    setVisible(true);
+    setOpacity(1.0);
+    setScale(1.0);
+    setScaled(false);
+    iconified = false;
 }
 
 void MCompositeWindow::setIconified(bool iconified)
@@ -213,11 +236,19 @@
     return iconify_state;
 }
 
+void MCompositeWindow::setIconifyState(MCompositeWindow::IconifyState state)
+{
+    iconify_state = state;
+}
+
 void MCompositeWindow::setWindowObscured(bool obscured, bool no_notify)
 {
-    if (obscured == window_obscured)
+    MCompositeManager *p = (MCompositeManager *) qApp;
+    short new_value = obscured ? 1 : 0;
+    if ((new_value == window_obscured && !newly_mapped)
+        || (!obscured && p->displayOff()))
         return;
-    window_obscured = obscured;
+    window_obscured = new_value;
 
     if (!no_notify) {
         XVisibilityEvent c;
@@ -231,8 +262,19 @@
     }
 }
 
+/*
+ * We ensure that ensure there are ALWAYS updated thumbnails in the 
+ * switcher by letting switcher know in advance of the presence of this window.
+ * Delay the minimize animation until we receive an iconGeometry update from
+ * the switcher
+ */
 void MCompositeWindow::startTransition()
 {
+    if (iconified) {
+        if (iconGeometry.isNull())
+            return;
+        setWindowObscured(true);
+    }
     if (anim->pendingAnimation()) {
         MCompositeWindow::setVisible(true);
         anim->startAnimation();
@@ -240,9 +282,38 @@
     }
 }
 
+void MCompositeWindow::updateIconGeometry()
+{
+    if (!pc)
+        return;
+    
+    iconGeometry = pc->iconGeometry();
+    if (iconGeometry.isNull())
+        return;
+    
+    // trigger transition the second time around and update animation values
+    if (iconified) {
+        qreal sx = iconGeometry.width() / boundingRect().width();
+        qreal sy = iconGeometry.height() / boundingRect().height();
+        anim->translateScale(qreal(1.0), qreal(1.0), sx, sy,
+                             iconGeometry.topLeft());
+        startTransition();
+    }
+}
+
 // TODO: have an option of disabling the animation
 void MCompositeWindow::restore(const QRectF &icongeometry, bool defer)
 {
+     // Custom restore handler
+    MCompositeManager *p = (MCompositeManager *) qApp;
+    QList<MCompositeManagerExtension*> evlist = p->d->m_extensions.values(MapNotify);
+    for (int i = 0; i < evlist.size(); ++i) { 
+        if (evlist[i]->windowRestored(this, defer)) {
+            iconified = false;
+            return;
+        }
+    }
+
     if (icongeometry.isEmpty())
         this->iconGeometry = fadeRect;
     else
@@ -258,59 +329,96 @@
     anim->translateScale(qreal(1.0), qreal(1.0), sx, sy, origPosition, true);
     iconified = false;
     // do this to avoid stacking code disturbing Z values
-    if (!is_transitioning) {
-        ++window_transitioning;
-        is_transitioning = true;
-    }
+    beginAnimation();
 }
 
-void MCompositeWindow::showWindow()
+bool MCompositeWindow::showWindow()
 {
     // defer putting this window in the _NET_CLIENT_LIST
     // only after animation is done to prevent the switcher from rendering it
-    if (!isAppWindow())
-        return;
+    if (!isAppWindow() || !pc || !pc->is_valid
+        // isAppWindow() returns true for system dialogs
+        || pc->windowTypeAtom() == ATOM(_NET_WM_WINDOW_TYPE_DIALOG))
+        return false;
     
     findBehindWindow();
-    if (!is_transitioning) {
-        ++window_transitioning;
-        is_transitioning = true;
-    }
-    if (newly_mapped) 
-        QTimer::singleShot(700, this, SLOT(q_fadeIn()));
-    else
+    beginAnimation();
+    if (newly_mapped) {
+        // NB#180628 - some stupid apps are listening for visibilitynotifies.
+        // Well, all of the toolkit anyways
+        setWindowObscured(false);
+        // waiting for two damage events seems to work for Meegotouch apps
+        // at least, for the rest, there is a timeout
+        waiting_for_damage = 2;
+        damage_timer->start(500);
+    } else
         q_fadeIn();
+    return true;
+}
+
+void MCompositeWindow::damageTimeout()
+{
+    damageReceived(true);
+}
+
+void MCompositeWindow::damageReceived(bool timeout)
+{
+    if (timeout || (waiting_for_damage > 0 && !--waiting_for_damage)) {
+        damage_timer->stop();
+        waiting_for_damage = 0;
+        q_fadeIn();
+    }
 }
 
 void MCompositeWindow::q_fadeIn()
 {   
-    if (is_transitioning) {
-        --window_transitioning;
-        is_transitioning = false;
-    }
+    endAnimation();
+    
     newly_mapped = false;
     setVisible(true);
     setOpacity(0.0);
     updateWindowPixmap();
     origPosition = pos();
+    newly_mapped = true;
+    
+    // Custom fade-in handler
+    MCompositeManager *p = (MCompositeManager *) qApp;
+    QList<MCompositeManagerExtension*> evlist = p->d->m_extensions.values(MapNotify);
+    for (int i = 0; i < evlist.size(); ++i) { 
+        if (evlist[i]->windowShown(this)) 
+            return;
+    }
+    
     setPos(fadeRect.topLeft());
     restore(fadeRect, false);
-    newly_mapped = true;
 }
 
-void MCompositeWindow::closeWindow()
+void MCompositeWindow::closeWindowRequest()
 {
-    if (!isAppWindow() || propertyCache()->windowState() == IconicState) {
-        setVisible(false);
-        emit windowClosed(this);
+    if (!pc || !pc->is_valid || (!isMapped() && !pc->beingMapped()))
         return;
-    }
-    if (window_status == MCompositeWindow::Hung) {
-        hide();
-        emit windowClosed(this);
+    if (!windowPixmap() && !pc->isInputOnly()) {
+        // get a Pixmap for the possible unmap animation
+        MCompositeManager *p = (MCompositeManager *) qApp;
+        if (!p->isCompositing())
+            p->d->enableCompositing(true);
+        updateWindowPixmap();
+    }
+    emit closeWindowRequest(this);
+}
+
+void MCompositeWindow::closeWindowAnimation()
+{
+    if (!pc || !pc->is_valid || window_status == Closing
+        || pc->isInputOnly() || pc->isOverrideRedirect()
+        || !windowPixmap() || !isAppWindow()
+        // isAppWindow() returns true for system dialogs
+        || pc->windowTypeAtom() == ATOM(_NET_WM_WINDOW_TYPE_DIALOG)
+        || propertyCache()->windowState() == IconicState
+        || window_status == MCompositeWindow::Hung) {
         return;
     }
-    window_status = MCompositeWindow::Closing;
+    window_status = Closing; // animating, do not disturb
     
     MCompositeManager *p = (MCompositeManager *) qApp;
     bool defer = false;
@@ -320,16 +428,27 @@
         defer = true;
     }
     
-    updateWindowPixmap();
     origPosition = pos();
+    
+    // Custom close window animation handler    
+    QList<MCompositeManagerExtension*> evlist = p->d->m_extensions.values(MapNotify);
+    for (int i = 0; i < evlist.size(); ++i) { 
+        if (evlist[i]->windowClosed(this)) {
+            window_status = Normal; // can't guarantee that Closing is cleared
+            return;
+        }
+    }
     iconify(fadeRect, defer);
 }
 
-void MCompositeWindow::deleteLater()
+bool MCompositeWindow::event(QEvent *e)
 {
-    destroyed = true;
-    if (!is_transitioning)
-        QObject::deleteLater();
+    if (e->type() == QEvent::DeferredDelete && is_transitioning) {
+        // Can't delete the object yet, try again in the next iteration.
+        deleteLater();
+        return true;
+    } else
+        return QObject::event(e);
 }
 
 void MCompositeWindow::prettyDestroy()
@@ -341,31 +460,30 @@
 
 void MCompositeWindow::finalizeState()
 {
-    if (is_transitioning) {
-        --window_transitioning;
-        is_transitioning = false;
-    }
-    if (pc->windowTypeAtom() == ATOM(_NET_WM_WINDOW_TYPE_DESKTOP))
+    endAnimation();
+
+    // as far as this window is concerned, it's OK to direct render
+    window_status = Normal;
+    if (pc && pc->windowTypeAtom() == ATOM(_NET_WM_WINDOW_TYPE_DESKTOP))
         emit desktopActivated(this);
 
     // iconification status
     if (iconified) {
+        iconified = false;
         iconified_final = true;
         hide();
         iconify_state = TransitionIconifyState;
         emit itemIconified(this);
-        if (isClosing()) {
-            emit windowClosed(this);
-            return;
-        }
     } else {
         iconify_state = NoIconifyState;
         iconified_final = false;
         show();
-        QTimer::singleShot(200, this, SLOT(q_itemRestored()));
+        // no delay: window does not need to be repainted when restoring
+        // from the switcher (even then the animation should take long enough
+        // to allow it)
+        q_itemRestored();
     }
-    window_status = Normal;
-
+    
     // item lifetime
     if (destroyed)
         deleteLater();
@@ -380,7 +498,7 @@
 {
     // when animating, Z-value is set again after finishing the animation
     // (setting it later in finalizeState() caused flickering)
-    if (!anim->isActive() && !anim->pendingAnimation())
+    if (anim && !anim->isActive() && !anim->pendingAnimation())
         setZValue(zvalue);
 }
 
@@ -400,51 +518,13 @@
     scaled = s;
 }
 
-void MCompositeWindow::hoverEnterEvent(QGraphicsSceneHoverEvent *e)
-{
-    if (thumb_mode) {
-        zval = zValue();
-        setZValue(scene()->items().count() + 1);
-        setZValue(100);
-        anim->translateScale(scalefrom, scalefrom, scaleto, scaleto, pos());
-
-    }
-    return QGraphicsItem::hoverEnterEvent(e);
-}
-
-void MCompositeWindow::hoverLeaveEvent(QGraphicsSceneHoverEvent   *e)
-{
-    if (thumb_mode) {
-        setZValue(zval);
-        anim->translateScale(scalefrom, scalefrom, scaleto, scaleto, pos(), true);
-    }
-    return QGraphicsItem::hoverLeaveEvent(e);
-}
-
-void MCompositeWindow::mouseReleaseEvent(QGraphicsSceneMouseEvent *m)
-{
-    anim->restore();
-    setThumbMode(false);
-    setScaled(false);
-    setZValue(100);
-
-    emit acceptingInput();
-    windowRaised();
-    QGraphicsItem::mouseReleaseEvent(m);
-}
-
-void MCompositeWindow::manipulationEnabled(bool isEnabled)
-{
-    setFlag(QGraphicsItem::ItemIsMovable, isEnabled);
-    setFlag(QGraphicsItem::ItemIsSelectable, isEnabled);
-}
-
 void MCompositeWindow::setVisible(bool visible)
 {
-    if (pc->isInputOnly() || (visible && newly_mapped && isAppWindow()) ||
-        (!visible && is_transitioning)) 
+    if ((pc && pc->isInputOnly())
+        || (visible && newly_mapped && isAppWindow()) 
+        || (!visible && is_transitioning)) 
         return;
-    
+
     // Set the iconification status as well
     iconified_final = !visible;
     if (visible != window_visible)
@@ -454,6 +534,10 @@
     QGraphicsItem::setVisible(visible);
     MCompositeManager *p = (MCompositeManager *) qApp;
     p->d->setWindowDebugProperties(window());
+
+    QGraphicsScene* sc = scene();    
+    if (sc && !visible && sc->items().count() == 1)
+        clearTexture();
 }
 
 void MCompositeWindow::startPing()
@@ -483,7 +567,7 @@
 {
     received_ping_timestamp = serverTimeStamp;
     
-    if (window_status != Minimizing || window_status != Closing)
+    if (window_status != Minimizing && window_status != Closing)
         window_status = Normal;
     if (blurred())
         setBlurred(false);
@@ -492,11 +576,10 @@
 void MCompositeWindow::pingTimeout()
 {
     if (pinging_enabled && received_ping_timestamp < sent_ping_timestamp
-        && window_status != Hung) {
+        && window_status != Hung
+        && window_status != Minimizing && window_status != Closing) {
         setBlurred(true);
-        
-        if (window_status != Minimizing || window_status != Closing)
-            window_status = Hung;
+        window_status = Hung;
         emit windowHung(this);
     }
     if (pinging_enabled)
@@ -544,25 +627,28 @@
     return p->d->windows.value(window, 0);
 }
 
-void MCompositeWindow::windowTransitioning()
+void MCompositeWindow::beginAnimation()
 {
+    if (!isMapped() && window_status != Closing)
+        return;
+
     if (!is_transitioning) {
-        ++window_transitioning;
+        ++window_transitioning;        
         is_transitioning = true;
     }
 }
 
-bool MCompositeWindow::hasTransitioningWindow()
-{
-    return window_transitioning > 0;
+void MCompositeWindow::endAnimation()
+{    
+    if (is_transitioning) {
+        --window_transitioning;
+        is_transitioning = false;
+    }
 }
 
-void MCompositeWindow::q_delayShow()
+bool MCompositeWindow::hasTransitioningWindow()
 {
-    MCompositeWindow::setVisible(true);
-    updateWindowPixmap();
-    MCompositeManager *p = (MCompositeManager *) qApp;
-    p->d->updateWinList();
+    return window_transitioning > 0;
 }
 
 QVariant MCompositeWindow::itemChange(GraphicsItemChange change, const QVariant &value)
@@ -574,8 +660,13 @@
         p->d->setWindowDebugProperties(window());
     }
     
+    /* disabled to avoid glSwapBuffers call without painting any item (Qt bug)
+     * see NB#189519
     if (zvalChanged || change == ItemVisibleHasChanged || change == ItemParentHasChanged)
+    {
         p->d->glwidget->update();
+    }
+    */
 
     return QGraphicsItem::itemChange(change, value);
 }
@@ -615,7 +706,7 @@
     if (!include_transients && p->d->getLastVisibleParent(pc))
         return false;
     
-    if (!pc->isOverrideRedirect() &&
+    if (pc && !pc->isOverrideRedirect() &&
             (pc->windowTypeAtom() == ATOM(_NET_WM_WINDOW_TYPE_NORMAL) ||
              pc->windowTypeAtom() == ATOM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE) ||
              /* non-modal, non-transient dialogs behave like applications */
@@ -640,7 +731,10 @@
 Window MCompositeWindow::lastVisibleParent() const
 {
     MCompositeManager *p = (MCompositeManager *) qApp;
-    return p->d->getLastVisibleParent(propertyCache());
+    if (pc && pc->is_valid)
+        return p->d->getLastVisibleParent(pc);
+    else
+        return None;
 }
 
 int MCompositeWindow::indexInStack() const
@@ -651,10 +745,21 @@
 
 void MCompositeWindow::setIsMapped(bool mapped) 
 { 
-    pc->setIsMapped(mapped); 
+    if (mapped)
+        window_status = Normal; // make sure Closing -> Normal when remapped
+    if (pc) pc->setIsMapped(mapped); 
 }
 
 bool MCompositeWindow::isMapped() const 
 {
-    return pc->isMapped();
+    return pc ? pc->isMapped() : false;
+}
+
+MCompositeWindowGroup* MCompositeWindow::group() const
+{
+#ifdef GLES2_VERSION
+    return renderer()->current_window_group;
+#else
+    return 0;
+#endif
 }
--- src/mcompositewindow.h
+++ src/mcompositewindow.h
@@ -24,10 +24,11 @@
 #include <QtOpenGL>
 #include <QPointer>
 #include <X11/Xutil.h>
-#include "mcompatoms_p.h"
 #include "mwindowpropertycache.h"
 
 class MCompWindowAnimator;
+class MTexturePixmapPrivate;
+class MCompositeWindowGroup;
 
 /*!
  * This is the base class for composited window items. It provided general
@@ -40,8 +41,9 @@
     Q_OBJECT
 #if QT_VERSION >= 0x040600
     Q_INTERFACES(QGraphicsItem)
+    Q_PROPERTY(QPointF pos READ pos WRITE setPos)
+    Q_PROPERTY(qreal scale READ scale WRITE setScale)
 #endif
-
 public:
     
     enum WindowStatus {
@@ -72,10 +74,8 @@
 
     Qt::HANDLE window() const { return win_id; }
 
-    /*!
-     * Overriden QObject::deleteLater()
-     */
-    void deleteLater();
+    // Reimplemented to defer deleteLater()s until transitions are over.
+    virtual bool event(QEvent *);
 
     /*!
      * Saves the global state of this item. Possibly transformations and
@@ -165,10 +165,26 @@
     void setIconified(bool iconified);
 
     /*!
+     * Set scale, opacity etc. to normal values.
+     */
+    void setUntransformed();
+
+    /*!
+     * True if this window is waiting for damage event before it can animate.
+     */
+    bool waitingForDamage() const { return waiting_for_damage > 0; }
+
+    /*!
      * Returns how this window was iconified.
      */
     IconifyState iconifyState() const;
 
+    
+    /*!
+     * Sets how this window was iconified.
+     */
+    void setIconifyState(IconifyState state);
+
     /*!
      * Returns true if this window needs a decoration
      */
@@ -196,7 +212,7 @@
      * Overrides QGraphicsItem::update() so we have complete control of item
      * updates.
      */
-    void update();
+    static void update();
 
     bool blurred();
 
@@ -217,22 +233,18 @@
 
     static MCompositeWindow *compositeWindow(Qt::HANDLE window);
 
-    virtual void windowRaised() = 0;
-
     /*!
      * Ensures that the corresponding texture reflects the contents of the
      * associated pixmap and schedules a redraw of this item.
      */
-    virtual void updateWindowPixmap(XRectangle *rects = 0, int num = 0) = 0;
+    virtual void updateWindowPixmap(XRectangle *rects = 0, int num = 0,
+                                    Time when = 0) = 0;
 
     /*!
-     * Creates the pixmap id and saves the offscreen buffer that represents
-     * this window
-     *
-     * \param renew Set to true if the window was just mapped or resized. This
-     * will update the offscreen backing store.
+     * Recreates the pixmap id and saves the offscreen buffer that represents
+     * this window. This will update the offscreen backing store.
      */
-    virtual void saveBackingStore(bool renew = false) = 0;
+    virtual void saveBackingStore() = 0;
 
     /*!
       Clears the texture that is associated with the offscreen pixmap
@@ -240,6 +252,11 @@
     virtual void clearTexture() = 0;
 
     /*!
+      Returns pixmap for the window.
+     */
+    virtual Pixmap windowPixmap() const = 0;
+
+    /*!
       Returns true if the window corresponding to the offscreen pixmap
       is rendering directly to the framebuffer, otherwise return false.
      */
@@ -285,22 +302,49 @@
      * Returns whatever window is directly behind this window. 0 if there is none.
      */
     MCompositeWindow* behind() const { return behind_window; }
+
+    /*!
+     *  Returns a pointer to this window's group if it belongs to a group and 0
+     * if 0 if not a member
+     */
+    MCompositeWindowGroup* group() const;
     
     /*! Disabled alpha-blending for a dim-effect instead */
     void setDimmedEffect(bool dimmed) { dimmed_effect = dimmed; }
     
     bool dimmedEffect() const { return dimmed_effect; }
-
+    
 public slots:
 
+    void updateIconGeometry();
     void startTransition();
-    void manipulationEnabled(bool isEnabled);
-    void setUnBlurred();
     void setBlurred(bool);
     
     /* Operations with transition animations*/
-    void closeWindow();
-    void showWindow();
+    // set to Closing state and send delete/kill
+    void closeWindowRequest();
+    // start unmap animation
+    void closeWindowAnimation();
+    bool showWindow();
+
+    /*!
+      * This slot is called whenever a start of window animation occurs. This
+      * is an atomic operation. Ensure that endTransition() is invoked when
+      * the animation is finished.
+      */
+    void beginAnimation();
+    
+    /*!
+      * This slot is called whenever the window has finished animating its 
+      * effects
+      */
+     void endAnimation();
+
+    /*!
+     * Called on first showing of a window when first damage event is received
+     * or on timeout.
+     */
+    void damageReceived(bool timeout);
     
 private slots:
 
@@ -310,9 +354,8 @@
     void finalizeState();
 
     void pingTimeout();
+    void damageTimeout();
     void pingWindow();
-    void windowTransitioning();
-    void q_delayShow();
     void q_itemRestored();
     void q_fadeIn();
     
@@ -322,7 +365,6 @@
      */
     void windowHung(MCompositeWindow *window);
 
-    void acceptingInput();
     void visualized(bool);
 
     /*! Emitted when this window gets restored from an iconified state */
@@ -331,18 +373,18 @@
     void itemIconified(MCompositeWindow *window);
     /*! Emitted when desktop is raised */
     void desktopActivated(MCompositeWindow *window);
-    /*! Emitted when this window is closed   */
-    void windowClosed(MCompositeWindow *window);
+    /*! Emitted when the user wants to close this window */
+    void closeWindowRequest(MCompositeWindow *window);
 
 protected:
 
-    virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *);
-    virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *);
-    virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
     virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value);    
     virtual QPainterPath shape() const;
-    
+        
 private:
+    /* re-implemented in GL/GLES2 backends for internal interaction
+      between shader effects */
+    virtual MTexturePixmapPrivate* renderer() const = 0;
     void findBehindWindow();
 
     QPointer<MWindowPropertyCache> pc;
@@ -363,13 +405,13 @@
     WindowStatus window_status;
     bool need_decor;
     bool window_visible;
-    bool window_obscured;
+    short window_obscured;
     bool is_valid;
     bool newly_mapped;
-    bool is_closing;
     bool is_transitioning;
     bool pinging_enabled;
     bool dimmed_effect;
+    char waiting_for_damage;
 
     static int window_transitioning;
 
@@ -379,9 +421,11 @@
 
     // Main ping timer
     QTimer *t_ping;
+    QTimer *damage_timer;
     Qt::HANDLE win_id;
 
     friend class MTexturePixmapPrivate;
+    friend class MCompositeWindowShaderEffect;
 };
 
 #endif
--- src/mcompositewindowgroup.cpp
+++ src/mcompositewindowgroup.cpp
+/***************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (directui at nokia.com)
+**
+** This file is part of mcompositor.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at directui at nokia.com.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation
+** and appearing in the file LICENSE.LGPL included in the packaging
+** of this file.
+**
+****************************************************************************/
+/*!
+  \class MCompositeWindowGroup
+  \brief MCompositeWindowGroup allows a collection of windows to be rendered
+  as a single texture.
+  
+  This class is useful for rendering a list of windows that needs to 
+  be treated as one item with transformations applied only to a single texture.
+  Unlike QGraphicsItemGroup where each item is rendered separately for each
+  frame, MCompositeWindowGroup can pre-render all items to an off-screen buffer 
+  before a frame starts and can render the resulting texture afterwards as a 
+  single quad which reduces GPU load and helps performance especially in panning
+  and scaling transformations. 
+  
+  Use this class to render a main window with its transient windows. Another
+  use case is for a window that needs to have similar transformations to a
+  main window. The addChildWindow() function adds windows that need to 
+  animate synchronously  with the main window. The removeChildWindow() function
+  removes a window from the group.  
+
+  Implementation is hw-dependent. It relies on framebuffer objects on GLES2 
+  and the GL_EXT_framebuffer_object extension on the desktop.
+*/
+
+#include <QtOpenGL> 
+#include <QList>
+#include <mcompositewindowgroup.h>
+
+#include <mtexturepixmapitem.h>
+#include <mcompositemanager.h>
+
+#ifdef GLES2_VERSION
+#define FORMAT GL_RGBA
+#define DEPTH GL_DEPTH_COMPONENT16
+#else
+#define FORMAT GL_RGBA8
+#define DEPTH GL_DEPTH_COMPONENT
+#endif
+
+class MCompositeWindowGroupPrivate
+{
+public:
+    MCompositeWindowGroupPrivate(MTexturePixmapItem* mainWindow)
+        :main_window(mainWindow),
+         texture(0),
+         fbo(0),
+         depth_buffer(0),
+         valid(false),
+         renderer(new MTexturePixmapPrivate(0, mainWindow))            
+    {       
+    }
+    MTexturePixmapItem* main_window;
+    GLuint texture;
+    GLuint fbo;
+    GLuint depth_buffer;
+    
+    bool valid;
+    QList<MTexturePixmapItem*> item_list;
+    MTexturePixmapPrivate* renderer;
+};
+
+/*!
+  Creates a window group object. Specify the main window
+  with \a mainWindow
+ */
+MCompositeWindowGroup::MCompositeWindowGroup(MTexturePixmapItem* mainWindow)
+    :MCompositeWindow(0, MWindowDummyPropertyCache::get()),
+     d_ptr(new MCompositeWindowGroupPrivate(mainWindow))
+{
+    MCompositeManager *p = (MCompositeManager *) qApp;
+    p->scene()->addItem(this);
+    
+    mainWindow->d->current_window_group = this;
+    connect(mainWindow, SIGNAL(destroyed()), SLOT(deleteLater()));
+    init();
+    updateWindowPixmap();
+    setZValue(mainWindow->zValue());
+    stackBefore(mainWindow);
+}
+
+/*!
+  Destroys this window group and frees resources. All windows that are within 
+  this group revert back to directly rendering its own texture.
+ */
+MCompositeWindowGroup::~MCompositeWindowGroup()
+{
+    Q_D(MCompositeWindowGroup);
+    
+    if (!QGLContext::currentContext()) {
+        qWarning("MCompositeWindowGroup::%s(): no current GL context",
+                 __func__);
+        return;
+    }
+    
+    GLuint texture = d->texture;
+    glDeleteTextures(1, &texture);
+    GLuint depth_buffer = d->depth_buffer;
+    glDeleteRenderbuffers(1, &depth_buffer);
+    GLuint fbo = d->fbo;
+    glDeleteFramebuffers(1, &fbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+    update();
+}
+
+void MCompositeWindowGroup::init()
+{
+    Q_D(MCompositeWindowGroup);
+    
+    if (!QGLContext::currentContext()) {
+        qWarning("MCompositeWindowGroup::%s(): no current GL context",
+                 __func__);
+        d->valid = false;
+        return;
+    }
+    d->renderer->current_window_group = this;
+    
+    glGenFramebuffers(1, &d->fbo);
+    glGenRenderbuffers(1, &d->depth_buffer);
+    glBindFramebuffer(GL_RENDERBUFFER, d->fbo);
+    
+    glGenTextures(1, &d->texture);
+    glBindTexture(GL_TEXTURE_2D, d->texture);
+    
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    
+    glBindRenderbuffer(GL_RENDERBUFFER, d->depth_buffer);
+    glRenderbufferStorage(GL_RENDERBUFFER, DEPTH, 
+                          d->main_window->boundingRect().width(), 
+                          d->main_window->boundingRect().height());
+
+    glBindFramebuffer(GL_FRAMEBUFFER, d->fbo);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                           GL_TEXTURE_2D, d->texture, 0);
+
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                              GL_RENDERBUFFER, d->depth_buffer);
+    
+    glBindTexture(GL_TEXTURE_2D, d->texture);
+    glTexImage2D(GL_TEXTURE_2D, 0, FORMAT, 
+                 d->main_window->boundingRect().width(), 
+                 d->main_window->boundingRect().height(), 0,
+                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    
+    GLenum ret = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    if (ret == GL_FRAMEBUFFER_COMPLETE)
+        d->valid = true;
+    else         
+        qWarning("MCompositeWindowGroup::%s(): incomplete FBO attachment 0x%x",
+                 __func__, ret);           
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);    
+}
+
+static bool behindCompare(MTexturePixmapItem* a, MTexturePixmapItem* b)
+{
+    return a->indexInStack() < b->indexInStack();
+}
+
+/*!
+  Adds the given \a window to this group. The window's transformations will
+  remain unmodified
+ */
+void MCompositeWindowGroup::addChildWindow(MTexturePixmapItem* window)
+{
+    Q_D(MCompositeWindowGroup);
+    window->d->current_window_group = this;
+    connect(window, SIGNAL(destroyed()), SLOT(q_removeWindow()));
+    d->item_list.append(window);
+    
+    // ensure group windows are already stacked in proper order in advance
+    // for back to front rendering. Could use depth buffer attachment at some 
+    // point so this might be unecessary
+    qSort(d->item_list.begin(), d->item_list.end(), behindCompare);
+    updateWindowPixmap();
+}
+
+/*!
+  Removes the given \a window to from group. 
+ */
+void MCompositeWindowGroup::removeChildWindow(MTexturePixmapItem* window)
+{
+    Q_D(MCompositeWindowGroup);
+    window->d->current_window_group = 0;
+    d->item_list.removeAll(window);
+}
+
+void MCompositeWindowGroup::q_removeWindow()
+{
+    Q_D(MCompositeWindowGroup);
+    MTexturePixmapItem* w = qobject_cast<MTexturePixmapItem*>(sender());
+    if (w) 
+        d->item_list.removeAll(w);
+}
+
+void MCompositeWindowGroup::saveBackingStore() {}
+
+void MCompositeWindowGroup::resize(int , int) {}
+
+void MCompositeWindowGroup::clearTexture() {}
+
+bool MCompositeWindowGroup::isDirectRendered() const { return false; }
+
+QRectF MCompositeWindowGroup::boundingRect() const 
+{
+    Q_D(const MCompositeWindowGroup);
+    return d->main_window->boundingRect();
+}
+
+void MCompositeWindowGroup::paint(QPainter* painter, 
+                                  const QStyleOptionGraphicsItem* options, 
+                                  QWidget* widget) 
+{    
+    Q_D(MCompositeWindowGroup);
+    Q_UNUSED(options)
+    Q_UNUSED(widget)
+
+#if QT_VERSION < 0x040600
+    if (painter->paintEngine()->type() != QPaintEngine::OpenGL)
+        return;
+#else
+    if (painter->paintEngine()->type() != QPaintEngine::OpenGL2) {
+        return;
+    }
+#endif
+    
+    glBindTexture(GL_TEXTURE_2D, d->texture);    
+    if (d->main_window->propertyCache()->hasAlpha() || 
+        (opacity() < 1.0f && !dimmedEffect()) ) {
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    }
+    d->renderer->drawTexture(painter->combinedTransform(), boundingRect(), 
+                             opacity());    
+    glBlendFunc(GL_ONE, GL_ZERO);
+    glDisable(GL_BLEND);
+}
+
+void MCompositeWindowGroup::windowRaised()
+{
+}
+
+void MCompositeWindowGroup::updateWindowPixmap(XRectangle *rects, int num,
+                                               Time t)
+{
+    Q_UNUSED(rects)
+    Q_UNUSED(num)
+    Q_UNUSED(t)
+    Q_D(MCompositeWindowGroup);
+    
+    if (!d->valid) {
+        qDebug() << "invalid fbo";
+        return;
+    }
+
+    glBindFramebuffer(GL_FRAMEBUFFER, d->fbo);
+    GLenum ret = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    if (ret == GL_FRAMEBUFFER_COMPLETE)
+        d->valid = true;
+    else {
+        qWarning("MCompositeWindowGroup::%s(): incomplete FBO attachment 0x%x",
+                 __func__, ret); 
+        d->valid = false;
+    }
+    d->main_window->d->inverted_texture = false;
+    d->main_window->renderTexture(d->main_window->sceneTransform());
+    d->main_window->d->inverted_texture = true;
+    for (int i = 0; i < d->item_list.size(); ++i) {
+        MTexturePixmapItem* item = d->item_list[i];
+        item->d->inverted_texture = false;
+        item->renderTexture(item->sceneTransform());
+        item->d->inverted_texture = true;
+    }
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+// internal re-implementation from MCompositeWindow
+MTexturePixmapPrivate* MCompositeWindowGroup::renderer() const
+{
+    Q_D(const MCompositeWindowGroup);
+    return d->renderer;
+}
+
+/*!
+  \return Returns the texture used by the off-screen buffer
+*/
+GLuint MCompositeWindowGroup::texture()
+{
+    Q_D(MCompositeWindowGroup);
+    return d->texture;
+}
+
+
--- src/mcompositewindowgroup.h
+++ src/mcompositewindowgroup.h
+/***************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (directui at nokia.com)
+**
+** This file is part of mcompositor.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at directui at nokia.com.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation
+** and appearing in the file LICENSE.LGPL included in the packaging
+** of this file.
+**
+****************************************************************************/
+
+#ifndef MCOMPOSITEWINDOWGROUP_H
+#define MCOMPOSITEWINDOWGROUP_H
+
+#include <mcompositewindow.h>
+
+class MTexturePixmapItem;
+class MCompositeWindowGroupPrivate;
+
+class MCompositeWindowGroup: public MCompositeWindow
+{
+    Q_OBJECT        
+ public: 
+    enum { Type =  UserType + 2 };
+
+    MCompositeWindowGroup(MTexturePixmapItem* mainWindow);
+    virtual ~MCompositeWindowGroup();
+    
+    void addChildWindow(MTexturePixmapItem* window);
+    void removeChildWindow(MTexturePixmapItem* window);
+    GLuint texture();
+    
+    //! \reimp  
+    virtual void windowRaised();
+    virtual void updateWindowPixmap(XRectangle *rects = 0, int num = 0, 
+                                    Time = 0);
+    virtual void saveBackingStore();
+    virtual void resize(int , int);
+    virtual void clearTexture();
+    virtual bool isDirectRendered() const;
+    virtual QRectF boundingRect() const;
+    virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*);
+    virtual Pixmap windowPixmap() const { return 0; }    
+    //! \reimp_end
+    
+    virtual int	type () const { return Type; }
+       
+ private slots:
+    void q_removeWindow();
+
+ private:
+    Q_DECLARE_PRIVATE(MCompositeWindowGroup)       
+    void init();
+    virtual MTexturePixmapPrivate* renderer() const;
+    
+    QScopedPointer<MCompositeWindowGroupPrivate> d_ptr;
+};
+
+#endif // MCOMPOSITEWINDOWGROUP_H
--- src/mcompositewindowshadereffect.cpp
+++ src/mcompositewindowshadereffect.cpp
+/***************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (directui at nokia.com)
+**
+** This file is part of mcompositor.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at directui at nokia.com.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation
+** and appearing in the file LICENSE.LGPL included in the packaging
+** of this file.
+**
+****************************************************************************/
+
+/*!
+  \class MCompositeWindowShaderEffect
+  \brief MCompositeWindowShaderEffect is the base class for shader effects on windows
+  
+  Shader effects can change the appearance of composited windows by hooking
+  into the rendering pipeline of the compositor. It allows manipulation
+  of how a composited window is rendered by using custom GLSL fragment shaders
+  and direct access to the texture rendering function.  
+  An effect can be disabled by calling setEnabled(false). If effects are 
+  disabled, the window texture is rendered directly.
+  
+  To add special effects to composited windows, subclass MCompositeWindowShaderEffect 
+  and reimplement the pure virtual function drawTexture()
+*/
+
+#include "mtexturepixmapitem.h"
+#include "mcompositewindowshadereffect.h"
+#include "mtexturepixmapitem_p.h"
+#include "mcompositewindowgroup.h"
+#include <QByteArray>
+
+static const char default_frag[] = "\
+    lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) { \
+        return texture2D(imageTexture, textureCoords); \
+    }\n";
+
+MCompositeWindowShaderEffectPrivate::MCompositeWindowShaderEffectPrivate(MCompositeWindowShaderEffect* e)
+    :effect(e),
+     priv_render(0),
+     active_fragment(0)
+{
+}
+
+void MCompositeWindowShaderEffectPrivate::drawTexture(MTexturePixmapPrivate* render, const QTransform &transform, const QRectF &drawRect, qreal opacity)
+{
+    priv_render = render;
+    effect->drawTexture(transform, drawRect, opacity);
+    enabled = false;
+}
+
+/*!
+ * Creates a window effect object
+ */
+MCompositeWindowShaderEffect::MCompositeWindowShaderEffect(QObject* parent)
+    :QObject(parent),
+     d(new MCompositeWindowShaderEffectPrivate(this))
+{    
+    // install default pixel shader
+    QByteArray code = default_frag;
+    d->active_fragment = installShaderFragment(code);
+}
+
+/*!
+  Destroys the graphics effect and deletes GLSL fragment programs from
+  the compositor's rendering engine if any are installed from this effect
+*/
+MCompositeWindowShaderEffect::~MCompositeWindowShaderEffect()
+{
+}
+
+/*!
+  Adds and installs the source code for a pixel shader fragment to \a code.
+  
+  The \a code must define a GLSL function with the signature
+  \c{lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)}
+  that returns the source pixel value to use in the paint engine's
+  shader program.  The following is the default pixel shader fragment,
+  which draws a texture with no effect applied:
+  
+  \code
+  lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)
+  {
+      return texture2D(imageTexture, textureCoords);
+  }
+  \endcode
+  
+  \return The id of the fragment shader. If the fragment shader is invalid,
+  return 0.
+  
+  \sa setUniforms()
+*/   
+GLuint MCompositeWindowShaderEffect::installShaderFragment(const QByteArray& code)
+{
+    GLuint id = MTexturePixmapPrivate::installPixelShader(code);
+    d->pixfrag_ids.push_back(id);
+    return id;
+}
+
+ /*!
+   \return Texture id of the currently rendered window
+ */
+GLuint MCompositeWindowShaderEffect::texture() const
+{
+    // TODO: This assumes we have always have hadware TFP support 
+    if (d->priv_render) {
+#ifdef GLES2_VERSION
+        if (!d->priv_render->current_window_group)
+            return d->priv_render->textureId;
+        else
+            return d->priv_render->current_window_group->texture();
+#else
+        return d->priv_render->textureId;
+#endif
+    }
+    return 0;
+}
+
+const QVector<GLuint>& MCompositeWindowShaderEffect::fragmentIds() const
+{
+    return d->pixfrag_ids;
+}
+
+/*!
+  Sets the rendering pipeline to use shader fragment specified by \a id 
+*/
+void MCompositeWindowShaderEffect::setActiveShaderFragment(GLuint id)
+{
+    d->active_fragment = id;
+}
+
+/*!
+  \return The id of the currently active shader fragment
+*/
+GLuint MCompositeWindowShaderEffect::activeShaderFragment() const
+{
+    return d->active_fragment;
+}
+
+/*!
+  \fn void MCompositeWindowShaderEffect::enabledChanged( bool enabled);
+  Emmitted if this effect gets disabled or enabled
+*/
+
+/*!
+  \fn virtual void MCompositeWindowShaderEffect::drawTexture(const QTransform &transform, const QRectF &drawRect, qreal opacity) = 0;
+
+  This pure virtual function is called whenever the windows texture is
+  rendered. Reimplement it to completely customize how the texture of this
+  window is rendered using the given transformation 
+  matrix \a transform, texture geometry \a drawRect, and \a opacity.
+*/
+
+/*!
+  Draws currently bound source window texture. Specify a transformation matrix to
+  \a transform and texture geometry to \a drawRect. Opacity can be set
+  by specifying \a opacity (0.0 - 1.0). 
+  This function should only be called inside drawTexture()      
+*/
+void MCompositeWindowShaderEffect::drawSource(const QTransform &transform, 
+                                              const QRectF &drawRect, 
+                                              qreal opacity)
+{
+    if (d->priv_render)
+        d->priv_render->q_drawTexture(transform, drawRect, opacity);
+}
+
+/*!
+  Install this effect on a composite window object \a window. Note that
+  we override QGraphicsItem::setGraphicsEffect() because
+  we have a completely different painting engine.
+  If a window has a previous effect, it will be overriden by the new one
+*/
+void MCompositeWindowShaderEffect::installEffect(MCompositeWindow* window)
+{
+    if (!window->isValid() && (window->type() != MCompositeWindowGroup::Type))
+        return;
+
+    // only happens with GL. sorry n800 guys :p
+#ifdef QT_OPENGL_LIB
+    window->renderer()->installEffect(this);    
+#endif
+}
+
+/*!
+  Remove this effect from a composite window object \a window. After removing
+  the effect the window will use default shaders.
+*/
+void MCompositeWindowShaderEffect::removeEffect(MCompositeWindow* window)
+{
+    if (!window->isValid() && (window->type() != MCompositeWindowGroup::Type))
+        return;
+
+#ifdef QT_OPENGL_LIB
+    window->renderer()->installEffect(0);    
+#endif
+}
+
+/*!
+  \return Whether this effect is enabled or not
+*/
+bool MCompositeWindowShaderEffect::enabled() const
+{
+    return d->enabled;
+}
+
+/*!
+  Enable or disable this effect 
+*/
+void MCompositeWindowShaderEffect::setEnabled(bool enabled)
+{
+    d->enabled = enabled;
+    emit enabledChanged(enabled);
+}
+
+/*!
+  Set the uniform values on the currently active shader \a program.
+  Default implementation does nothing. Reimplement this function to
+  set values if you specified a custom pixel shader in your effects.
+*/
+void MCompositeWindowShaderEffect::setUniforms(QGLShaderProgram* program)
+{
+    Q_UNUSED(program);
+}
+
--- src/mcompositewindowshadereffect.h
+++ src/mcompositewindowshadereffect.h
+/***************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (directui at nokia.com)
+**
+** This file is part of mcompositor.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at directui at nokia.com.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation
+** and appearing in the file LICENSE.LGPL included in the packaging
+** of this file.
+**
+****************************************************************************/
+
+#ifndef MCOMPOSITEWINDOWSHADEREFFECT_H
+#define MCOMPOSITEWINDOWSHADEREFFECT_H
+
+#include <QObject>
+#include <QVector>
+#include <QGLShaderProgram>
+
+class QTransform;
+class QRectF;
+class MCompositeWindowShaderEffect;
+class MTexturePixmapPrivate;
+class MCompositeWindow;
+class MCompositeWindowShaderEffectPrivate;
+
+class MCompositeWindowShaderEffect: public QObject
+{
+    Q_OBJECT
+ public:
+    MCompositeWindowShaderEffect(QObject* parent = 0);
+    virtual ~MCompositeWindowShaderEffect();
+    
+    GLuint installShaderFragment(const QByteArray& code);
+    GLuint texture() const;
+    void setActiveShaderFragment(GLuint id);
+    GLuint activeShaderFragment() const;
+
+    void installEffect(MCompositeWindow* window);
+    void removeEffect(MCompositeWindow* window);
+    bool enabled() const;
+
+ public slots:
+    void setEnabled(bool enabled);
+
+ signals:
+    void enabledChanged( bool enabled);
+    
+ protected: 
+    void drawSource(const QTransform &transform,
+                    const QRectF &drawRect, qreal opacity);
+    virtual void drawTexture(const QTransform &transform,
+                             const QRectF &drawRect, qreal opacity) = 0;
+    virtual void setUniforms(QGLShaderProgram* program);
+
+ private:    
+    /* \cond */
+    const QVector<GLuint>& fragmentIds() const;
+
+    MCompositeWindowShaderEffectPrivate* d;
+    friend class MTexturePixmapPrivate;
+    friend class MCompositeWindowShaderEffectPrivate;
+    /* \endcond */
+
+};
+
+/* \cond
+ * Internal class. Do not use! Not part of public API
+ */
+class MCompositeWindowShaderEffectPrivate
+{
+ public:    
+    void drawTexture(MTexturePixmapPrivate* render,
+                     const QTransform &transform,
+                     const QRectF &drawRect, qreal opacity);
+
+ private:
+    explicit MCompositeWindowShaderEffectPrivate(MCompositeWindowShaderEffect*);
+    
+    MCompositeWindowShaderEffect* effect;
+    MTexturePixmapPrivate* priv_render;
+    //  QMap<GLuint, QByteArray> pixelfragments;
+    QVector<GLuint> pixfrag_ids;
+    GLuint active_fragment;
+    
+    bool enabled;
+
+    friend class MCompositeWindowShaderEffect;
+};
+
+/* \endcond */
+#endif
--- src/mcompwindowanimator.cpp
+++ src/mcompwindowanimator.cpp
@@ -29,13 +29,13 @@
     return ((x2 - x1) * step) + x1;
 }
 
-MCompWindowAnimator::MCompWindowAnimator(MCompositeWindow *item)
-    : QObject(item),
+MCompWindowAnimator::MCompWindowAnimator(MCompositeWindow *comp_win)
+    : QObject(comp_win),
       timer(200),
       reversed(false),
       deferred_animation(false)
 {
-    this->item = item;
+    item = comp_win;
     timer.setFrameRange(0, 2000);
     timer.setUpdateInterval(int(1000.0 / Fps));
 
@@ -88,9 +88,9 @@
     
     // TODO: move calculation to GPU to imrpove speed
     // TODO: Use QPropertyAnimation instead
-    ((MCompositeWindow*)item)->setDimmedEffect(false);
+    item->setDimmedEffect(false);
     item->setOpacity(!reversed ? opac_norm : opac_rev);
-    MCompositeWindow* behind = ((MCompositeWindow*)item)->behind();
+    MCompositeWindow* behind = item->behind();
     if (behind) {
         behind->setDimmedEffect(true);
         behind->setOpacity(!reversed ? opac_rev : opac_norm);
@@ -102,7 +102,12 @@
 
 void MCompWindowAnimator::resetState()
 {
-    MCompositeWindow* behind = ((MCompositeWindow*)item)->behind();
+    if (!reversed) {
+        item->setPos(anim.posAt(1.0));
+        item->setOpacity(1.0);
+        item->setTransform(matrix);
+    }
+    MCompositeWindow* behind = item->behind();
     if (behind) {
         behind->setOpacity(1.0); 
     }
@@ -201,6 +206,12 @@
     }
 }
 
+void MCompWindowAnimator::stopAnimation()
+{
+    timer.stop();
+    item->setTransform(matrix);
+}
+
 void MCompWindowAnimator::deferAnimation(bool defer)
 {
     deferred_animation = defer;
--- src/mcompwindowanimator.h
+++ src/mcompwindowanimator.h
@@ -73,6 +73,7 @@
     bool isActive();
 
     void startAnimation();
+    void stopAnimation();
     void deferAnimation(bool);
 
     //! There is a pending animation to be executed soon
@@ -99,7 +100,7 @@
     QTransform matrix;
     QTransform local;
     bool visibility;
-    QGraphicsItem *item;
+    MCompositeWindow *item;
     QGraphicsItemAnimation anim;
     QTimeLine timer;
     int zval;
--- src/mdecoratorframe.cpp
+++ src/mdecoratorframe.cpp
@@ -152,6 +152,7 @@
 
 void MDecoratorFrame::destroyDecorator()
 {
+    setDecoratorAvailableRect(QRect());
     decorator_item = 0;
     decorator_window = 0;
 }
--- src/mdecoratorframe.h
+++ src/mdecoratorframe.h
@@ -92,6 +92,7 @@
     void setDecoratorItem(MCompositeWindow *window);
 
     MCompositeWindow *decoratorItem() const;
+    const QRect &decoratorRect() const { return decorator_rect; }
 
 public slots:
     void setDecoratorAvailableRect(const QRect& r);
--- src/mdevicestate.cpp
+++ src/mdevicestate.cpp
@@ -31,7 +31,7 @@
     if (mode == MCE_DISPLAY_OFF_STRING) {
         display_off = true;
         emit displayStateChange(true);
-    } else if (mode == MCE_DISPLAY_ON_STRING) {
+    } else {  // "on" or "dimmed"
         display_off = false;
         emit displayStateChange(false);
     }
--- src/mtexturepixmapitem.h
+++ src/mtexturepixmapitem.h
@@ -21,6 +21,7 @@
 #define DUITEXTUREPIXMAPITEM_H
 
 #include "mcompositewindow.h"
+#include "mtexturepixmapitem_p.h"
 
 #include <QtOpenGL>
 #include <QPixmap>
@@ -40,6 +41,7 @@
  */
 class MTexturePixmapItem: public MCompositeWindow
 {
+    Q_OBJECT
 public:
     /*!
      * Constructs a MTexturePixmapItem
@@ -49,7 +51,7 @@
      * \param parent QGraphicsItem, defaults to 0
      */
     MTexturePixmapItem(Window window, MWindowPropertyCache *mpc,
-                       QGLWidget *glwidget, QGraphicsItem *parent = 0);
+                       QGraphicsItem *parent = 0);
     /*!
      * Destroys the MTexturePixmapItem and frees the allocated
      * surface and texture
@@ -60,16 +62,14 @@
      * Ensures that the corresponding texture reflects the contents of the
      * associated pixmap and schedules a redraw of this item.
      */
-    void updateWindowPixmap(XRectangle *rects = 0, int num = 0);
+    void updateWindowPixmap(XRectangle *rects = 0, int num = 0,
+                            Time when = 0);
 
     /*!
-     * Creates the pixmap id and saves the offscreen buffer that represents
-     * this window
-     *
-     * \param renew Set to true if the window was just mapped or resized. This
-     * will update the offscreen backing store.
+     * Recreates the pixmap id and saves the offscreen buffer that represents
+     * this window. This will update the offscreen backing store.
      */
-    void saveBackingStore(bool renew = false);
+    void saveBackingStore();
 
     /*!
       Clears the texture that is associated with the offscreen pixmap
@@ -90,6 +90,8 @@
     void enableDirectFbRendering();
     void enableRedirectedRendering();
 
+    virtual Pixmap windowPixmap() const { return d->windowp; }
+
 protected:
     void paint(QPainter *painter,
                const QStyleOptionGraphicsItem *option,
@@ -97,17 +99,22 @@
 
     QSizeF sizeHint(Qt::SizeHint, const QSizeF &) const;
     QRectF boundingRect() const;
-    virtual void windowRaised();
 
 private:
+    virtual MTexturePixmapPrivate* renderer() const;
     void init();
     void initCustomTfp();
     void cleanup();
     void rebindPixmap();
+    void doTFP();
+    void renderTexture(const QTransform& transform);
 
     MTexturePixmapPrivate *const d;
     friend class MTexturePixmapPrivate;
     friend class MCompositeManagerPrivate;
+    friend class MCompositeWindowShaderEffect;
+    friend class MCompositeWindowGroupPrivate;
+    friend class MCompositeWindowGroup;
 };
 
 #endif // DUIGLXTEXTUREPIXMAPITEM_H
--- src/mtexturepixmapitem_egl.cpp
+++ src/mtexturepixmapitem_egl.cpp
@@ -19,6 +19,7 @@
 
 #include "mtexturepixmapitem.h"
 #include "mtexturepixmapitem_p.h"
+#include "mcompositewindowgroup.h"
 
 #include <QPainterPath>
 #include <QRect>
@@ -91,14 +92,13 @@
         QString exts = QLatin1String(eglQueryString(dpy, EGL_EXTENSIONS));
         if ((exts.contains("EGL_KHR_image") &&
              exts.contains("EGL_KHR_image_pixmap") &&
-             exts.contains("EGL_KHR_gl_texture_2D_image")) || 1) {
+             exts.contains("EGL_KHR_gl_texture_2D_image"))) {
             has_tfp = true;
             eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
             eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR"); 
             glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES"); 
         } else {
-            qCritical() << "EGL extensions:" << exts;
-            qFatal("no EGL tfp support, aborting\n");
+            qDebug("No EGL tfp support.\n");
         }
         texman = new EglTextureManager();
     }
@@ -133,56 +133,40 @@
         d->eglresource = new EglResourceManager();
 
     d->custom_tfp = !d->eglresource->texturePixmapSupport();
-    if (d->custom_tfp) {
-        initCustomTfp();
-        return;
-    }
-    saveBackingStore();
-    d->ctx->makeCurrent();
-    d->egl_image = eglCreateImageKHR(d->eglresource->dpy, 0,
-                                     EGL_NATIVE_PIXMAP_KHR,
-                                     (EGLClientBuffer)d->windowp,
-                                     attribs);
-    if (d->egl_image == EGL_NO_IMAGE_KHR) {
-        qWarning("MTexturePixmapItem::%s(): Cannot create EGL image: 0x%x",
-                 __func__, eglGetError());
-        return;
-    }
-    
     d->textureId = d->eglresource->texman->getTexture();
     glEnable(GL_TEXTURE_2D);
-    glBindTexture(GL_TEXTURE_2D, d->textureId);
     
-    if (d->egl_image != EGL_NO_IMAGE_KHR)
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, d->egl_image);
+    if (d->custom_tfp)
+        d->inverted_texture = false;
     
+    glBindTexture(GL_TEXTURE_2D, d->textureId);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    
+    d->saveBackingStore();
 }
 
 MTexturePixmapItem::MTexturePixmapItem(Window window, MWindowPropertyCache *mpc,
-                                       QGLWidget *glwidget,
                                        QGraphicsItem* parent)
     : MCompositeWindow(window, mpc, parent),
-      d(new MTexturePixmapPrivate(window, glwidget, this))
+      d(new MTexturePixmapPrivate(window, this))
 {
-    if (!d->ctx)
-        d->ctx = const_cast<QGLContext *>(glwidget->context());
     init();
 }
 
-void MTexturePixmapItem::saveBackingStore(bool renew)
+void MTexturePixmapItem::saveBackingStore()
 {
-    d->saveBackingStore(renew);
+    d->saveBackingStore();
 }
 
 void MTexturePixmapItem::rebindPixmap()
 {
-    if (d->egl_image != EGL_NO_IMAGE_KHR) {
+    if (!d->custom_tfp && d->egl_image != EGL_NO_IMAGE_KHR) {
         eglDestroyImageKHR(d->eglresource->dpy, d->egl_image);
+        d->egl_image = EGL_NO_IMAGE_KHR;
         glBindTexture(GL_TEXTURE_2D, 0);
     }
 
@@ -192,31 +176,23 @@
     }
     
     d->ctx->makeCurrent();
-    d->egl_image = eglCreateImageKHR(d->eglresource->dpy, 0,
-                                     EGL_NATIVE_PIXMAP_KHR,
-                                     (EGLClientBuffer)d->windowp,
-                                     attribs);
-    if (d->egl_image == EGL_NO_IMAGE_KHR)
-        qWarning("MTexturePixmapItem::%s(): Cannot create EGL image: 0x%x",
-                 __func__, eglGetError());
-    
-    glBindTexture(GL_TEXTURE_2D, d->textureId);
-    if (d->egl_image != EGL_NO_IMAGE_KHR)
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, d->egl_image);
+    doTFP();
 }
 
 void MTexturePixmapItem::enableDirectFbRendering()
 {
-    d->damageTracking(false);
-
-    if (d->direct_fb_render && d->egl_image == EGL_NO_IMAGE_KHR)
+    if (d->direct_fb_render)
         return;
+    if (d->item->propertyCache())
+        d->item->propertyCache()->damageTracking(false);
 
     d->direct_fb_render = true;
 
-    glBindTexture(GL_TEXTURE_2D, 0);
-    eglDestroyImageKHR(d->eglresource->dpy, d->egl_image);
-    d->egl_image = EGL_NO_IMAGE_KHR;
+    if(!d->custom_tfp &&  d->egl_image != EGL_NO_IMAGE_KHR) {
+        glBindTexture(GL_TEXTURE_2D, 0);
+        eglDestroyImageKHR(d->eglresource->dpy, d->egl_image);
+        d->egl_image = EGL_NO_IMAGE_KHR;
+    }
     if (d->windowp) {
         XFreePixmap(QX11Info::display(), d->windowp);
         d->windowp = 0;
@@ -227,15 +203,15 @@
 
 void MTexturePixmapItem::enableRedirectedRendering()
 {
-    d->damageTracking(true);
-
-    if (!d->direct_fb_render && d->egl_image != EGL_NO_IMAGE_KHR)
+    if (!d->direct_fb_render)
         return;
+    if (d->item->propertyCache())
+        d->item->propertyCache()->damageTracking(true);
 
     d->direct_fb_render = false;
     XCompositeRedirectWindow(QX11Info::display(), window(),
                              CompositeRedirectManual);
-    saveBackingStore(true);
+    saveBackingStore();
     updateWindowPixmap();
 }
 
@@ -252,24 +228,21 @@
 
 void MTexturePixmapItem::initCustomTfp()
 {
-    d->ctextureId = d->eglresource->texman->getTexture();
-
-    glBindTexture(GL_TEXTURE_2D, d->ctextureId);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    // UNUSED. 
+    // TODO: GLX backend should probably use same approach as here and
+    // re-use same texture id
 }
 
 void MTexturePixmapItem::cleanup()
-{    
-    EGLImageKHR egl_image =  d->egl_image;
+{
     EGLDisplay dpy = d->eglresource->dpy;
-    eglDestroyImageKHR(dpy, egl_image);
-    d->egl_image = EGL_NO_IMAGE_KHR;
 
-    if (!d->custom_tfp)
-        d->eglresource->texman->closeTexture(d->textureId);
-    else
-        d->eglresource->texman->closeTexture(d->ctextureId);
+    if (!d->custom_tfp && d->egl_image != EGL_NO_IMAGE_KHR) {
+        EGLImageKHR egl_image =  d->egl_image;
+        eglDestroyImageKHR(dpy, egl_image);
+        d->egl_image = EGL_NO_IMAGE_KHR;
+    }
+    d->eglresource->texman->closeTexture(d->textureId);
 
     // Work-around for crashes on some versions of below Qt 4.6
 #if (QT_VERSION < 0x040600)
@@ -279,36 +252,72 @@
     XFreePixmap(QX11Info::display(), d->windowp);
 }
 
-void MTexturePixmapItem::updateWindowPixmap(XRectangle *rects, int num)
+void MTexturePixmapItem::updateWindowPixmap(XRectangle *rects, int num,
+                                            Time when)
 {
-    if (hasTransitioningWindow() || d->direct_fb_render || !windowVisible()
-        || propertyCache()->isInputOnly())
+    // When a window is in transitioning limit the number of updates
+    // to @limit/@expiry miliseconds.
+    const unsigned expiry = 1000;
+    const int      limit  =   10;
+
+    if (hasTransitioningWindow()) {
+        // Limit the number of damages we're willing to process if we're
+        // in the middle of a transition, so the competition for the GL
+        // resources will be less tight.
+        if (d->pastDamages) {
+            // Forget about pastDamages we received long ago.
+            while (d->pastDamages->size() > 0
+                   && d->pastDamages->first() + expiry < when)
+                d->pastDamages->removeFirst();
+            if (d->pastDamages->size() >= limit)
+                // Too many damages in the given timeframe, throttle.
+                return;
+        } else
+            d->pastDamages = new QList<Time>;
+        // Can afford this damage, but recoed when we received it,
+        // so to know when to forget about them.
+        d->pastDamages->append(when);
+    } else if (d->pastDamages) {
+        // The window is not transitioning, forget about all pastDamages.
+        delete d->pastDamages;
+        d->pastDamages = NULL;
+    }
+
+    // we want to update the pixmap even if the item is not visible because
+    // certain animations require up-to-date pixmap (alternatively we could mark
+    // it dirty and update it before the animation starts...)
+    if (d->direct_fb_render || propertyCache()->isInputOnly())
         return;
 
     QRegion r;
     for (int i = 0; i < num; ++i)
         r += QRegion(rects[i].x, rects[i].y, rects[i].width, rects[i].height);
     d->damageRegion = r;
-
-    // Our very own custom texture from pixmap
+    
+    bool new_image = false;
     if (d->custom_tfp) {
         QPixmap qp = QPixmap::fromX11Pixmap(d->windowp);
-
+        
         QImage img = d->glwidget->convertToGLFormat(qp.toImage());
-        glBindTexture(GL_TEXTURE_2D, d->ctextureId);
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0,
-                     GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
-        update();
-    } else {
-        if (d->egl_image == EGL_NO_IMAGE_KHR)
-            saveBackingStore(true);
-        d->glwidget->update();
+        glBindTexture(GL_TEXTURE_2D, d->textureId);
+        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, img.width(), 
+                        img.height(), GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
+        new_image = true;
+    } else if (d->egl_image == EGL_NO_IMAGE_KHR) {
+        saveBackingStore();
+        new_image = true;
+    }    
+    if (new_image || !d->damageRegion.isEmpty()) {
+        if (!d->current_window_group) 
+            d->glwidget->update();
+        else
+            d->current_window_group->updateWindowPixmap();
     }
 }
 
 void MTexturePixmapItem::paint(QPainter *painter,
-                                 const QStyleOptionGraphicsItem *option,
-                                 QWidget *widget)
+                               const QStyleOptionGraphicsItem *option,
+                               QWidget *widget)
 {
     Q_UNUSED(option)
     Q_UNUSED(widget)
@@ -330,11 +339,17 @@
     if (!d->ctx)
         d->ctx = const_cast<QGLContext *>(gl->context());
 
+    if (!d->current_window_group) 
+        renderTexture(painter->combinedTransform());
+}
+
+void MTexturePixmapItem::renderTexture(const QTransform& transform)
+{    
     if (propertyCache()->hasAlpha() || (opacity() < 1.0f && !dimmedEffect()) ) {
         glEnable(GL_BLEND);
         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    } 
-    glBindTexture(GL_TEXTURE_2D, d->custom_tfp ? d->ctextureId : d->textureId);
+    }
+    glBindTexture(GL_TEXTURE_2D, d->textureId);
 
     const QRegion &shape = propertyCache()->shapeRegion();
     // FIXME: not optimal. probably would be better to replace with 
@@ -355,7 +370,7 @@
                        d->damageRegion.rects().at(i).height()),
                       d->damageRegion.rects().at(i).width(),
                       d->damageRegion.rects().at(i).height());
-            d->drawTexture(painter->combinedTransform(), boundingRect(), opacity());        
+            d->drawTexture(transform, boundingRect(), opacity());        
         }
     } else if (shape_on) {
         // draw a shaped window using glScissor
@@ -366,11 +381,10 @@
                        shape.rects().at(i).height()),
                       shape.rects().at(i).width(),
                       shape.rects().at(i).height());
-            d->drawTexture(painter->combinedTransform(),
-                           boundingRect(), opacity());
+            d->drawTexture(transform, boundingRect(), opacity());
         }
     } else
-        d->drawTexture(painter->combinedTransform(), boundingRect(), opacity());
+        d->drawTexture(transform, boundingRect(), opacity());
     
     if (scissor_on)
         glDisable(GL_SCISSOR_TEST);
@@ -381,11 +395,6 @@
     glDisable(GL_BLEND);
 }
 
-void MTexturePixmapItem::windowRaised()
-{
-    d->windowRaised();
-}
-
 void MTexturePixmapItem::resize(int w, int h)
 {
     d->resize(w, h);
@@ -403,7 +412,45 @@
 
 void MTexturePixmapItem::clearTexture()
 {
-    glBindTexture(GL_TEXTURE_2D, d->custom_tfp ? d->ctextureId : d->textureId);
+    glBindTexture(GL_TEXTURE_2D, d->textureId);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, GL_RGBA,
                  GL_UNSIGNED_BYTE, 0);
+
+    glClearColor(0.0, 0.0, 0.0, 0.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void MTexturePixmapItem::doTFP()
+{
+    if (isClosing()) // Pixmap is already freed. No sense to create EGL image
+        return;      // from it again
+    
+    //no EGL texture from pixmap extensions available
+    //use regular X11/GL calls to copy pixels from Pixmap to GL Texture
+    if (d->custom_tfp) {
+        QPixmap qp = QPixmap::fromX11Pixmap(d->windowp);
+        QImage img = QGLWidget::convertToGLFormat(qp.toImage());
+        glBindTexture(GL_TEXTURE_2D, d->textureId);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
+    }
+    //use EGL extensions
+    else {
+        d->egl_image = eglCreateImageKHR(d->eglresource->dpy, 0,
+                                         EGL_NATIVE_PIXMAP_KHR,
+                                         (EGLClientBuffer)d->windowp,
+                                         attribs);
+        if (d->egl_image == EGL_NO_IMAGE_KHR) {
+            qWarning("MTexturePixmapItem::%s(): Cannot create EGL image: 0x%x",
+                     __func__, eglGetError());
+            return;
+        } else {
+            glBindTexture(GL_TEXTURE_2D, d->textureId);
+            glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, d->egl_image);
+        }
+    }
+}
+
+MTexturePixmapPrivate* MTexturePixmapItem::renderer() const
+{
+    return d;
 }
--- src/mtexturepixmapitem_glx.cpp
+++ src/mtexturepixmapitem_glx.cpp
@@ -93,7 +93,6 @@
         return;
 
     d->glpixmap = 0;
-    saveBackingStore();
 
     d->custom_tfp = !hasTextureFromPixmap();
 
@@ -158,21 +157,21 @@
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
     glXBindTexImageEXT(QX11Info::display(), d->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
+    saveBackingStore();
 }
 
 MTexturePixmapItem::MTexturePixmapItem(Window window,
                                        MWindowPropertyCache *pc,
-                                       QGLWidget *glwidget,
                                        QGraphicsItem *parent)
     : MCompositeWindow(window, pc, parent),
-      d(new MTexturePixmapPrivate(window, glwidget, this))
+      d(new MTexturePixmapPrivate(window, this))
 {
     init();
 }
 
-void MTexturePixmapItem::saveBackingStore(bool renew)
+void MTexturePixmapItem::saveBackingStore()
 {
-    d->saveBackingStore(renew);
+    d->saveBackingStore();
 }
 
 void MTexturePixmapItem::rebindPixmap()
@@ -184,7 +183,7 @@
         None
     };
 
-    if (!d->custom_tfp) {
+    if (!d->custom_tfp && d->windowp) {
         Display *display = QX11Info::display();
         glXReleaseTexImageEXT(display, d->glpixmap, GLX_FRONT_LEFT_EXT);
         glXDestroyPixmap(display, d->glpixmap);
@@ -198,7 +197,8 @@
 
 void MTexturePixmapItem::enableDirectFbRendering()
 {
-    d->damageTracking(false);
+    if (d->item->propertyCache())
+        d->item->propertyCache()->damageTracking(false);
 
     if ((d->direct_fb_render || d->glpixmap == 0) && !d->custom_tfp)
         return;
@@ -224,7 +224,8 @@
 
 void MTexturePixmapItem::enableRedirectedRendering()
 {
-    d->damageTracking(true);
+    if (d->item->propertyCache())
+        d->item->propertyCache()->damageTracking(true);
 
     if ((!d->direct_fb_render || d->glpixmap != 0) && !d->custom_tfp)
         return;
@@ -233,7 +234,7 @@
     XCompositeRedirectWindow(QX11Info::display(), window(),
                              CompositeRedirectManual);
     XSync(QX11Info::display(), FALSE);
-    saveBackingStore(true);
+    saveBackingStore();
     updateWindowPixmap();
 }
 
@@ -272,10 +273,12 @@
         XFreePixmap(QX11Info::display(), d->windowp);
 }
 
-void MTexturePixmapItem::updateWindowPixmap(XRectangle *rects, int num)
+void MTexturePixmapItem::updateWindowPixmap(XRectangle *rects, int num,
+                                            Time when)
 {
     Q_UNUSED(rects);
     Q_UNUSED(num);
+    Q_UNUSED(when);
 
     if (isWindowTransitioning() || d->direct_fb_render || !windowVisible())
         return;
@@ -284,10 +287,14 @@
     if (d->custom_tfp && d->windowp) {
         QPixmap qp = QPixmap::fromX11Pixmap(d->windowp);
 
-        QImage img = d->glwidget->convertToGLFormat(qp.toImage());
-        glBindTexture(GL_TEXTURE_2D, d->ctextureId);
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0,
-                     GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
+        QT_TRY {
+            QImage img = d->glwidget->convertToGLFormat(qp.toImage());
+            glBindTexture(GL_TEXTURE_2D, d->ctextureId);
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0,
+                         GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
+       } QT_CATCH(std::bad_alloc e) {
+           /* XGetImage() failed, the window has been unmapped. */;
+       }
     }
     update();
 }
@@ -303,7 +310,8 @@
     if (painter->paintEngine()->type()  != QPaintEngine::OpenGL)
         return;
 #else
-    if (painter->paintEngine()->type()  != QPaintEngine::OpenGL2) {
+    if (painter->paintEngine()->type()  != QPaintEngine::OpenGL2 &&
+        painter->paintEngine()->type()  != QPaintEngine::OpenGL) {
         return;
     }
 #endif
@@ -365,11 +373,6 @@
 
 }
 
-void MTexturePixmapItem::windowRaised()
-{
-    d->windowRaised();
-}
-
 void MTexturePixmapItem::resize(int w, int h)
 {
     d->resize(w, h);
@@ -390,4 +393,12 @@
     glBindTexture(GL_TEXTURE_2D, d->custom_tfp ? d->ctextureId : d->textureId);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, GL_RGBA,
                  GL_UNSIGNED_BYTE, 0);
+
+    glClearColor(0.0, 0.0, 0.0, 0.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+MTexturePixmapPrivate* MTexturePixmapItem::renderer() const
+{
+    return d;
 }
--- src/mtexturepixmapitem_p.cpp
+++ src/mtexturepixmapitem_p.cpp
@@ -22,6 +22,8 @@
 #endif
 #include "mtexturepixmapitem.h"
 #include "texturepixmapshaders.h"
+#include "mcompositewindowshadereffect.h"
+#include "mcompositemanager.h"
 
 #include <QX11Info>
 #include <QRect>
@@ -41,6 +43,8 @@
 #include "mtexturepixmapitem_p.h"
 
 bool MTexturePixmapPrivate::inverted_texture = true;
+QGLWidget *MTexturePixmapPrivate::glwidget = 0;
+QGLContext *MTexturePixmapPrivate::ctx = 0;
 MGLResourceManager *MTexturePixmapPrivate::glresource = 0;
 
 static const GLuint D_VERTEX_COORDS = 0;
@@ -53,12 +57,63 @@
     p->bindAttributeLocation(attrib, location);
 }
 
+class MShaderProgram : public QGLShaderProgram
+{
+public:
+    MShaderProgram(const QGLContext* context, QObject* parent)
+        : QGLShaderProgram(context, parent)
+    {
+        texture = -1;
+        opacity = -1;
+        blurstep = -1;
+    }
+    void setWorldMatrix(GLfloat m[4][4]) {
+        static bool init = true;
+        if (init || memcmp(m, worldMatrix, sizeof(worldMatrix))) {
+            setUniformValue("matWorld", m);
+            memcpy(worldMatrix, m, sizeof(worldMatrix));
+            init = false;
+        }
+    }
+
+    void setTexture(GLuint t) {
+        if (t != texture) {
+            setUniformValue("texture", t);
+            texture = t;
+        }
+    }
+
+    void setOpacity(GLfloat o) {
+        if (o != opacity) {
+            setUniformValue("opacity", o);
+            opacity = o;
+        }
+    }
+    void setBlurStep(GLfloat b) {
+        if (b != blurstep) {
+            setUniformValue("blurstep", b);
+            blurstep = b;
+        }
+    }
+
+private:
+    // static because this is set in the shared vertex shader
+    static GLfloat worldMatrix[4][4];
+    GLfloat opacity, blurstep;
+    GLuint texture;
+};
+
+GLfloat MShaderProgram::worldMatrix[4][4];
+
 // OpenGL ES 2.0 / OpenGL 2.0 - compatible texture painter
 class MGLResourceManager: public QObject
 {
 public:
 
-    /* add more values here as we add more effects */
+    /*
+     * This is the default set of shaders.
+     * Use MCompositeWindowShaderEffect class to add more shader effects 
+     */
     enum ShaderType {
         NormalShader = 0,
         BlurShader,
@@ -67,20 +122,24 @@
 
     MGLResourceManager(QGLWidget *glwidget)
         : QObject(glwidget),
-          currentShader(0) {
-        QGLShader *sharedVertexShader = new QGLShader(QGLShader::Vertex,
+          glcontext(glwidget->context()),
+          currentShader(0)
+    {
+        sharedVertexShader = new QGLShader(QGLShader::Vertex,
                 glwidget->context(), this);
         if (!sharedVertexShader->compileSourceCode(QLatin1String(TexpVertShaderSource)))
             qWarning("vertex shader failed to compile");
 
-        QGLShaderProgram *normalShader = new QGLShaderProgram(glwidget->context(), this);
-        shader[NormalShader] = normalShader;
+        MShaderProgram *normalShader = new MShaderProgram(glwidget->context(), 
+                                                          this);
         normalShader->addShader(sharedVertexShader);
         if (!normalShader->addShaderFromSourceCode(QGLShader::Fragment,
                 QLatin1String(TexpFragShaderSource)))
             qWarning("normal fragment shader failed to compile");
+        shader[NormalShader] = normalShader;
 
-        QGLShaderProgram *blurShader = new QGLShaderProgram(glwidget->context(), this);
+        MShaderProgram *blurShader = new MShaderProgram(glwidget->context(), 
+                                                        this);
         shader[BlurShader] = blurShader;
         blurShader->addShader(sharedVertexShader);
         if (!blurShader->addShaderFromSourceCode(QGLShader::Fragment,
@@ -132,10 +191,8 @@
         }
     }
 
-    void updateVertices(const QTransform &t, ShaderType type) {
-        if (shader[type] != currentShader)
-            currentShader = shader[type];
-
+    void updateVertices(const QTransform &t) 
+    {
         worldMatrix[0][0] = t.m11();
         worldMatrix[0][1] = t.m12();
         worldMatrix[0][3] = t.m13();
@@ -145,33 +202,95 @@
         worldMatrix[3][0] = t.dx();
         worldMatrix[3][1] = t.dy();
         worldMatrix[3][3] = t.m33();
+    }
+
+    void updateVertices(const QTransform &t, ShaderType type) 
+    {        
+        if (shader[type] != currentShader)
+            currentShader = shader[type];
+        
+        updateVertices(t);
         currentShader->bind();
-        currentShader->setUniformValue("matWorld", worldMatrix);
+        currentShader->setWorldMatrix(worldMatrix);
+    }
+
+    
+    void updateVertices(const QTransform &t, GLuint customShaderId) 
+    {                
+        if (!customShaderId)
+            return;
+        MShaderProgram* frag = customShaders.value(customShaderId, 0);
+        if (!frag)
+            return;
+        currentShader = frag;        
+        updateVertices(t);
+        currentShader->bind();
+        currentShader->setWorldMatrix(worldMatrix);
+    }
+
+    GLuint installPixelShader(const QByteArray& code)
+    {
+        QByteArray source = code;
+        source.append(TexpCustomShaderSource);
+        MShaderProgram *p = new MShaderProgram(glcontext, this);
+        p->addShader(sharedVertexShader);
+        if (!p->addShaderFromSourceCode(QGLShader::Fragment,
+                QLatin1String(source)))
+            qWarning("custom fragment shader failed to compile");
+
+        bindAttribLocation(p, "inputVertex", D_VERTEX_COORDS);
+        bindAttribLocation(p, "textureCoord", D_TEXTURE_COORDS);
+
+        if (p->link()) {
+            customShaders[p->programId()] = p;
+            return p->programId();
+        } 
+       
+        qWarning() << "failed installing custom fragment shader:"
+                   << p->log();
+        p->deleteLater();
+        
+        return 0;
     }
 
 private:
-    static QGLShaderProgram *shader[ShaderTotal];
+    static MShaderProgram *shader[ShaderTotal];
+    QHash<GLuint, MShaderProgram *> customShaders;
+    QGLShader *sharedVertexShader;
+    const QGLContext* glcontext;    
+    
     GLfloat projMatrix[4][4];
     GLfloat worldMatrix[4][4];
     GLfloat vertCoords[8];
     GLfloat texCoords[8];
     GLfloat texCoordsInv[8];
-    QGLShaderProgram *currentShader;
+    MShaderProgram *currentShader;
     int width;
     int height;
 
     friend class MTexturePixmapPrivate;
 };
 
-QGLShaderProgram *MGLResourceManager::shader[ShaderTotal];
+MShaderProgram *MGLResourceManager::shader[ShaderTotal];
 #endif
 
+
 void MTexturePixmapPrivate::drawTexture(const QTransform &transform, const QRectF &drawRect, qreal opacity)
 {
-    // TODO only update if matrix is dirty
-    glresource->updateVertices(transform, item->blurred() ?
-                               MGLResourceManager::BlurShader :
-                               MGLResourceManager::NormalShader);
+    if (current_effect) {
+        current_effect->d->drawTexture(this, transform, drawRect, opacity);
+    } else
+        q_drawTexture(transform, drawRect, opacity);
+}
+
+void MTexturePixmapPrivate::q_drawTexture(const QTransform &transform, const QRectF &drawRect, qreal opacity)
+{
+    if (current_effect)
+        glresource->updateVertices(transform, current_effect->activeShaderFragment());
+    else
+        glresource->updateVertices(transform, item->blurred() ?
+                                   MGLResourceManager::BlurShader :
+                                   MGLResourceManager::NormalShader);
     GLfloat vertexCoords[] = {
         drawRect.left(),  drawRect.top(),
         drawRect.left(),  drawRect.bottom(),
@@ -187,10 +306,13 @@
     else
         glVertexAttribPointer(D_TEXTURE_COORDS, 2, GL_FLOAT, GL_FALSE, 0,
                               glresource->texCoords);
-    if (item->blurred())
-        glresource->currentShader->setUniformValue("blurstep", (GLfloat) 0.5);
-    glresource->currentShader->setUniformValue("opacity", (GLfloat) opacity);
-    glresource->currentShader->setUniformValue("texture", 0);
+    
+    if (current_effect)
+        current_effect->setUniforms(glresource->currentShader);
+    else if (item->blurred())
+        glresource->currentShader->setBlurStep((GLfloat) 0.5);
+    glresource->currentShader->setOpacity((GLfloat) opacity);
+    glresource->currentShader->setTexture(0);
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
     glDisableVertexAttribArray(D_VERTEX_COORDS);
@@ -200,6 +322,65 @@
     glActiveTexture(GL_TEXTURE0);
 }
 
+void MTexturePixmapPrivate::installEffect(MCompositeWindowShaderEffect* effect)
+{
+    if (effect == prev_effect)
+        return;
+
+    if (prev_effect) {
+        disconnect(prev_effect, SIGNAL(enabledChanged(bool)), this,
+                   SLOT(activateEffect(bool)));
+        disconnect(prev_effect, SIGNAL(destroyed()), this,
+                   SLOT(removeEffect()));
+    }
+    current_effect = effect;
+    prev_effect = effect;
+    if (effect) {
+        connect(effect, SIGNAL(enabledChanged(bool)),
+                SLOT(activateEffect(bool)), Qt::UniqueConnection);
+        connect(effect, SIGNAL(destroyed()), SLOT(removeEffect()),
+                Qt::UniqueConnection);
+    }
+}
+
+void MTexturePixmapPrivate::removeEffect()
+{
+    MCompositeWindowShaderEffect* e= (MCompositeWindowShaderEffect* ) sender();
+    if (e == prev_effect)
+        prev_effect = 0;
+    for (int i=0; i < e->fragmentIds().size(); ++i) {
+        GLuint id = e->fragmentIds()[i];
+        QGLShaderProgram* frag = glresource->customShaders.value(id, 0);
+        if (frag)
+            delete frag;
+        glresource->customShaders.remove(id);
+    }    
+}
+
+GLuint MTexturePixmapPrivate::installPixelShader(const QByteArray& code)
+{
+    if (!glwidget) {
+        MCompositeManager *m = (MCompositeManager*)qApp;
+        glwidget = m->glWidget();
+    }
+    if (!glresource) {
+        glresource = new MGLResourceManager(glwidget);
+        glresource->initVertices(glwidget);
+    }
+    if (glresource)
+        return glresource->installPixelShader(code);
+
+    return 0;
+}
+
+void MTexturePixmapPrivate::activateEffect(bool enabled)
+{
+    if (enabled)
+        current_effect = (MCompositeWindowShaderEffect* ) sender();
+    else
+        current_effect = 0;
+}
+
 void MTexturePixmapPrivate::init()
 {
     if (!item->is_valid)
@@ -216,66 +397,67 @@
                  item->propertyCache()->realGeometry().y());
 }
 
-MTexturePixmapPrivate::MTexturePixmapPrivate(Qt::HANDLE window, QGLWidget *w, MTexturePixmapItem *p)
-    : ctx(0),
-      glwidget(w),
-      window(window),
+MTexturePixmapPrivate::MTexturePixmapPrivate(Qt::HANDLE window,
+                                             MTexturePixmapItem *p)
+    : window(window),
       windowp(0),
-#ifdef DESKTOP_VERSION
+#ifdef GLES2_VERSION
+      egl_image(EGL_NO_IMAGE_KHR),
+#else
       glpixmap(0),
 #endif
       textureId(0),
       ctextureId(0),
       custom_tfp(false),
-      direct_fb_render(false),
+      direct_fb_render(false), // root's children start redirected
       angle(0),
-      damage_object(0),
-      item(p)
+      item(p),
+      prev_effect(0),
+      pastDamages(0)
 {
-    damageTracking(true);
+    if (!glwidget) {
+        MCompositeManager *m = (MCompositeManager*)qApp;
+        glwidget = m->glWidget();
+    }
+    if (!ctx)
+        ctx = const_cast<QGLContext *>(glwidget->context());
+    if (item->propertyCache())
+        item->propertyCache()->damageTracking(true);
     init();
 }
 
 MTexturePixmapPrivate::~MTexturePixmapPrivate()
 {
-    damageTracking(false);
-}
+    if (item->propertyCache())
+        item->propertyCache()->damageTracking(false);
 
-void MTexturePixmapPrivate::damageTracking(bool enabled)
-{
-    if (damage_object) {
-        XDamageDestroy(QX11Info::display(), damage_object);
-        damage_object = NULL;
-    }
+    if (windowp)
+        XFreePixmap(QX11Info::display(), windowp);
 
-    if (enabled && !damage_object && !item->propertyCache()->isInputOnly())
-        damage_object = XDamageCreate(QX11Info::display(), window,
-                                      XDamageReportNonEmpty); 
+    if (pastDamages)
+        delete pastDamages;
 }
 
-void MTexturePixmapPrivate::saveBackingStore(bool renew)
+void MTexturePixmapPrivate::saveBackingStore()
 {
     if ((item->propertyCache()->is_valid && !item->propertyCache()->isMapped())
-        || item->propertyCache()->isInputOnly())
+        || item->propertyCache()->isInputOnly()
+        || !window)
         return;
 
     if (windowp)
         XFreePixmap(QX11Info::display(), windowp);
-    Pixmap px = XCompositeNameWindowPixmap(QX11Info::display(), item->window());
-    windowp = px;
-    if (renew)
-        item->rebindPixmap();
-}
-
-void MTexturePixmapPrivate::windowRaised()
-{
-    XRaiseWindow(QX11Info::display(), item->window());
+    windowp = XCompositeNameWindowPixmap(QX11Info::display(), item->window());
+    item->rebindPixmap(); // windowp == 0 is also handled here
 }
 
 void MTexturePixmapPrivate::resize(int w, int h)
 {
+    if (!window)
+        return;
+    
     if (!brect.isEmpty() && !item->isDirectRendered() && (brect.width() != w || brect.height() != h)) {
-        item->saveBackingStore(true);
+        item->saveBackingStore();
         item->updateWindowPixmap();
     }
     brect.setWidth(w);
--- src/mtexturepixmapitem_p.h
+++ src/mtexturepixmapitem_p.h
@@ -20,10 +20,11 @@
 #ifndef DUITEXTUREPIXMAPITEM_P_H
 #define DUITEXTUREPIXMAPITEM_P_H
 
+#include <QObject>
 #include <QRect>
 #include <QRegion>
-
-#include <X11/extensions/Xdamage.h>
+#include <QPointer>
+#include <X11/Xlib.h>
 
 #ifdef GLES2_VERSION
 #include <EGL/egl.h>
@@ -39,28 +40,34 @@
 class QGraphicsItem;
 class MTexturePixmapItem;
 class QGLContext;
+class QTransform;
 class MGLResourceManager;
+class MCompositeWindowShaderEffect;
+class MCompositeWindowGroup;
 
 /*! Internal private implementation of MTexturePixmapItem
   Warning! Interface here may change at any time!
  */
-class MTexturePixmapPrivate
+class MTexturePixmapPrivate: QObject
 {
+    Q_OBJECT
 public:
-    MTexturePixmapPrivate(Window window, QGLWidget *w, MTexturePixmapItem *item);
+    MTexturePixmapPrivate(Window window, MTexturePixmapItem *item);
     ~MTexturePixmapPrivate();
     void init();
     void updateWindowPixmap(XRectangle *rects = 0, int num = 0);
-    void saveBackingStore(bool renew = false);
+    void saveBackingStore();
     void clearTexture();
     bool isDirectRendered() const;
     void resize(int w, int h);
-    void windowRaised();
     void drawTexture(const QTransform& transform, const QRectF& drawRect, qreal opacity);
-    void damageTracking(bool enabled);
+    
+    void q_drawTexture(const QTransform& transform, const QRectF& drawRect, qreal opacity);
+    void installEffect(MCompositeWindowShaderEffect* effect);
+    static GLuint installPixelShader(const QByteArray& code);
                 
-    QGLContext *ctx;
-    QGLWidget *glwidget;
+    static QGLContext *ctx;
+    static QGLWidget *glwidget;
     Window window;
     Pixmap windowp;
 #ifdef GLES2_VERSION
@@ -78,13 +85,26 @@
     QRegion damageRegion;
     qreal angle;
 
-    Damage damage_object;
     MTexturePixmapItem *item;
+    QPointer<MCompositeWindowShaderEffect> current_effect;
+#ifdef GLES2_VERSION
+    QPointer<MCompositeWindowGroup> current_window_group;
+#endif
+    const MCompositeWindowShaderEffect *prev_effect;
+
+    // Contains a limited number of server times we received damage
+    // notifications for this window.  Only used by the EGL variant
+    // to throttle repairs if the window is transitioning.
+    QList<Time> *pastDamages;
 
 #ifdef GLES2_VERSION
     static EglResourceManager *eglresource;
 #endif
     static MGLResourceManager* glresource;
+
+private slots:
+    void activateEffect(bool enabled);
+    void removeEffect();
 };
 
 #endif //DUITEXTUREPIXMAPITEM_P_H
--- src/mwindowpropertycache.cpp
+++ src/mwindowpropertycache.cpp
@@ -17,6 +17,7 @@
 **
 ****************************************************************************/
 
+#include <QtGui>
 #include <stdlib.h>
 #include <QX11Info>
 #include <QRect>
@@ -25,65 +26,86 @@
 #include <X11/extensions/Xrender.h>
 #include <X11/extensions/shape.h>
 #include <X11/Xmd.h>
+#include "mcompositemanager.h"
 #include "mwindowpropertycache.h"
+#include "mcompositemanager_p.h"
 
 #define MAX_TYPES 10
 
 xcb_connection_t *MWindowPropertyCache::xcb_conn;
 
-MWindowPropertyCache::MWindowPropertyCache(Window w,
-                        xcb_get_window_attributes_reply_t *wa,
-                        xcb_get_geometry_reply_t *geom)
-    : transient_for((Window)-1),
-      wm_protocols_valid(false),
-      icon_geometry_valid(false),
-      decor_buttons_valid(false),
-      shape_rects_valid(false),
-      real_geom_valid(false),
-      net_wm_state_valid(false),
-      wm_state_query(true),
-      has_alpha(-1),
-      global_alpha(-1),
-      video_global_alpha(-1),
-      is_decorator(-1),
-      wmhints(0),
-      attrs(0),
-      meego_layer(-1),
-      window_state(-1),
-      window_type(MCompAtoms::INVALID),
-      window(w),
-      parent_window(RootWindow(QX11Info::display(), 0)),
-      being_mapped(false),
-      xcb_real_geom(0)
+void MWindowPropertyCache::init()
 {
+    transient_for = -1,
+    wm_protocols_valid = false;
+    icon_geometry_valid = false;
+    decor_buttons_valid = false;
+    shape_rects_valid = false;
+    real_geom_valid = false;
+    net_wm_state_valid = false;
+    wm_state_query = true;
+    has_alpha = -1;
+    global_alpha = -1;
+    video_global_alpha = -1;
+    is_decorator = -1;
+    wmhints = 0;
+    attrs = 0;
+    meego_layer = -1;
+    window_state = -1;
+    window_type = MCompAtoms::INVALID;
+    parent_window = QX11Info::appRootWindow();
+    always_mapped = -1;
+    cannot_minimize = -1;
+    desktop_view = -1;
+    being_mapped = false;
+    dont_iconify = false;
+    custom_region = 0;
+    custom_region_request_fired = false;
+    xcb_real_geom = 0;
+    damage_object = 0;
+
     memset(&req_geom, 0, sizeof(req_geom));
     memset(&home_button_geom, 0, sizeof(home_button_geom));
     memset(&close_button_geom, 0, sizeof(close_button_geom));
     window_type_atom = 0;
     memset(&xcb_real_geom_cookie, 0, sizeof(xcb_real_geom_cookie));
+}
 
+void MWindowPropertyCache::init_invalid()
+{
+    is_valid = false;
+    memset(&xcb_transient_for_cookie, 0,
+           sizeof(xcb_transient_for_cookie));
+    memset(&xcb_meego_layer_cookie, 0, sizeof(xcb_meego_layer_cookie));
+    memset(&xcb_is_decorator_cookie, 0, sizeof(xcb_is_decorator_cookie));
+    memset(&xcb_window_type_cookie, 0, sizeof(xcb_window_type_cookie));
+    memset(&xcb_decor_buttons_cookie, 0, sizeof(xcb_decor_buttons_cookie));
+    memset(&xcb_wm_protocols_cookie, 0, sizeof(xcb_wm_protocols_cookie));
+    memset(&xcb_wm_state_cookie, 0, sizeof(xcb_wm_state_cookie));
+    memset(&xcb_wm_hints_cookie, 0, sizeof(xcb_wm_hints_cookie));
+    memset(&xcb_icon_geom_cookie, 0, sizeof(xcb_icon_geom_cookie));
+    memset(&xcb_global_alpha_cookie, 0, sizeof(xcb_global_alpha_cookie));
+    memset(&xcb_video_global_alpha_cookie, 0,
+           sizeof(xcb_video_global_alpha_cookie));
+    memset(&xcb_net_wm_state_cookie, 0, sizeof(xcb_net_wm_state_cookie));
+    memset(&xcb_always_mapped_cookie, 0, sizeof(xcb_always_mapped_cookie));
+    memset(&xcb_cannot_minimize_cookie, 0, sizeof(xcb_always_mapped_cookie));
+    memset(&xcb_pict_formats_cookie, 0, sizeof(xcb_pict_formats_cookie));
+    memset(&xcb_shape_rects_cookie, 0, sizeof(xcb_shape_rects_cookie));
+}
+
+MWindowPropertyCache::MWindowPropertyCache(Window w,
+                        xcb_get_window_attributes_reply_t *wa,
+                        xcb_get_geometry_reply_t *geom)
+    : window(w)
+{
+    init();
     if (!wa) {
         attrs = xcb_get_window_attributes_reply(xcb_conn,
                         xcb_get_window_attributes(xcb_conn, window), 0);
         if (!attrs) {
             qWarning("%s: invalid window 0x%lx", __func__, window);
-            is_valid = false;
-            memset(&xcb_transient_for_cookie, 0,
-                   sizeof(xcb_transient_for_cookie));
-            memset(&xcb_meego_layer_cookie, 0, sizeof(xcb_meego_layer_cookie));
-            memset(&xcb_is_decorator_cookie, 0, sizeof(xcb_is_decorator_cookie));
-            memset(&xcb_window_type_cookie, 0, sizeof(xcb_window_type_cookie));
-            memset(&xcb_decor_buttons_cookie, 0, sizeof(xcb_decor_buttons_cookie));
-            memset(&xcb_wm_protocols_cookie, 0, sizeof(xcb_wm_protocols_cookie));
-            memset(&xcb_wm_state_cookie, 0, sizeof(xcb_wm_state_cookie));
-            memset(&xcb_wm_hints_cookie, 0, sizeof(xcb_wm_hints_cookie));
-            memset(&xcb_icon_geom_cookie, 0, sizeof(xcb_icon_geom_cookie));
-            memset(&xcb_global_alpha_cookie, 0, sizeof(xcb_global_alpha_cookie));
-            memset(&xcb_video_global_alpha_cookie, 0,
-                   sizeof(xcb_video_global_alpha_cookie));
-            memset(&xcb_net_wm_state_cookie, 0, sizeof(xcb_net_wm_state_cookie));
-            memset(&xcb_pict_formats_cookie, 0, sizeof(xcb_pict_formats_cookie));
-            memset(&xcb_shape_rects_cookie, 0, sizeof(xcb_shape_rects_cookie));
+            init_invalid();
             return;
         }
     } else
@@ -141,6 +163,29 @@
     xcb_net_wm_state_cookie = xcb_get_property(xcb_conn, 0, window,
                                                ATOM(_NET_WM_STATE),
                                                XCB_ATOM_ATOM, 0, 100);
+    xcb_always_mapped_cookie = xcb_get_property(xcb_conn, 0, window,
+                                                ATOM(_MEEGOTOUCH_ALWAYS_MAPPED),
+                                                XCB_ATOM_CARDINAL, 0, 1);
+    xcb_cannot_minimize_cookie = xcb_get_property(xcb_conn, 0, window,
+                                         ATOM(_MEEGOTOUCH_CANNOT_MINIMIZE),
+                                         XCB_ATOM_CARDINAL, 0, 1);
+    // add any transients to the transients list
+    MCompositeManager *m = (MCompositeManager*)qApp;
+    for (QList<Window>::const_iterator it = m->d->stacking_list.begin();
+         it != m->d->stacking_list.end(); ++it) {
+        MWindowPropertyCache *p = m->d->prop_caches.value(*it, 0);
+        if (p && p != this && p->transientFor() == window)
+            transients.append(*it);
+    }
+    connect(this, SIGNAL(meegoDecoratorButtonsChanged(Window)),
+            m->d, SLOT(setupButtonWindows(Window)));
+}
+
+MWindowPropertyCache::MWindowPropertyCache()
+    : window(None)
+{
+    init();
+    init_invalid();
 }
 
 MWindowPropertyCache::~MWindowPropertyCache()
@@ -165,11 +210,26 @@
         free(xcb_real_geom);
         xcb_real_geom = 0;
     }
+    if (transient_for && transient_for != (Window)-1) {
+        MCompositeManager *m = (MCompositeManager*)qApp;
+        // remove reference from the old "parent"
+        MWindowPropertyCache *p = m->d->prop_caches.value(transient_for, 0);
+        if (p) p->transients.removeAll(window);
+    }
     xcb_get_property_reply_t *r;
     if (transient_for == (Window)-1) {
         r = xcb_get_property_reply(xcb_conn, xcb_transient_for_cookie, 0);
         if (r) free(r);
     }
+    if (always_mapped < 0) {
+        r = xcb_get_property_reply(xcb_conn, xcb_always_mapped_cookie, 0);
+        if (r) free(r);
+    }
+    if (cannot_minimize < 0) {
+        r = xcb_get_property_reply(xcb_conn, xcb_cannot_minimize_cookie, 0);
+        if (r) free(r);
+    }
+    desktopView(false);  // free the reply if it has been requested
     if (meego_layer < 0) {
         r = xcb_get_property_reply(xcb_conn, xcb_meego_layer_cookie, 0);
         if (r) free(r);
@@ -196,6 +256,11 @@
         r = xcb_get_property_reply(xcb_conn, xcb_wm_protocols_cookie, 0);
         if (r) free(r);
     }
+    if (custom_region_request_fired) {
+        r = xcb_get_property_reply(xcb_conn, xcb_custom_region_cookie, 0);
+        if (r) free(r);
+    } 
+    if (custom_region) delete custom_region;
     if (wm_state_query)
         windowState();
     if (!icon_geometry_valid)
@@ -286,6 +351,44 @@
     return shape_region;
 }
 
+const QRegion &MWindowPropertyCache::customRegion(bool request_only)
+{
+    if (!is_valid) {
+        if (!custom_region) custom_region = new QRegion(0, 0, 0, 0);
+        return *custom_region;
+    }
+    if (request_only || (!custom_region && !custom_region_request_fired)) {
+        if (custom_region_request_fired)
+            customRegion(false); // free the old reply
+        xcb_custom_region_cookie = xcb_get_property(xcb_conn, 0, window,
+                                         ATOM(_MEEGOTOUCH_CUSTOM_REGION),
+                                         XCB_ATOM_CARDINAL, 0, 10 * 4);
+        custom_region_request_fired = true;
+    }
+    if (!request_only && custom_region_request_fired) {
+        xcb_get_property_reply_t *r;
+        r = xcb_get_property_reply(xcb_conn, xcb_custom_region_cookie, 0);
+        custom_region_request_fired = false;
+        if (custom_region)
+            delete custom_region;
+        custom_region = new QRegion(0, 0, 0, 0);
+        if (r) {
+            int len = xcb_get_property_value_length(r);
+            if (len >= (int)sizeof(CARD32) * 4) {
+                int n = len / sizeof(CARD32) / 4;
+                CARD32 *p = (CARD32*)xcb_get_property_value(r);
+                for (int i = 0; i < n; ++i) {
+                     int j = i * 4;
+                     QRect tmp(p[j], p[j + 1], p[j + 2], p[j + 3]);
+                     *custom_region += tmp;
+                }
+            }
+            free(r);
+        }
+    }
+    return *custom_region;
+}
+
 Window MWindowPropertyCache::transientFor()
 {
     if (is_valid && transient_for == (Window)-1) {
@@ -299,11 +402,84 @@
             free(r);
             if (transient_for == window)
                 transient_for = 0;
-        }
+            if (transient_for) {
+                MCompositeManager *m = (MCompositeManager*)qApp;
+                // add reference to the "parent"
+                MWindowPropertyCache *p = m->d->prop_caches.value(
+                                                        transient_for, 0);
+                if (p) p->transients.append(window);
+                // need to check stacking again to make sure the "parent" is
+                // stacked according to the changed transient window list
+                m->d->dirtyStacking(false);
+            }
+        } else
+            transient_for = 0;
     }
     return transient_for;
 }
 
+int MWindowPropertyCache::cannotMinimize()
+{
+    if (is_valid && cannot_minimize < 0) {
+        xcb_get_property_reply_t *r;
+        r = xcb_get_property_reply(xcb_conn, xcb_cannot_minimize_cookie, 0);
+        if (r) {
+            if (xcb_get_property_value_length(r) == sizeof(CARD32))
+                cannot_minimize = *((CARD32*)xcb_get_property_value(r));
+            else
+                cannot_minimize = 0;
+            free(r);
+        } else
+            cannot_minimize = 0;
+    }
+    return cannot_minimize;
+}
+
+int MWindowPropertyCache::alwaysMapped()
+{
+    if (is_valid && always_mapped < 0) {
+        xcb_get_property_reply_t *r;
+        r = xcb_get_property_reply(xcb_conn, xcb_always_mapped_cookie, 0);
+        if (r) {
+            if (xcb_get_property_value_length(r) == sizeof(CARD32))
+                always_mapped = *((CARD32*)xcb_get_property_value(r));
+            else
+                always_mapped = 0;
+            free(r);
+        } else
+            always_mapped = 0;
+    }
+    return always_mapped;
+}
+
+int MWindowPropertyCache::desktopView(bool request_only)
+{
+    static bool request_fired = false;
+    static xcb_get_property_cookie_t c;
+    if (is_valid && request_only) {
+        if (request_fired)
+            // free the old reply
+            desktopView(false);
+        c = xcb_get_property(xcb_conn, 0, window,
+                             ATOM(_MEEGOTOUCH_DESKTOP_VIEW),
+                             XCB_ATOM_CARDINAL, 0, 1);
+        request_fired = true;
+    } else if (is_valid && request_fired) {
+        xcb_get_property_reply_t *r;
+        r = xcb_get_property_reply(xcb_conn, c, 0);
+        if (r) {
+            if (xcb_get_property_value_length(r) == sizeof(CARD32))
+                desktop_view = *((CARD32*)xcb_get_property_value(r));
+            else
+                desktop_view = -1;
+            free(r);
+        } else
+            desktop_view = -1;
+        request_fired = false;
+    }
+    return desktop_view;
+}
+
 bool MWindowPropertyCache::isDecorator()
 {
     if (is_valid && is_decorator < 0) {
@@ -334,6 +510,9 @@
         }
     }
     if (meego_layer > 6) meego_layer = 6;
+    if (meego_layer == 1 || meego_layer == 2)
+        // these (screen/device lock) cannot be iconified by default
+        dont_iconify = true;
     return (unsigned)meego_layer;
 }
 
@@ -389,11 +568,36 @@
         if (transient_for == (Window)-1)
             // collect the old reply
             transientFor();
+        if (transient_for && transient_for != (Window)-1) {
+            MCompositeManager *m = (MCompositeManager*)qApp;
+            // remove reference from the old "parent"
+            MWindowPropertyCache *p = m->d->prop_caches.value(transient_for, 0);
+            if (p) p->transients.removeAll(window);
+        }
         transient_for = (Window)-1;
         xcb_transient_for_cookie = xcb_get_property(xcb_conn, 0, window,
                                                     XCB_ATOM_WM_TRANSIENT_FOR,
                                                     XCB_ATOM_WINDOW, 0, 1);
         return true;
+    } else if (e->atom == ATOM(_MEEGOTOUCH_ALWAYS_MAPPED)) {
+        if (always_mapped < 0)
+            // collect the old reply
+            alwaysMapped();
+        always_mapped = -1;
+        xcb_always_mapped_cookie = xcb_get_property(xcb_conn, 0, window,
+                                           ATOM(_MEEGOTOUCH_ALWAYS_MAPPED),
+                                           XCB_ATOM_CARDINAL, 0, 1);
+        emit alwaysMappedChanged(this);
+    } else if (e->atom == ATOM(_MEEGOTOUCH_CANNOT_MINIMIZE)) {
+        if (cannot_minimize < 0)
+            // collect the old reply
+            cannotMinimize();
+        cannot_minimize = -1;
+        xcb_cannot_minimize_cookie = xcb_get_property(xcb_conn, 0, window,
+                                           ATOM(_MEEGOTOUCH_CANNOT_MINIMIZE),
+                                           XCB_ATOM_CARDINAL, 0, 1);
+    } else if (e->atom == ATOM(_MEEGOTOUCH_DESKTOP_VIEW)) {
+        emit desktopViewChanged(this);
     } else if (e->atom == ATOM(WM_HINTS)) {
         if (!wmhints)
             // collect the old reply
@@ -419,6 +623,7 @@
         xcb_icon_geom_cookie = xcb_get_property(xcb_conn, 0, window,
                                             ATOM(_NET_WM_ICON_GEOMETRY),
                                             XCB_ATOM_CARDINAL, 0, 4);
+        emit iconGeometryUpdated();
     } else if (e->atom == ATOM(_MEEGOTOUCH_GLOBAL_ALPHA)) {
         if (global_alpha < 0)
             // collect the old reply
@@ -443,8 +648,7 @@
         xcb_decor_buttons_cookie = xcb_get_property(xcb_conn, 0, window,
                                        ATOM(_MEEGOTOUCH_DECORATOR_BUTTONS),
                                        XCB_ATOM_CARDINAL, 0, 8);
-        // TODO: could be based on a signal
-        return true;
+        emit meegoDecoratorButtonsChanged(window);
     } else if (e->atom == ATOM(WM_PROTOCOLS)) {
         if (!wm_protocols_valid)
             // collect the old reply
@@ -477,7 +681,12 @@
         xcb_meego_layer_cookie = xcb_get_property(xcb_conn, 0, window,
                                                   ATOM(_MEEGO_STACKING_LAYER),
                                                   XCB_ATOM_CARDINAL, 0, 1);
+        // raise it so that it becomes on top of same-leveled windows
+        MCompositeManager *m = (MCompositeManager*)qApp;
+        m->d->positionWindow(window, true);
         return true;
+    } else if (e->atom == ATOM(_MEEGOTOUCH_CUSTOM_REGION)) {
+        emit customRegionChanged(this);
     }
     return false;
 }
@@ -490,7 +699,8 @@
         if (r && (unsigned)xcb_get_property_value_length(r) >= sizeof(CARD32))
             window_state = ((CARD32*)xcb_get_property_value(r))[0];
         else {
-            window_state = NormalState;
+            // mark it so that MCompositeManagerPrivate::setWindowState sets it
+            window_state = -1;
         }
         if (r) free(r);
         wm_state_query = false;
@@ -613,7 +823,6 @@
     return icon_geometry;
 }
 
-#define OPAQUE 0xffffffff
 int MWindowPropertyCache::alphaValue(xcb_get_property_cookie_t c)
 {
     xcb_get_property_reply_t *r;
@@ -626,9 +835,11 @@
         free(r);
         return 255;
     }
-    CARD32 i = *((CARD32*)xcb_get_property_value(r));
-    double opacity = i * 1.0 / OPAQUE;
-    return opacity * 255;
+
+    /* Map 0..0xFFFFFFFF -> 0..0xFF. */
+    int ret = *(CARD32*)xcb_get_property_value(r) >> 24;
+    free(r);
+    return ret;
 }
 
 int MWindowPropertyCache::globalAlpha()
@@ -637,7 +848,6 @@
         return global_alpha;
     
     global_alpha = alphaValue(xcb_global_alpha_cookie);
-
     return global_alpha;
 }
 
@@ -697,3 +907,19 @@
     return window_type;
 }
 
+// MWindowDummyPropertyCache
+MWindowDummyPropertyCache *MWindowDummyPropertyCache::singleton;
+
+MWindowDummyPropertyCache *MWindowDummyPropertyCache::get()
+{
+    if (!singleton)
+        singleton = new MWindowDummyPropertyCache();
+    return singleton;
+}
+
+bool MWindowDummyPropertyCache::event(QEvent *e)
+{
+    // Ignore deleteLater().
+    return e->type() == QEvent::DeferredDelete
+        ? true : MWindowPropertyCache::event(e);
+}
--- src/mwindowpropertycache.h
+++ src/mwindowpropertycache.h
@@ -20,24 +20,29 @@
 #ifndef MWINDOWPROPERTYCACHE_H
 #define MWINDOWPROPERTYCACHE_H
 
+#include <QRegion>
+#include <QX11Info>
 #include <X11/Xutil.h>
 #include <X11/Xlib-xcb.h>
 #include <xcb/render.h>
 #include <xcb/shape.h>
 #include <X11/extensions/shape.h>
+#include <X11/extensions/Xdamage.h>
 #include "mcompatoms_p.h"
-#include <QRegion>
 
 /*!
  * This is a class for caching window property values for a window.
  */
 class MWindowPropertyCache: public QObject
 {
+    Q_OBJECT
 public:
 
     /*! Construct a MWindowPropertyCache
      * \param window id to the window whose properties are cached
+     *        Without one constructs a placeholder object.
      */
+    MWindowPropertyCache();
     MWindowPropertyCache(Window window,
                          xcb_get_window_attributes_reply_t *attrs = 0,
                          xcb_get_geometry_reply_t *geom = 0);
@@ -93,6 +98,7 @@
                                                           ShapeBounding);
     }
 
+    Window winId() const { return window; }
     Window parentWindow() const { return parent_window; }
     void setParentWindow(Window w) { parent_window = w; }
 
@@ -121,6 +127,11 @@
      */
     const QList<Atom>& netWmState();
 
+    /*!
+     * Returns list of transients of the window.
+     */
+    const QList<Window>& transientWindows() const { return transients; }
+
     // used to set the atom list now, for immediate effect in e.g. stacking
     void setNetWmState(const QList<Atom>& s) {
         if (!is_valid)
@@ -139,6 +150,14 @@
     bool beingMapped() const { return being_mapped; }
     void setBeingMapped(bool s) { being_mapped = s; }
 
+    /*!
+     * Used for special windows that should not be minimised/iconified.
+     */
+    bool dontIconify() {
+        return cannotMinimize() > 0 || dont_iconify;
+    }
+    void setDontIconify(bool s) { dont_iconify = s; }
+
     bool isMapped() const {
         if (!is_valid || !attrs)
             return false;
@@ -152,7 +171,7 @@
         if (s)
             attrs->map_state = XCB_MAP_STATE_VIEWABLE;
         else
-            attrs->map_state = XCB_MAP_STATE_UNVIEWABLE;
+            attrs->map_state = XCB_MAP_STATE_UNMAPPED;
     }
 
     /*!
@@ -193,6 +212,26 @@
     unsigned int meegoStackingLayer();
 
     /*!
+     * Returns value of _MEEGOTOUCH_ALWAYS_MAPPED.
+     */
+    int alwaysMapped();
+
+    /*!
+     * Returns value of _MEEGOTOUCH_CANNOT_MINIMIZE.
+     */
+    int cannotMinimize();
+
+    /*!
+     * Returns value of _MEEGOTOUCH_DESKTOP_VIEW (makes sense for desktop only).
+     */
+    int desktopView(bool request_only = false);
+
+    /*!
+     * Returns value of _MEEGOTOUCH_CUSTOM_REGION.
+     */
+    const QRegion &customRegion(bool request_only = false);
+
+    /*!
      * Called on PropertyNotify for this window.
      * Returns true if we should re-check stacking order.
      */
@@ -210,12 +249,35 @@
         MWindowPropertyCache::xcb_conn = c;
     }
 
+    void damageTracking(bool enabled)
+    {
+        if (damage_object && enabled)
+            return;
+        if (damage_object && !enabled) {
+            XDamageDestroy(QX11Info::display(), damage_object);
+            damage_object = 0;
+        }
+        else if (enabled && !damage_object && !isInputOnly())
+            damage_object = XDamageCreate(QX11Info::display(), window,
+                                          XDamageReportNonEmpty); 
+    }
+
+signals:
+    void iconGeometryUpdated();
+    void meegoDecoratorButtonsChanged(Window w);
+    void desktopViewChanged(MWindowPropertyCache *pc);
+    void alwaysMappedChanged(MWindowPropertyCache *pc);
+    void customRegionChanged(MWindowPropertyCache *pc);
+
 private:
+    void init();
+    void init_invalid();
     int alphaValue(xcb_get_property_cookie_t c);
     void buttonGeometryHelper();
 
     Atom window_type_atom;
     Window transient_for;
+    QList<Window> transients;
     QList<Atom> wm_protocols;
     bool wm_protocols_valid;
     bool icon_geometry_valid;
@@ -237,7 +299,10 @@
     int meego_layer, window_state;
     MCompAtoms::Type window_type;
     Window window, parent_window;
-    bool being_mapped;
+    int always_mapped, cannot_minimize, desktop_view;
+    bool being_mapped, dont_iconify;
+    QRegion *custom_region;
+    bool custom_region_request_fired;
     // geometry is requested only once in the beginning, after that, we
     // use ConfigureNotifys to update the size through setRealGeometry()
     xcb_get_geometry_reply_t *xcb_real_geom;
@@ -254,11 +319,27 @@
     xcb_get_property_cookie_t xcb_global_alpha_cookie;
     xcb_get_property_cookie_t xcb_video_global_alpha_cookie;
     xcb_get_property_cookie_t xcb_net_wm_state_cookie;
+    xcb_get_property_cookie_t xcb_always_mapped_cookie;
+    xcb_get_property_cookie_t xcb_cannot_minimize_cookie;
+    xcb_get_property_cookie_t xcb_custom_region_cookie;
     xcb_render_query_pict_formats_cookie_t xcb_pict_formats_cookie;
     xcb_shape_get_rectangles_cookie_t xcb_shape_rects_cookie;
     QRegion shape_region;
 
     static xcb_connection_t *xcb_conn;
+    Damage damage_object;
+};
+
+// Non-deletable dummy MWindowPropertyCache.
+class MWindowDummyPropertyCache: public MWindowPropertyCache
+{
+public:
+    static MWindowDummyPropertyCache *get();
+
+private:
+    virtual bool event(QEvent *e);
+
+    static MWindowDummyPropertyCache *singleton;
 };
 
 #endif
--- src/src.pro
+++ src/src.pro
@@ -2,26 +2,25 @@
 
 contains(QT_CONFIG, opengles2) {
      message("building Makefile for EGL/GLES2 version")
-     DEFINES += GLES2_VERSION
-     SOURCES += mtexturepixmapitem_egl.cpp
+     SOURCES += mtexturepixmapitem_egl.cpp mcompositewindowgroup.cpp
+     HEADERS += mcompositewindowgroup.h
+     publicHeaders.files +=  mcompositewindowgroup.h
 } else {
      # Qt wasn't built with EGL/GLES2 support but EGL is present
      # ensure we still use the EGL back-end 
      exists($$QMAKE_INCDIR_OPENGL/EGL) {
          message("building Makefile for EGL/GLES2 version")
-         DEFINES += GLES2_VERSION
          SOURCES += mtexturepixmapitem_egl.cpp
          LIBS += -lEGL
      } 
      # Otherwise use GLX backend
      else {
          message("building Makefile for GLX version")
-         DEFINES += DESKTOP_VERSION
          SOURCES += mtexturepixmapitem_glx.cpp
      }
 } 
 
-TEMPLATE = app
+TEMPLATE = lib
 TARGET = mcompositor
 DEPENDPATH += .
 QT += dbus
@@ -30,6 +29,7 @@
 INCLUDEPATH += ../decorators/libdecorator/
 HEADERS += \
     mtexturepixmapitem.h \
+    mtexturepixmapitem_p.h \
     mcompositescene.h \
     mcompositewindow.h \
     mwindowpropertycache.h \
@@ -39,10 +39,12 @@
     mcompositemanager_p.h \
     mdevicestate.h \
     mcompatoms_p.h \
-    mdecoratorframe.h
+    mdecoratorframe.h \
+    mcompositemanagerextension.h \
+    mcompositewindowshadereffect.h \
+    mcompmgrextensionfactory.h
 
 SOURCES += \
-    main.cpp \
     mtexturepixmapitem_p.cpp \
     mcompositescene.cpp \
     mcompositewindow.cpp \
@@ -51,7 +53,9 @@
     mcompositemanager.cpp \
     msimplewindowframe.cpp \
     mdevicestate.cpp \
-    mdecoratorframe.cpp
+    mdecoratorframe.cpp \
+    mcompositemanagerextension.cpp \
+    mcompositewindowshadereffect.cpp
 
 RESOURCES = tools.qrc
 
@@ -59,11 +63,22 @@
 PKGCONFIG += contextsubscriber-1.0
 QT += core gui opengl
 
-target.path += $$M_INSTALL_BIN
+# TODO: refactor the headers to exclude private stuff
+publicHeaders.files += mcompositewindow.h \
+                      mcompositemanager.h \
+                      mcompositewindowshadereffect.h \
+                      mcompositemanagerextension.h \
+                      mwindowpropertycache.h \
+                      mcompatoms_p.h \
+                      mcompmgrextensionfactory.h
+publicHeaders.path = $$M_INSTALL_HEADERS/mcompositor
+INSTALLS += publicHeaders
+
+target.path += /usr/lib
 INSTALLS += target 
 
 LIBS += -lXdamage -lXcomposite -lXfixes -lX11-xcb -lxcb-render -lxcb-shape \
-        ../decorators/libdecorator/libdecorator.so
+        -lXrandr ../decorators/libdecorator/libdecorator.so
 
 QMAKE_EXTRA_TARGETS += check
 check.depends = $$TARGET
--- src/texturepixmapshaders.h
+++ src/texturepixmapshaders.h
@@ -40,6 +40,15 @@
             gl_FragColor = texture2D(texture, fragTexCoord) * opacity; \
     }";
 
+static const char* TexpCustomShaderSource = "\
+    varying highp vec2 fragTexCoord;\n\
+    uniform lowp sampler2D texture;\n\
+    uniform lowp float opacity;\n\
+    void main(void) \n\
+    {\n\
+            gl_FragColor = customShader(texture, fragTexCoord) * opacity; \n\
+    }\n\n";
+
 
 #if 0
 static const char *AlphaTestFragShaderSource = "\
--- tests/functional/createTestXml
+++ tests/functional/createTestXml
@@ -60,7 +60,12 @@
     BNAME=${CASEFILE}.testdata
     if [ -e $BNAME ]; then
         . ./$BNAME
-        TESTCASE_TEMPLATE="\t\t\t<case name=\"$CaseName\" description=\"$CaseDescription\" requirement=\"$CaseRequirement\" timeout=\"$CaseTimeout\">\n\t\t\t\t<step expected_result=\"0\">$INSTALL_PATH/$CASEFILE</step>\n\t\t\t</case>\n"
+        if [ x$CaseInsignificant != x ]; then
+            TESTCASE_TEMPLATE="\t\t\t<case name=\"$CaseName\" description=\"$CaseDescription\" requirement=\"$CaseRequirement\" timeout=\"$CaseTimeout\" insignificant=\"$CaseInsignificant\">\n\t\t\t\t<step expected_result=\"0\">$INSTALL_PATH/$CASEFILE</step>\n\t\t\t</case>\n"
+        else
+            TESTCASE_TEMPLATE="\t\t\t<case name=\"$CaseName\" description=\"$CaseDescription\" requirement=\"$CaseRequirement\" timeout=\"$CaseTimeout\">\n\t\t\t\t<step expected_result=\"0\">$INSTALL_PATH/$CASEFILE</step>\n\t\t\t</case>\n"
+        fi
+      unset CaseInsignificant
       TESTCASES="${TESTCASES}${TESTCASE_TEMPLATE}"
     fi
 done
--- tests/functional/functional.pro
+++ tests/functional/functional.pro
@@ -1,6 +1,6 @@
 TEMPLATE=subdirs
 
-QMAKE_EXTRA_TARGETS += metadata 
+QMAKE_EXTRA_TARGETS += metadata initScript
 XMLLINT= xmllint --noout --schema /usr/share/test-definition/testdefinition-syntax.xsd --schema /usr/share/test-definition/testdefinition-tm_terms.xsd 
 
 SUITENAME=mcompositor-functional-tests
@@ -20,5 +20,7 @@
 
 metadata.CONFIG += no_check_exist
 
-INSTALLS += metadata scripts
+initScript.files = mcompositor-test-init.py
+initScript.path = /usr/bin
 
+INSTALLS += metadata scripts initScript
--- tests/functional/mcompositor-test-init.py
+++ tests/functional/mcompositor-test-init.py
+#!/usr/bin/python
+# Common initialisation commands for each test.
+
+import os, sys
+
+if os.system('/sbin/mcetool --unblank-screen --set-tklock-mode=unlocked --set-inhibit-mode=stay-on'):
+  print 'mcetool is missing!'
+
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled false'):
+  print 'cannot disable notifications'
+
+if os.system('pidof mcompositor'):
+  print 'mcompositor is not running'
+  sys.exit(1)
+
+os.system('aegis-su -o com.nokia.maemo -n /usr/bin/windowstack')
+os.system('aegis-su -o com.nokia.maemo -n /usr/bin/windowctl')
+
+if os.system('windowstack m | grep mdecorator'):
+  print 'mdecorator is not mapped!'
+  sys.exit(1)
+
+os.system('uptime')
--- tests/functional/test0.py
+++ tests/functional/test0.py
@@ -10,15 +10,7 @@
 
 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)
-
-if os.system('windowstack m | grep mdecorator'):
-  print 'mdecorator is not mapped!'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowctl kn')
@@ -51,4 +43,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test1.py
+++ tests/functional/test1.py
@@ -10,11 +10,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowctl kn')
@@ -47,4 +43,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test10.py
+++ tests/functional/test10.py
@@ -14,11 +14,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowstack m')
@@ -94,4 +90,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test11.py
+++ tests/functional/test11.py
@@ -13,11 +13,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowstack m')
@@ -71,4 +67,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test12.py
+++ tests/functional/test12.py
@@ -15,11 +15,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowctl kn')
@@ -106,4 +102,8 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
+
 sys.exit(ret)
--- tests/functional/test13.py
+++ tests/functional/test13.py
@@ -10,11 +10,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 def get_window_size(w):
@@ -29,7 +25,8 @@
       break
   return ret
 
-(fs_w, fs_h) = (864, 480)
+(fs_w, fs_h) = [ int(x) for x in os.popen("windowctl D").readline().split() ]
+
 
 # map non-fullscreen application window
 fd = os.popen('windowctl n')
@@ -53,4 +50,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test14.py
+++ tests/functional/test14.py
@@ -11,11 +11,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 def get_window_size(w):
@@ -30,7 +26,7 @@
       break
   return ret
 
-(fs_w, fs_h) = (864, 480)
+(fs_w, fs_h) = [ int(x) for x in os.popen("windowctl D").readline().split() ]
 
 # map fullscreen application window
 fd = os.popen('windowctl fn')
@@ -54,4 +50,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test15.py
+++ tests/functional/test15.py
@@ -17,11 +17,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 ret = 0
@@ -74,4 +70,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test16.py
+++ tests/functional/test16.py
@@ -9,11 +9,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowstack m')
@@ -51,4 +47,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test17.py
+++ tests/functional/test17.py
@@ -38,11 +38,7 @@
     print fd.read(5000)
     ret = 1
 
-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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowstack m')
@@ -94,4 +90,7 @@
 time.sleep(1)
 check_focus(home_win)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test18.py
+++ tests/functional/test18.py
@@ -18,11 +18,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 ret = 0
@@ -103,4 +99,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test19.py
+++ tests/functional/test19.py
@@ -14,11 +14,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowstack m')
@@ -84,4 +80,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test2.py
+++ tests/functional/test2.py
@@ -10,11 +10,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 # create two dialogs
@@ -41,4 +37,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test20.py
+++ tests/functional/test20.py
@@ -14,11 +14,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowstack m')
@@ -57,7 +53,7 @@
 
 # simulate a phone call
 fd = os.popen('windowctl P')
-time.sleep(3)
+time.sleep(15)
 
 # create a fullscreen application window
 fd = os.popen('windowctl fn')
@@ -81,4 +77,7 @@
 os.popen('pkill context-provide')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test20.py.testdata
+++ tests/functional/test20.py.testdata
@@ -1,6 +1,7 @@
 CaseName="jammed_and_fullscreen_app_during_call_are_decorated"
 CaseRequirement="NONE"
 CaseTimeout="360"
+CaseInsignificant=true
 CaseDescription="Check that jammed and (during call) fullscreen apps are decorated.\n
 \n
 - Test steps\n
--- tests/functional/test21.py
+++ tests/functional/test21.py
+#!/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('mcompositor-test-init.py'):
+  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
+  elif not re.search(" no-TYPE ", l.strip()):
+    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'
+  elif not re.search(" no-TYPE ", l.strip()):
+    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)
--- tests/functional/test21.py.testdata
+++ tests/functional/test21.py.testdata
+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"
--- tests/functional/test22.py
+++ tests/functional/test22.py
+#!/usr/bin/python
+
+# Some tests for correct WM_STATE setting (Qt is very fond of it).
+
+#* Test steps
+#  * map an application window
+#  * check that it is in Normal state
+#  * minimise the application window
+#  * check that it is in Iconic state
+#  * maximise the application window
+#  * check that it is in Normal state
+#  * unmap the application window
+#  * check that it is in Withdrawn state
+#  * map the application window
+#* Post-conditions
+#  * check that it is in Normal state and stacked on top
+
+import os, re, sys, time
+
+if os.system('mcompositor-test-init.py'):
+  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()
+
+if home_win == 0:
+  print 'FAIL: desktop not found'
+  sys.exit(1)
+
+# create an application window
+fd = os.popen('windowctl kne')
+app = fd.readline().strip()
+time.sleep(1)
+
+ret = 0
+fd = os.popen("xprop -id %s | grep 'window state' | awk '{print $3}'" % app)
+if fd.readline().strip() != 'Normal':
+  print 'FAIL: app is not in Normal state after mapping it'
+  ret = 1
+
+# minimise the application window
+os.popen("windowctl A %s" % home_win)
+time.sleep(1)
+
+fd = os.popen("xprop -id %s | grep 'window state' | awk '{print $3}'" % app)
+if fd.readline().strip() != 'Iconic':
+  print 'FAIL: app is not in Iconic state'
+  ret = 1
+
+# maximise the application window
+os.popen("windowctl A %s" % app)
+time.sleep(1)
+
+fd = os.popen("xprop -id %s | grep 'window state' | awk '{print $3}'" % app)
+if fd.readline().strip() != 'Normal':
+  print 'FAIL: app is not in Normal state after maximising it'
+  ret = 1
+
+# unmap the application window
+os.popen("windowctl U %s" % app)
+time.sleep(1)
+
+fd = os.popen("xprop -id %s | grep 'window state' | awk '{print $3}'" % app)
+if fd.readline().strip() != 'Withdrawn':
+  print 'FAIL: app is not in Withdrawn state after unmapping it'
+  ret = 1
+
+# map the application window
+os.popen("windowctl M %s" % app)
+time.sleep(1)
+
+fd = os.popen("xprop -id %s | grep 'window state' | awk '{print $3}'" % app)
+if fd.readline().strip() != 'Normal':
+  print 'FAIL: app is not in Normal state after re-mapping it'
+  ret = 1
+
+# check the application window is on top
+fd = os.popen('windowstack m')
+s = fd.read(5000)
+for l in s.splitlines():
+  if re.search('%s ' % home_win, l.strip()):
+    print 'FAIL: app is not on top'
+    print 'Failed stack:\n', s
+    ret = 1
+    break
+  elif re.search("%s " % app, l.strip()):
+    print app, 'found'
+    break
+
+# cleanup
+os.popen('pkill windowctl')
+time.sleep(1)
+
+sys.exit(ret)
--- tests/functional/test22.py.testdata
+++ tests/functional/test22.py.testdata
+CaseName="WM_STATE_setting"
+CaseRequirement="NONE"
+CaseTimeout="360"
+CaseDescription="Some tests for correct WM_STATE setting.\n
+\n
+- Test steps\n
+\t- map an application window\n
+\t- check that it is in Normal state\n
+\t- minimise the application window\n
+\t- check that it is in Iconic state\n
+\t- maximise the application window\n
+\t- check that it is in Normal state\n
+\t- unmap the application window\n
+\t- check that it is in Withdrawn state\n
+\t- map the application window\n
+- Post-conditions\n
+\t- check that it is in Normal state and stacked on top\n"
--- tests/functional/test3.py
+++ tests/functional/test3.py
@@ -10,11 +10,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowctl kn')
@@ -70,4 +66,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test4.py
+++ tests/functional/test4.py
@@ -10,11 +10,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowctl an')
@@ -41,4 +37,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test5.py
+++ tests/functional/test5.py
@@ -11,11 +11,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 # create two dialogs
@@ -51,4 +47,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test6.py
+++ tests/functional/test6.py
@@ -12,11 +12,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 def rotate_screen(top_edge):
@@ -80,4 +76,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test7.py
+++ tests/functional/test7.py
@@ -14,11 +14,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 # create notification, app, dialog, and input windows
@@ -62,4 +58,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test8.py
+++ tests/functional/test8.py
@@ -11,16 +11,18 @@
 #  * check that the transient is above the application window
 #  * iconify the application window
 #  * activate the transient window
-#* Post-conditions
 #  * check that the transient is above the application window
+#  * create and show a dialog window that is transient for the previous dialog
+#  * iconify the application window
+#  * activate the application window
+#  * check that both transients are above the application window and in order
+#  * swap the transiencies of the dialogs
+#* Post-conditions
+#  * check that both transients are above the application window and in order
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 fd = os.popen('windowstack m')
@@ -101,8 +103,90 @@
     ret = 1
     break
 
+# create a dialog that is transient to the first dialog
+fd = os.popen("windowctl kd %s" % new_win)
+new_dialog = fd.readline().strip()
+time.sleep(1)
+
+# iconify the application
+os.popen("windowctl O %s" % old_win)
+time.sleep(2)
+
+# activate the application (this should raise the dialogs too)
+os.popen("windowctl A %s" % old_win)
+time.sleep(1)
+
+new_dialog_found = new_win_found = 0
+fd = os.popen('windowstack m')
+s = fd.read(5000)
+for l in s.splitlines():
+  if re.search("%s " % new_dialog, l.strip()):
+    print new_dialog, 'found'
+    new_dialog_found = 1
+  elif re.search("%s " % new_win, l.strip()) and new_dialog_found:
+    print new_win, 'found'
+    new_win_found = 1
+  elif re.search("%s " % new_win, l.strip()):
+    print 'FAIL: old dialog is stacked before new dialog'
+    print 'Failed stack:\n', s
+    ret = 1
+    break
+  elif re.search("%s " % home_win, l.strip()):
+    print 'FAIL: home is stacked before app'
+    print 'Failed stack:\n', s
+    ret = 1
+    break
+  elif re.search("%s " % old_win, l.strip()) and new_dialog_found \
+       and new_win_found:
+    print old_win, 'found'
+    break
+  elif re.search("%s " % old_win, l.strip()):
+    print 'FAIL: app is stacked before a transient dialog'
+    print 'Failed stack:\n', s
+    ret = 1
+    break
+
+# swap the transiencies of the dialogs
+# (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
+fd = os.popen('windowstack m')
+s = fd.read(5000)
+for l in s.splitlines():
+  if re.search("%s " % new_win, l.strip()):
+    print new_win, 'found'
+    new_win_found = 1
+  elif re.search("%s " % new_dialog, l.strip()) and new_win_found:
+    print new_dialog, 'found'
+    new_dialog_found = 1
+  elif re.search("%s " % new_dialog, l.strip()):
+    print 'FAIL: lower dialog is stacked before the upper dialog'
+    print 'Failed stack:\n', s
+    ret = 1
+    break
+  elif re.search("%s " % home_win, l.strip()):
+    print 'FAIL: home is stacked before app'
+    print 'Failed stack:\n', s
+    ret = 1
+    break
+  elif re.search("%s " % old_win, l.strip()) and new_dialog_found \
+       and new_win_found:
+    print old_win, 'found'
+    break
+  elif re.search("%s " % old_win, l.strip()):
+    print 'FAIL: app is stacked before a transient dialog'
+    print 'Failed stack:\n', s
+    ret = 1
+    break
+
 # cleanup
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/functional/test8.py.testdata
+++ tests/functional/test8.py.testdata
@@ -12,5 +12,11 @@
 \t- check that the transient is above the application window\n
 \t- iconify the application window\n
 \t- activate the transient window\n
+\t- check that the transient is above the application window\n
+\t- create and show a dialog window that is transient for the previous dialog\n
+\t- iconify the application window\n
+\t- activate the application window\n
+\t- check that both transients are above the application window and in order\n
+\t- swap the transiencies of the dialogs\n
 - Post-conditions\n
-\t- check that the transient is above the application window\n"
+\t- check that both transients are above the application window and in order\n"
--- tests/functional/test9.py
+++ tests/functional/test9.py
@@ -13,11 +13,7 @@
 
 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'
+if os.system('mcompositor-test-init.py'):
   sys.exit(1)
 
 # create two application windows
@@ -81,4 +77,7 @@
 os.popen('pkill windowctl')
 time.sleep(1)
 
+if os.system('/usr/bin/gconftool-2 --type bool --set /desktop/meego/notifications/previews_enabled true'):
+  print 'cannot re-enable notifications'
+
 sys.exit(ret)
--- tests/windowctl/windowctl.cpp
+++ tests/windowctl/windowctl.cpp
@@ -22,8 +22,7 @@
 #include <signal.h>
 #include <sys/prctl.h>
 
-#define WIN_W 864
-#define WIN_H 480
+static int WIN_W, WIN_H;
 
 static Atom win_type_atom, trans_for_atom, workarea_atom;
 static int xerror_happened;
@@ -169,6 +168,15 @@
   XSync(dpy, False);
 }
 
+static void set_always_mapped (Display *dpy, Window w, int value)
+{
+  long data = value;
+  Atom a = XInternAtom (dpy, "_MEEGOTOUCH_ALWAYS_MAPPED", False);
+  XChangeProperty (dpy, w, a, XA_CARDINAL, 32, PropModeReplace,
+                   (unsigned char*)&data, 1);
+  XSync(dpy, False);
+}
+
 static void set_decorator_buttons (Display *dpy, Window w)
 {
   unsigned int data[8] = {0, 0, 100, 100,
@@ -179,6 +187,16 @@
   XSync(dpy, False);
 }
 
+static void set_mstatusbar_geom (Display *dpy, Window win, unsigned x,
+                                 unsigned y, unsigned w, unsigned h)
+{
+  unsigned int data[4] = {x, y, w, h};
+  Atom a = XInternAtom (dpy, "_MEEGOTOUCH_MSTATUSBAR_GEOMETRY", False);
+  XChangeProperty (dpy, win, a, XA_CARDINAL, 32, PropModeReplace,
+                   (unsigned char*)&data, 4);
+  XSync(dpy, False);
+}
+
 static void set_shaped (Display *dpy, Window w)
 {
   XRectangle rect = {250, 120, 300, 200};
@@ -288,7 +306,11 @@
                             visual,
                             attr_mask | CWColormap | CWBorderPixel, &attrs);
         } else {
-	  attrs.background_pixel = BlackPixel (dpy, 0);
+          XColor color;
+          if (!XParseColor(dpy, DefaultColormap(dpy, 0), "red", &color))
+              attrs.background_pixel = BlackPixel(dpy, 0);
+          else
+	      attrs.background_pixel = color.pixel;
           w = XCreateWindow(dpy, DefaultRootWindow (dpy), 0, 0,
                             width, height, 0, input_only ? 0 : CopyFromParent,
                             input_only ? InputOnly : InputOutput,
@@ -337,7 +359,7 @@
 static void print_usage_and_exit(QString& stdOut)
 {
 #define PROG "windowctl"
-  stdOut = "Usage 1: " PROG " [afoemksIchpl](n|d|i|b) [transient for <XID>]\n"
+  stdOut = "Usage 1: " PROG " [afoemksIchpl(j[12])](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"
@@ -350,6 +372,8 @@
          "h - set _MEEGOTOUCH_DECORATOR_BUTTONS for home and close buttons\n"
          "p - claim to support the _NET_WM_PING protocol (but don't)\n"
          "l - use InputOnly window class\n"
+         "j1 - set _MEEGOTOUCH_ALWAYS_MAPPED property to 1\n"
+         "j2 - set _MEEGOTOUCH_ALWAYS_MAPPED property to 2\n"
 	 "n - WM_TYPE_NORMAL window (if 'k' is given, that is the first type)\n"
 	 "d - WM_TYPE_DIALOG window\n"
 	 "i - WM_TYPE_INPUT window\n"
@@ -379,7 +403,17 @@
 	 "Usage 5: " PROG " K <name>\n"
 	 "K - run 'pkill <name>'\n"
 	 "Usage 6: " PROG " E [<XID>] (0-10)\n"
-	 "E - set _MEEGO_STACKING_LAYER of new window / window <XID> to 0-10\n";
+	 "E - set _MEEGO_STACKING_LAYER of new window / window <XID> to 0-10\n"
+	 "Usage 7: " PROG " J <XID> N\n"
+	 "J - set _MEEGOTOUCH_ALWAYS_MAPPED of window <XID> to N (>= 0)\n"
+	 "Usage 8: " PROG " X <XID> x y w h\n"
+         "X - set _MEEGOTOUCH_MSTATUSBAR_GEOMETRY of window <XID> to (x y w h)\n"
+	 "Usage 9: " PROG " CM <XID> <ClientMessage type name> <window>\n"
+	 "CM - send a ClientMessage (where window=<window>) to window <XID> "
+	 "(0 assumed that = the root window)\n"
+	 "Usage 10: " PROG " D\n"
+	 "D - print the display resolution\n"
+         ;
 }
 
 static void configure (Display *dpy, char *first, char *second, bool above)
@@ -608,10 +642,10 @@
 	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, initial_iconic = 0, no_focus = 0, support_ping = 0,
-            input_only = 0;
+            input_only = 0, always_mapped = -1;
 	WindowType windowtype = TYPE_INVALID;
 
-	if (args.count() < 1 || args.count() > 4) {
+	if (args.count() < 1 || args.count() > 6) {
 	  print_usage_and_exit(stdOut);
 	  return false;
 	}
@@ -624,6 +658,9 @@
         /* catch X errors */
         XSetErrorHandler (error_handler);
 
+        WIN_W = DisplayWidth(dpy, DefaultScreen(dpy));
+        WIN_H = DisplayHeight(dpy, DefaultScreen(dpy));
+
         win_type_atom = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
 	/*trans_for_atom = XInternAtom(dpy, "WM_TRANSIENT_FOR", False);*/
 	workarea_atom = XInternAtom(dpy, "_NET_WORKAREA", False);
@@ -761,6 +798,27 @@
 		    stdOut.append("execve() failed!");
                     return false;
                 }
+		if (*p == 'j') {
+                    if (*(p + 1) == '2') {
+                        always_mapped = 2;
+                        ++p;
+                    } else if (*(p + 1) == '1') {
+                        always_mapped = 1;
+                        ++p;
+                    } else {
+                        print_usage_and_exit(stdOut);
+                        return false;
+                    }
+                    continue;
+                }
+		if (*p == 'J') {
+                        if (args.count() == 3) {
+                                set_always_mapped(dpy,
+                                    strtol(args.at(1).toAscii().data(), 0, 16),
+                                    atoi(args.at(2).toAscii().data()));
+                                return true;
+                        }
+                }
 		if (*p == 'E') {
 			if (args.count() == 3) {
                                 set_meego_layer(dpy,
@@ -770,11 +828,45 @@
                         } else if (args.count() == 2) {
 			        meego_layer = atoi(args.at(1).toAscii().data());
                                 break;
-                        } else {
-	  			print_usage_and_exit(stdOut);
-				return false;
                         }
                 }
+		if (*p == 'X') {
+			if (args.count() == 6) {
+                                set_mstatusbar_geom(dpy,
+                                    strtol(args.at(1).toAscii().data(), 0, 16),
+                                    atoi(args.at(2).toAscii().data()),
+                                    atoi(args.at(3).toAscii().data()),
+                                    atoi(args.at(4).toAscii().data()),
+                                    atoi(args.at(5).toAscii().data()));
+                                return true;
+                        }
+                }
+		if (*p == 'C' && *(p + 1) == 'M') {
+                    if (args.count() != 4) {
+                        print_usage_and_exit(stdOut); return false;
+                    }
+                    Atom a = XInternAtom(dpy, args.at(2).toAscii().data(),
+                                         False);
+                    XEvent ev;
+                    memset(&ev, 0, sizeof(ev));
+                    ev.xclient.type = ClientMessage;
+                    ev.xclient.message_type = a;
+                    ev.xclient.window = strtol(args.at(3).toAscii().data(),
+                                               NULL, 16);
+                    ev.xclient.format = 32;
+                    Window w = strtol(args.at(1).toAscii().data(), NULL, 16);
+                    if (w == 0) {
+                        w = DefaultRootWindow(dpy); 
+                        XSendEvent(dpy, w, False, SubstructureRedirectMask, &ev);
+                    } else
+                        XSendEvent(dpy, w, False, NoEventMask, &ev);
+                    XSync(dpy, False);
+                    return true;
+                }
+                if (*p == 'D') {
+                    printf("%u %u\n", WIN_W, WIN_H);
+                    return true;
+                }
 		if ((command = strchr("NUFCMTAWHSO", *p))) {
 			if (args.count() != 2) {
 	  			print_usage_and_exit(stdOut);
@@ -811,6 +903,8 @@
 
         if (meego_layer >= 0)
                 set_meego_layer(dpy, w, meego_layer);
+        if (always_mapped >= 0)
+                set_always_mapped(dpy, w, always_mapped);
 
         if (decor_buttons) set_decorator_buttons(dpy, w);
         if (shaped) set_shaped(dpy, w);
@@ -922,6 +1016,14 @@
 		    /* our window was unmapped */
 	            exit(0);
                 }
+#if 0
+                else if (xev.type == ClientMessage) {
+                  XClientMessageEvent *e = (XClientMessageEvent*)&xev;
+                  printf("0x%lx: ClientMessage %d %ld %ld\n", w,
+                         e->message_type,
+                         e->data.l[0], e->data.l[1]);
+                }
+#endif
                 else if (xev.type == ConfigureNotify) {
                   /*XConfigureEvent *e = (XConfigureEvent*)&xev;*/
                 }

++++++ meegotouch-compositor.yaml
--- meegotouch-compositor.yaml
+++ meegotouch-compositor.yaml
@@ -1,20 +1,17 @@
 Name: meegotouch-compositor
 Summary: MeeGo UI Compositing Window Manager
-Version: 0.5.8
+Version: 0.8.0
 Release: 1
 Group: System/Desktop
 License: LGPLv2.1
 URL: http://meego.gitorious.org/meegotouch/meegotouch-compositor
 Sources:
-    - "%{name}-%{version}.tar.bz2"
-    - mdecorator.desktop
+    - "%{name}-%{version}.tar.gz"
 Patches:
     - add_Xext_lib_to_windowctl.patch
     - fix_test_compile_issues.patch
     - fix_build_on_ARM.patch
     - initialize_EGL_library.patch
-    - mcompositor-black-screen-gtk.patch
-    - re-add_fallback_when_Image_extension_is_not_available.patch
 Description: |
     This package contains the Direct UI compositing window manager.
 PkgConfigBR:
@@ -22,13 +19,13 @@
     - QtNetwork
     - QtOpenGL
     - contextprovider-1.0
-    - gl
     - meegotouch
     - x11
     - xcomposite
     - xdamage
     - xext
     - xrender
+    - xrandr
 Provides:
     - duicompositor >= 0.3.9
     - mcompositor >= 0.4.6
@@ -37,6 +34,8 @@
     - mcompositor < 0.4.6
 Configure: none
 Builder: qmake
+ExtraSources:
+    - mdecorator.desktop;%{_sysconfdir}/xdg/autostart
 SubPackages:
     - Name: devel
       Summary: Development files for building mcompositor decorators

++++++ deleted files:
--- mcompositor-black-screen-gtk.patch
--- re-add_fallback_when_Image_extension_is_not_available.patch




More information about the MeeGo-commits mailing list