Bug 501490 - Enable Taskbar Previews for Windows 7 r=jimm sr=roc
authorRob Arnold <tellrob@gmail.com>
Mon, 05 Oct 2009 22:26:54 -0400
changeset 33486 5d4df2ddcc206edcb7b7d3678e39dc24683d75de
parent 33485 c94021897336c89abcbcba66bcc5477c3fa642a3
child 33487 4fabad3d0522cfa0d52de3de32b5cfd7abe000e6
push idunknown
push userunknown
push dateunknown
reviewersjimm, roc
bugs501490
milestone1.9.3a1pre
Bug 501490 - Enable Taskbar Previews for Windows 7 r=jimm sr=roc
widget/public/Makefile.in
widget/public/nsITaskbarPreview.idl
widget/public/nsITaskbarPreviewButton.idl
widget/public/nsITaskbarPreviewController.idl
widget/public/nsITaskbarTabPreview.idl
widget/public/nsITaskbarWindowPreview.idl
widget/public/nsIWinTaskbar.idl
widget/public/nsWidgetsCID.h
widget/src/build/nsWinWidgetFactory.cpp
widget/src/windows/Makefile.in
widget/src/windows/TaskbarPreview.cpp
widget/src/windows/TaskbarPreview.h
widget/src/windows/TaskbarPreviewButton.cpp
widget/src/windows/TaskbarPreviewButton.h
widget/src/windows/TaskbarTabPreview.cpp
widget/src/windows/TaskbarTabPreview.h
widget/src/windows/TaskbarWindowPreview.cpp
widget/src/windows/TaskbarWindowPreview.h
widget/src/windows/WinTaskbar.cpp
widget/src/windows/WinTaskbar.h
widget/src/windows/nsAppShell.cpp
widget/src/windows/nsAppShell.h
widget/src/windows/nsUXThemeData.h
widget/src/windows/nsWindow.cpp
widget/src/windows/nsWindow.h
widget/src/windows/nsWindowDbg.cpp
widget/tests/Makefile.in
widget/tests/taskbar_previews.xul
--- a/widget/public/Makefile.in
+++ b/widget/public/Makefile.in
@@ -108,17 +108,23 @@ XPIDLSRCS	= \
 		nsIPrintSession.idl \
 		nsIPrintSettings.idl \
 		nsIPrintSettingsService.idl \
 		nsIPrintOptions.idl \
 		nsIIdleService.idl \
 		$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-XPIDLSRCS	+= nsIPrintSettingsWin.idl
+XPIDLSRCS	+= nsIPrintSettingsWin.idl \
+		nsIWinTaskbar.idl	\
+		nsITaskbarPreview.idl	\
+		nsITaskbarTabPreview.idl \
+		nsITaskbarWindowPreview.idl \
+		nsITaskbarPreviewController.idl \
+		nsITaskbarPreviewButton.idl
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 ifndef MOZ_COCOA_PRINTING
 XPIDLSRCS	+= nsIPrintSettingsX.idl \
 		nsIPrintSessionX.idl
 endif
 endif
new file mode 100644
--- /dev/null
+++ b/widget/public/nsITaskbarPreview.idl
@@ -0,0 +1,104 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+#include "nsIBaseWindow.idl"
+
+interface nsITaskbarPreviewController;
+
+/**
+ * nsITaskbarPreview
+ *
+ * Common interface for both window and tab taskbar previews. This interface
+ * cannot be instantiated directly.
+ *
+ */
+[scriptable, uuid(CBFDF766-D002-403B-A3D9-B091C9AD465B)]
+interface nsITaskbarPreview : nsISupports
+{
+  /**
+   * The controller for this preview. A controller is required to provide
+   * the behavior and appearance of the taskbar previews. It is responsible for
+   * determining the size and contents of the preview, which buttons are
+   * displayed and how the application responds to user actions on the preview.
+   *
+   * Neither preview makes full use of the controller. See the documentation
+   * for nsITaskbarWindowPreview and nsITaskbarTabPreview for details on which
+   * controller methods are used.
+   *
+   * The controller is not allowed to be null.
+   *
+   * @see nsITaskbarPreviewController
+   */
+  attribute nsITaskbarPreviewController controller;
+
+  /**
+   * The tooltip displayed above the preview when the user hovers over it
+   *
+   * Default: an empty string
+   */
+  attribute DOMString tooltip;
+
+  /**
+   * Whether or not the preview is visible.
+   *
+   * Changing this option is expensive for tab previews since toggling this
+   * option will destroy/create the proxy window and its registration with the
+   * taskbar. If any step of that fails, an exception will be thrown.
+   *
+   * For window previews, this operation is very cheap.
+   *
+   * Default: false
+   */
+  attribute boolean visible;
+
+  /**
+   * Gets/sets whether or not the preview is marked active (selected) in the
+   * taskbar.
+   */
+  attribute boolean active;
+
+  /**
+   * Invalidates the taskbar's cached image of this preview, forcing a redraw
+   * if necessary
+   */
+  void invalidate();
+};
+
new file mode 100644
--- /dev/null
+++ b/widget/public/nsITaskbarPreviewButton.idl
@@ -0,0 +1,96 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface imgIContainer;
+
+/**
+ * nsITaskbarPreviewButton
+ *
+ * Provides access to a window preview's toolbar button's properties.
+ */
+[scriptable, uuid(CED8842D-FE37-4767-9A8E-FDFA56510C75)]
+interface nsITaskbarPreviewButton : nsISupports
+{
+  /**
+   * The button's tooltip.
+   *
+   * Default: an empty string
+   */
+  attribute DOMString tooltip;
+
+  /**
+   * True if the array of previews should be dismissed when this button is clicked.
+   *
+   * Default: false
+   */
+  attribute boolean dismissOnClick;
+
+  /**
+   * True if the taskbar should draw a border around this button's image.
+   *
+   * Default: true
+   */
+  attribute boolean hasBorder;
+
+  /**
+   * True if the button is disabled. This is not the same as visible.
+   *
+   * Default: false
+   */
+  attribute boolean disabled;
+
+  /**
+   * The icon used for the button.
+   *
+   * Default: null
+   */
+  attribute imgIContainer image;
+
+  /**
+   * True if the button is shown. Buttons that are invisible do not
+   * participate in the layout of buttons underneath the preview.
+   *
+   * Default: false
+   */
+  attribute boolean visible;
+};
+
new file mode 100644
--- /dev/null
+++ b/widget/public/nsITaskbarPreviewController.idl
@@ -0,0 +1,126 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIDocShell;
+interface nsIDOMCanvasRenderingContext2D;
+interface nsITaskbarPreview;
+interface nsITaskbarPreviewButton;
+
+/**
+ * nsITaskbarPreviewController
+ *
+ * nsITaskbarPreviewController provides the behavior for the taskbar previews.
+ * Its methods and properties are used by nsITaskbarPreview. Clients are
+ * intended to provide their own implementation of this interface. Depending on
+ * the interface the controller is attached to, only certain methods/attributes
+ * are required to be implemented.
+ */
+[scriptable, uuid(4FC0AFBB-3E22-4FBA-AC21-953350AF0411)]
+interface nsITaskbarPreviewController : nsISupports
+{
+  /**
+   * The width of the preview image. This value is allowed to change at any
+   * time. See drawPreview for more information.
+   */
+  readonly attribute unsigned long width;
+
+  /**
+   * The height of the preview image. This value is allowed to change at any
+   * time.  See drawPreview for more information.
+   */
+  readonly attribute unsigned long height;
+
+  /**
+   * The aspect ratio of the thumbnail - this does not need to match the ratio
+   * of the preview. This value is allowed to change at any time. See
+   * drawThumbnail for more information.
+   */
+  readonly attribute float thumbnailAspectRatio;
+
+  /**
+   * Invoked by nsITaskbarPreview when it needs to render the preview. The
+   * context is attached to a surface with the controller's width and height
+   * which are obtained immediately before the call.
+   *
+   * Note that the context is not attached to a canvas element.
+   *
+   * @param ctx Canvas drawing context
+   */
+  boolean drawPreview(in nsIDOMCanvasRenderingContext2D ctx);
+
+  /**
+   * Invoked by the taskbar preview when it needs to draw the thumbnail in the
+   * taskbar's application preview window.
+   *
+   * Note: it is guaranteed that width/height == thumbnailAspectRatio
+   * (modulo rounding errors)
+   *
+   * Also note that the context is not attached to a canvas element.
+   *
+   * @param ctx Canvas drawing context
+   * @param width The width of the surface backing the drawing context
+   * @param height The height of the surface backing the drawing context
+   */
+  boolean drawThumbnail(in nsIDOMCanvasRenderingContext2D ctx, in unsigned long width, in unsigned long height);
+
+  /**
+   * Invoked when the user presses the close button on the tab preview.
+   */
+  void onClose();
+
+  /**
+   * Invoked when the user clicks on the tab preview.
+   *
+   * @return true if the top level window corresponding to the preview should
+   *         be activated, false if activation is not accepted.
+   */
+  boolean onActivate();
+
+  /**
+   * Invoked when one of the buttons on the window preview's toolbar is pressed.
+   *
+   * @param button The button that was pressed. This can be compared with the
+   *               buttons returned by nsITaskbarWindowPreview.getButton.
+   */
+  void onClick(in nsITaskbarPreviewButton button);
+};
+
new file mode 100644
--- /dev/null
+++ b/widget/public/nsITaskbarTabPreview.idl
@@ -0,0 +1,96 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsITaskbarPreview.idl"
+interface imgIContainer;
+
+/*
+ * nsITaskbarTabPreview
+ *
+ * This interface controls tab preview-specific behavior. Creating an
+ * nsITaskbarTabPreview for a window will hide that window's
+ * nsITaskbarWindowPreview in the taskbar - the native API performs this
+ * unconditionally. When there are no more tab previews for a window, the
+ * nsITaskbarWindowPreview will automatically become visible again.
+ *
+ * An application may have as many tab previews per window as memory allows.
+ *
+ */
+[scriptable, uuid(11E4C8BD-5C2D-4E1A-A9A1-79DD5B0FE544)]
+interface nsITaskbarTabPreview : nsITaskbarPreview
+{
+  /**
+   * The title displayed above the thumbnail
+   *
+   * Default: an empty string
+   */
+  attribute DOMString title;
+
+  /**
+   * The icon displayed next to the title in the preview
+   *
+   * Default: null
+   */
+  attribute imgIContainer icon;
+
+  /**
+   * Rearranges the preview relative to another tab preview from the same window
+   * @param aNext The preview to the right of this one. A value of null
+   *              indicates that the preview is the rightmost one.
+   */
+  void move(in nsITaskbarTabPreview aNext);
+
+  /**
+   * Used internally to grab the handle to the proxy window.
+   */
+  [notxpcom]
+  nativeWindow GetHWND();
+
+  /**
+   * Used internally to ensure that the taskbar knows about this preview. If a
+   * preview is not registered, then the API call to set its sibling (via move)
+   * will silently fail.
+   *
+   * This method is only invoked when it is safe to make taskbar API calls.
+   */
+  [notxpcom]
+  void EnsureRegistration();
+};
+
new file mode 100644
--- /dev/null
+++ b/widget/public/nsITaskbarWindowPreview.idl
@@ -0,0 +1,103 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsITaskbarPreview.idl"
+interface nsITaskbarPreviewButton;
+
+/*
+ * nsITaskbarWindowPreview
+ *
+ * This interface represents the preview for a window in the taskbar. By
+ * default, Windows implements much of the behavior for applications by
+ * default. The primary purpose of this interface is to allow Gecko
+ * applications to take control over parts of the preview. Some parts are not
+ * controlled through this interface: the title and icon of the preview match
+ * the title and icon of the window always.
+ *
+ * By default, Windows takes care of drawing the thumbnail and preview for the
+ * application however if enableCustomDrawing is set to true, then the
+ * controller will start to receive drawPreview and drawThumbnail calls as well
+ * as reads on the thumbnailAspectRatio, width and height properties.
+ *
+ * By default, nsITaskbarWindowPreviews are visible. When made invisible, the
+ * window disappears from the list of windows in the taskbar for the
+ * application.
+ *
+ * If the window has any visible nsITaskbarTabPreviews, then the
+ * nsITaskbarWindowPreview for the corresponding window is automatically
+ * hidden. This is not reflected in the visible property. Note that other parts
+ * of the system (such as alt-tab) may still request thumbnails and/or previews
+ * through the nsITaskbarWindowPreview's controller.
+ *
+ * nsITaskbarWindowPreview will never invoke the controller's onClose or
+ * onActivate methods since handling them may conflict with other internal
+ * Gecko state and there is existing infrastructure in place to allow clients
+ * to handle those events 
+ *
+ * Window previews may have a toolbar with up to 7 buttons. See
+ * nsITaskbarPreviewButton for more information about button properties.
+ */
+[scriptable, uuid(EC67CC57-342D-4064-B4C6-74A375E07B10)]
+interface nsITaskbarWindowPreview : nsITaskbarPreview
+{
+  /**
+   * Max 7 buttons per preview per the Windows Taskbar API
+   */
+  const long NUM_TOOLBAR_BUTTONS = 7;
+
+  /**
+   * Gets the nth button for the preview image. By default, all of the buttons
+   * are invisible.
+   *
+   * @see nsITaskbarPreviewButton
+   *
+   * @param index The index into the button array. Must be >= 0 and <
+   *              MAX_TOOLBAR_BUTTONS.
+   */
+  nsITaskbarPreviewButton getButton(in unsigned long index);
+
+  /**
+   * Enables/disables custom drawing of thumbnails and previews
+   *
+   * Default value: false
+   */
+  attribute boolean enableCustomDrawing;
+};
+
new file mode 100644
--- /dev/null
+++ b/widget/public/nsIWinTaskbar.idl
@@ -0,0 +1,93 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+#include "nsIBaseWindow.idl"
+
+interface nsIDocShell;
+interface nsITaskbarTabPreview;
+interface nsITaskbarWindowPreview;
+interface nsITaskbarPreviewController;
+
+/*
+ * nsIWinTaskbar
+ *
+ * This interface represents a service which exposes the APIs provided by the
+ * Windows taskbar to applications.
+ *
+ * Starting in Windows 7, applications gain some control over their appearance
+ * in the taskbar. By default, there is one taskbar preview per top level
+ * window (excluding popups). This preview is represented by an
+ * nsITaskbarWindowPreview object.
+ *
+ * An application can register its own "tab" previews. Such previews will hide
+ * the corresponding nsITaskbarWindowPreview automatically (though this is not
+ * reflected in the visible attribute of the nsITaskbarWindowPreview). These
+ * tab previews do not have to correspond to tabs in the application - they can
+ * vary in size, shape and location. They do not even need to be actual GUI
+ * elements on the window. Unlike window previews, tab previews require most of
+ * the functionality of the nsITaskbarPreviewController to be implemented.
+ *
+ */
+[scriptable, uuid(180F1D93-A94D-4D8A-AE37-A388372269B3)]
+interface nsIWinTaskbar : nsISupports
+{
+  /**
+   * Returns true if the taskbar service is available. This value does not
+   * change during runtime.
+   */
+  readonly attribute boolean available;
+
+  /**
+   * Creates a taskbar preview. The docshell is used to find the toplevel window.
+   * See the documentation for nsITaskbarTabPreview for more information.
+   */
+  nsITaskbarTabPreview createTaskbarTabPreview(in nsIDocShell shell,
+                                               in nsITaskbarPreviewController controller);
+
+  /**
+   * Gets the taskbar preview for a window. The docshell is used to find the
+   * toplevel window. See the documentation for nsITaskbarTabPreview for more
+   * information.
+   *
+   * Note: to implement custom drawing or buttons, a controller is required.
+   */
+  nsITaskbarWindowPreview getTaskbarWindowPreview(in nsIDocShell shell);
+};
--- a/widget/public/nsWidgetsCID.h
+++ b/widget/public/nsWidgetsCID.h
@@ -129,16 +129,19 @@
 
 #define NS_SCREENMANAGER_CID \
 { 0xc401eb80, 0xf9ea, 0x11d3, { 0xbb, 0x6f, 0xe7, 0x32, 0xb7, 0x3e, 0xbe, 0x7c } }
 
 // {6987230e-0089-4e78-bc5f-1493ee7519fa}
 #define NS_IDLE_SERVICE_CID \
 { 0x6987230e, 0x0098, 0x4e78, { 0xbc, 0x5f, 0x14, 0x93, 0xee, 0x75, 0x19, 0xfa } }
 
