[meego-commits] 14872: Changes to Trunk/meegotouch-home

Ulf Hofemeier no_reply at build.meego.com
Wed Mar 16 13:35:43 UTC 2011


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

Thank You,
Ulf Hofemeier

[This message was auto-generated]

---

Request #14872:

  submit:   Trunk:Testing/meegotouch-home(r2) -> Trunk/meegotouch-home


Message:
    * Thu Mar 01 2011 Miroslav Safr <miroslav.safr at tieto.com.com> 0.23.10
- updated to 0.20.10 
* Thu Feb 24 2011 Miroslav Safr <miroslav.safr at tieto.com.com> 0.23.9
- Update meegotouch components to week 8 (BMC#13802)

State:   new          2011-03-16T06:35:31 ulf
Comment: None



changes files:
--------------
--- meegotouch-home.changes
+++ meegotouch-home.changes
@@ -0,0 +1,6 @@
+* Thu Mar 01 2011 Miroslav Safr <miroslav.safr at tieto.com.com> 0.23.10
+- updated to 0.20.10 
+
+* Thu Feb 24 2011 Miroslav Safr <miroslav.safr at tieto.com.com> 0.23.9
+- Update meegotouch components to week 8 (BMC#13802)
+

old:
----
  meegotouch-home-0.23.5.tar.bz2

new:
----
  meegotouch-home-0.23.10.tar.bz2

spec files:
-----------
--- meegotouch-home.spec
+++ meegotouch-home.spec
@@ -1,13 +1,13 @@
 # 
 # Do NOT Edit the Auto-generated Part!
-# Generated by: spectacle version 0.21
+# Generated by: spectacle version 0.22
 # 
 # >> macros
 # << macros
 
 Name:       meegotouch-home
 Summary:    MeeGo Touch Homescreen
-Version:    0.23.5
+Version:    0.23.10
 Release:    1
 Group:      System/Desktop
 License:    LGPL v2.1

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

++++++ meegotouch-home-0.23.5.tar.bz2 -> meegotouch-home-0.23.10.tar.bz2
--- debian/changelog
+++ debian/changelog
@@ -1,7 +1,37 @@
+meegotouchhome (0.23.10-1) unstable; urgency=low
+
+  * Fixes: NB#222322 - [Harmmattan03-8]Ovi Store icon is missing after rebooting if user updated the ovi store client
+
+ -- Eetu Lehmusvuo <ext-eetu.6.lehmusvuo at nokia.com>  Mon, 28 Feb 2011 14:14:17 +0200
+
+meegotouchhome (0.23.9-1) unstable; urgency=low
+
+  * Fixes: Launcher buttons were not updated when the .desktop files were modified
+
+ -- Vesa Halttunen <vesa.halttunen at nokia.com>  Thu, 24 Feb 2011 15:47:09 +0200
+
+meegotouchhome (0.23.8-1) unstable; urgency=low
+
+  * Fixes: NB#229767 - meegotouchhome crashes when tapping thumbnail
+
+ -- Vesa Halttunen <vesa.halttunen at nokia.com>  Wed, 23 Feb 2011 19:25:22 +0200
+
+meegotouchhome (0.23.7-1) unstable; urgency=low
+
+  * Fixes: NB#227550 - Manage window backing pixmaps more carefully in SwitcherButtonView
+
+ -- Vesa Halttunen <vesa.halttunen at nokia.com>  Wed, 23 Feb 2011 14:48:30 +0200
+
+meegotouchhome (0.23.6-1) unstable; urgency=low
+
+  * Fixes: NB#220833 - Panning switcher page delivers useless PropertyNotify events to applications
+  * Fixes: NB#226086 - Windows that refuse to close when the close button is pressed in Recents do not reappear in Recents in full size
+
+ -- Vesa Halttunen <vesa.halttunen at nokia.com>  Fri, 18 Feb 2011 15:56:35 +0200
+
 meegotouchhome (0.23.5-1) unstable; urgency=low
 
   * Fixes: NB#226006 Pinch gesture will break portrait only homescreen mode
-  * Fixes: NB#224497 - Home does pointless XSync calls
 
  -- Pankaj Saharan <pankaj.saharan at nokia.com>  Thu, 10 Feb 2011 16:28:13 +0200
 
--- src/libmeegotouchhome/applicationpackagemonitor.cpp
+++ src/libmeegotouchhome/applicationpackagemonitor.cpp
@@ -16,7 +16,6 @@
 ** of this file.
 **
 ****************************************************************************/
-
 #include "applicationpackagemonitor.h"
 #include "launcherdatastore.h"
 #include <QDir>
@@ -36,7 +35,7 @@
 
 static const QString DESKTOPENTRY_PREFIX = "DesktopEntries";
 static const QString PACKAGE_PREFIX = "Packages/";
-static const QString INSTALLER_EXTRA = "installer-extra/";
+const QString ApplicationPackageMonitor::INSTALLER_EXTRA_FOLDER = "installer-extra/";
 
 static const QString CONFIG_PATH = "/.config/meegotouchhome";
 
@@ -85,7 +84,7 @@
     dataStore = new MFileDataStore(dataStoreFileName);
 
     // ExtraDirWatcher takes ownership of dataStore
-    extraDirWatcher = QSharedPointer<ExtraDirWatcher>(new ExtraDirWatcher(dataStore, QStringList() << (APPLICATIONS_DIRECTORY+INSTALLER_EXTRA)));
+    extraDirWatcher = QSharedPointer<ExtraDirWatcher>(new ExtraDirWatcher(dataStore, QStringList() << (APPLICATIONS_DIRECTORY+INSTALLER_EXTRA_FOLDER)));
 
     connect(extraDirWatcher.data(), SIGNAL(desktopEntryAdded(QString)), this, SLOT(updatePackageState(QString)), Qt::UniqueConnection);
     connect(extraDirWatcher.data(), SIGNAL(desktopEntryChanged(QString)), this, SLOT(updatePackageState(QString)), Qt::UniqueConnection);
@@ -121,7 +120,7 @@
 {
     QStringList keyList(dataStore->allKeys());
 
-    foreach (QString key, keyList) {
+    foreach (const QString &key, keyList) {
         if (key.contains(PACKAGE_PREFIX)) {
             QString desktopEntryPath = dataStore->value(key).toString();
             QString state = dataStore->value(DESKTOPENTRY_PREFIX + desktopEntryPath).toString();
@@ -215,7 +214,7 @@
             QString packageState = entry.value(DESKTOP_ENTRY_GROUP_MEEGO, DESKTOP_ENTRY_KEY_PACKAGE_STATE);
             if (packageState == PACKAGE_STATE_INSTALLED || packageState == PACKAGE_STATE_UPDATEABLE) {
                 // Application is previously installed. Downloading update failed but application still usable.
-                emit operationSuccess(properties.desktopEntryName.replace(INSTALLER_EXTRA, QString()));
+                emit operationSuccess(properties.desktopEntryName.replace(INSTALLER_EXTRA_FOLDER, QString()));
                 storePackageState(packageName, packageState);
             } else {
                 emit operationError(properties.desktopEntryName, error);
@@ -223,7 +222,7 @@
             }
         }
     } else {
-        emit operationSuccess(properties.desktopEntryName.replace(INSTALLER_EXTRA, QString()));
+        emit operationSuccess(properties.desktopEntryName.replace(INSTALLER_EXTRA_FOLDER, QString()));
         storePackageState(packageName, PACKAGE_STATE_INSTALLED);
     }
 
--- src/libmeegotouchhome/applicationpackagemonitor.h
+++ src/libmeegotouchhome/applicationpackagemonitor.h
@@ -54,6 +54,9 @@
      */
     void updatePackageStates();
 
+    //! Installer extra folder path
+    static const QString INSTALLER_EXTRA_FOLDER;
+
 signals:
     /*!
      * Status of download progress of package being installed.
--- src/libmeegotouchhome/applicationpackagemonitorlistener.cpp
+++ src/libmeegotouchhome/applicationpackagemonitorlistener.cpp
@@ -69,3 +69,8 @@
 {
     packageMonitor->updatePackageStates();
 }
+
+bool ApplicationPackageMonitorListener::isInstallerExtraEntry(const QString &desktopEntryPath)
+{
+    return desktopEntryPath.contains(ApplicationPackageMonitor::INSTALLER_EXTRA_FOLDER);
+}
--- src/libmeegotouchhome/applicationpackagemonitorlistener.h
+++ src/libmeegotouchhome/applicationpackagemonitorlistener.h
@@ -48,6 +48,9 @@
      */
     void updatePackageStates();
 
+    //! Checks whether given desktop entry is located in installer extra folder
+    static bool isInstallerExtraEntry(const QString &desktopEntryPath);
+
 signals:
 
     /*!
--- src/libmeegotouchhome/desktopview.cpp
+++ src/libmeegotouchhome/desktopview.cpp
@@ -36,6 +36,7 @@
 #include "mdesktopbackgroundextensioninterface.h"
 #include "mfiledatastore.h"
 #include "applicationpackagemonitorlistener.h"
+#include "homewindowmonitor.h"
 
 #include <MViewCreator>
 #include <MDeviceProfile>
@@ -104,7 +105,6 @@
 
 DesktopView::DesktopView(Desktop *desktop) :
     MWidgetView(desktop),
-    homeWindowMonitor(new HomeWindowMonitor),
     switcher(new Switcher),
     switcherWindow(new MSceneWindow),
     switcherHasContent(false),
@@ -146,7 +146,7 @@
     launcher->setLauncherDataStore(launcherDataStore);
     launcher->setApplicationPackageMonitorListener(packageMonitorListener);
     connect(qApp, SIGNAL(focusToLauncherAppRequested(const QString &)), this, SLOT(showLauncherAndFocusToButton(const QString &)));
-    connect(homeWindowMonitor.data(), SIGNAL(fullscreenWindowOnTopOfOwnWindow()), SLOT(hideLauncher()));
+    connect(HomeWindowMonitor::instance(), SIGNAL(fullscreenWindowOnTopOfOwnWindow()), SLOT(hideLauncher()));
     connect(switcher, SIGNAL(windowListUpdated(const QList<WindowInfo> &)), this, SLOT(setSwitcherHasContent(const QList<WindowInfo> &)));
     windowLayout = new QGraphicsLinearLayout();
     windowLayout->setContentsMargins(0, 0, 0, 0);
--- src/libmeegotouchhome/desktopview.h
+++ src/libmeegotouchhome/desktopview.h
@@ -24,7 +24,6 @@
 #include "desktopmodel.h"
 #include "desktopstyle.h"
 #include "mdesktopbackgroundextensioninterface.h"
-#include "homewindowmonitor.h"
 #include "windowinfo.h"
 
 class Desktop;
@@ -138,9 +137,6 @@
      */
     LauncherDataStore *createLauncherDataStore();
 
-    //! The window manager
-    QSharedPointer<HomeWindowMonitor> homeWindowMonitor;
-
     //! The switcher widget
     Switcher *switcher;
 
--- src/libmeegotouchhome/homewindowmonitor.cpp
+++ src/libmeegotouchhome/homewindowmonitor.cpp
@@ -22,6 +22,18 @@
 #include "homewindowmonitor.h"
 #include "x11wrapper.h"
 
+
+QSharedPointer<HomeWindowMonitor> HomeWindowMonitor::windowMonitorInstance = QSharedPointer<HomeWindowMonitor>();
+
+const HomeWindowMonitor *HomeWindowMonitor::instance()
+{
+    if (windowMonitorInstance.isNull()) {
+        windowMonitorInstance = QSharedPointer<HomeWindowMonitor>(new HomeWindowMonitor());
+    }
+
+    return windowMonitorInstance.data();
+}
+
 HomeWindowMonitor::HomeWindowMonitor() :
         nonFullscreenApplicationWindowTypes(QSet<Atom>() << WindowInfo::NotificationAtom <<
                                                             WindowInfo::DialogAtom <<
--- src/libmeegotouchhome/homewindowmonitor.h
+++ src/libmeegotouchhome/homewindowmonitor.h
@@ -33,10 +33,9 @@
     Q_OBJECT
 
 public:
-    /*!
-     * Constructor.
-     */
-    HomeWindowMonitor();
+
+    //! brief Get HomeWindowMonitor singleton instance.
+    static const HomeWindowMonitor *instance();
 
     /*!
      * Destructor.
@@ -48,7 +47,17 @@
     virtual bool handleXEvent(const XEvent& event);
     //! \reimp_end
 
+protected:
+    /*!
+     * Constructor.
+     */
+    HomeWindowMonitor();
+
 private:
+
+    // HomeWindowMonitor singleton instance.
+    static QSharedPointer<HomeWindowMonitor> windowMonitorInstance;
+
     //! The window types for windows that are not considered to be full screen
     //! application windows
     const QSet<Atom> nonFullscreenApplicationWindowTypes;
@@ -61,6 +70,14 @@
      * in that order. The topmost window is the last one in the list.
      */
     QList<Window> windowStackingOrder();
+
+#ifdef UNIT_TEST
+    friend class Ut_HomeWindowMonitor;
+    friend class Ut_Switcher;
+    friend class Ut_DesktopView;
+    friend class Ut_LauncherButton;
+#endif
+
 };
 
 #endif // HOMEWINDOWMONITOR_H
--- src/libmeegotouchhome/launcher.cpp
+++ src/libmeegotouchhome/launcher.cpp
@@ -16,7 +16,6 @@
 ** of this file.
 **
 ****************************************************************************/
-
 #include "launcher.h"
 #include "launcherbutton.h"
 #include "launcherdatastore.h"
@@ -97,13 +96,14 @@
     Launcher::Placement buttonPlacementInDatastore = entryPlacementInDatastore(desktopEntryPath);
     if (buttonPlacementInDatastore.location.isEmpty() || buttonPlacementInDatastore.location == Launcher::LOCATION_IDENTIFIER) {
         QSharedPointer<LauncherButton> button = placeholderButton(desktopEntryPath);
-        // Remove old placement from store
-        // This is needed in case path to used desktop entry has changed between applications and extra directory
-        removeButtonPlacementFromStore(button->desktopEntry());
-
-        button->setState(state, progress, desktopEntryPath);
+        if (!ApplicationPackageMonitorListener::isInstallerExtraEntry(desktopEntryPath)) {
+            // If new entry is an applications entry path then remove the old entry path from store and update the new entry
+            removeButtonPlacementFromStore(button->desktopEntry());
+            updateButtonPlacementInStore(desktopEntryPath);
+            button->updateFromDesktopEntry(desktopEntryPath);
+        }
 
-        updateButtonPlacementInStore(desktopEntryPath);
+        button->setState(state, progress);
 
         if (!QFileInfo(desktopEntryPath).exists()) {
             // In error case that package doesn't have desktop entry yet,
@@ -283,6 +283,8 @@
         model()->setLauncherPages(pages);
 
         updateButtonPlacementInStore(desktopEntryPath);
+    } else {
+        updateLauncherButton(desktopEntryPath);
     }
 }
 
@@ -340,7 +342,16 @@
 {
     bool found = false;
     foreach (QSharedPointer<LauncherPage> page, model()->launcherPages()) {
-        if (page->updateButton(desktopEntryPath)) {
+        QSharedPointer<LauncherButton> button = page->button(desktopEntryPath);
+        if (!button.isNull()) {
+            // If old entry is an installer extra entry path then remove it and update the new entry path
+            QString oldEntryPath = button->desktopEntry();
+            if (ApplicationPackageMonitorListener::isInstallerExtraEntry(oldEntryPath)) {
+                removeButtonPlacementFromStore(oldEntryPath);
+                updateButtonPlacementInStore(desktopEntryPath);
+            }
+
+            button->updateFromDesktopEntry(desktopEntryPath);
             found = true;
             break;
         }
--- src/libmeegotouchhome/launcher.h
+++ src/libmeegotouchhome/launcher.h
@@ -185,8 +185,7 @@
     /*!
      * Add a launcher button to launcher.
      *
-     * Button is not added if it already exists in launcher.
-     * updateLauncherButton() and updateButtonState() are used to update existing buttons.
+     * If button already exists in launcher then it is updated.
      *
      * \param desktopEntryPath Path to desktop entry that button should represent
      */
--- src/libmeegotouchhome/launcherbutton.cpp
+++ src/libmeegotouchhome/launcherbutton.cpp
@@ -16,7 +16,6 @@
 ** of this file.
 **
 ****************************************************************************/
-
 #include "launcherbutton.h"
 #include "launcher.h"
 #include <MDesktopEntry>
@@ -30,8 +29,7 @@
 bool LauncherButton::launching = false;
 
 LauncherButton::LauncherButton(const QString &desktopEntryPath, MWidget *parent) :
-        MButton(parent, new LauncherButtonModel),
-        windowMonitor(new HomeWindowMonitor)
+        MButton(parent, new LauncherButtonModel)
 {
     init();
 
@@ -64,7 +62,7 @@
         if (model()->buttonState() == LauncherButtonModel::Installed) {
             model()->setButtonState(LauncherButtonModel::Launching);
 
-            connect(windowMonitor.data(), SIGNAL(fullscreenWindowOnTopOfOwnWindow()), SLOT(stopLaunchProgress()));
+            connect(HomeWindowMonitor::instance(), SIGNAL(fullscreenWindowOnTopOfOwnWindow()), SLOT(stopLaunchProgress()));
 
             launching = true;
             action.trigger();
@@ -90,7 +88,7 @@
 
     launching = false;
 
-    disconnect(windowMonitor.data(), SIGNAL(fullscreenWindowOnTopOfOwnWindow()), this, SLOT(stopLaunchProgress()));
+    disconnect(HomeWindowMonitor::instance(), SIGNAL(fullscreenWindowOnTopOfOwnWindow()), this, SLOT(stopLaunchProgress()));
 }
 
 void LauncherButton::retranslateUi()
@@ -103,25 +101,18 @@
 
 void LauncherButton::updateFromDesktopEntry(const QString &desktopEntryPath)
 {
-    if (model()->desktopEntry().isNull() || desktopEntryPath != model()->desktopEntry()->fileName()) {
-        QSharedPointer<MDesktopEntry> entry(new MDesktopEntry(desktopEntryPath));
-        setText(entry->name());
-        action = LauncherAction(desktopEntryPath);
-        model()->setDesktopEntry(entry);
-    }
+    QSharedPointer<MDesktopEntry> entry(new MDesktopEntry(desktopEntryPath));
+    setText(entry->name());
+    action = LauncherAction(desktopEntryPath);
+    model()->setDesktopEntry(entry);
 }
 
-void LauncherButton::setState(LauncherButtonModel::State state, int progress, const QString &desktopEntryPath)
+void LauncherButton::setState(LauncherButtonModel::State state, int progress)
 {
     model()->setButtonState(state);
     if (progress >= 0 && progress <= 100) {
         model()->setOperationProgress(progress);
     }
-
-    // Override the current desktop entry when changing to broken or installed state
-    if (state == LauncherButtonModel::Broken || state == LauncherButtonModel::Installed) {
-        updateFromDesktopEntry(desktopEntryPath);
-    }
 }
 
 int LauncherButton::operationProgress() const
--- src/libmeegotouchhome/launcherbutton.h
+++ src/libmeegotouchhome/launcherbutton.h
@@ -24,8 +24,6 @@
 #include "launcherbuttonmodel.h"
 #include "launcheraction.h"
 
-class HomeWindowMonitor;
-
 /*!
  * A button widget that represents a .desktop file. Triggers the default
  * action associated with the .desktop file when clicked.
@@ -76,9 +74,8 @@
      * Progress property is changed only if parameter progress is valid (0..100)
      * \param state State of a button
      * \param progress Progress of operation
-     * \param desktopEntryPath Path to the desktop entry.
      */
-    void setState(LauncherButtonModel::State state, int progress, const QString &desktopEntryPath);
+    void setState(LauncherButtonModel::State state, int progress);
 
     /*!
      * Returns progress of button's ongoing operation
@@ -108,10 +105,6 @@
      */
     void init();
 
-    //! A window monitor for monitoring when windows appear on top of the window where
-    //! this button is
-    QSharedPointer<HomeWindowMonitor> windowMonitor;
-
     //! Whether an object represented by any launcher button is being launched or not
     static bool launching;
 
--- src/libmeegotouchhome/launcherpage.cpp
+++ src/libmeegotouchhome/launcherpage.cpp
@@ -16,7 +16,6 @@
 ** of this file.
 **
 ****************************************************************************/
-
 #include "launcherpage.h"
 #include "launcherpagemodel.h"
 #include "launcherpageview.h"
@@ -101,7 +100,7 @@
     int buttonIndex = 0;
 
     QString desktopFileName = QFileInfo(desktopEntryPath).fileName();
-    foreach(QSharedPointer<LauncherButton> button, model()->launcherButtons()) {
+    foreach(const QSharedPointer<LauncherButton> &button, model()->launcherButtons()) {
         if (QFileInfo(button->desktopEntry()).fileName() == desktopFileName) {
             position = buttonIndex;
             break;
@@ -111,3 +110,13 @@
 
     return position;
 }
+
+QSharedPointer<LauncherButton> LauncherPage::button(const QString &desktopEntryPath)
+{
+    int buttonPosition = launcherButtonPosition(desktopEntryPath);
+    QSharedPointer<LauncherButton> button;
+    if (buttonPosition > -1) {
+        button = model()->launcherButtons().at(buttonPosition);
+    }
+    return button;
+}
--- src/libmeegotouchhome/launcherpage.h
+++ src/libmeegotouchhome/launcherpage.h
@@ -104,6 +104,13 @@
      *\return int position of button on page. Returns -1 if button is not found.
      */
     int launcherButtonPosition(const QString &desktopEntryPath);
+
+    /*! \brief Returns button representing the given entry.
+     *
+     * \param desktopEntryPath Desktop entry path specifying the button to return
+     * \return Button representing the given desktop entry or NULL shared pointer if button is not found
+     */
+    QSharedPointer<LauncherButton> button(const QString &desktopEntryPath);
 };
 
 #endif
--- src/libmeegotouchhome/quicklaunchbar.cpp
+++ src/libmeegotouchhome/quicklaunchbar.cpp
@@ -64,7 +64,7 @@
     QString entryFileName = QFileInfo(desktopEntryPath).fileName();
     for (int i = 0 ; i < buttons.count() ; i++) {
         if (QFileInfo(buttons.at(i)->desktopEntry()).fileName() == entryFileName) {
-            buttons.at(i)->setState(state, progress, desktopEntryPath);
+            buttons.at(i)->setState(state, progress);
         }
     }
 }
--- src/libmeegotouchhome/switcher.cpp
+++ src/libmeegotouchhome/switcher.cpp
@@ -16,7 +16,6 @@
 ** of this file.
 **
 ****************************************************************************/
-
 #include <QX11Info>
 #include <QEvent>
 #include "switcher.h"
@@ -32,13 +31,9 @@
 // The time to wait until updating the model when a new application is started
 #define UPDATE_DELAY_MS 700
 
-Switcher::Switcher(const WindowMonitor *windowMonitor, MWidget *parent, SwitcherModel *model) :
-        MWidgetController(model, parent),
-        windowMonitor(windowMonitor)
+Switcher::Switcher(MWidget *parent, SwitcherModel *model) :
+        MWidgetController(model, parent)
 {
-    if (this->windowMonitor == NULL) {
-        this->windowMonitor = new HomeWindowMonitor;
-    }
 
     // Get the X11 Atoms for closing and activating a window and for other switcher functionalities
     Display *display = QX11Info::display();
@@ -62,7 +57,7 @@
     updateButtonsTimer.setInterval(UPDATE_DELAY_MS);
     connect(&updateButtonsTimer, SIGNAL(timeout()), this, SLOT(updateButtons()));
 
-    connect(this->windowMonitor, SIGNAL(windowStackingOrderChanged(QList<WindowInfo>)),
+    connect(HomeWindowMonitor::instance(), SIGNAL(windowStackingOrderChanged(QList<WindowInfo>)),
             this, SLOT(handleWindowInfoList(QList<WindowInfo>)));
 
 
@@ -73,7 +68,6 @@
 
 Switcher::~Switcher()
 {
-    delete windowMonitor;
 }
 
 bool Switcher::handleXEvent(const XEvent &event)
@@ -122,7 +116,7 @@
             applicationWindowListChanged = true;
         }
 
-        if (windowMonitor != NULL && !windowMonitor->isOwnWindow(wi.window())) {
+        if (!HomeWindowMonitor::instance()->isOwnWindow(wi.window())) {
             // The Switcher needs to know about Visibility and
             // property changes of other applications' windows
             // (but not of the homescreen window).
@@ -154,8 +148,10 @@
             applicationWindows.removeOne(*windowInfo);
             applicationWindowListChanged = true;
         }
+        windowsBeingClosed.remove(windowInfo->window());
         windowInfoSet.remove(*windowInfo);
     }
+
     return applicationWindowListChanged;
 }
 
@@ -174,7 +170,9 @@
     // Add the window to the windows being closed list - but only if it is a
     // known window, as only known windows can be removed from the list
     if (windowInfoFromSet(windowInfoSet, window) != NULL) {
-        windowsBeingClosedInfo.insert(WindowInfo(window));
+        windowsBeingClosed.insert(window);
+        // Remove the closed window immediately by updating the buttons
+        updateButtons();
     }
 }
 
@@ -229,27 +227,24 @@
     QSet<WindowInfo> newWindowSet = newWindowList.toSet();
     QSet<WindowInfo> oldWindowSet = windowInfoSet;
     QSet<WindowInfo> closedWindowSet = oldWindowSet - newWindowSet;
-    QSet<WindowInfo> openedWindowSet = newWindowSet - oldWindowSet - windowsBeingClosedInfo;
+    QSet<WindowInfo> openedWindowSet = newWindowSet - oldWindowSet;
 
     bool added = addWindows(openedWindowSet);
-    bool removed = removeWindows(closedWindowSet + windowsBeingClosedInfo);
-
-    windowsBeingClosedInfo -= closedWindowSet;
+    bool removed = removeWindows(closedWindowSet);
 
     // The stacking order needs to be cleared out before we start updating the
     // buttons as the topmostWindow is set in the 'updateButtons()' method and
     // the method call is scheduled with a timer in the case of an addition
     QList<WindowInfo> stackingWindowList;
     foreach (WindowInfo window, newWindowList) {
-        if (!windowsBeingClosedInfo.contains(window)) {
-            stackingWindowList.append(window);
-        }
+        stackingWindowList.append(window);
     }
 
     if (!stackingWindowList.isEmpty()){
         topmostWindow = stackingWindowList.last().window();
+        // Restore a possible window that was being removed but has now come on top
+        added |= restoreButtonBeingRemoved(topmostWindow, false);
     }
-
     if (added || removed) {
         if (!removed) {
             // If windows have been added but not removed, update the switcher with a delay
@@ -259,7 +254,7 @@
             updateButtons();
         }
     } else if (!stackingWindowList.isEmpty()) {
-        if (!windowMonitor->isOwnWindow(topmostWindow)) {
+        if (!HomeWindowMonitor::instance()->isOwnWindow(topmostWindow)) {
             // The view might also need to react (== pan to the correct page) if no buttons were added
             // but the stacking order was changed, i.e. due to app chaining or some other activity
             model()->setTopmostWindow(topmostWindow);
@@ -339,13 +334,13 @@
 void Switcher::updateButtons()
 {
     // List of existing buttons for which a window still exists
-    QList<SwitcherButton *> validOldButtons;
+    QList<QSharedPointer<SwitcherButton> > validOldButtons;
 
     // List of newly created buttons
     QList< QSharedPointer<SwitcherButton> > newButtons;
 
     // The new mapping of known windows to the buttons
-    QHash<Window, SwitcherButton *> newSwitcherButtonMap;
+    QHash<Window, QSharedPointer<SwitcherButton> > newSwitcherButtonMap;
 
     // Go through the windows and create new buttons for new windows
     foreach (const WindowInfo &windowInfo, applicationWindows) {
@@ -353,7 +348,7 @@
         WindowInfo topmostWindowInfo = WindowInfo(w);
         if (windowInfoSet.contains(topmostWindowInfo)) {
             if (switcherButtonMap.contains(windowInfo.window())) {
-                SwitcherButton *button = switcherButtonMap[windowInfo.window()];
+                QSharedPointer<SwitcherButton> button = switcherButtonMap[windowInfo.window()];
 
                 // Button already exists - set title (as it may have changed)
                 button->setText(topmostWindowInfo.title());
@@ -362,8 +357,10 @@
                 if (button->xWindow() != topmostWindowInfo.window()) {
                     button->setXWindow(topmostWindowInfo.window());
                 }
-
-                validOldButtons.append(button);
+                // Only add to model if button is not being closed
+                if (!windowsBeingClosed.contains(windowInfo.window())) {
+                    validOldButtons.append(button);
+                }
                 newSwitcherButtonMap.insert(windowInfo.window(), button);
             } else {
                 QSharedPointer<SwitcherButton> button = createSwitcherButton();
@@ -372,26 +369,25 @@
                 connect(button.data(), SIGNAL(windowToFront(Window)), this, SLOT(windowToFront(Window)));
                 connect(button.data(), SIGNAL(closeWindow(Window)), this, SLOT(closeWindow(Window)));
                 connect(button.data(), SIGNAL(closeAllWindows()), this, SLOT(closeAllWindows()));
+                connect(button.data(), SIGNAL(closeTimedOutForWindow(Window)), this, SLOT(restoreButtonBeingRemoved(Window)));
 
                 newButtons.append(button);
-                newSwitcherButtonMap.insert(windowInfo.window(), button.data());
+                newSwitcherButtonMap.insert(windowInfo.window(), button);
             }
         }
     }
 
-    int firstNewButtonIndex = 0;
     foreach(QSharedPointer<SwitcherButton> button, model()->buttons()) {
-        // Keep only the buttons for which a window still exists
-        if (validOldButtons.contains(button.data())) {
-            newButtons.insert(firstNewButtonIndex++, button);
+        if (!validOldButtons.contains(button)) {
             // If button that still has a window is removed from switcher (e.g. window acquires a SkipTaskbarAtom)
-            // _MEEGOTOUCH_VISIBLE_IN_SWITCHER should be set to 0 for a window.
-        } else if (windowInfoSet.contains(WindowInfo(button->xWindow()))) {
+            // _MEEGOTOUCH_VISIBLE_IN_SWITCHER should be set to 0 for the window.
             button->setVisibleInSwitcherProperty(false);
         }
     }
 
-     // Take the new set of buttons into use
+    newButtons.append(validOldButtons);
+
+    // Take the new set of buttons into use
     switcherButtonMap = newSwitcherButtonMap;
     model()->setButtons(newButtons);
 
@@ -433,6 +429,10 @@
     if (windowInfo.transientFor() != 0 && windowInfo.transientFor() != window) {
         closeWindow(windowInfo.transientFor());
     }
+
+    windowsBeingClosed.insert(window);
+    // Remove the closed window immediately by updating the buttons
+    updateButtons();
 }
 
 void Switcher::closeAllWindows()
@@ -462,5 +462,14 @@
 
 QSharedPointer<SwitcherButton> Switcher::createSwitcherButton()
 {
-    return QSharedPointer<SwitcherButton>(new SwitcherButton);
+     return QSharedPointer<SwitcherButton>(new SwitcherButton);
+}
+
+bool Switcher::restoreButtonBeingRemoved(Window window, bool forceUpdateButtons)
+{
+    bool removed = windowsBeingClosed.remove(window);
+    if (removed && forceUpdateButtons) {
+        updateButtons();
+    }
+    return removed;
 }
--- src/libmeegotouchhome/switcher.h
+++ src/libmeegotouchhome/switcher.h
@@ -26,7 +26,6 @@
 #include "windowinfo.h"
 #include <X11/Xlib.h>
 
-class WindowMonitor;
 
 /*!
  * Switcher is a widget that shows the available windows.
@@ -39,12 +38,10 @@
 public:
     /*!
      * Constructs a Switcher widget.
-     * \param windowMonitor a window monitor instance to be used by this switcher.
-     *        Switcher takes ownership of the window monitor passed in.
      * \param parent the parent widget of the Switcher, defaults to NULL
      * \param model model to be used with Switcher, defaults SwitcherModel
      */
-    Switcher(const WindowMonitor *windowMonitor = NULL, MWidget *parent = NULL, SwitcherModel *model = new SwitcherModel);
+    Switcher(MWidget *parent = NULL, SwitcherModel *model = new SwitcherModel);
 
     /*!
      * Destroys the Switcher.
@@ -82,6 +79,15 @@
      */
     void handleWindowInfoList(QList<WindowInfo> newWindowList);
 
+    /*!
+     * Restore a button that were being removed.
+     *
+     * \param window
+     * \param forceUpdateButtons Whether buttons should be updated
+     * \return Whether windon was removed from list
+     */
+    bool restoreButtonBeingRemoved(Window window, bool forceUpdateButtons = true);
+
 protected:
     //! \reimp
     /*!
@@ -97,7 +103,6 @@
     virtual QSharedPointer<SwitcherButton> createSwitcherButton();
 
     //! The window monitor instance this switcher uses
-    const WindowMonitor *windowMonitor;
 
 private slots:
     /*!
@@ -250,10 +255,10 @@
     Atom windowNameAtom;
 
     //! A mapping from known X Window IDs to SwitcherButtons
-    QHash<Window, SwitcherButton *> switcherButtonMap;
+    QHash<Window, QSharedPointer<SwitcherButton> > switcherButtonMap;
 
     //! A list of windows that are being closed
-    QSet<WindowInfo> windowsBeingClosedInfo;
+    QSet<Window> windowsBeingClosed;
 
     //! Mapping of the current X windows
     QSet<WindowInfo> windowInfoSet;
--- src/libmeegotouchhome/switcherbutton.cpp
+++ src/libmeegotouchhome/switcherbutton.cpp
@@ -30,7 +30,7 @@
 Atom SwitcherButton::visibleAtom = 0;
 
 SwitcherButton::SwitcherButton(QGraphicsItem *parent, SwitcherButtonModel *model) :
-    MButton(parent, model), visibilityPropertyEnabled(true)
+    MButton(parent, model)
 {
     // Configure timers
     windowCloseTimer.setSingleShot(true);
@@ -42,6 +42,10 @@
     }
 
     connect(this, SIGNAL(clicked()), this, SLOT(switchToWindow()));
+
+    // Initialize to negation to force the property initialization
+    visibility = !isVisible();
+    setVisibilityPropertyEnabled(true);
 }
 
 SwitcherButton::~SwitcherButton()
@@ -80,6 +84,7 @@
 {
     setVisible(true);
     prepareGeometryChange();
+    emit closeTimedOutForWindow(model()->xWindow());
 }
 
 void SwitcherButton::enterDisplayEvent()
@@ -94,7 +99,7 @@
 
 void SwitcherButton::setVisibleInSwitcherProperty(bool set)
 {
-    if(visibilityPropertyEnabled) {
+    if(visibilityPropertyEnabled && visibility != set) {
         Display *dpy = QX11Info::display();
         if (dpy) {
             if (set) {
@@ -104,9 +109,8 @@
                 unsigned char data = 0;
                 X11Wrapper::XChangeProperty(dpy, xWindow(), visibleAtom, XA_CARDINAL, 8, PropModeReplace, &data, 1);
             }
+            visibility = set;
         }
-    } else {
-        visibility = set;
     }
 }
 
@@ -114,6 +118,6 @@
 {
     visibilityPropertyEnabled = enable;
     if(enable) {
-        setVisibleInSwitcherProperty(visibility);
+        setVisibleInSwitcherProperty(isVisible());
     }
 }
--- src/libmeegotouchhome/switcherbutton.h
+++ src/libmeegotouchhome/switcherbutton.h
@@ -89,6 +89,11 @@
      */
     void closeAllWindows();
 
+    /*!
+     * \brief A signal for notifying that window close timer timed out.
+     */
+    void closeTimedOutForWindow(Window window);
+
 public slots:
     /*!
      * \brief Slot for notifying that the window represented by this button should be brought to front
@@ -103,7 +108,7 @@
     /*!
      * A slot that should be called when window closing has been requested but the window has not closed during a certain time.
      */
-    void resetState();
+    virtual void resetState();
 
     /*!
      * \brief Enables or disables the setting of the visibility property of the button
--- src/libmeegotouchhome/switcherbuttonview.cpp
+++ src/libmeegotouchhome/switcherbuttonview.cpp
@@ -79,9 +79,9 @@
 // Time between icon geometry updates in milliseconds
 static const int ICON_GEOMETRY_UPDATE_INTERVAL = 200;
 // Time between icon pixmap fetch retries in milliseconds
-static const int ICON_PIXMAP_RETRY_INTERVAL = 100;
+static const int ICON_PIXMAP_RETRY_INTERVAL = 500;
 // Maximun number of icon pixmap fetch retries
-static const int ICON_PIXMAP_RETRY_MAX_COUNT = 5;
+static const int ICON_PIXMAP_RETRY_MAX_COUNT = 2;
 Atom SwitcherButtonView::iconGeometryAtom = 0;
 
 SwitcherButtonView::SwitcherButtonView(SwitcherButton *button) :
@@ -215,6 +215,7 @@
 
 void SwitcherButtonView::setupModel()
 {
+    // The MButtonView implementation is skipped on purpose so that MButtonView's MLabel is not set up
     MWidgetView::setupModel();
 
     if (model()->xWindow() != 0) {
@@ -228,7 +229,9 @@
 
 void SwitcherButtonView::updateData(const QList<const char *>& modifications)
 {
+    // The MButtonView implementation is skipped on purpose so that MButtonView's MLabel is not set up
     MWidgetView::updateData(modifications);
+
     const char *member;
     foreach(member, modifications) {
         if (member == SwitcherButtonModel::XWindow && model()->xWindow() != 0) {
@@ -244,7 +247,8 @@
 
 void SwitcherButtonView::applyStyle()
 {
-    MWidgetView::applyStyle();
+    // MButtonView's implementation must be called starting from libmeegotouch 0.20.86
+    MButtonView::applyStyle();
 }
 
 void SwitcherButtonView::updateViewMode()
@@ -261,51 +265,57 @@
         break;
     }
 
-    // When the style mode changes, the style is not automatically applied -> call it explicitly
-    applyStyle();
+    // When the style mode changes, the style is not automatically applied -> call it explicitly (skipping the MButtonView's implementation so that the mode setting does not get reset)
+    MWidgetView::applyStyle();
 }
 
 void SwitcherButtonView::updateXWindowPixmap()
 {
 #ifdef Q_WS_X11
-    // Unregister the old pixmap from XDamage events
-    destroyDamage();
-
-    if (xWindowPixmap != 0) {
-        // Dereference the old pixmap ID
-        X11Wrapper::XFreePixmap(QX11Info::display(), xWindowPixmap);
-        xWindowPixmap = 0;
-    }
 
-    // It is possible that the window is not redirected so check for errors
+    // It is possible that the window is not redirected so check for errors.
+    // XSync() needs to be called so that previous errors go to the original
+    // handler.
+    X11Wrapper::XSync(QX11Info::display(), FALSE);
     XErrorHandler errh = X11Wrapper::XSetErrorHandler(handleXError);
+    badMatchOccurred = false;
 
     // Get the pixmap ID of the X window
-    xWindowPixmap = X11Wrapper::XCompositeNameWindowPixmap(QX11Info::display(), model()->xWindow());
+    Pixmap newWindowPixmap = X11Wrapper::XCompositeNameWindowPixmap(QX11Info::display(), model()->xWindow());
+    // XCompositeNameWindowPixmap doesn't wait for the server to reply, we'll
+    // need to do it ourselves to catch the possible BadMatch
+    X11Wrapper::XSync(QX11Info::display(), FALSE);
 
-    // If a BadMatch error occurred set the window pixmap ID to 0
+    // If a BadMatch error occurred the window wasn't redirected yet
     if (badMatchOccurred) {
-        xWindowPixmap = 0;
-        badMatchOccurred = false;
         if (++updateXWindowPixmapRetryCount
             <= ICON_PIXMAP_RETRY_MAX_COUNT) {
             updateXWindowPixmapRetryTimer.start();
-        } else {
-            updateXWindowPixmapRetryCount = 0;
         }
-    }
+    } else {
+        updateXWindowPixmapRetryCount = 0;
 
-    // Reset the error handler
-    X11Wrapper::XSetErrorHandler(errh);
+        // Unregister the old pixmap from XDamage events
+        destroyDamage();
 
-    // Register the pixmap for XDamage events
-    createDamage();
+        if (xWindowPixmap != 0) {
+            // Dereference the old pixmap ID
+            X11Wrapper::XFreePixmap(QX11Info::display(), xWindowPixmap);
+        }
+
+        xWindowPixmap = newWindowPixmap;
+
+        // Register the pixmap for XDamage events
+        createDamage();
 
-    if (xWindowPixmap != 0) {
         qWindowPixmap = QPixmap::fromX11Pixmap(xWindowPixmap, QPixmap::ExplicitlyShared);
+
+        update();
     }
+
+    // Reset the error handler.
+    X11Wrapper::XSetErrorHandler(errh);
 #endif
-    update();
 }
 
 #ifdef Q_WS_X11
@@ -385,7 +395,8 @@
 
 void SwitcherButtonView::updateXWindowIconGeometryIfNecessary() const
 {
-    if (updatedXWindowIconPosition != controller->mapToScene(thumbnailPosition())) {
+    // Update only if position has changed
+    if (updatedXWindowIconGeometry.topLeft() != controller->mapToScene(thumbnailPosition())) {
         // Update the icon geometry in a moment. If timer was already active, restart it so
         // we don't send constantly updates while the button is moving.
         updateXWindowIconGeometryTimer.start();
@@ -401,16 +412,19 @@
     iconSceneGeometry.setCoords(topLeft.x(), topLeft.y(), bottomRight.x(), bottomRight.y());
     iconSceneGeometry = iconSceneGeometry.normalized();
 
-    // Replace the old X icon geometry property for the window with iconGeometry, which consists of 4 unsigned ints (32 bits)
-    unsigned int iconGeometry[4];
-    iconGeometry[0] = iconSceneGeometry.x();
-    iconGeometry[1] = iconSceneGeometry.y();
-    iconGeometry[2] = iconSceneGeometry.width();
-    iconGeometry[3] = iconSceneGeometry.height();
-    X11Wrapper::XChangeProperty(QX11Info::display(), model()->xWindow(), iconGeometryAtom, XA_CARDINAL, sizeof(unsigned int) * 8, PropModeReplace, (unsigned char *)&iconGeometry, 4);
+    // Update only if geometry has changed
+    if (updatedXWindowIconGeometry != iconSceneGeometry) {
+        // Replace the old X icon geometry property for the window with iconGeometry, which consists of 4 unsigned ints (32 bits)
+        unsigned int iconGeometry[4];
+        iconGeometry[0] = iconSceneGeometry.x();
+        iconGeometry[1] = iconSceneGeometry.y();
+        iconGeometry[2] = iconSceneGeometry.width();
+        iconGeometry[3] = iconSceneGeometry.height();
+        X11Wrapper::XChangeProperty(QX11Info::display(), model()->xWindow(), iconGeometryAtom, XA_CARDINAL, sizeof(unsigned int) * 8, PropModeReplace, (unsigned char *)&iconGeometry, 4);
 
-    // Store which position has already been updated
-    updatedXWindowIconPosition = topLeft;
+        // Store which position has already been updated
+        updatedXWindowIconGeometry = iconSceneGeometry;
+    }
 }
 
 M_REGISTER_VIEW_NEW(SwitcherButtonView, SwitcherButton)
--- src/libmeegotouchhome/switcherbuttonview.h
+++ src/libmeegotouchhome/switcherbuttonview.h
@@ -117,7 +117,6 @@
     //! SwitcherButton controller
     SwitcherButton *controller;
 
-private:
     //! Starts a timer for updating the icon geometry if the icon geometry has changed after the last update
     void updateXWindowIconGeometryIfNecessary() const;
 
@@ -157,8 +156,8 @@
     //! Current count of retries for updating icon's pixmap
     int updateXWindowPixmapRetryCount;
 
-    //! The icon's position in scene coordinates
-    QPointF updatedXWindowIconPosition;
+    //! The icon's current geometry in scene coordinates
+    QRectF updatedXWindowIconGeometry;
 
     //! X11 Atom for the icon geometry
     static Atom iconGeometryAtom;
--- src/libmeegotouchhome/switcherviewbase.cpp
+++ src/libmeegotouchhome/switcherviewbase.cpp
@@ -16,7 +16,6 @@
  ** of this file.
  **
  ****************************************************************************/
-#include <MCancelEvent>
 #include "switcherviewbase.h"
 #include "switcher.h"
 #include "switcherbutton.h"
@@ -83,6 +82,7 @@
         e->setAccepted(true);
         return true;
     }
+
     return MWidgetView::event(e);
 }
 
@@ -147,16 +147,32 @@
     pinchedButtonPosition = buttonIndex(closestButton);
 }
 
-void SwitcherViewBase::pinchBegin(const QPointF &centerPoint)
+void SwitcherViewBase::setViewportPhysicsEnabled(bool enabled)
 {
-    // Send cancel event to all items below, to prevent panning during the pinch
-    MScene *scene = MainWindow::instance()->scene();
-    QList<QGraphicsItem*> items = scene->items(controller->mapToScene(controller->rect().center()));
-    MCancelEvent cancelEvent;
+    // When re-enabling, only enable the exact items that were disabled before
+    static QList<QGraphicsItem*> items;
+
+    if(!enabled) {
+        MScene *scene = MainWindow::instance()->scene();
+        items = scene->items(controller->mapToScene(controller->rect().center()));
+    }
+
     foreach(QGraphicsItem *item, items) {
-        scene->sendEvent(item, &cancelEvent);
+        if(MPannableViewport *vp = dynamic_cast<MPannableViewport *>(item)) {
+            vp->physics()->setEnabled(enabled);
+        }
     }
 
+    if(enabled) {
+        items.clear();
+    }
+}
+
+void SwitcherViewBase::pinchBegin(const QPointF &centerPoint)
+{
+    // Prevent panning during the pinch
+    setViewportPhysicsEnabled(false);
+
     calculateNearestButtonAt(centerPoint);
 
     foreach(const QSharedPointer<SwitcherButton> &button, model()->buttons()) {
@@ -168,6 +184,10 @@
 void SwitcherViewBase::pinchUpdate(float scaleFactor)
 {
     if(!layoutAnimation->isAnimating()) {
+        if(scaleFactor == 1.0f) {
+            return;
+        }
+
         pinchGestureTargetMode = scaleFactor >= 1 ? SwitcherModel::Detailview : SwitcherModel::Overview;
 
         overpinch = pinchGestureTargetMode == model()->switcherMode();
@@ -202,6 +222,9 @@
 
 void SwitcherViewBase::pinchEnd()
 {
+    // Re-enable panning
+    setViewportPhysicsEnabled(true);
+
     layoutAnimation->setManualControl(false);
 
     if(bounceAnimation->state() == QAbstractAnimation::Paused) {
@@ -222,7 +245,11 @@
 
 void SwitcherViewBase::pinchGestureEvent(QGestureEvent *event, QPinchGesture *gesture)
 {
-    /*! Finish any currently running animation before starting a new one */
+    // For preventing acting on two GestureStarted events before receiving GestureFinished on the first,
+    // which occurs sometimes (a bug in Qt).
+    static bool gestureActive = false;
+
+    // Finish any currently running animation before starting a new one
     if((layoutAnimation->isAnimating() && !layoutAnimation->manualControl()) || bounceAnimation->state() == QAbstractAnimation::Running) {
         return;
     }
@@ -231,13 +258,26 @@
 
     switch(gesture->state()) {
     case Qt::GestureStarted:
-        pinchBegin(controller->mapFromScene(gesture->centerPoint()));
+        if(!gestureActive) {
+            gestureActive = true;
+            pinchBegin(controller->mapFromScene(gesture->centerPoint()));
+        }
+
         break;
     case Qt::GestureUpdated:
-        pinchUpdate(gesture->totalScaleFactor());
+        if(gestureActive) {
+            pinchUpdate(gesture->totalScaleFactor());
+        }
         break;
     case Qt::GestureFinished:
-        pinchEnd();
+        if(gestureActive) {
+            pinchEnd();
+            gestureActive = false;
+        }
+
+        break;
+    case Qt::GestureCanceled:
+        gestureActive = false;
         break;
     default:
         break;
--- src/libmeegotouchhome/switcherviewbase.h
+++ src/libmeegotouchhome/switcherviewbase.h
@@ -112,6 +112,10 @@
     /*! Called when the pinch gesture ends */
     virtual void pinchEnd();
 
+    /*! Enables or disables the physics of the viewports under this widget, to prevent unwanted movement
+      \param enabled the enabled or disabled state to set */
+    void setViewportPhysicsEnabled(bool enabled);
+
     /*! The switcher controller */
     Switcher *controller;
 
--- src/libmeegotouchhome/x11wrapper.cpp
+++ src/libmeegotouchhome/x11wrapper.cpp
@@ -79,6 +79,11 @@
     ::XDamageDestroy(dpy, damage);
 }
 
+int X11Wrapper::XSync(Display *display, Bool discard)
+{
+    return ::XSync(display, discard);
+}
+
 XErrorHandler X11Wrapper::XSetErrorHandler(XErrorHandler handler)
 {
     return ::XSetErrorHandler(handler);
--- src/libmeegotouchhome/x11wrapper.h
+++ src/libmeegotouchhome/x11wrapper.h
@@ -41,6 +41,7 @@
     static Pixmap XCompositeNameWindowPixmap(Display *dpy, Window window);
     static Damage XDamageCreate(Display *dpy, Drawable drawable, int level);
     static void XDamageDestroy(Display *dpy, Damage damage);
+    static int XSync(Display *display, Bool discard);
     static XErrorHandler XSetErrorHandler(XErrorHandler handler);
     static int XChangeProperty(Display *display, Window w, Atom property, Atom type, int format, int mode, unsigned char *data, int nelements);
     static Status XSendEvent(Display *display, Window w, Bool propagate, long event_mask, XEvent *event_send);
--- tests/stubs/applicationpackagemonitor_stub.h
+++ tests/stubs/applicationpackagemonitor_stub.h
@@ -11,6 +11,8 @@
     ~ExtraDirWatcher(){}
 };
 
+const QString ApplicationPackageMonitor::INSTALLER_EXTRA_FOLDER = "installer-extra/";
+
 // 1. DECLARE STUB
 // FIXME - stubgen is not yet finished
 class ApplicationPackageMonitorStub : public StubBase {
@@ -24,7 +26,7 @@
   virtual void updatePackageState(const QString &desktopEntryPath);
   virtual QString desktopEntryName(const QString &packageName);
   virtual void packageRemoved(const QString &desktopEntryPath);
-  void updatePackageStates();
+  virtual void updatePackageStates();
 };
 
 // 2. IMPLEMENT STUB
--- tests/stubs/applicationpackagemonitorlistener_stub.h
+++ tests/stubs/applicationpackagemonitorlistener_stub.h
@@ -16,7 +16,7 @@
   virtual void setInstallProgress(const QString &desktopEntryPath, int percentage);
   virtual void setOperationSuccess(const QString &desktopEntryPath);
   virtual void setOperationError(const QString &desktopEntryPath, const QString &error);
-  ApplicationPackageMonitor *packageMonitor ;
+  virtual bool isInstallerExtraEntry(const QString &desktopEntryPath);
 }; 
 
 // 2. IMPLEMENT STUB
@@ -32,7 +32,7 @@
 
 void ApplicationPackageMonitorListenerStub::setDownloadProgress(const QString &desktopEntryPath, int bytesLoaded, int bytesTotal) {
   QList<ParameterBase*> params;
-  params.append( new Parameter<const QString & >(desktopEntryPath));
+  params.append( new Parameter<QString>(desktopEntryPath));
   params.append( new Parameter<int >(bytesLoaded));
   params.append( new Parameter<int >(bytesTotal));
   stubMethodEntered("setDownloadProgress",params);
@@ -40,25 +40,30 @@
 
 void ApplicationPackageMonitorListenerStub::setInstallProgress(const QString &desktopEntryPath, int percentage) {
   QList<ParameterBase*> params;
-  params.append( new Parameter<const QString & >(desktopEntryPath));
+  params.append( new Parameter<QString>(desktopEntryPath));
   params.append( new Parameter<int >(percentage));
   stubMethodEntered("setInstallProgress",params);
 }
 
 void ApplicationPackageMonitorListenerStub::setOperationSuccess(const QString &desktopEntryPath) {
   QList<ParameterBase*> params;
-  params.append( new Parameter<const QString & >(desktopEntryPath));
+  params.append( new Parameter<QString>(desktopEntryPath));
   stubMethodEntered("setOperationSuccess",params);
 }
 
 void ApplicationPackageMonitorListenerStub::setOperationError(const QString &desktopEntryPath, const QString &error) {
   QList<ParameterBase*> params;
-  params.append( new Parameter<const QString & >(desktopEntryPath));
-  params.append( new Parameter<const QString & >(error));
+  params.append( new Parameter<QString>(desktopEntryPath));
+  params.append( new Parameter<QString>(error));
   stubMethodEntered("setOperationError",params);
 }
 
-
+bool ApplicationPackageMonitorListenerStub::isInstallerExtraEntry(const QString &desktopEntryPath) {
+  QList<ParameterBase*> params;
+  params.append( new Parameter<QString>(desktopEntryPath));
+  stubMethodEntered("isInstallerExtraEntry",params);
+  return stubReturnValue<bool>("isInstallerExtraEntry");
+}
 
 // 3. CREATE A STUB INSTANCE
 ApplicationPackageMonitorListenerStub gDefaultApplicationPackageMonitorListenerStub;
@@ -95,4 +100,7 @@
 }
 
 
+bool ApplicationPackageMonitorListener::isInstallerExtraEntry(const QString &desktopEntryPath) {
+  return gApplicationPackageMonitorListenerStub->isInstallerExtraEntry(desktopEntryPath);
+}
 #endif
--- tests/stubs/homewindowmonitor_stub.h
+++ tests/stubs/homewindowmonitor_stub.h
@@ -29,11 +29,18 @@
 // FIXME - stubgen is not yet finished
 class HomeWindowMonitorStub : public StubBase {
 public:
+    virtual const HomeWindowMonitor *instance();
     virtual bool isOwnWindow(WId wid);
     virtual bool handleXEvent(const XEvent& event);
 };
 
 // 2. IMPLEMENT STUB
+
+const HomeWindowMonitor *HomeWindowMonitorStub::instance() {
+    stubMethodEntered("instance");
+    return stubReturnValue<HomeWindowMonitor*>("instance");
+}
+
 bool HomeWindowMonitorStub::isOwnWindow(WId wid) {
     QList<ParameterBase*> params;
     params.append(new Parameter<WId>(wid));
@@ -61,6 +68,10 @@
 {
 }
 
+const HomeWindowMonitor *HomeWindowMonitor::instance() {
+    return gHomeWindowMonitorStub->instance();
+}
+
 bool HomeWindowMonitor::isOwnWindow(WId wid) const {
     return gHomeWindowMonitorStub->isOwnWindow(wid);
 }
--- tests/stubs/launcherbutton_stub.h
+++ tests/stubs/launcherbutton_stub.h
@@ -18,7 +18,7 @@
   virtual void retranslateUi();
   virtual void launch();
   virtual void stopLaunchProgress();
-  virtual void setState(LauncherButtonModel::State state, int progress, const QString &desktopEntryPath);
+  virtual void setState(LauncherButtonModel::State state, int progress);
   virtual int operationProgress() const;
   virtual void init();
   virtual LauncherButtonModel::State buttonState() const;
@@ -66,11 +66,10 @@
   return stubReturnValue<LauncherButtonModel::State>("buttonState");
 }
 
-void LauncherButtonStub::setState(LauncherButtonModel::State state, int progress, const QString &desktopEntryPath) {
+void LauncherButtonStub::setState(LauncherButtonModel::State state, int progress) {
   QList<ParameterBase*> params;
   params.append( new Parameter<LauncherButtonModel::State>(state));
   params.append( new Parameter<int>(progress));
-  params.append( new Parameter<QString>(desktopEntryPath));
   stubMethodEntered("setState",params);
 }
 
@@ -121,9 +120,9 @@
     return gLauncherButtonStub->buttonState();
 }
 
-void LauncherButton::setState(LauncherButtonModel::State state, int progress, const QString &desktopEntryPath)
+void LauncherButton::setState(LauncherButtonModel::State state, int progress)
 {
-    gLauncherButtonStub->setState(state, progress, desktopEntryPath);
+    gLauncherButtonStub->setState(state, progress);
 }
 
 int LauncherButton::operationProgress() const {
--- tests/stubs/stubbase.cpp
+++ tests/stubs/stubbase.cpp
@@ -36,11 +36,26 @@
         delete p;
     }
 
+    foreach(QList<ParameterBase *> valueList, _stubReturnValueLists) {
+        foreach(ParameterBase *p, valueList) {
+            delete p;
+        }
+    }
+
+    _stubReturnValueLists.clear();
+    _stubReturnValueListCurrentIndex.clear();
     _stubReturnValues.clear();
     _stubCallCounts.clear();
     _stubCallHistory.clear();
 }
 
+void StubBase::stubResetReturnValueListIndex(const QString &methodName) const
+{
+    if (_stubReturnValueListCurrentIndex.contains(methodName)) {
+        _stubReturnValueListCurrentIndex[methodName] = -1;
+    }
+}
+
 int StubBase::stubCallCount(const QString &method) const
 {
     return _stubCallCounts[method];
@@ -64,8 +79,17 @@
 {
     ParameterBase *retVal = NULL;
 
-    if (_stubReturnValues.contains(methodName))
+    if (_stubReturnValueLists.contains(methodName) && !_stubReturnValueLists[methodName].isEmpty()) {
+        _stubReturnValueListCurrentIndex[methodName]++;
+                // List has been iterated to end, start from beginning
+        if (_stubReturnValueListCurrentIndex[methodName] >= _stubReturnValueLists[methodName].count()) {
+            _stubReturnValueListCurrentIndex[methodName] = 0;
+        }
+
+        retVal = _stubReturnValueLists[methodName].at(_stubReturnValueListCurrentIndex[methodName]);
+    } else if (_stubReturnValues.contains(methodName)) {
         retVal = _stubReturnValues[methodName];
+    }
 
     return retVal;
 }
--- tests/stubs/stubbase.h
+++ tests/stubs/stubbase.h
@@ -54,6 +54,10 @@
     template <typename T>
     void stubSetReturnValue(const QString &methodName, T value) const;
 
+    // Set the return value list for methodName calls
+    template <typename T>
+    void stubSetReturnValueList(const QString &methodName, QList<T> valueList) const;
+
     // Return the return value set for methodName
     template <typename T>
     T &stubReturnValue(const QString &methodName) const;
@@ -66,9 +70,12 @@
     ParameterBase *stubReturnValue(const QString &methodName) const;
     void stubMethodEntered(const QString &methodName, QList<ParameterBase *> params) const;
     void stubMethodEntered(const QString &methodName) const;
+    void stubResetReturnValueListIndex(const QString &methodName) const;
 
 private:
     mutable QMap<QString, ParameterBase *> _stubReturnValues;
+    mutable QMap<QString, QList<ParameterBase *> > _stubReturnValueLists;
+    mutable QMap<QString, int> _stubReturnValueListCurrentIndex;
     mutable QMap<QString, int> _stubCallCounts;
     mutable QList<MethodCall *> _stubCallHistory;
 
@@ -82,13 +89,31 @@
 }
 
 template <typename T>
+void StubBase::stubSetReturnValueList(const QString &methodName, QList<T> valueList) const
+{
+    QList<ParameterBase *> newValueList;
+    foreach(T value, valueList) {
+        Parameter<T>* param = new Parameter<T>(value);
+        newValueList.append(param);
+    }
+    _stubReturnValueLists[methodName] = newValueList;
+    _stubReturnValueListCurrentIndex[methodName] = -1;
+}
+
+template <typename T>
 T &StubBase::stubReturnValue(const QString &methodName) const
 {
-    if (! _stubReturnValues.contains(methodName)) {
-        stubSetReturnValue<T>(methodName, T());
+    ParameterBase *base;
+    if (_stubReturnValueLists.contains(methodName) && !_stubReturnValueLists[methodName].isEmpty() && _stubReturnValueListCurrentIndex[methodName] > -1) {
+        base = _stubReturnValueLists[methodName].at(_stubReturnValueListCurrentIndex[methodName]);
+    } else {
+        if (! _stubReturnValues.contains(methodName)) {
+            stubSetReturnValue<T>(methodName, T());
+        }
+
+        base = _stubReturnValues[methodName];
     }
 
-    ParameterBase *base = _stubReturnValues[methodName];
     Parameter<T>* param = dynamic_cast<Parameter<T>*>(base);
     if (!param) {
         QString msg = QString("StubBase::") + __func__ + ": failed dynamic_cast, check that return value type matches the method; check also that you have used stubSetReturnValue(" + methodName + ")";
--- tests/stubs/switcher_stub.h
+++ tests/stubs/switcher_stub.h
@@ -27,7 +27,7 @@
 class SwitcherStub : public StubBase
 {
 public:
-    virtual void switcherConstructor(const WindowMonitor *windowMonitor, MWidget *parent = NULL, SwitcherModel *model = NULL);
+    virtual void switcherConstructor(MWidget *parent = NULL, SwitcherModel *model = NULL);
     virtual void switcherDestructor();
     virtual bool handleXEvent(const XEvent &event);
     virtual void updateButtons();
@@ -39,12 +39,12 @@
     virtual bool sceneEvent(QEvent *event);
     virtual void updateAnimationStatus(bool animating);
     virtual QSharedPointer<SwitcherButton> createSwitcherButton();
+    virtual bool restoreButtonBeingRemoved(Window window, bool forceUpdateButtons);
 };
 
-void SwitcherStub::switcherConstructor(const WindowMonitor *windowMonitor, MWidget *parent, SwitcherModel *model)
+void SwitcherStub::switcherConstructor(MWidget *parent, SwitcherModel *model)
 {
     QList<ParameterBase *> params;
-    params.append(new Parameter<const WindowMonitor *>(windowMonitor));
     params.append(new Parameter<MWidget *>(parent));
     params.append(new Parameter<SwitcherModel *>(model));
     stubMethodEntered("switcherConstructor", params);
@@ -120,12 +120,22 @@
     return stubReturnValue<QSharedPointer<SwitcherButton> >("createSwitcherButton");
 }
 
+bool SwitcherStub::restoreButtonBeingRemoved(Window window, bool forceUpdateButtons)
+{
+    QList<ParameterBase *> params;
+    params.append(new Parameter< Window > (window));
+    params.append(new Parameter< bool > (forceUpdateButtons));
+    stubMethodEntered("restoreButtonBeingRemoved", params);
+    return stubReturnValue<bool>("restoreButtonBeingRemoved");
+}
+
+
 SwitcherStub gDefaultSwitcherStub;
 SwitcherStub *gSwitcherStub = &gDefaultSwitcherStub;
 
-Switcher::Switcher(const WindowMonitor *windowMonitor, MWidget *parent, SwitcherModel *model) : MWidgetController(parent)
+Switcher::Switcher(MWidget *parent, SwitcherModel *model) : MWidgetController(parent)
 {
-    gSwitcherStub->switcherConstructor(windowMonitor, parent, model);
+    gSwitcherStub->switcherConstructor(parent, model);
 }
 
 Switcher::~Switcher()
@@ -183,4 +193,9 @@
     return gSwitcherStub->createSwitcherButton();
 }
 
+bool Switcher::restoreButtonBeingRemoved(Window window, bool forceUpdateButtons)
+{
+    return gSwitcherStub->restoreButtonBeingRemoved(window, forceUpdateButtons);
+}
+
 #endif
--- tests/stubs/x11wrapper_stub.h
+++ tests/stubs/x11wrapper_stub.h
@@ -41,6 +41,7 @@
     virtual Damage XDamageCreate(Display *dpy, Drawable drawable, int level);
     virtual void XDamageSubtract(Display *display, Damage damage, XserverRegion repair, XserverRegion parts);
     virtual void XDamageDestroy(Display *dpy, Damage damage);
+    virtual int XSync(Display *display, Bool discard);
     virtual XErrorHandler XSetErrorHandler(XErrorHandler handler);
     virtual int XChangeProperty(Display *display, Window w, Atom property, Atom type, int format, int mode, unsigned char *data, int nelements);
     virtual Status XSendEvent(Display *display, Window w, Bool propagate, long event_mask, XEvent *event_send);
@@ -180,6 +181,15 @@
     stubMethodEntered("XDamageDestroy", params);
 }
 
+int X11WrapperStub::XSync(Display *display, Bool discard)
+{
+    QList<ParameterBase *> params;
+    params.append(new Parameter<Display * >(display));
+    params.append(new Parameter<Bool >(discard));
+    stubMethodEntered("XSync", params);
+    return stubReturnValue<int>("XSync");
+}
+
 XErrorHandler X11WrapperStub::XSetErrorHandler(XErrorHandler handler)
 {
     QList<ParameterBase *> params;
@@ -288,6 +298,11 @@
     gX11WrapperStub->XDamageDestroy(dpy, damage);
 }
 
+int X11Wrapper::XSync(Display *display, Bool discard)
+{
+    return gX11WrapperStub->XSync(display, discard);
+}
+
 XErrorHandler X11Wrapper::XSetErrorHandler(XErrorHandler handler)
 {
     return gX11WrapperStub->XSetErrorHandler(handler);
--- tests/ut_applicationpackagemonitorlistener/ut_applicationpackagemonitorlistener.cpp
+++ tests/ut_applicationpackagemonitorlistener/ut_applicationpackagemonitorlistener.cpp
@@ -133,4 +133,10 @@
     QCOMPARE(gApplicationPackageMonitorStub->stubCallCount("updatePackageStates"), 1);
 }
 
+void Ut_ApplicationPackageMonitorListener::testIsInstallerExtraEntry()
+{
+    QVERIFY(ApplicationPackageMonitorListener::isInstallerExtraEntry("/dev/null/installer-extra/entry.desktop"));
+    QVERIFY(!ApplicationPackageMonitorListener::isInstallerExtraEntry("/dev/null/entry.desktop"));
+}
+
 QTEST_APPLESS_MAIN(Ut_ApplicationPackageMonitorListener)
--- tests/ut_applicationpackagemonitorlistener/ut_applicationpackagemonitorlistener.h
+++ tests/ut_applicationpackagemonitorlistener/ut_applicationpackagemonitorlistener.h
@@ -50,6 +50,7 @@
     void testSetOperationSuccess();
     void testSetOperationError();
     void testUpdatePackageStates();
+    void testIsInstallerExtraEntry();
 
 private:
     // MApplication
--- tests/ut_desktopview/ut_desktopview.cpp
+++ tests/ut_desktopview/ut_desktopview.cpp
@@ -176,6 +176,11 @@
 
 }
 
+int X11Wrapper::XSync(Display *, Bool)
+{
+    return 0;
+}
+
 XErrorHandler X11Wrapper::XSetErrorHandler(XErrorHandler)
 {
     return 0;
@@ -319,6 +324,8 @@
 
 void Ut_DesktopView::init()
 {
+    homeWindowMonitor = new HomeWindowMonitor();
+    gHomeWindowMonitorStub->stubSetReturnValue("instance", homeWindowMonitor);
     desktop = new Desktop;
     desktopView = new TestDesktopView(desktop);
     desktop->setView(desktopView);
@@ -341,6 +348,9 @@
     qDirExistsDirs.clear();
     qDirMkPathDirs.clear();
     gLauncherDataStoreStub->stubReset();
+    gHomeWindowMonitorStub->stubReset();
+    delete homeWindowMonitor;
+    homeWindowMonitor = NULL;
 }
 
 void Ut_DesktopView::testToggleLauncher()
@@ -386,8 +396,7 @@
     gMSceneManagerStub->stubReset();
     gQGraphicsItemIsVisible = true;
 
-    connect(this, SIGNAL(obscured()), desktopView->homeWindowMonitor.data(), SIGNAL(fullscreenWindowOnTopOfOwnWindow()));
-    emit obscured();
+    desktopView->hideLauncher();
 
     verifyAppearDisappear(desktopView->switcherWindow, desktopView->launcherWindow);
 }
@@ -498,4 +507,9 @@
     QCOMPARE(gLauncherDataStoreStub->stubLastCallTo("LauncherDataStore").parameter<QStringList>(1), (QStringList() << APPLICATIONS_DIRECTORY << (QDir::homePath() + "/.local/share/applications/")));
 }
 
+void Ut_DesktopView::testConnectionsInConstructor()
+{
+    QVERIFY(disconnect(HomeWindowMonitor::instance(), SIGNAL(fullscreenWindowOnTopOfOwnWindow()), desktopView, SLOT(hideLauncher())));
+}
+
 QTEST_APPLESS_MAIN(Ut_DesktopView)
--- tests/ut_desktopview/ut_desktopview.h
+++ tests/ut_desktopview/ut_desktopview.h
@@ -30,6 +30,7 @@
 class QPainter;
 class QPixmap;
 class MButton;
+class HomeWindowMonitor;
 
 class TestDesktopBackgroundExtension : public MDesktopBackgroundExtensionInterface
 {
@@ -88,6 +89,7 @@
     void testDefocusing();
     void testDataStoreInitialization_data();
     void testDataStoreInitialization();
+    void testConnectionsInConstructor();
 
 public:
     // The main window
@@ -113,6 +115,7 @@
     QPixmap *backgroundImage;
     QPixmap *backgroundTopImage;
     QPixmap *backgroundBottomImage;
+    HomeWindowMonitor *homeWindowMonitor;
 };
 
 #endif
--- tests/ut_launcher/ut_launcher.cpp
+++ tests/ut_launcher/ut_launcher.cpp
@@ -34,6 +34,7 @@
 #include "mockdatastore.h"
 
 const static int BUTTONS_PER_PAGE = 12;
+const static QString INSTALLER_EXTRA_PATH = APPLICATIONS_DIRECTORY + ApplicationPackageMonitor::INSTALLER_EXTRA_FOLDER;
 
 QString qProcessProgramStarted;
 bool QProcess::startDetached(const QString &program)
@@ -104,6 +105,7 @@
 
     gLauncherButtonStub->stubReset();
     gLauncherDataStoreStub->stubReset();
+    gApplicationPackageMonitorListenerStub->stubReset();
 
     fileExists = true;
 }
@@ -137,6 +139,8 @@
     dataForAllDesktopEntries.insert(QString(APPLICATIONS_DIRECTORY) + "testApp41.desktop", QVariant("launcher/4/1"));
     dataForAllDesktopEntries.insert(QString(APPLICATIONS_DIRECTORY) + "testApp50.desktop", QVariant("launcher/5/0"));
     gLauncherDataStoreStub->stubSetReturnValue("dataForAllDesktopEntries", dataForAllDesktopEntries);
+
+    gLauncherButtonStub->stubSetReturnValueList("desktopEntry", dataForAllDesktopEntries.keys());
 }
 
 void Ut_Launcher::comparePageNumberArgument(QSignalSpy &spy, int page)
@@ -259,16 +263,37 @@
     // Fake a directory change notification
     emit directoryChanged(APPLICATIONS_DIRECTORY);
 
-    connect(this, SIGNAL(updateButton(QString)), launcher, SLOT(updateLauncherButton(QString)));
-
     QString updateButtonEntry = QString(APPLICATIONS_DIRECTORY) + "testApp20.desktop";
-    // Make one specific button to "simulate" updated button
-    // (Update is checked from button so that we don't have to stub LauncherPage just for this)
 
-    gLauncherButtonStub->stubSetReturnValue("desktopEntry", updateButtonEntry);
+    launcher->updateLauncherButton(updateButtonEntry);
+
+    QCOMPARE(gLauncherButtonStub->stubCallCount("updateFromDesktopEntry"), 1);
+}
+
+void Ut_Launcher::testUpdatingLauncherButtonFromInstallerExtraFolder()
+{
+    /* Initialize launcher with two buttons of which one is in installer-extra folder */
+    QString installerExtraButtonEntry = INSTALLER_EXTRA_PATH + "testApp2.desktop";
+    QString applicationsButtonEntry = QString(APPLICATIONS_DIRECTORY) + "testApp1.desktop";
+
+    QHash<QString, QVariant> dataForAllDesktopEntries;
+    dataForAllDesktopEntries.insert(applicationsButtonEntry, QVariant("launcher/0/0"));
+    dataForAllDesktopEntries.insert(installerExtraButtonEntry, QVariant("launcher/0/1"));
+    gLauncherDataStoreStub->stubSetReturnValue("dataForAllDesktopEntries", dataForAllDesktopEntries);
+    launcher->updatePagesFromDataStore();
+
+    QList<QString> entries;
+    entries << applicationsButtonEntry << installerExtraButtonEntry;
+    gLauncherButtonStub->stubSetReturnValueList("desktopEntry", entries);
+
+    gApplicationPackageMonitorListenerStub->stubSetReturnValue("isInstallerExtraEntry", true);
+
 
-    emit updateButton(updateButtonEntry);
+    QString updateButtonEntry = QString(APPLICATIONS_DIRECTORY) + "testApp2.desktop";
+    launcher->updateLauncherButton(updateButtonEntry);
 
+    QCOMPARE(gLauncherDataStoreStub->stubCallCount("removeDataForDesktopEntry"), 1);
+    QCOMPARE(gLauncherDataStoreStub->stubCallCount("updateDataForDesktopEntry"), 1);
     QCOMPARE(gLauncherButtonStub->stubCallCount("updateFromDesktopEntry"), 1);
 }
 
--- tests/ut_launcher/ut_launcher.h
+++ tests/ut_launcher/ut_launcher.h
@@ -76,6 +76,8 @@
     void testFocusToButton();
     // Test that launcher button is updated when signal received
     void testUpdatingLauncherButton();
+    // Test that launcher button is updated when signal received and button is in installer-extra folder
+    void testUpdatingLauncherButtonFromInstallerExtraFolder();
     // Test adding buttons
     void testAddingButtons();
     // Test adding buttons on multiple pages
--- tests/ut_launcherbutton/ut_launcherbutton.cpp
+++ tests/ut_launcherbutton/ut_launcherbutton.cpp
@@ -161,6 +161,11 @@
 
 }
 
+int X11Wrapper::XSync(Display *, Bool)
+{
+    return 0;
+}
+
 XErrorHandler X11Wrapper::XSetErrorHandler(XErrorHandler)
 {
     return 0;
@@ -316,6 +321,8 @@
 
 void Ut_LauncherButton::init()
 {
+    homeWindowMonitor = new HomeWindowMonitor();
+    gHomeWindowMonitorStub->stubSetReturnValue("instance", homeWindowMonitor);
     language = "english";
     contentActionPrivate.clear();
     contentActionTriggerCalls = 0;
@@ -323,7 +330,7 @@
 
     m_subject = new LauncherButton("");
     connect(this, SIGNAL(clicked()), m_subject, SLOT(launch()));
-    connect(this, SIGNAL(obscured()), m_subject->windowMonitor.data(), SIGNAL(fullscreenWindowOnTopOfOwnWindow()));
+    connect(this, SIGNAL(obscured()), HomeWindowMonitor::instance(), SIGNAL(fullscreenWindowOnTopOfOwnWindow()));
 }
 
 void Ut_LauncherButton::cleanup()
@@ -331,6 +338,9 @@
     m_subject->stopLaunchProgress();
     delete m_subject;
     gMDesktopEntryStub->stubReset();
+    gHomeWindowMonitorStub->stubReset();
+    delete homeWindowMonitor;
+    homeWindowMonitor = NULL;
 }
 
 void Ut_LauncherButton::testInitialization()
@@ -420,13 +430,13 @@
     QCOMPARE(m_subject->model()->operationProgress(), 0);
 
     int progress = 50;
-    m_subject->setState(LauncherButtonModel::Downloading, progress, "");
+    m_subject->setState(LauncherButtonModel::Downloading, progress);
     QCOMPARE(m_subject->model()->buttonState(), LauncherButtonModel::Downloading);
     QCOMPARE(m_subject->model()->operationProgress(), progress);
 
     //Only progress should change
     progress = 99;
-    m_subject->setState(LauncherButtonModel::Downloading, progress, "");
+    m_subject->setState(LauncherButtonModel::Downloading, progress);
     QCOMPARE(m_subject->model()->buttonState(), LauncherButtonModel::Downloading);
     QCOMPARE(m_subject->model()->operationProgress(), progress);
 }
@@ -435,48 +445,16 @@
 {
     //With invalid values progress shouldn't change from default value 0
     int progress = -1;
-    m_subject->setState(LauncherButtonModel::Installing, progress, "");
+    m_subject->setState(LauncherButtonModel::Installing, progress);
     QCOMPARE(m_subject->model()->buttonState(), LauncherButtonModel::Installing);
     QCOMPARE(m_subject->model()->operationProgress(), 0);
 
     progress = 101;
-    m_subject->setState(LauncherButtonModel::Downloading, progress, "");
+    m_subject->setState(LauncherButtonModel::Downloading, progress);
     QCOMPARE(m_subject->model()->buttonState(), LauncherButtonModel::Downloading);
     QCOMPARE(m_subject->model()->operationProgress(), 0);
 }
 
-void Ut_LauncherButton::testSettingButtonStateWithUpdatingDesktopEntry_data()
-{
-     QTest::addColumn<LauncherButtonModel::State>("state");
-     QTest::addColumn<bool>("shouldBeUpdated");
-     QTest::newRow("Installed") << LauncherButtonModel::Installed << true;
-     QTest::newRow("Installing") << LauncherButtonModel::Installing << false;
-     QTest::newRow("Downloading") << LauncherButtonModel::Downloading << false;
-     QTest::newRow("Broken") << LauncherButtonModel::Broken << true;
-}
-
-void Ut_LauncherButton::testSettingButtonStateWithUpdatingDesktopEntry()
-{
-    QFETCH(LauncherButtonModel::State, state);
-    QFETCH(bool, shouldBeUpdated);
-
-    QString initialDesktopEntry = "/dev/null/initial.desktop";
-    QString updatedDesktopEntry = "/dev/null/updated.desktop";
-
-    addActionPrivate(initialDesktopEntry,true,"initial","","","");
-    addActionPrivate(updatedDesktopEntry,true,"updated","","","");
-    m_subject->updateFromDesktopEntry(initialDesktopEntry);
-
-    gMDesktopEntryStub->stubReset();
-    m_subject->setState(state, 0, updatedDesktopEntry);
-
-    QCOMPARE(gMDesktopEntryStub->stubCallCount("MDesktopEntry"), shouldBeUpdated ? 1 : 0);
-    if (shouldBeUpdated) {
-        QCOMPARE(gMDesktopEntryStub->stubLastCallTo("MDesktopEntry").parameter<QString>(0), updatedDesktopEntry);
-    }
-    QCOMPARE(m_subject->action.name(), QString(shouldBeUpdated ? "updated" : "initial"));
-}
-
 void Ut_LauncherButton::testLaunchingMultipleTimes()
 {
     emit clicked();
--- tests/ut_launcherbutton/ut_launcherbutton.h
+++ tests/ut_launcherbutton/ut_launcherbutton.h
@@ -25,6 +25,7 @@
 
 class MApplication;
 class LauncherButton;
+class HomeWindowMonitor;
 
 class Ut_LauncherButton : public QObject
 {
@@ -50,8 +51,6 @@
     void testStopLaunchProgressIfObscured();
     void testSettingButtonStateAndProgress();
     void testSettingButtonStateAndProgressWithInvalidValues();
-    void testSettingButtonStateWithUpdatingDesktopEntry_data();
-    void testSettingButtonStateWithUpdatingDesktopEntry();
     void testLaunchingMultipleTimes();
     void testTryingToLaunchSecondActionWhileLaunching();
 
@@ -64,6 +63,7 @@
     MApplication *app;
     // The object being tested
     LauncherButton *m_subject;
+    HomeWindowMonitor *homeWindowMonitor;
 };
 
 #endif
--- tests/ut_launcherpage/ut_launcherpage.cpp
+++ tests/ut_launcherpage/ut_launcherpage.cpp
@@ -125,6 +125,22 @@
     QCOMPARE(result, 0);
 }
 
+void Ut_LauncherPage::testGetButton()
+{
+    QString desktopEntryPath = "test.desktop";
+    QSharedPointer<LauncherButton> button1 = createLauncherButton(desktopEntryPath);
+    m_subject->appendButton(button1);
+
+    QSharedPointer<LauncherButton> button2 = createLauncherButton("dummy.desktop");
+    m_subject->appendButton(button2);
+
+    gLauncherButtonStub->stubSetReturnValueList("desktopEntry", QList<QString>() << "test.desktop" << "dummy.desktop");
+    QSharedPointer<LauncherButton> button = m_subject->button(desktopEntryPath);
+    QVERIFY(!button.isNull());
+
+    button = m_subject->button("non-existing.desktop");
+    QVERIFY(button.isNull());
+}
 
 static QSharedPointer<LauncherButton> createLauncherButton(QString desktopFileName)
 {
--- tests/ut_launcherpage/ut_launcherpage.h
+++ tests/ut_launcherpage/ut_launcherpage.h
@@ -47,6 +47,7 @@
     void testUpdateButton();
     // Tests that position is returned for desktop entry file.
     void testLauncherButtonPosition();
+    void testGetButton();
 
 private:
     // MApplication
--- tests/ut_switcher/ut_switcher.cpp
+++ tests/ut_switcher/ut_switcher.cpp
@@ -308,6 +308,11 @@
 
 }
 
+int X11Wrapper::XSync(Display *, Bool)
+{
+    return 0;
+}
+
 XErrorHandler X11Wrapper::XSetErrorHandler(XErrorHandler)
 {
     return 0;
@@ -400,15 +405,6 @@
     gSwitcherButtonVisibleInSwitcherProperty[this] = set;
 }
 
-class MockWindowMonitor : public WindowMonitor {
-public:
-    virtual bool isOwnWindow(WId wid) const {
-        return ownWindows.contains(wid);
-    }
-
-    QList<WId> ownWindows;
-};
-
 // QTimer stubs
 bool qTimerImmediateTimeout;
 void QTimer::start(int)
@@ -444,9 +440,10 @@
 int Ut_Switcher::clientListNumberOfWindows;
 void Ut_Switcher::init()
 {
+    homeWindowMonitor = new HomeWindowMonitor();
+    gHomeWindowMonitorStub->stubSetReturnValue("instance", homeWindowMonitor);
     // Creating a switcher also creates the switcher view
-    mockWindowMonitor = new MockWindowMonitor;
-    switcher = new Switcher(mockWindowMonitor);
+    switcher = new Switcher();
 
     visibilityNotifyWindows.clear();
     propertyNotifyWindows.clear();
@@ -492,7 +489,9 @@
     // Destroy the switcher (and the associated view)
     delete switcher;
     switcher = NULL;
-    mockWindowMonitor = NULL;
+    gHomeWindowMonitorStub->stubReset();
+    delete homeWindowMonitor;
+    homeWindowMonitor = NULL;
 }
 
 void Ut_Switcher::initTestCase()
@@ -531,6 +530,17 @@
     g_windowTypeMap[window] = types;
 }
 
+void removeApplicationWindow(Window window)
+{
+    g_windows.remove(window);
+}
+
+void moveApplicationWindowTop(Window window)
+{
+    g_windows.remove(g_windows.indexOf(window));
+    g_windows.insert(0, window);
+}
+
 void Ut_Switcher::updateWindowList()
 {
     QList<WindowInfo> newWindowList;
@@ -570,6 +580,23 @@
     QCOMPARE(sec.event.xclient.data.l[2], 0L);
 }
 
+void Ut_Switcher::testWhenCloseWindowThenButtonRemovedFromModel()
+{
+    updateWindowList();
+    WindowListReceiver receiver;
+    connect(switcher, SIGNAL(windowListUpdated(const QList<WindowInfo> &)), &receiver,
+            SLOT(windowListUpdated(const QList<WindowInfo> &)));
+
+    switcher->closeWindow(FIRST_APPLICATION_WINDOW);
+
+    // Verify that button is in windowsBeingClosed and not in the model
+    QCOMPARE(switcher->windowsBeingClosed.count(), 1);
+    QVERIFY(switcher->windowsBeingClosed.contains(FIRST_APPLICATION_WINDOW));
+    QList<WindowInfo> remainingWindows = receiver.windowList;
+    remainingWindows.removeOne(WindowInfo(FIRST_APPLICATION_WINDOW));
+    verifyModel(remainingWindows);
+}
+
 void Ut_Switcher::testCloseAllWindows()
 {
     int numWindows = 5;
@@ -606,11 +633,16 @@
     // There given windows should be in the switcher model
     QCOMPARE(switcher->model()->buttons().count(), windowList.count());
 
-    for (int i = 0; i < windowList.count(); i++) {
-        // The buttons should match the windows
-        SwitcherButton *b = switcher->model()->buttons().at(i).data();
-        QCOMPARE(b->xWindow(), windowList.at(i).window());
-        QCOMPARE(b->text(), windowList.at(i).title());
+    // The model should contain all and only the buttons for the windows (not necessary in same order)
+    foreach (const WindowInfo &windowInfo, windowList) {
+        bool contains = false;
+        foreach(const QSharedPointer<SwitcherButton> &button, switcher->model()->buttons()) {
+            if ((button->xWindow() == windowInfo.window()) && button->text() == windowInfo.title()) {
+                contains = true;
+                break;
+            }
+        }
+        QVERIFY(contains);
     }
 }
 
@@ -677,51 +709,93 @@
     verifyModel(r.windowList);
 }
 
+void Ut_Switcher::testX11EventFilterWithClientMessage_data()
+{
+    QTest::addColumn<int>("type");
+    QTest::addColumn<Atom>("messageType");
+    QTest::addColumn<Window>("window");
+
+    QTest::addColumn<bool>("verifySuccess");
+
+    QTest::newRow("Wrong event and message type") << 0 << Atom(0) << Window(0) << false;
+    QTest::newRow("Wrong message type") << ClientMessage << Atom(0) << Window(0) << false;
+    QTest::newRow("Wrong event type")
+            << 0 << X11Wrapper::XInternAtom(QX11Info::display(), "_NET_CLOSE_WINDOW", False) << Window(0) << false;
+    QTest::newRow("Wrong window")
+            << ClientMessage << X11Wrapper::XInternAtom(QX11Info::display(), "_NET_CLOSE_WINDOW", False)
+            << Window(0) << true;
+    QTest::newRow("Correct event")
+            << ClientMessage << X11Wrapper::XInternAtom(QX11Info::display(), "_NET_CLOSE_WINDOW", False)
+            << Window(FIRST_APPLICATION_WINDOW) << true;
+}
+
 void Ut_Switcher::testX11EventFilterWithClientMessage()
 {
+    QFETCH(int, type);
+    QFETCH(Atom, messageType);
+    QFETCH(Window, window);
+
+    QFETCH(bool, verifySuccess);
+
+    // Update window list with an application
+    QList<WindowInfo> newWindowList;
+    newWindowList.append(WindowInfo(g_windows[0]));
+    switcher->handleWindowInfoList(newWindowList);
+
+    XEvent clientEvent;
+    clientEvent.type = type;
+    clientEvent.xclient.message_type = messageType;
+    clientEvent.xclient.window = window;
+    QCOMPARE(switcher->handleXEvent(clientEvent), verifySuccess);
+}
+
+void Ut_Switcher::testX11EventFilterCloseWindow()
+{
     updateWindowList();
 
-    WindowListReceiver r;
-    connect(switcher, SIGNAL(windowListUpdated(const QList<WindowInfo> &)), &r, SLOT(windowListUpdated(const QList<WindowInfo> &)));
+    WindowListReceiver receiver;
+    connect(switcher, SIGNAL(windowListUpdated(const QList<WindowInfo> &)), &receiver, SLOT(windowListUpdated(const QList<WindowInfo> &)));
 
-    // Verify that X11EventFilter only reacts to events it's supposed to react on (type and message_type are both set correctly)
     XEvent clientEvent;
-    clientEvent.type = 0;
-    clientEvent.xclient.message_type = 0;
-    QVERIFY(!switcher->handleXEvent(clientEvent));
     clientEvent.type = ClientMessage;
-    QVERIFY(!switcher->handleXEvent(clientEvent));
-    clientEvent.type = 0;
     clientEvent.xclient.message_type = X11Wrapper::XInternAtom(QX11Info::display(), "_NET_CLOSE_WINDOW", False);
-    QVERIFY(!switcher->handleXEvent(clientEvent));
-    clientEvent.type = ClientMessage;
-    clientEvent.xclient.window = FIRST_APPLICATION_WINDOW;
-    QVERIFY(switcher->handleXEvent(clientEvent));
+    clientEvent.xclient.window = Window(FIRST_APPLICATION_WINDOW);
+    switcher->handleXEvent(clientEvent);
 
-    // When the stacking list is updated the closed window should be excluded
-    updateWindowList();
+    // _NET_CLOSE_WINDOW shouldn't affect to the window list
+    QCOMPARE(receiver.windowList.count(), APPLICATION_WINDOWS);
 
-    // Make sure the window list change signal was emitted
-    QCOMPARE(r.count, 1);
+    // Verify that button is in windowsBeingClosed and not in the model
+    QCOMPARE(switcher->windowsBeingClosed.count(), 1);
+    QVERIFY(switcher->windowsBeingClosed.contains(FIRST_APPLICATION_WINDOW));
+    QList<WindowInfo> remainingWindows = receiver.windowList;
+    remainingWindows.removeOne(WindowInfo(FIRST_APPLICATION_WINDOW));
+    verifyModel(remainingWindows);
+}
 
-    // There should be 1 window in the window list
-    QCOMPARE(r.windowList.count(), APPLICATION_WINDOWS - 1);
-    verifyModel(r.windowList);
+void Ut_Switcher::testX11EventFilterCloseWindowForNonExistentWindow()
+{
+    WindowListReceiver receiver;
+    connect(switcher, SIGNAL(windowListUpdated(const QList<WindowInfo> &)), &receiver, SLOT(windowListUpdated(const QList<WindowInfo> &)));
+    updateWindowList();
 
-    // Close a non-existant window
+    // Try to close a non-existant window
+    XEvent clientEvent;
+    clientEvent.type = ClientMessage;
+    clientEvent.xclient.message_type = X11Wrapper::XInternAtom(QX11Info::display(), "_NET_CLOSE_WINDOW", False);
     clientEvent.xclient.window = 234;
-    QVERIFY(switcher->handleXEvent(clientEvent));
+    switcher->handleXEvent(clientEvent);
 
+    QCOMPARE(switcher->windowsBeingClosed.count(), 0);
+    verifyModel(receiver.windowList);
     // Now open a window with the same id, the previous
     // close event shouldn't affect this
     addApplicationWindow(234);
     updateWindowList();
 
     // Make sure the window list change signal was emitted
-    QCOMPARE(r.count, 2);
-
-    // There should be 2 windows in the window list again
-    QCOMPARE(r.windowList.count(), APPLICATION_WINDOWS);
+    QCOMPARE(receiver.windowList.count(), 3);
+    verifyModel(receiver.windowList);
 }
 
 void Ut_Switcher::testWhenStackingOrderChangesCorrectWindowsAreStored()
@@ -1007,4 +1081,52 @@
     QCOMPARE(gSwitcherButtonVisibleInSwitcherProperty[button.data()], false);
 }
 
+void Ut_Switcher::testRestoringButtonBeingClosedWhenWindowComesOnTop()
+{
+    updateWindowList();
+    WindowListReceiver receiver;
+    connect(switcher, SIGNAL(windowListUpdated(const QList<WindowInfo> &)), &receiver,
+            SLOT(windowListUpdated(const QList<WindowInfo> &)));
+
+    // Close window so it gets added to the buttons being closed list
+    const Window CLOSING_WINDOW = FIRST_APPLICATION_WINDOW + 1;
+    switcher->closeWindow(CLOSING_WINDOW);
+
+    QCOMPARE(switcher->windowsBeingClosed.count(), 1);
+    QCOMPARE(switcher->model()->buttons().count(), APPLICATION_WINDOWS - 1);
+
+    // Move window being closed to top and update window list
+    QList<WindowInfo> newWindowList = receiver.windowList;
+    newWindowList.move(newWindowList.indexOf(WindowInfo(CLOSING_WINDOW)), newWindowList.count() - 1);
+    switcher->handleWindowInfoList(newWindowList);
+
+    QCOMPARE(switcher->windowsBeingClosed.count(), 0);
+    QVERIFY(!switcher->windowsBeingClosed.contains(CLOSING_WINDOW));
+    verifyModel(receiver.windowList);
+}
+
+void Ut_Switcher::testRestoringButtonBeingClosedWhenButtonCloseTimerTimeouts()
+{
+    updateWindowList();
+    WindowListReceiver receiver;
+    connect(switcher, SIGNAL(windowListUpdated(const QList<WindowInfo> &)), &receiver,
+            SLOT(windowListUpdated(const QList<WindowInfo> &)));
+
+    // Close window so it gets added to the buttons being closed list
+    const Window CLOSING_WINDOW = FIRST_APPLICATION_WINDOW + 1;
+    switcher->closeWindow(CLOSING_WINDOW);
+
+    QCOMPARE(switcher->windowsBeingClosed.count(), 1);
+    QCOMPARE(switcher->model()->buttons().count(), APPLICATION_WINDOWS - 1);
+
+    foreach(const QSharedPointer<SwitcherButton> &button, switcher->model()->buttons()) {
+        QVERIFY(disconnect(button.data(), SIGNAL(closeTimedOutForWindow(Window)),
+                           switcher, SLOT(restoreButtonBeingRemoved(Window))));
+    }
+    switcher->restoreButtonBeingRemoved(CLOSING_WINDOW);
+    QCOMPARE(switcher->windowsBeingClosed.count(), 0);
+    QVERIFY(!switcher->windowsBeingClosed.contains(CLOSING_WINDOW));
+    verifyModel(receiver.windowList);
+}
+
 QTEST_APPLESS_MAIN(Ut_Switcher)
--- tests/ut_switcher/ut_switcher.h
+++ tests/ut_switcher/ut_switcher.h
@@ -24,13 +24,13 @@
 #include "windowinfo.h"
 
 class MApplication;
-class MockWindowMonitor;
 class Switcher;
 class SwitcherButton;
 class MSceneManager;
 class QSizeF;
 class QRectF;
 class QPointF;
+class HomeWindowMonitor;
 
 class WindowListReceiver : public QObject
 {
@@ -90,7 +90,6 @@
 
 private:
     MApplication *app;
-    MockWindowMonitor *mockWindowMonitor;
     Switcher *switcher;
 
     void updateWindowList();
@@ -116,6 +115,9 @@
     // Test closing windows
     void testCloseWindow();
 
+    // Test when closing window then button is removed from model
+    void testWhenCloseWindowThenButtonRemovedFromModel();
+
     // Test closing all windows
     void testCloseAllWindows();
 
@@ -123,8 +125,15 @@
     void testX11EventFilterWithPropertyNotify();
 
     // Test X11EventFilter with ClientMessage events
+    void testX11EventFilterWithClientMessage_data();
     void testX11EventFilterWithClientMessage();
 
+    // Test X11EventFilter with _NET_CLOSE_WINDOW
+    void testX11EventFilterCloseWindow();
+
+    // Test X11EventFilter with _NET_CLOSE_WINDOW and non-existent window
+    void testX11EventFilterCloseWindowForNonExistentWindow();
+
     // Test the stacking order signal is hanled correctly
     void testWhenStackingOrderChangesCorrectWindowsAreStored();
     void testWhenStackingOrderChangesTopmostWindowGetsUpdated();
@@ -155,7 +164,11 @@
 
     void testThatSwitcherButtonVisibleInSwitcherPropertyIsSetToFalseWhenApplicationWindowIsRemoved();
 
+    void testRestoringButtonBeingClosedWhenWindowComesOnTop();
+    void testRestoringButtonBeingClosedWhenButtonCloseTimerTimeouts();
+
 private:
     MSceneManager *mSceneManager;
+    HomeWindowMonitor *homeWindowMonitor;
 };
 #endif //_UT_SWITCHER_
--- tests/ut_switcherbutton/ut_switcherbutton.cpp
+++ tests/ut_switcherbutton/ut_switcherbutton.cpp
@@ -196,6 +196,9 @@
 
 void Ut_SwitcherButton::testSetVisibleInSwitcherProperty()
 {
+    // Initialize to invisible
+    button->setVisibleInSwitcherProperty(false);
+
     // Set window visible in the Switcher
     button->setVisibleInSwitcherProperty(true);
 
@@ -223,8 +226,23 @@
     QVERIFY(data[0] == 0);
 }
 
+void Ut_SwitcherButton::testSetVisibleInSwitcherPropertyNotUpdatedWhenValueDoesNotChange()
+{
+    // Set visible and after that set the window to -1
+    button->setVisibleInSwitcherProperty(true);
+    Ut_SwitcherButton::xChangePropertyWindow = -1;
+
+    button->setVisibleInSwitcherProperty(true);
+
+    // Verify that XChangeProperty wasn't called
+    QCOMPARE(Ut_SwitcherButton::xChangePropertyWindow, Window(-1));
+}
+
 void Ut_SwitcherButton::testWhenVisibilityPropertyDisabledThenPropertyChangesOnlyWhenEnabledAgain()
 {
+    // Initialize to invisible
+    button->setVisibleInSwitcherProperty(false);
+
     button->setVisibilityPropertyEnabled(false);
     button->setVisibleInSwitcherProperty(true);
     QCOMPARE(Ut_SwitcherButton::xChangePropertyWindow, Window(0));
--- tests/ut_switcherbutton/ut_switcherbutton.h
+++ tests/ut_switcherbutton/ut_switcherbutton.h
@@ -83,6 +83,7 @@
     void testPrepareGeometryChange();
     // Test that X11 properties are set correctly if visible in switcher
     void testSetVisibleInSwitcherProperty();
+    void testSetVisibleInSwitcherPropertyNotUpdatedWhenValueDoesNotChange();
     void testWhenVisibilityPropertyDisabledThenPropertyChangesOnlyWhenEnabledAgain();
 };
 
--- tests/ut_switcherbuttonview/ut_switcherbuttonview.cpp
+++ tests/ut_switcherbuttonview/ut_switcherbuttonview.cpp
@@ -133,6 +133,11 @@
     }
 }
 
+int X11Wrapper::XSync(Display *, Bool)
+{
+    return 0;
+}
+
 void X11Wrapper::XDamageSubtract(Display *dpy, Damage damage, XserverRegion, XserverRegion)
 {
     Ut_SwitcherButtonView::damageSubtracted = true;
@@ -253,9 +258,12 @@
     Ut_SwitcherButtonView::timerStarted = false;
 }
 
+Qt::HANDLE gQPixmapX11Handle;
+
 // QPixmap stubs (used by SwitcherButtonView)
-QPixmap QPixmap::fromX11Pixmap(Qt::HANDLE, ShareMode)
+QPixmap QPixmap::fromX11Pixmap(Qt::HANDLE handle, ShareMode)
 {
+    gQPixmapX11Handle = handle;
     return QPixmap();
 }
 
@@ -280,6 +288,7 @@
     damageSubtractDisplay = NULL;
     gQPainter_drawPixmap_throwsBadAlloc = false;
     gQPainter_restore_called = false;
+    gQPixmapX11Handle = 0;
 }
 
 void Ut_SwitcherButtonView::cleanup()
@@ -511,34 +520,51 @@
     QCOMPARE(iconGeometry[3], (unsigned int)iconSceneGeometry.height());
 }
 
-static const int ICON_PIXMAP_RETRY_MAX_COUNT = 5;
+static const int ICON_PIXMAP_RETRY_MAX_COUNT = 2;
 void Ut_SwitcherButtonView::testUpdateXWindowPixmap()
 {
     // damage handling is tested elsewhere, this test
-    // tests the retrying logic
+    // tests the error handling and retrying logic
 
-    // test that the timer is started each time the pixmap
-    // fetch causes a badmatch, up to the max count
+    // first update the pixmap successfully
+    xCompositeNameWindowPixmapCausesBadMatch = false;
     button->model()->setXWindow(1);
+    Pixmap oldPixmap = m_subject->xWindowPixmap;
+    QCOMPARE(allocatedPixmaps.count(), 1);
+    QCOMPARE(gQPixmapX11Handle, oldPixmap);
+
+    // test that the timer is started each time the pixmap
+    // fetch causes a badmatch, up to the max count and that
+    // nothing else is done
     xCompositeNameWindowPixmapCausesBadMatch = true;
     for (int i = 0; i < ICON_PIXMAP_RETRY_MAX_COUNT; ++i) {
         timerStarted = false;
         m_subject->updateXWindowPixmap();
         QVERIFY(timerStarted);
         QCOMPARE(m_subject->updateXWindowPixmapRetryCount, i + 1);
+        QCOMPARE(m_subject->xWindowPixmap, oldPixmap);
+        QCOMPARE(allocatedPixmaps.count(), 1);
+        QCOMPARE(gQPixmapX11Handle, oldPixmap);
     }
-    // the next attempt after max count doesn't start the
+    // the next attempt after max count doesn't even start the
     // timer anymore
     timerStarted = false;
     m_subject->updateXWindowPixmap();
     QVERIFY(!timerStarted);
-    QCOMPARE(m_subject->updateXWindowPixmapRetryCount, 0);
-    // when badmatch doesn't occur, the timer is not started either
+    QCOMPARE(m_subject->xWindowPixmap, oldPixmap);
+    QCOMPARE(allocatedPixmaps.count(), 1);
+    QCOMPARE(gQPixmapX11Handle, oldPixmap);
+
+    // when badmatch doesn't occur the timer is not started,
+    // but the pixmap does get updated
     xCompositeNameWindowPixmapCausesBadMatch = false;
     timerStarted = false;
     m_subject->updateXWindowPixmap();
     QVERIFY(!timerStarted);
     QCOMPARE(m_subject->updateXWindowPixmapRetryCount, 0);
+    QVERIFY(m_subject->xWindowPixmap != oldPixmap);
+    QCOMPARE(gQPixmapX11Handle, m_subject->xWindowPixmap);
+    QCOMPARE(allocatedPixmaps.count(), 1);
 }
 
 const Window CORRECT_WINDOW_ID = 1001;
--- tests/ut_switcherview/ut_switcherview.cpp
+++ tests/ut_switcherview/ut_switcherview.cpp
@@ -208,7 +208,6 @@
     return true;
 }
 