+#define NS_WIN_TASKBAR_CID \
+{ 0xb8e5bc54, 0xa22f, 0x4eb2, {0xb0, 0x61, 0x24, 0xcb, 0x6d, 0x19, 0xc1, 0x5f } }
+
 //-----------------------------------------------------------
 //Printing
 //-----------------------------------------------------------
 #define NS_DEVICE_CONTEXT_SPEC_CID \
 { 0xd3f69889, 0xe13a, 0x4321, \
 { 0x98, 0x0c, 0xa3, 0x93, 0x32, 0xe2, 0x1f, 0x34 } }
 
 #define NS_PRINTSETTINGSSERVICE_CID \
--- a/widget/src/build/nsWinWidgetFactory.cpp
+++ b/widget/src/build/nsWinWidgetFactory.cpp
@@ -49,16 +49,17 @@
 #include "nsIServiceManager.h"
 #include "nsIdleServiceWin.h"
 #include "nsLookAndFeel.h"
 #include "nsNativeThemeWin.h"
 #include "nsScreenManagerWin.h"
 #include "nsSound.h"
 #include "nsToolkit.h"
 #include "nsWindow.h"
+#include "WinTaskbar.h"
 
 // Drag & Drop, Clipboard
 
 #include "nsClipboardHelper.h"
 
 #ifdef WINCE
 #include "nsClipboardCE.h"
 #else
@@ -84,16 +85,21 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePic
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsLookAndFeel)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsToolkit)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerWin)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsIdleServiceWin)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboard)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
 
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+using namespace mozilla::widget;
+NS_GENERIC_FACTORY_CONSTRUCTOR(WinTaskbar)
+#endif
+
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
 #ifndef WINCE
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBidiKeyboard)
 #endif
 
 #ifdef NS_PRINTING
@@ -159,16 +165,22 @@ static const nsModuleComponentInfo compo
     "@mozilla.org/widget/transferable;1",
     nsTransferableConstructor },
   { "HTML Format Converter",
     NS_HTMLFORMATCONVERTER_CID,
     "@mozilla.org/widget/htmlformatconverter;1",
     nsHTMLFormatConverterConstructor },
 
 #ifndef WINCE
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+  { "Windows Taskbar Server",
+    NS_WIN_TASKBAR_CID ,
+    "@mozilla.org/windows-taskbar;1",
+    WinTaskbarConstructor },
+#endif
   { "Drag Service",
     NS_DRAGSERVICE_CID,
     "@mozilla.org/widget/dragservice;1",
     nsDragServiceConstructor },
   { "Bidi Keyboard",
     NS_BIDIKEYBOARD_CID,
     "@mozilla.org/widget/bidikeyboard;1",
     nsBidiKeyboardConstructor },
--- a/widget/src/windows/Makefile.in
+++ b/widget/src/windows/Makefile.in
@@ -60,16 +60,21 @@ CPPSRCS		= \
 	nsUXThemeData.cpp \
 	nsNativeThemeWin.cpp \
 	nsWinGesture.cpp \
 	nsIdleServiceWin.cpp \
 	nsSound.cpp \
 	nsIMM32Handler.cpp \
 	WindowHook.cpp \
 	nsAccelerometerWin.cpp \
+	WinTaskbar.cpp \
+	TaskbarPreview.cpp \
+	TaskbarTabPreview.cpp \
+	TaskbarWindowPreview.cpp \
+	TaskbarPreviewButton.cpp \
 	$(NULL)
 
 ifdef NS_PRINTING
 CPPSRCS		+= \
 	nsPrintOptionsWin.cpp \
 	nsPrintSettingsWin.cpp \
 	nsDeviceContextSpecWin.cpp \
 	$(NULL)
new file mode 100644
--- /dev/null
+++ b/widget/src/windows/TaskbarPreview.cpp
@@ -0,0 +1,403 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#include "TaskbarPreview.h"
+#include <nsITaskbarPreviewController.h>
+#include <windows.h>
+
+#include <nsError.h>
+#include <nsCOMPtr.h>
+#include <nsIWidget.h>
+#include <nsIBaseWindow.h>
+#include <nsIObserverService.h>
+#include <nsServiceManagerUtils.h>
+
+#include "nsUXThemeData.h"
+#include "nsWindow.h"
+#include "nsAppShell.h"
+#include "TaskbarPreviewButton.h"
+
+#include <nsIBaseWindow.h>
+#include <nsICanvasRenderingContextInternal.h>
+#include <nsIDOMCanvasRenderingContext2D.h>
+#include <imgIContainer.h>
+#include <nsIDocShell.h>
+
+// Defined in dwmapi in a header that needs a higher numbered _WINNT #define
+#define DWM_SIT_DISPLAYFRAME 0x1
+
+namespace mozilla {
+namespace widget {
+
+namespace {
+/* Helper method to create a canvas rendering context backed by the given surface
+ *
+ * @param shell The docShell used by the canvas context for text settings and other
+ *              misc things.
+ * @param surface The gfxSurface backing the context
+ * @param width The width of the given surface
+ * @param height The height of the given surface
+ * @param aCtx Out-param - a canvas context backed by the given surface
+ */
+nsresult
+CreateRenderingContext(nsIDocShell *shell, gfxASurface *surface, PRUint32 width, PRUint32 height, nsICanvasRenderingContextInternal **aCtx) {
+  nsresult rv;
+  nsCOMPtr<nsICanvasRenderingContextInternal> ctx(do_CreateInstance(
+    "@mozilla.org/content/canvas-rendering-context;1?id=2d", &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = ctx->InitializeWithSurface(shell, surface, width, height);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  NS_ADDREF(*aCtx = ctx);
+  return NS_OK;
+}
+
+}
+
+TaskbarPreview::TaskbarPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
+  : mTaskbar(aTaskbar),
+    mController(aController),
+    mWnd(aHWND),
+    mVisible(PR_FALSE),
+    mDocShell(do_GetWeakReference(aShell))
+{
+  // TaskbarPreview may outlive the WinTaskbar that created it
+  ::CoInitialize(NULL);
+
+  WindowHook &hook = GetWindowHook();
+  hook.AddMonitor(WM_DESTROY, MainWindowHook, this);
+}
+
+TaskbarPreview::~TaskbarPreview() {
+  // Avoid dangling pointer
+  if (sActivePreview == this)
+    sActivePreview = nsnull;
+
+  // Here we remove the hook since this preview is dying before the nsWindow
+  if (mWnd)
+    DetachFromNSWindow(PR_TRUE);
+
+  // Make sure to release before potentially uninitializing COM
+  mTaskbar = NULL;
+
+  ::CoUninitialize();
+}
+
+NS_IMETHODIMP
+TaskbarPreview::SetController(nsITaskbarPreviewController *aController) {
+  NS_ENSURE_ARG(aController);
+
+  mController = aController;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreview::GetController(nsITaskbarPreviewController **aController) {
+  NS_ADDREF(*aController = mController);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreview::GetTooltip(nsAString &aTooltip) {
+  aTooltip = mTooltip;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreview::SetTooltip(const nsAString &aTooltip) {
+  return NS_OK;
+  mTooltip = aTooltip;
+  return CanMakeTaskbarCalls() ? UpdateTooltip() : NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreview::SetVisible(PRBool visible) {
+  if (mVisible == visible) return NS_OK;
+  mVisible = visible;
+
+  return visible ? Enable() : Disable();
+}
+
+NS_IMETHODIMP
+TaskbarPreview::GetVisible(PRBool *visible) {
+  *visible = mVisible;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreview::SetActive(PRBool active) {
+  if (active)
+    sActivePreview = this;
+  else if (sActivePreview == this)
+    sActivePreview = NULL;
+
+  return CanMakeTaskbarCalls() ? ShowActive(active) : NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreview::GetActive(PRBool *active) {
+  *active = sActivePreview == this;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreview::Invalidate() {
+  if (!mVisible)
+    return NS_ERROR_FAILURE;
+
+  // DWM Composition is required for previews
+  if (!nsUXThemeData::CheckForCompositor())
+    return NS_OK;
+
+  HWND previewWindow = PreviewWindow();
+  return FAILED(nsUXThemeData::dwmInvalidateIconicBitmapsPtr(previewWindow))
+       ? NS_ERROR_FAILURE
+       : NS_OK;
+}
+
+nsresult
+TaskbarPreview::UpdateTaskbarProperties() {
+  nsresult rv = UpdateTooltip();
+
+  // If we are the active preview and our window is the active window, restore
+  // our active state - otherwise some other non-preview window is now active
+  // and should be displayed as so.
+  if (sActivePreview == this) {
+    if (mWnd == ::GetActiveWindow()) {
+      nsresult rvActive = ShowActive(PR_TRUE);
+      if (NS_FAILED(rvActive))
+        rv = rvActive;
+    } else {
+      sActivePreview = nsnull;
+    }
+  }
+  return rv;
+}
+
+nsresult
+TaskbarPreview::Enable() {
+  nsresult rv = NS_OK;
+  if (CanMakeTaskbarCalls()) {
+    rv = UpdateTaskbarProperties();
+  } else {
+    WindowHook &hook = GetWindowHook();
+    hook.AddMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(), MainWindowHook, this);
+  }
+  return rv;
+}
+
+nsresult
+TaskbarPreview::Disable() {
+  WindowHook &hook = GetWindowHook();
+  (void) hook.RemoveMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(), MainWindowHook, this);
+
+  return NS_OK;
+}
+
+void
+TaskbarPreview::DetachFromNSWindow(PRBool windowIsAlive) {
+  if (windowIsAlive) {
+    WindowHook &hook = GetWindowHook();
+    hook.RemoveMonitor(WM_DESTROY, MainWindowHook, this);
+  }
+  mWnd = NULL;
+}
+
+LRESULT
+TaskbarPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
+  switch (nMsg) {
+    case WM_DWMSENDICONICTHUMBNAIL:
+      {
+        PRUint32 width = HIWORD(lParam);
+        PRUint32 height = LOWORD(lParam);
+        float aspectRatio = width/float(height);
+
+        nsresult rv;
+        float preferredAspectRatio;
+        rv = mController->GetThumbnailAspectRatio(&preferredAspectRatio);
+        if (NS_FAILED(rv))
+          break;
+
+        PRUint32 thumbnailWidth = width;
+        PRUint32 thumbnailHeight = height;
+
+        if (aspectRatio > preferredAspectRatio) {
+          thumbnailWidth = PRUint32(thumbnailHeight * preferredAspectRatio);
+        } else {
+          thumbnailHeight = PRUint32(thumbnailWidth / preferredAspectRatio);
+        }
+
+        DrawBitmap(thumbnailWidth, thumbnailHeight, PR_FALSE);
+      }
+      break;
+    case WM_DWMSENDICONICLIVEPREVIEWBITMAP:
+      {
+        PRUint32 width, height;
+        nsresult rv;
+        rv = mController->GetWidth(&width);
+        if (NS_FAILED(rv))
+          break;
+        rv = mController->GetHeight(&height);
+        if (NS_FAILED(rv))
+          break;
+
+        DrawBitmap(width, height, PR_TRUE);
+      }
+      break;
+  }
+  return ::DefWindowProcW(PreviewWindow(), nMsg, wParam, lParam);
+}
+
+PRBool
+TaskbarPreview::CanMakeTaskbarCalls() {
+  nsWindow *window = nsWindow::GetNSWindowPtr(mWnd);
+  NS_ASSERTION(window, "Cannot use taskbar previews in an embedded context!");
+
+  return mVisible && window->HasTaskbarIconBeenCreated();
+}
+
+WindowHook&
+TaskbarPreview::GetWindowHook() {
+  nsWindow *window = nsWindow::GetNSWindowPtr(mWnd);
+  NS_ASSERTION(window, "Cannot use taskbar previews in an embedded context!");
+
+  return window->GetWindowHook();
+}
+
+void
+TaskbarPreview::EnableCustomDrawing(HWND aHWND, PRBool aEnable) {
+  nsUXThemeData::dwmSetWindowAttributePtr(
+      aHWND,
+      DWMWA_FORCE_ICONIC_REPRESENTATION,
+      &aEnable,
+      sizeof(aEnable));
+
+  nsUXThemeData::dwmSetWindowAttributePtr(
+      aHWND,
+      DWMWA_HAS_ICONIC_BITMAP,
+      &aEnable,
+      sizeof(aEnable));
+}
+
+
+nsresult
+TaskbarPreview::UpdateTooltip() {
+  NS_ASSERTION(CanMakeTaskbarCalls() && mVisible, "UpdateTooltip called on invisible tab preview");
+
+  if (FAILED(mTaskbar->SetThumbnailTooltip(PreviewWindow(), mTooltip.get())))
+    return NS_ERROR_FAILURE;
+  return NS_OK;
+}
+
+void
+TaskbarPreview::DrawBitmap(PRUint32 width, PRUint32 height, PRBool isPreview) {
+  nsresult rv;
+  nsRefPtr<gfxWindowsSurface> surface = new gfxWindowsSurface(gfxIntSize(width, height), gfxASurface::ImageFormatARGB32);
+
+  nsCOMPtr<nsIDocShell> shell = do_QueryReferent(mDocShell);
+
+  if (!shell)
+    return;
+
+  nsCOMPtr<nsICanvasRenderingContextInternal> ctxI;
+  rv = CreateRenderingContext(shell, surface, width, height, getter_AddRefs(ctxI));
+
+  nsCOMPtr<nsIDOMCanvasRenderingContext2D> ctx = do_QueryInterface(ctxI);
+
+  PRBool drawFrame = PR_FALSE;
+  if (NS_SUCCEEDED(rv) && ctx) {
+    if (isPreview)
+      rv = mController->DrawPreview(ctx, &drawFrame);
+    else
+      rv = mController->DrawThumbnail(ctx, width, height, &drawFrame);
+
+  }
+
+  if (NS_FAILED(rv))
+    return;
+
+  HDC hDC = surface->GetDC();
+  HBITMAP hBitmap = (HBITMAP)GetCurrentObject(hDC, OBJ_BITMAP);
+
+  DWORD flags = drawFrame ? DWM_SIT_DISPLAYFRAME : 0;
+  POINT pptClient = { 0, 0 };
+  if (isPreview)
+    nsUXThemeData::dwmSetIconicLivePreviewBitmapPtr(PreviewWindow(), hBitmap, &pptClient, flags);
+  else
+    nsUXThemeData::dwmSetIconicThumbnailPtr(PreviewWindow(), hBitmap, flags);
+}
+
+/* static */
+PRBool
+TaskbarPreview::MainWindowHook(void *aContext,
+                               HWND hWnd, UINT nMsg,
+                               WPARAM wParam, LPARAM lParam,
+                               LRESULT *aResult)
+{
+  NS_ASSERTION(nMsg == nsAppShell::GetTaskbarButtonCreatedMessage() ||
+               nMsg == WM_DESTROY,
+               "Window hook proc called with wrong message");
+  TaskbarPreview *preview = reinterpret_cast<TaskbarPreview*>(aContext);
+  if (nMsg == WM_DESTROY) {
+    // nsWindow is being destroyed
+    // Don't remove the hook since it is currently in dispatch
+    // and the window is being destroyed
+    preview->DetachFromNSWindow(PR_FALSE);
+  } else {
+    nsWindow *window = nsWindow::GetNSWindowPtr(preview->mWnd);
+    NS_ASSERTION(window, "Cannot use taskbar previews in an embedded context!");
+
+    window->SetHasTaskbarIconBeenCreated();
+
+    if (preview->mVisible)
+      preview->UpdateTaskbarProperties();
+  }
+  return PR_FALSE;
+}
+
+TaskbarPreview *
+TaskbarPreview::sActivePreview = nsnull;
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
new file mode 100644
--- /dev/null
+++ b/widget/src/windows/TaskbarPreview.h
@@ -0,0 +1,137 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __mozilla_widget_TaskbarPreview_h__
+#define __mozilla_widget_TaskbarPreview_h__
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#include <windows.h>
+#include <shobjidl.h>
+
+#include <nsITaskbarPreview.h>
+#include <nsAutoPtr.h>
+#include <nsString.h>
+#include <nsWeakPtr.h>
+#include <nsIDocShell.h>
+#include "WindowHook.h"
+
+namespace mozilla {
+namespace widget {
+
+class TaskbarPreview : public nsITaskbarPreview
+{
+public:
+  TaskbarPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell);
+  virtual ~TaskbarPreview();
+
+  NS_DECL_NSITASKBARPREVIEW
+
+protected:
+  // Called to update ITaskbarList4 dependent properties
+  virtual nsresult UpdateTaskbarProperties();
+
+  // Invoked when the preview is made visible
+  virtual nsresult Enable();
+  // Invoked when the preview is made invisible
+  virtual nsresult Disable();
+
+  // Detaches this preview from the nsWindow instance it's tied to
+  virtual void DetachFromNSWindow(PRBool windowIsAlive);
+
+  // Marks this preview as being active
+  virtual nsresult ShowActive(PRBool active) = 0;
+  // Gets a reference to the window used to handle the preview messages
+  virtual HWND& PreviewWindow() = 0;
+
+  // Window procedure for the PreviewWindow (hooked for window previews)
+  virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam);
+
+  // Returns whether or not the taskbar icon has been created for mWnd The
+  // ITaskbarList4 API requires that we wait until the icon has been created
+  // before we can call its methods.
+  PRBool CanMakeTaskbarCalls();
+
+  // Gets the WindowHook for the nsWindow
+  WindowHook &GetWindowHook();
+
+  // Enables/disables custom drawing for the given window
+  static void EnableCustomDrawing(HWND aHWND, PRBool aEnable);
+
+  // MSCOM Taskbar interface
+  nsRefPtr<ITaskbarList4> mTaskbar;
+  // Controller for this preview
+  nsCOMPtr<nsITaskbarPreviewController> mController;
+  // The HWND to the nsWindow that this object previews
+  HWND                    mWnd;
+  // Whether or not this preview is visible
+  PRBool                  mVisible;
+
+private:
+  // Called when the tooltip should be updated
+  nsresult UpdateTooltip();
+
+  // Requests the controller to draw into a canvas of the given width and
+  // height. The resulting bitmap is sent to the DWM to display.
+  void DrawBitmap(PRUint32 width, PRUint32 height, PRBool isPreview);
+
+  // WindowHook procedure for hooking mWnd
+  static PRBool MainWindowHook(void *aContext,
+                               HWND hWnd, UINT nMsg,
+                               WPARAM wParam, LPARAM lParam,
+                               LRESULT *aResult);
+
+  // Docshell corresponding to the <window> the nsWindow contains
+  nsWeakPtr               mDocShell;
+  nsString                mTooltip;
+
+  // The preview currently marked as active in the taskbar. nsnull if no
+  // preview is active (some other window is).
+  static TaskbarPreview  *sActivePreview;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#endif /* __mozilla_widget_TaskbarPreview_h__ */
+
+
new file mode 100644
--- /dev/null
+++ b/widget/src/windows/TaskbarPreviewButton.cpp
@@ -0,0 +1,180 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#include <windows.h>
+#include <strsafe.h>
+
+#include "TaskbarWindowPreview.h"
+#include "TaskbarPreviewButton.h"
+#include "nsWindowGfx.h"
+#include <imgIContainer.h>
+
+namespace mozilla {
+namespace widget {
+
+NS_IMPL_ISUPPORTS2(TaskbarPreviewButton, nsITaskbarPreviewButton, nsISupportsWeakReference)
+
+TaskbarPreviewButton::TaskbarPreviewButton(TaskbarWindowPreview* preview, PRUint32 index)
+  : mPreview(preview), mIndex(index)
+{
+}
+
+TaskbarPreviewButton::~TaskbarPreviewButton() {
+  SetVisible(PR_FALSE);
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::GetTooltip(nsAString &aTooltip) {
+  aTooltip = mTooltip;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::SetTooltip(const nsAString &aTooltip) {
+  mTooltip = aTooltip;
+  size_t destLength = sizeof Button().szTip / (sizeof Button().szTip[0]);
+  wchar_t *tooltip = &(Button().szTip[0]);
+  StringCchCopyNW(tooltip,
+                  destLength,
+                  mTooltip.get(),
+                  mTooltip.Length());
+  return Update();
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::GetDismissOnClick(PRBool *dismiss) {
+  *dismiss = (Button().dwFlags & THBF_DISMISSONCLICK) == THBF_DISMISSONCLICK;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::SetDismissOnClick(PRBool dismiss) {
+  if (dismiss)
+    Button().dwFlags |= THBF_DISMISSONCLICK;
+  else
+    Button().dwFlags &= ~THBF_DISMISSONCLICK;
+  return Update();
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::GetHasBorder(PRBool *hasBorder) {
+  *hasBorder = (Button().dwFlags & THBF_NOBACKGROUND) != THBF_NOBACKGROUND;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::SetHasBorder(PRBool hasBorder) {
+  if (hasBorder)
+    Button().dwFlags &= ~THBF_NOBACKGROUND;
+  else
+    Button().dwFlags |= THBF_NOBACKGROUND;
+  return Update();
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::GetDisabled(PRBool *disabled) {
+  *disabled = (Button().dwFlags & THBF_DISABLED) == THBF_DISABLED;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::SetDisabled(PRBool disabled) {
+  if (disabled)
+    Button().dwFlags |= THBF_DISABLED;
+  else
+    Button().dwFlags &= ~THBF_DISABLED;
+  return Update();
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::GetImage(imgIContainer **img) {
+  if (mImage)
+    NS_ADDREF(*img = mImage);
+  else
+    *img = NULL;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::SetImage(imgIContainer *img) {
+  if (Button().hIcon)
+    ::DestroyIcon(Button().hIcon);
+  if (img) {
+    nsresult rv;
+    rv = nsWindowGfx::CreateIcon(img, PR_FALSE, 0, 0, &Button().hIcon);
+    NS_ENSURE_SUCCESS(rv, rv);
+  } else {
+    Button().hIcon = NULL;
+  }
+  return Update();
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::GetVisible(PRBool *visible) {
+  *visible = (Button().dwFlags & THBF_HIDDEN) == THBF_HIDDEN;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarPreviewButton::SetVisible(PRBool visible) {
+  if (visible)
+    Button().dwFlags &= ~THBF_HIDDEN;
+  else
+    Button().dwFlags |= THBF_HIDDEN;
+  return Update();
+}
+
+THUMBBUTTON&
+TaskbarPreviewButton::Button() {
+  return mPreview->mThumbButtons[mIndex];
+}
+
+nsresult
+TaskbarPreviewButton::Update() {
+  return mPreview->UpdateButton(mIndex);
+}
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7 
+
new file mode 100644
--- /dev/null
+++ b/widget/src/windows/TaskbarPreviewButton.h
@@ -0,0 +1,84 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __mozilla_widget_TaskbarPreviewButton_h__
+#define __mozilla_widget_TaskbarPreviewButton_h__
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#include <windows.h>
+#include <shobjidl.h>
+
+#include <nsITaskbarPreviewButton.h>
+#include <nsAutoPtr.h>
+#include <nsString.h>
+#include <nsWeakReference.h>
+
+namespace mozilla {
+namespace widget {
+
+class TaskbarWindowPreview;
+class TaskbarPreviewButton : public nsITaskbarPreviewButton, public nsSupportsWeakReference
+{
+public: 
+  TaskbarPreviewButton(TaskbarWindowPreview* preview, PRUint32 index);
+  virtual ~TaskbarPreviewButton();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSITASKBARPREVIEWBUTTON
+
+private:
+  THUMBBUTTON&            Button();
+  nsresult                Update();
+
+  nsRefPtr<TaskbarWindowPreview> mPreview;
+  PRUint32                mIndex;
+  nsString                mTooltip;
+  nsCOMPtr<imgIContainer> mImage;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#endif /* __mozilla_widget_TaskbarPreviewButton_h__ */
+
+
new file mode 100644
--- /dev/null
+++ b/widget/src/windows/TaskbarTabPreview.cpp
@@ -0,0 +1,309 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#include "TaskbarTabPreview.h"
+#include "nsWindowGFX.h"
+#include "nsUXThemeData.h"
+#include <nsITaskbarPreviewController.h>
+
+#define TASKBARPREVIEW_HWNDID L"TaskbarTabPreviewHwnd"
+
+namespace mozilla {
+namespace widget {
+
+NS_IMPL_ISUPPORTS1(TaskbarTabPreview, nsITaskbarTabPreview)
+
+const PRUnichar *const kWindowClass = L"MozillaTaskbarPreviewClass";
+
+TaskbarTabPreview::TaskbarTabPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
+  : TaskbarPreview(aTaskbar, aController, aHWND, aShell),
+    mProxyWindow(NULL),
+    mIcon(NULL),
+    mRegistered(PR_FALSE)
+{
+}
+
+TaskbarTabPreview::~TaskbarTabPreview() {
+  if (mIcon) {
+    ::DestroyIcon(mIcon);
+    mIcon = NULL;
+  }
+  // Do this here because this is our last chance to execute methods in this class
+  (void) SetVisible(PR_FALSE);
+}
+
+nsresult
+TaskbarTabPreview::ShowActive(PRBool active) {
+  NS_ASSERTION(mVisible && CanMakeTaskbarCalls(), "ShowActive called on invisible window or before taskbar calls can be made for this window");
+  return FAILED(mTaskbar->SetTabActive(active ? mProxyWindow : NULL, mWnd, 0))
+       ? NS_ERROR_FAILURE
+       : NS_OK;
+}
+
+HWND &
+TaskbarTabPreview::PreviewWindow() {
+  return mProxyWindow;
+}
+
+nativeWindow
+TaskbarTabPreview::GetHWND() {
+  return mProxyWindow;
+}
+
+void
+TaskbarTabPreview::EnsureRegistration() {
+  NS_ASSERTION(mVisible && CanMakeTaskbarCalls(), "EnsureRegistration called when it is not safe to do so");
+
+  (void) UpdateTaskbarProperties();
+}
+
+NS_IMETHODIMP
+TaskbarTabPreview::GetTitle(nsAString &aTitle) {
+  aTitle = mTitle;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarTabPreview::SetTitle(const nsAString &aTitle) {
+  mTitle = aTitle;
+  return mVisible ? UpdateTitle() : NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarTabPreview::SetIcon(imgIContainer *icon) {
+  HICON hIcon = NULL;
+  if (icon) {
+    nsresult rv;
+    rv = nsWindowGfx::CreateIcon(icon, PR_FALSE, 0, 0, &hIcon);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  if (mIcon)
+    ::DestroyIcon(mIcon);
+  mIcon = hIcon;
+  mIconImage = icon;
+  return mVisible ? UpdateIcon() : NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarTabPreview::GetIcon(imgIContainer **icon) {
+  NS_ADDREF(*icon = mIconImage);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarTabPreview::Move(nsITaskbarTabPreview *aNext) {
+  if (aNext == this)
+    return NS_ERROR_INVALID_ARG;
+  mNext = aNext;
+  return CanMakeTaskbarCalls() ? UpdateNext() : NS_OK;
+}
+
+nsresult
+TaskbarTabPreview::UpdateTaskbarProperties() {
+  if (mRegistered)
+    return NS_OK;
+
+  if (FAILED(mTaskbar->RegisterTab(mProxyWindow, mWnd)))
+    return NS_ERROR_FAILURE;
+
+  nsresult rv = UpdateNext();
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = TaskbarPreview::UpdateTaskbarProperties();
+  mRegistered = PR_TRUE;
+  return rv;
+}
+
+LRESULT
+TaskbarTabPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
+  nsRefPtr<TaskbarTabPreview> kungFuDeathGrip(this);
+  switch (nMsg) {
+    case WM_CREATE:
+      TaskbarPreview::EnableCustomDrawing(mProxyWindow, PR_TRUE);
+      return 0;
+    case WM_CLOSE:
+      mController->OnClose();
+      return 0;
+    case WM_ACTIVATE:
+      if (LOWORD(wParam) != WA_INACTIVE) {
+        PRBool activateWindow;
+        nsresult rv = mController->OnActivate(&activateWindow);
+        if (NS_SUCCEEDED(rv) && activateWindow) {
+          ::SetActiveWindow(mWnd);
+          if (::IsIconic(mWnd))
+            ::ShowWindow(mWnd, SW_RESTORE);
+          else
+            ::BringWindowToTop(mWnd);
+        }
+      }
+      return 0;
+    case WM_GETICON:
+      return (LRESULT)mIcon;
+  }
+  return TaskbarPreview::WndProc(nMsg, wParam, lParam);
+}
+
+/* static */
+LRESULT CALLBACK
+TaskbarTabPreview::GlobalWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) {
+  TaskbarTabPreview *preview(nsnull);
+  if (nMsg == WM_CREATE) {
+    CREATESTRUCT *cs = reinterpret_cast<CREATESTRUCT*>(lParam);
+    preview = reinterpret_cast<TaskbarTabPreview*>(cs->lpCreateParams);
+    if (!::SetPropW(hWnd, TASKBARPREVIEW_HWNDID, preview))
+      NS_ERROR("Could not associate native window with tab preview");
+    preview->mProxyWindow = hWnd;
+  } else {
+    preview = reinterpret_cast<TaskbarTabPreview*>(::GetPropW(hWnd, TASKBARPREVIEW_HWNDID));
+  }
+
+  if (preview)
+    return preview->WndProc(nMsg, wParam, lParam);
+  return ::DefWindowProcW(hWnd, nMsg, wParam, lParam);
+}
+
+nsresult
+TaskbarTabPreview::Enable() {
+  WNDCLASSW wc;
+  HINSTANCE module = GetModuleHandle(NULL);
+
+  if (!GetClassInfoW(module, kWindowClass, &wc)) {
+    wc.style         = 0;
+    wc.lpfnWndProc   = GlobalWndProc;
+    wc.cbClsExtra    = 0;
+    wc.cbWndExtra    = 0;
+    wc.hInstance     = module;
+    wc.hIcon         = NULL;
+    wc.hCursor       = NULL;
+    wc.hbrBackground = (HBRUSH) NULL;
+    wc.lpszMenuName  = (LPCWSTR) NULL;
+    wc.lpszClassName = kWindowClass;
+    RegisterClassW(&wc);
+  }
+  ::CreateWindowW(kWindowClass, L"TaskbarPreviewWindow",
+                  WS_CAPTION, 0, 0, 200, 60, NULL, NULL, module, this);
+  // GlobalWndProc will set mProxyWindow so that WM_CREATE can have a valid HWND
+  if (!mProxyWindow)
+    return NS_ERROR_INVALID_ARG;
+
+  nsresult rv = TaskbarPreview::Enable();
+  nsresult rvUpdate;
+  rvUpdate = UpdateTitle();
+  if (NS_FAILED(rvUpdate))
+    rv = rvUpdate;
+
+  rvUpdate = UpdateIcon();
+  if (NS_FAILED(rvUpdate))
+    rv = rvUpdate;
+
+  return rv;
+}
+
+nsresult
+TaskbarTabPreview::Disable() {
+  TaskbarPreview::Disable();
+
+  if (FAILED(mTaskbar->UnregisterTab(mProxyWindow)))
+    return NS_ERROR_FAILURE;
+  mRegistered = PR_FALSE;
+
+  // TaskbarPreview::WndProc will set mProxyWindow to null
+  if (!DestroyWindow(mProxyWindow))
+    return NS_ERROR_FAILURE;
+  mProxyWindow = NULL;
+  return NS_OK;
+}
+
+void
+TaskbarTabPreview::DetachFromNSWindow(PRBool windowIsAlive) {
+  (void) SetVisible(PR_FALSE);
+
+  TaskbarPreview::DetachFromNSWindow(windowIsAlive);
+}
+
+nsresult
+TaskbarTabPreview::UpdateTitle() {
+  NS_ASSERTION(mVisible, "UpdateTitle called on invisible preview");
+
+  if (!::SetWindowTextW(mProxyWindow, mTitle.get()))
+    return NS_ERROR_FAILURE;
+  return NS_OK;
+}
+
+nsresult
+TaskbarTabPreview::UpdateIcon() {
+  NS_ASSERTION(mVisible, "UpdateIcon called on invisible preview");
+
+  ::SendMessageW(mProxyWindow, WM_SETICON, ICON_SMALL, (LPARAM)mIcon);
+
+  return NS_OK;
+}
+
+nsresult
+TaskbarTabPreview::UpdateNext() {
+  NS_ASSERTION(CanMakeTaskbarCalls() && mVisible, "UpdateNext called on invisible tab preview");
+  HWND hNext = NULL;
+  if (mNext) {
+    PRBool visible;
+    nsresult rv = mNext->GetVisible(&visible);
+
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Can only move next to enabled previews
+    if (!visible)
+      return NS_ERROR_FAILURE;
+
+    hNext = (HWND)mNext->GetHWND();
+
+    // hNext must be registered with the taskbar if the call is to succeed
+    mNext->EnsureRegistration();
+  }
+  if (FAILED(mTaskbar->SetTabOrder(mProxyWindow, hNext)))
+    return NS_ERROR_FAILURE;
+  return NS_OK;
+}
+
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
new file mode 100644
--- /dev/null
+++ b/widget/src/windows/TaskbarTabPreview.h
@@ -0,0 +1,94 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __mozilla_widget_TaskbarTabPreview_h__
+#define __mozilla_widget_TaskbarTabPreview_h__
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#include "nsITaskbarTabPreview.h"
+#include "TaskbarPreview.h"
+
+namespace mozilla {
+namespace widget {
+
+class TaskbarTabPreview : public nsITaskbarTabPreview,
+                          public TaskbarPreview
+{
+public:
+  TaskbarTabPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell);
+  virtual ~TaskbarTabPreview();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSITASKBARTABPREVIEW
+  NS_FORWARD_NSITASKBARPREVIEW(TaskbarPreview::)
+
+private:
+  virtual nsresult ShowActive(PRBool active);
+  virtual HWND &PreviewWindow();
+  virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam);
+  static LRESULT CALLBACK GlobalWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);
+
+  virtual nsresult UpdateTaskbarProperties();
+  virtual nsresult Enable();
+  virtual nsresult Disable();
+  virtual void DetachFromNSWindow(PRBool windowIsAlive);
+  nsresult UpdateTitle();
+  nsresult UpdateIcon();
+  nsresult UpdateNext();
+
+  // Handle to the toplevel proxy window
+  HWND                    mProxyWindow;
+  nsString                mTitle;
+  nsCOMPtr<imgIContainer> mIconImage;
+  // Cached Windows icon of mIconImage
+  HICON                   mIcon;
+  // Preview that follows this preview in the taskbar (left-to-right order)
+  nsCOMPtr<nsITaskbarTabPreview> mNext;
+  // True if this preview has been registered with the taskbar
+  PRBool                  mRegistered;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#endif /* __mozilla_widget_TaskbarTabPreview_h__ */
new file mode 100644
--- /dev/null
+++ b/widget/src/windows/TaskbarWindowPreview.cpp
@@ -0,0 +1,237 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#include <nsITaskbarPreviewController.h>
+#include "TaskbarWindowPreview.h"
+#include "WindowHook.h"
+#include "nsUXThemeData.h"
+#include "TaskbarPreviewButton.h"
+#include "nsWindow.h"
+
+namespace mozilla {
+namespace widget {
+
+namespace {
+PRBool WindowHookProc(void *aContext, HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT *aResult)
+{
+  TaskbarWindowPreview *preview = reinterpret_cast<TaskbarWindowPreview*>(aContext);
+  *aResult = preview->WndProc(nMsg, wParam, lParam);
+  return PR_TRUE;
+}
+}
+
+NS_IMPL_ISUPPORTS2(TaskbarWindowPreview, nsITaskbarWindowPreview, nsISupportsWeakReference)
+
+TaskbarWindowPreview::TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
+  : TaskbarPreview(aTaskbar, aController, aHWND, aShell),
+    mCustomDrawing(PR_FALSE),
+    mHaveButtons(PR_FALSE)
+{
+  // Window previews are visible by default
+  (void) SetVisible(PR_TRUE);
+
+  memset(mThumbButtons, 0, sizeof mThumbButtons);
+  for (PRInt32 i = 0; i < nsITaskbarWindowPreview::MAX_TOOLBAR_BUTTONS; i++) {
+    mThumbButtons[i].dwMask = THB_FLAGS | THB_ICON | THB_TOOLTIP;
+    mThumbButtons[i].iId = i;
+    mThumbButtons[i].dwFlags = THBF_HIDDEN;
+  }
+
+}
+
+TaskbarWindowPreview::~TaskbarWindowPreview() {
+  if (mWnd)
+    DetachFromNSWindow(PR_TRUE);
+}
+
+nsresult
+TaskbarWindowPreview::ShowActive(PRBool active) {
+  return FAILED(mTaskbar->ActivateTab(active ? mWnd : NULL))
+       ? NS_ERROR_FAILURE
+       : NS_OK;
+
+}
+
+HWND &
+TaskbarWindowPreview::PreviewWindow() {
+  return mWnd;
+}
+
+nsresult
+TaskbarWindowPreview::GetButton(PRUint32 index, nsITaskbarPreviewButton **_retVal) {
+  if (index >= nsITaskbarWindowPreview::MAX_TOOLBAR_BUTTONS)
+    return NS_ERROR_INVALID_ARG;
+
+  nsCOMPtr<nsITaskbarPreviewButton> button(do_QueryReferent(mWeakButtons[index]));
+
+  if (!button) {
+    // Lost reference
+    button = new TaskbarPreviewButton(this, index);
+    if (!button) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    mWeakButtons[index] = do_GetWeakReference(button);
+  }
+
+  if (!mHaveButtons) {
+    mHaveButtons = PR_TRUE;
+
+    WindowHook &hook = GetWindowHook();
+    (void) hook.AddHook(WM_COMMAND, WindowHookProc, this);
+
+    if (mVisible && FAILED(mTaskbar->ThumbBarAddButtons(mWnd, nsITaskbarWindowPreview::MAX_TOOLBAR_BUTTONS, mThumbButtons))) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+  button.forget(_retVal);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarWindowPreview::SetEnableCustomDrawing(PRBool aEnable) {
+  if (aEnable == mCustomDrawing)
+    return NS_OK;
+  mCustomDrawing = aEnable;
+  TaskbarPreview::EnableCustomDrawing(mWnd, aEnable);
+
+  WindowHook &hook = GetWindowHook();
+  if (aEnable) {
+    (void) hook.AddHook(WM_DWMSENDICONICTHUMBNAIL, WindowHookProc, this);
+    (void) hook.AddHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP, WindowHookProc, this);
+  } else {
+    (void) hook.RemoveHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP, WindowHookProc, this);
+    (void) hook.RemoveHook(WM_DWMSENDICONICTHUMBNAIL, WindowHookProc, this);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+TaskbarWindowPreview::GetEnableCustomDrawing(PRBool *aEnable) {
+  *aEnable = mCustomDrawing;
+  return NS_OK;
+}
+
+nsresult
+TaskbarWindowPreview::UpdateTaskbarProperties() {
+  if (mHaveButtons) {
+    if (FAILED(mTaskbar->ThumbBarAddButtons(mWnd, nsITaskbarWindowPreview::MAX_TOOLBAR_BUTTONS, mThumbButtons)))
+      return NS_ERROR_FAILURE;
+  }
+  return TaskbarPreview::UpdateTaskbarProperties();
+}
+
+LRESULT
+TaskbarWindowPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
+  nsRefPtr<TaskbarWindowPreview> kungFuDeathGrip(this);
+  switch (nMsg) {
+    case WM_COMMAND:
+      {
+        PRUint32 id = LOWORD(wParam);
+        PRUint32 index = id;
+        nsCOMPtr<nsITaskbarPreviewButton> button;
+        nsresult rv = GetButton(index, getter_AddRefs(button));
+        if (NS_SUCCEEDED(rv))
+          mController->OnClick(button);
+      }
+      return 0;
+  }
+  return TaskbarPreview::WndProc(nMsg, wParam, lParam);
+}
+
+nsresult
+TaskbarWindowPreview::Enable() {
+  nsresult rv = TaskbarPreview::Enable();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return FAILED(mTaskbar->AddTab(mWnd))
+       ? NS_ERROR_FAILURE
+       : NS_OK;
+}
+
+nsresult
+TaskbarWindowPreview::Disable() {
+  nsresult rv = TaskbarPreview::Disable();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return FAILED(mTaskbar->DeleteTab(mWnd))
+       ? NS_ERROR_FAILURE
+       : NS_OK;
+}
+
+void
+TaskbarWindowPreview::DetachFromNSWindow(PRBool windowIsAlive) {
+  if (windowIsAlive) {
+    // Remove the hooks we have for drawing
+    SetEnableCustomDrawing(PR_FALSE);
+
+    WindowHook &hook = GetWindowHook();
+    (void) hook.RemoveHook(WM_COMMAND, WindowHookProc, this);
+  }
+
+  TaskbarPreview::DetachFromNSWindow(windowIsAlive);
+}
+
+nsresult
+TaskbarWindowPreview::UpdateButtons() {
+  NS_ASSERTION(mVisible, "UpdateButtons called on invisible preview");
+
+  if (FAILED(mTaskbar->ThumbBarUpdateButtons(mWnd, nsITaskbarWindowPreview::MAX_TOOLBAR_BUTTONS, mThumbButtons)))
+    return NS_ERROR_FAILURE;
+  return NS_OK;
+}
+
+nsresult
+TaskbarWindowPreview::UpdateButton(PRUint32 index) {
+  if (index >= nsITaskbarWindowPreview::MAX_TOOLBAR_BUTTONS)
+    return NS_ERROR_INVALID_ARG;
+  if (mVisible) {
+    if (FAILED(mTaskbar->ThumbBarUpdateButtons(mWnd, 1, &mThumbButtons[index])))
+      return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
new file mode 100644
--- /dev/null
+++ b/widget/src/windows/TaskbarWindowPreview.h
@@ -0,0 +1,96 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __mozilla_widget_TaskbarWindowPreview_h__
+#define __mozilla_widget_TaskbarWindowPreview_h__
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#include "nsITaskbarWindowPreview.h"
+#include "TaskbarPreview.h"
+#include <nsWeakReference.h>
+
+namespace mozilla {
+namespace widget {
+
+class TaskbarPreviewButton;
+class TaskbarWindowPreview : public TaskbarPreview,
+                             public nsITaskbarWindowPreview,
+                             public nsSupportsWeakReference
+{
+public:
+  TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell);
+  virtual ~TaskbarWindowPreview();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSITASKBARWINDOWPREVIEW
+  NS_FORWARD_NSITASKBARPREVIEW(TaskbarPreview::)
+
+  virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam);
+private:
+  virtual nsresult ShowActive(PRBool active);
+  virtual HWND &PreviewWindow();
+
+  virtual nsresult UpdateTaskbarProperties();
+  virtual nsresult Enable();
+  virtual nsresult Disable();
+  virtual void DetachFromNSWindow(PRBool windowIsAlive);
+  nsresult UpdateButton(PRUint32 index);
+  nsresult UpdateButtons();
+
+  // Is custom drawing enabled?
+  PRBool                  mCustomDrawing;
+  // Have we made any buttons?
+  PRBool                  mHaveButtons;
+  // Windows button format
+  THUMBBUTTON             mThumbButtons[nsITaskbarWindowPreview::MAX_TOOLBAR_BUTTONS];
+  // Pointers to our button class (cached instances)
+  nsWeakPtr               mWeakButtons[nsITaskbarWindowPreview::MAX_TOOLBAR_BUTTONS];
+
+  friend class TaskbarPreviewButton;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#endif /* __mozilla_widget_TaskbarWindowPreview_h__ */
+
new file mode 100644
--- /dev/null
+++ b/widget/src/windows/WinTaskbar.cpp
@@ -0,0 +1,235 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#include "WinTaskbar.h"
+#include "TaskbarPreview.h"
+#include <nsITaskbarPreviewController.h>
+
+#include <nsError.h>
+#include <nsCOMPtr.h>
+#include <nsIWidget.h>
+#include <nsIBaseWindow.h>
+#include <nsIObserverService.h>
+#include <nsServiceManagerUtils.h>
+#include <nsAutoPtr.h>
+#include "nsUXThemeData.h"
+#include "nsWindow.h"
+#include "TaskbarTabPreview.h"
+#include "TaskbarWindowPreview.h"
+#include <io.h>
+
+namespace {
+HWND
+GetHWNDFromDocShell(nsIDocShell *aShell) {
+  nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(reinterpret_cast<nsISupports*>(aShell)));
+
+  if (!baseWindow)
+    return NULL;
+
+  nsCOMPtr<nsIWidget> widget;
+  baseWindow->GetMainWidget(getter_AddRefs(widget));
+
+  return widget ? (HWND)widget->GetNativeData(NS_NATIVE_WINDOW) : NULL;
+}
+
+// Default controller for TaskbarWindowPreviews
+class DefaultController : public nsITaskbarPreviewController
+{
+  HWND mWnd;
+public:
+  DefaultController(HWND hWnd) 
+    : mWnd(hWnd)
+  {
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSITASKBARPREVIEWCONTROLLER
+};
+
+NS_IMETHODIMP
+DefaultController::GetWidth(PRUint32 *aWidth)
+{
+  RECT r;
+  ::GetClientRect(mWnd, &r);
+  *aWidth = r.right;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DefaultController::GetHeight(PRUint32 *aHeight)
+{
+  RECT r;
+  ::GetClientRect(mWnd, &r);
+  *aHeight = r.bottom;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DefaultController::GetThumbnailAspectRatio(float *aThumbnailAspectRatio) {
+  PRUint32 width, height;
+  GetWidth(&width);
+  GetHeight(&height);
+  if (!height)
+    height = 1;
+
+  *aThumbnailAspectRatio = width/float(height);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DefaultController::DrawPreview(nsIDOMCanvasRenderingContext2D *ctx, PRBool *rDrawFrame) {
+  *rDrawFrame = PR_TRUE;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DefaultController::DrawThumbnail(nsIDOMCanvasRenderingContext2D *ctx, PRUint32 width, PRUint32 height, PRBool *rDrawFrame) {
+  *rDrawFrame = PR_FALSE;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DefaultController::OnClose(void) {
+  NS_NOTREACHED("OnClose should not be called for TaskbarWindowPreviews");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DefaultController::OnActivate(PRBool *rAcceptActivation) {
+  *rAcceptActivation = PR_TRUE;
+  NS_NOTREACHED("OnActivate should not be called for TaskbarWindowPreviews");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DefaultController::OnClick(nsITaskbarPreviewButton *button) {
+  return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS1(DefaultController, nsITaskbarPreviewController);
+}
+
+namespace mozilla {
+namespace widget {
+
+NS_IMPL_ISUPPORTS1(WinTaskbar, nsIWinTaskbar)
+
+WinTaskbar::WinTaskbar() 
+  : mTaskbar(nsnull) {
+  ::CoInitialize(NULL);
+  HRESULT hr = ::CoCreateInstance(CLSID_TaskbarList,
+                                  NULL,
+                                  CLSCTX_INPROC_SERVER,
+                                  IID_ITaskbarList4,
+                                  (void**)&mTaskbar);
+  if (FAILED(hr))
+    return;
+
+  hr = mTaskbar->HrInit();
+  if (FAILED(hr)) {
+    NS_WARNING("Unable to initialize taskbar");
+    NS_RELEASE(mTaskbar);
+  }
+}
+
+WinTaskbar::~WinTaskbar() {
+  NS_IF_RELEASE(mTaskbar);
+  ::CoUninitialize();
+}
+
+NS_IMETHODIMP
+WinTaskbar::GetAvailable(PRBool *aAvailable) {
+  *aAvailable = mTaskbar != nsnull;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WinTaskbar::CreateTaskbarTabPreview(nsIDocShell *shell, nsITaskbarPreviewController *controller, nsITaskbarTabPreview **_retval) {
+  if (!mTaskbar)
+    return NS_ERROR_NOT_INITIALIZED;
+
+  NS_ENSURE_ARG_POINTER(shell);
+  NS_ENSURE_ARG_POINTER(controller);
+
+  HWND toplevelHWND = ::GetAncestor(GetHWNDFromDocShell(shell), GA_ROOT);
+
+  nsRefPtr<TaskbarTabPreview> preview(new TaskbarTabPreview(mTaskbar, controller, toplevelHWND, shell));
+  if (!preview)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  preview.forget(_retval);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WinTaskbar::GetTaskbarWindowPreview(nsIDocShell *shell, nsITaskbarWindowPreview **_retval) {
+  if (!mTaskbar)
+    return NS_ERROR_NOT_INITIALIZED;
+
+  NS_ENSURE_ARG_POINTER(shell);
+
+  HWND toplevelHWND = ::GetAncestor(GetHWNDFromDocShell(shell), GA_ROOT);
+
+  nsWindow *window = nsWindow::GetNSWindowPtr(toplevelHWND);
+
+  if (!window)
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsITaskbarWindowPreview> preview = window->GetTaskbarPreview();
+  if (!preview) {
+    nsRefPtr<DefaultController> defaultController = new DefaultController(toplevelHWND);
+    preview = new TaskbarWindowPreview(mTaskbar, defaultController, toplevelHWND, shell);
+    if (!preview)
+      return NS_ERROR_OUT_OF_MEMORY;
+    window->SetTaskbarPreview(preview);
+  }
+
+  preview.forget(_retval);
+
+  return NS_OK;
+}
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
new file mode 100644
--- /dev/null
+++ b/widget/src/windows/WinTaskbar.h
@@ -0,0 +1,71 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Arnold <tellrob@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __WinTaskbar_h__
+#define __WinTaskbar_h__
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#include <windows.h>
+#include <shobjidl.h>
+#include <nsIWinTaskbar.h>
+
+namespace mozilla {
+namespace widget {
+
+class WinTaskbar : public nsIWinTaskbar
+{
+public: 
+  WinTaskbar();
+  virtual ~WinTaskbar();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIWINTASKBAR
+private:
+  ITaskbarList4 *mTaskbar;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+
+#endif /* __WinTaskbar_h__ */
+
--- a/widget/src/windows/nsAppShell.cpp
+++ b/widget/src/windows/nsAppShell.cpp
@@ -54,16 +54,25 @@ BOOL WaitMessage(VOID)
   }
   
   return retval;
 }
 #endif
 
 static UINT sMsgId;
 
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+static UINT sTaskbarButtonCreatedMsg;
+
+/* static */
+UINT nsAppShell::GetTaskbarButtonCreatedMessage() {
+	return sTaskbarButtonCreatedMsg;
+}
+#endif
+
 //-------------------------------------------------------------------------
 
 static BOOL PeekKeyAndIMEMessage(LPMSG msg, HWND hwnd)
 {
   MSG msg1, msg2, *lpMsg;
   BOOL b1, b2;
   b1 = ::PeekMessageW(&msg1, NULL, WM_KEYFIRST, WM_IME_KEYLAST, PM_NOREMOVE);
   b2 = ::PeekMessageW(&msg2, NULL, WM_IME_SETCONTEXT, WM_IME_KEYUP, PM_NOREMOVE);
@@ -106,16 +115,21 @@ nsAppShell::~nsAppShell()
 }
 
 nsresult
 nsAppShell::Init()
 {
   if (!sMsgId)
     sMsgId = RegisterWindowMessageW(L"nsAppShell:EventID");
 
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+  sTaskbarButtonCreatedMsg = ::RegisterWindowMessageW(L"TaskbarButtonCreated");
+  NS_ASSERTION(sTaskbarButtonCreatedMsg, "Could not register taskbar button creation message");
+#endif
+
   WNDCLASSW wc;
   HINSTANCE module = GetModuleHandle(NULL);
 
   const PRUnichar *const kWindowClass = L"nsAppShell:EventWindowClass";
   if (!GetClassInfoW(module, kWindowClass, &wc)) {
     wc.style         = 0;
     wc.lpfnWndProc   = EventWindowProc;
     wc.cbClsExtra    = 0;
--- a/widget/src/windows/nsAppShell.h
+++ b/widget/src/windows/nsAppShell.h
@@ -46,16 +46,20 @@
  */
 class nsAppShell : public nsBaseAppShell
 {
 public:
   nsAppShell() : mEventWnd(NULL) {}
 
   nsresult Init();
 
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+  static UINT GetTaskbarButtonCreatedMessage();
+#endif
+
 protected:
   virtual void ScheduleNativeEventCallback();
   virtual PRBool ProcessNextNativeEvent(PRBool mayWait);
   virtual ~nsAppShell();
 
   static LRESULT CALLBACK EventWindowProc(HWND, UINT, WPARAM, LPARAM);
 
 protected:
--- a/widget/src/windows/nsUXThemeData.h
+++ b/widget/src/windows/nsUXThemeData.h
@@ -60,16 +60,21 @@ struct MARGINS
 #endif
 
 // Windows 7 additions
 #ifndef WM_DWMSENDICONICTHUMBNAIL
 #define WM_DWMSENDICONICTHUMBNAIL 0x0323
 #define WM_DWMSENDICONICLIVEPREVIEWBITMAP 0x0326
 #endif
 
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
+#define DWMWA_FORCE_ICONIC_REPRESENTATION 7
+#define DWMWA_HAS_ICONIC_BITMAP           10
+#endif
+
 enum nsUXThemeClass {
   eUXButton = 0,
   eUXEdit,
   eUXTooltip,
   eUXRebar,
   eUXMediaRebar,
   eUXCommunicationsRebar,
   eUXBrowserTabBarRebar,
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -179,16 +179,20 @@
 #if !defined(WINABLEAPI)
 #include <winable.h>
 #endif // !defined(WINABLEAPI)
 #include "nsIAccessible.h"
 #include "nsIAccessibleDocument.h"
 #include "nsIAccessNode.h"
 #endif // defined(ACCESSIBILITY)
 
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+#include "nsIWinTaskbar.h"
+#endif
+
 #if defined(NS_ENABLE_TSF)
 #include "nsTextStore.h"
 #endif // defined(NS_ENABLE_TSF)
 
 #if defined(MOZ_SPLASHSCREEN)
 #include "nsSplashScreen.h"
 #endif // defined(MOZ_SPLASHSCREEN)
 
@@ -378,16 +382,21 @@ nsWindow::nsWindow() : nsBaseWidget()
   mBrush                = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
   mForeground           = ::GetSysColor(COLOR_WINDOWTEXT);
 
 #ifdef WINCE_WINDOWS_MOBILE
   mInvalidatedRegion = do_CreateInstance(kRegionCID);
   mInvalidatedRegion->Init();
 #endif
 
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+  mTaskbarPreview = nsnull;
+  mHasTaskbarIconBeenCreated = PR_FALSE;
+#endif
+
   // Global initialization
   if (!sInstanceCount) {
 #if !defined(WINCE)
   gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
 #endif
 
   // Init IME handler
   nsIMM32Handler::Initialize();
@@ -876,17 +885,20 @@ DWORD nsWindow::WindowExStyle()
  * Create and Destroy.
  *
  **************************************************************/
 
 // Subclass (or remove the subclass from) this component's nsWindow
 void nsWindow::SubclassWindow(BOOL bState)
 {
   if (NULL != mWnd) {
-    NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
+    //NS_PRECONDITION(::IsWindow(mWnd), "Invalid window handle");
+    if (!::IsWindow(mWnd)) {
+      NS_ERROR("Invalid window handle");
+    }
 
     if (bState) {
       // change the nsWindow proc
       if (mUnicodeWidget)
         mPrevWndProc = (WNDPROC)::SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
                                                 (LONG_PTR)nsWindow::WindowProc);
       else
         mPrevWndProc = (WNDPROC)::SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
@@ -4396,16 +4408,20 @@ PRBool nsWindow::ProcessMessage(UINT msg
       }
 #endif //NS_ENABLE_TSF
 #if defined(HEAP_DUMP_EVENT)
       if (msg == GetHeapMsg()) {
         HeapDump(msg, wParam, lParam);
         result = PR_TRUE;
       }
 #endif
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+      if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
+        SetHasTaskbarIconBeenCreated();
+#endif
     }
     break;
   }
 
   //*aRetValue = result;
   if (mWnd) {
     return result;
   }
--- a/widget/src/windows/nsWindow.h
+++ b/widget/src/windows/nsWindow.h
@@ -62,16 +62,17 @@
 #include "nsWinGesture.h"
 #endif
 
 #if defined(WINCE)
 #include "nsWindowCE.h"
 #endif
 
 #include "WindowHook.h"
+#include "TaskbarWindowPreview.h"
 
 #ifdef ACCESSIBILITY
 #include "OLEACC.H"
 #include "nsIAccessible.h"
 #endif
 
 /**
  * Forward class definitions
@@ -84,16 +85,19 @@ class imgIContainer;
 
 /**
  * Native WIN32 window wrapper.
  */
 
 class nsWindow : public nsBaseWidget
 {
   typedef mozilla::widget::WindowHook WindowHook;
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+  typedef mozilla::widget::TaskbarWindowPreview TaskbarWindowPreview;
+#endif
 public:
   nsWindow();
   virtual ~nsWindow();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   friend class nsWindowGfx;
 
@@ -219,16 +223,30 @@ public:
   virtual PRBool          AutoErase(HDC dc);
   nsIntPoint*             GetLastPoint() { return &mLastPoint; }
   PRInt32                 GetNewCmdMenuId() { mMenuCmdId++; return mMenuCmdId; }
   PRBool                  GetIMEEnabled() { return mIMEEnabled; }
   // needed in nsIMM32Handler.cpp
   PRBool                  PluginHasFocus() { return mIMEEnabled == nsIWidget::IME_STATUS_PLUGIN; }
   virtual void            SetUpForPaint(HDC aHDC);
 
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+  PRBool HasTaskbarIconBeenCreated() { return mHasTaskbarIconBeenCreated; }
+  // Called when either the nsWindow or an nsITaskbarTabPreview receives the noticiation that this window
+  // has its icon placed on the taskbar.
+  void SetHasTaskbarIconBeenCreated(PRBool created = PR_TRUE) { mHasTaskbarIconBeenCreated = created; }
+
+  // Getter/setter for the nsITaskbarWindowPreview for this nsWindow
+  already_AddRefed<nsITaskbarWindowPreview> GetTaskbarPreview() {
+    nsCOMPtr<nsITaskbarWindowPreview> preview(do_QueryReferent(mTaskbarPreview));
+    return preview.forget();
+  }
+  void SetTaskbarPreview(nsITaskbarWindowPreview *preview) { mTaskbarPreview = do_GetWeakReference(preview); }
+#endif
+
 protected:
 
   /**
    * Callbacks
    */
   static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
   static BOOL CALLBACK    BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg);
   static BOOL CALLBACK    BroadcastMsg(HWND aTopWindow, LPARAM aMsg);
@@ -453,16 +471,24 @@ protected:
   nsTransparencyMode    mTransparencyMode;
 #endif // MOZ_XUL
 
   // Win7 Gesture processing and management
 #if !defined(WINCE)
   nsWinGesture          mGesture;
 #endif // !defined(WINCE)
 
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
+  // Weak ref to the nsITaskbarWindowPreview associated with this window
+  nsWeakPtr             mTaskbarPreview;
+  // True if the taskbar (possibly through the tab preview) tells us that the
+  // icon has been created on the taskbar.
+  PRBool                mHasTaskbarIconBeenCreated;
+#endif
+
 #if defined(WINCE_HAVE_SOFTKB)
   static PRBool         sSoftKeyMenuBar;
   static PRBool         sSoftKeyboardState;
 #endif // defined(WINCE_HAVE_SOFTKB)
 
 #ifdef ACCESSIBILITY
   static BOOL           sIsAccessibilityOn;
   static HINSTANCE      sAccLib;
--- a/widget/src/windows/nsWindowDbg.cpp
+++ b/widget/src/windows/nsWindowDbg.cpp
@@ -382,16 +382,18 @@ EventMsgInfo gAllEvents[] = {
   {"WM_AFXLAST",                          0x037F},
   {"WM_PENWINFIRST",                      0x0380},
   {"WM_PENWINLAST",                       0x038F},
   {"WM_APP",                              0x8000},
   {"WM_DWMCOMPOSITIONCHANGED",            0x031E},
   {"WM_DWMNCRENDERINGCHANGED",            0x031F},
   {"WM_DWMCOLORIZATIONCOLORCHANGED",      0x0320},
   {"WM_DWMWINDOWMAXIMIZEDCHANGE",         0x0321},
+  {"WM_DWMSENDICONICTHUMBNAIL",           0x0323},
+  {"WM_DWMSENDICONICLIVEPREVIEWBITMAP",   0x0326},
   {"WM_TABLET_QUERYSYSTEMGESTURESTATUS",  0x02CC},
   {"WM_GESTURE",                          0x0119},
   {"WM_GESTURENOTIFY",                    0x011A},
   {NULL, 0x0}
 };
 
 static long gEventCounter = 0;
 static long gLastEventMsg = 0;
--- a/widget/tests/Makefile.in
+++ b/widget/tests/Makefile.in
@@ -70,10 +70,16 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
                native_mouse_mac_window.xul \
                test_native_mouse_mac.xul \
                test_bug428405.xul \
                test_bug466599.xul \
                test_platform_colors.xul \
                $(NULL)
 endif
 
+ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
+ifneq ($(OS_ARCH), WINCE)
+_TEST_FILES += taskbar_previews.xul
+endif
+endif
+
 libs:: $(_TEST_FILES)
 	$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/widget/tests/taskbar_previews.xul
@@ -0,0 +1,128 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<window title="Taskbar Previews Test"
+  xmlns:html="http://www.w3.org/1999/xhtml"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  onload="loaded();">
+
+  <title>Previews - yeah!</title>
+  <script type="application/javascript" 
+   src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+  <script class="testbody" type="application/javascript">
+  <![CDATA[
+    let Cc = Components.classes;
+    let Ci = Components.interfaces;
+    let Cu = Components.utils;
+    Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+    let taskbar = Cc["@mozilla.org/windows-taskbar;1"].getService(Ci.nsIWinTaskbar);
+
+    function IsWin7OrHigher() {
+      try {
+        var sysInfo = Cc["@mozilla.org/system-info;1"].
+                      getService(Ci.nsIPropertyBag2);
+        var ver = parseFloat(sysInfo.getProperty("version"));
+        if (ver >= 6.1)
+          return true;
+      } catch (ex) { }
+      return false;
+    }
+    isnot(taskbar, null, "Taskbar service is defined");
+    is(taskbar.available, IsWin7OrHigher(), "Expected availability of taskbar");
+
+    SimpleTest.waitForExplicitFinish();
+
+    function stdPreviewSuite(p) {
+      p.visible = !p.visible;
+      p.visible = !p.visible;
+      p.visible = true;
+      p.invalidate();
+      p.visible = false;
+    }
+
+    function loaded()
+    {
+      if (!taskbar.available)
+        SimpleTest.finish();
+      let controller = {
+        width: 400,
+        height: 400,
+        thumbnailAspectRatio: 1.0,
+        drawThumbnail: function () { return false; },
+        drawPreview: function () { return false; },
+        get wrappedJSObject() { return this; }
+      }
+      // HACK from mconnor:
+      var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+      let win = wm.getMostRecentWindow("navigator:browser");
+      let docShell = win.gBrowser.docShell;
+
+      let winPreview = taskbar.getTaskbarWindowPreview(docShell);
+      isnot(winPreview, null, "Window preview is not null");
+      winPreview.controller = controller;
+      let button = winPreview.getButton(0);
+      isnot(button, null, "Could get button at valid index");
+      try {
+        winPreview.getButton(-1);
+        ok(false, "Got button at negative index");
+      } catch (ex) {}
+      try {
+        winPreview.getButton(Ci.nsITaskbarWindowPreview.NUM_TOOLBAR_BUTTONS);
+        ok(false, "Got button at index that is too large");
+      } catch (ex) {}
+      button.image = null;
+      stdPreviewSuite(winPreview);
+      // Let's not perma-hide this window from the taskbar
+      winPreview.visible = true;
+
+      let tabP = taskbar.createTaskbarTabPreview(docShell, controller);
+      isnot(tabP, null, "Tab preview is not null");
+      is(tabP.controller.wrappedJSObject, controller, "Controllers match");
+      tabP.icon = null;
+      tabP.move(null);
+      try {
+        tabP.move(tabP);
+        ok(false, "Moved a preview next to itself!");
+      } catch (ex) {}
+      stdPreviewSuite(tabP);
+
+      let tabP2 = taskbar.createTaskbarTabPreview(docShell, controller);
+      tabP.visible = true;
+      tabP2.visible = true;
+
+      isnot(tabP2, null, "2nd Tab preview is not null");
+      isnot(tabP,tabP2, "Tab previews are different");
+      tabP.active = true;
+      ok(tabP.active && !tabP2.active, "Only one tab is active (part 1)");
+      tabP2.active = true;
+      ok(!tabP.active && tabP2.active, "Only one tab is active (part 2)");
+      tabP.active = true;
+      ok(tabP.active && !tabP2.active, "Only one tab is active (part 3)");
+      tabP.active = false;
+      ok(!tabP.active && !tabP2.active, "Neither tab is active");
+      is(winPreview.active, false, "Window preview is not active");
+      tabP.active = true;
+      winPreview.active = true;
+      ok(winPreview.active && !tabP.active, "Tab preview takes activation from window");
+      tabP.active = true;
+      ok(tabP.active && !winPreview.active, "Tab preview takes activation from window");
+
+      tabP.visible = false;
+      tabP2.visible = false;
+
+      SimpleTest.finish();
+    }
+  ]]>
+  </script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <p id="display"></p>
+    <div id="content" style="display: none"></div>
+    <pre id="test"></pre>
+  </body>
+
+</window>