-
 QList<QPair<QGraphicsItem*, QGraphicsItem*> > gQGraphicsItem_installSceneEventFilter;
 void QGraphicsItem::installSceneEventFilter(QGraphicsItem *filterItem)
 {
@@ -994,12 +993,17 @@
     QCOMPARE(m_subject->sceneEventFilter(&item, &mouseMoveEvent), false);
 }
 
-void Ut_SwitcherView::testWhenPinchingStartsThenEventsAreCanceledForOtherItems()
+void Ut_SwitcherView::testWhenPinchingStartsOrStopsThenViewportPhysicsEnabledOrDisabled()
 {
-    gSceneItems << new QGraphicsWidget;
-    gSceneItems << new QGraphicsWidget;
+    MPannableViewport *vp1 = new MPannableViewport;
+    MPannableViewport *vp2 = new MPannableViewport;
+    gSceneItems << vp1 << vp2;
     m_subject->pinchBegin(QPointF());
-    QCOMPARE(gSceneItems, gQGraphicsSceneSendCancelEventItems);
+    QVERIFY(!vp1->physics()->enabled());
+    QVERIFY(!vp2->physics()->enabled());
+    m_subject->pinchEnd();
+    QVERIFY(vp1->physics()->enabled());
+    QVERIFY(vp2->physics()->enabled());
 }
 
 
--- tests/ut_switcherview/ut_switcherview.h
+++ tests/ut_switcherview/ut_switcherview.h
@@ -94,7 +94,7 @@
     void testOtherThanGraphicsSceneMouseMoveEventsDoNotGetFilteredForSwitcherButtons();
     void testGraphicsSceneMouseMoveEventsDoNotGetFilteredForOtherThanSwitcherButtons();
     void testPanningDisabledWhenNoSwitcherButtons_NB186716();
-    void testWhenPinchingStartsThenEventsAreCanceledForOtherItems();
+    void testWhenPinchingStartsOrStopsThenViewportPhysicsEnabledOrDisabled();
 
 private:
     void verifyButtonModesInOverviewMode(M::Orientation orientation);
--- tests/ut_windowinfo/ut_windowinfo.cpp
+++ tests/ut_windowinfo/ut_windowinfo.cpp
@@ -130,6 +130,11 @@
 
 }
 
+int X11Wrapper::XSync(Display *, Bool)
+{
+    return 0;
+}
+
 XErrorHandler X11Wrapper::XSetErrorHandler(XErrorHandler)
 {
     return 0;

++++++ meegotouch-home.yaml
--- meegotouch-home.yaml
+++ meegotouch-home.yaml
@@ -1,6 +1,6 @@
 Name: meegotouch-home
 Summary: MeeGo Touch Homescreen
-Version: 0.23.5
+Version: 0.23.10
 Release: 1
 Group: System/Desktop
 License: LGPL v2.1




More information about the MeeGo-commits mailing list