Bug 515907 - Support taskbar icon overlays in Windows 7. Original patch by Tim Miller <mille449@gmail.com>. r=jimm, sr=roc

This commit is contained in:
Siddharth Agarwal 2011-09-29 00:06:43 +05:30
parent fdea173fa7
commit 79c05b8d5c
11 changed files with 238 additions and 22 deletions

View File

@ -140,6 +140,7 @@ XPIDLSRCS += nsIPrintSettingsWin.idl \
nsITaskbarPreviewButton.idl \
nsITaskbarProgress.idl \
nsITaskbarPreviewButton.idl \
nsITaskbarOverlayIconController.idl \
nsIJumpListBuilder.idl \
nsIJumpListItem.idl \
$(NULL)

View File

@ -0,0 +1,72 @@
/* -*- Mode: IDL; 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
* Tim Miller <mille449@gmail.com>.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Siddharth Agarwal <sid.bugzilla@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;
/**
* Starting in Windows 7, applications can display an overlay on the icon in
* the taskbar. This class wraps around the native functionality to do this.
*/
[scriptable, uuid(b1858889-a698-428a-a14b-b5d60cff6de2)]
interface nsITaskbarOverlayIconController : nsISupports
{
/**
* Sets the overlay icon and its corresponding alt text.
*
* @param statusIcon The handle to the overlay icon. The icon will be scaled
* to the small icon size (16x16 at 96 dpi). Can be null, in
* which case if the taskbar button represents a single window
* the icon is removed.
* @param statusDescription The alt text version of the information
* conveyed by the overlay, for accessibility
* purposes.
*
* @note The behavior for window groups is managed by Windows.
* - If an overlay icon is set for any window in a window group and another
* overlay icon is already applied to the corresponding taskbar button, that
* existing overlay is replaced.
* - If null is passed in to replace the overlay currently being displayed,
* and if a previous overlay set for a different window in the group is
* still available, then that previous overlay is displayed.
*/
void setOverlayIcon(in imgIContainer statusIcon,
in AString statusDescription);
};

View File

@ -48,6 +48,7 @@ interface nsITaskbarTabPreview;
interface nsITaskbarWindowPreview;
interface nsITaskbarPreviewController;
interface nsITaskbarProgress;
interface nsITaskbarOverlayIconController;
interface nsIJumpListBuilder;
interface nsIDOMWindow;
@ -83,7 +84,7 @@ interface nsIDOMWindow;
* See nsIJumpListBuilder for more information.
*/
[scriptable, uuid(9fc572db-1089-4d43-9121-f4833d77a2df)]
[scriptable, uuid(3232f40a-e94b-432d-9496-096abf1387bd)]
interface nsIWinTaskbar : nsISupports
{
/**
@ -132,6 +133,17 @@ interface nsIWinTaskbar : nsISupports
*/
nsITaskbarProgress getTaskbarProgress(in nsIDocShell shell);
/**
* Taskbar icon overlay
*/
/**
* Gets the taskbar icon overlay controller for a window. The docshell is used
* to find the toplevel window. See the documentation in
* nsITaskbarOverlayIconController for more details.
*/
nsITaskbarOverlayIconController getOverlayIconController(in nsIDocShell shell);
/**
* Taskbar and start menu jump list management
*/

View File

@ -140,7 +140,9 @@ TaskbarPreviewButton::SetImage(imgIContainer *img) {
::DestroyIcon(Button().hIcon);
if (img) {
nsresult rv;
rv = nsWindowGfx::CreateIcon(img, PR_FALSE, 0, 0, &Button().hIcon);
rv = nsWindowGfx::CreateIcon(img, PR_FALSE, 0, 0,
nsWindowGfx::GetIconMetrics(nsWindowGfx::kRegularIcon),
&Button().hIcon);
NS_ENSURE_SUCCESS(rv, rv);
} else {
Button().hIcon = NULL;

View File

@ -125,7 +125,9 @@ TaskbarTabPreview::SetIcon(imgIContainer *icon) {
HICON hIcon = NULL;
if (icon) {
nsresult rv;
rv = nsWindowGfx::CreateIcon(icon, PR_FALSE, 0, 0, &hIcon);
rv = nsWindowGfx::CreateIcon(icon, PR_FALSE, 0, 0,
nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon),
&hIcon);
NS_ENSURE_SUCCESS(rv, rv);
}

View File

@ -47,6 +47,7 @@
#include "nsUXThemeData.h"
#include "TaskbarPreviewButton.h"
#include "nsWindow.h"
#include "nsWindowGfx.h"
namespace mozilla {
namespace widget {
@ -60,8 +61,9 @@ PRBool WindowHookProc(void *aContext, HWND hWnd, UINT nMsg, WPARAM wParam, LPARA
}
}
NS_IMPL_ISUPPORTS3(TaskbarWindowPreview, nsITaskbarWindowPreview,
nsITaskbarProgress, nsISupportsWeakReference)
NS_IMPL_ISUPPORTS4(TaskbarWindowPreview, nsITaskbarWindowPreview,
nsITaskbarProgress, nsITaskbarOverlayIconController,
nsISupportsWeakReference)
/**
* These correspond directly to the states defined in nsITaskbarProgress.idl, so
@ -82,7 +84,8 @@ TaskbarWindowPreview::TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPr
mHaveButtons(PR_FALSE),
mState(TBPF_NOPROGRESS),
mCurrentValue(0),
mMaxValue(0)
mMaxValue(0),
mOverlayIcon(NULL)
{
// Window previews are visible by default
(void) SetVisible(PR_TRUE);
@ -97,10 +100,15 @@ TaskbarWindowPreview::TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPr
WindowHook &hook = GetWindowHook();
if (!CanMakeTaskbarCalls())
hook.AddMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
TaskbarProgressWindowHook, this);
TaskbarWindowHook, this);
}
TaskbarWindowPreview::~TaskbarWindowPreview() {
if (mOverlayIcon) {
::DestroyIcon(mOverlayIcon);
mOverlayIcon = NULL;
}
if (IsWindowAvailable()) {
DetachFromNSWindow();
} else {
@ -199,6 +207,35 @@ TaskbarWindowPreview::SetProgressState(nsTaskbarProgressState aState,
return CanMakeTaskbarCalls() ? UpdateTaskbarProgress() : NS_OK;
}
NS_IMETHODIMP
TaskbarWindowPreview::SetOverlayIcon(imgIContainer* aStatusIcon,
const nsAString& aStatusDescription) {
nsresult rv;
if (aStatusIcon) {
// The image shouldn't be animated
PRBool isAnimated;
rv = aStatusIcon->GetAnimated(&isAnimated);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_FALSE(isAnimated, NS_ERROR_INVALID_ARG);
}
HICON hIcon = NULL;
if (aStatusIcon) {
rv = nsWindowGfx::CreateIcon(aStatusIcon, false, 0, 0,
nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon),
&hIcon);
NS_ENSURE_SUCCESS(rv, rv);
}
if (mOverlayIcon)
::DestroyIcon(mOverlayIcon);
mOverlayIcon = hIcon;
mIconDescription = aStatusDescription;
// Only update if we can
return CanMakeTaskbarCalls() ? UpdateOverlayIcon() : NS_OK;
}
nsresult
TaskbarWindowPreview::UpdateTaskbarProperties() {
if (mHaveButtons) {
@ -207,6 +244,8 @@ TaskbarWindowPreview::UpdateTaskbarProperties() {
}
nsresult rv = UpdateTaskbarProgress();
NS_ENSURE_SUCCESS(rv, rv);
rv = UpdateOverlayIcon();
NS_ENSURE_SUCCESS(rv, rv);
return TaskbarPreview::UpdateTaskbarProperties();
}
@ -220,6 +259,13 @@ TaskbarWindowPreview::UpdateTaskbarProgress() {
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
}
nsresult
TaskbarWindowPreview::UpdateOverlayIcon() {
HRESULT hr = mTaskbar->SetOverlayIcon(mWnd, mOverlayIcon,
mIconDescription.get());
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
}
LRESULT
TaskbarWindowPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
nsRefPtr<TaskbarWindowPreview> kungFuDeathGrip(this);
@ -240,17 +286,17 @@ TaskbarWindowPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
/* static */
PRBool
TaskbarWindowPreview::TaskbarProgressWindowHook(void *aContext,
HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam,
LRESULT *aResult)
TaskbarWindowPreview::TaskbarWindowHook(void *aContext,
HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam,
LRESULT *aResult)
{
NS_ASSERTION(nMsg == nsAppShell::GetTaskbarButtonCreatedMessage(),
"Window hook proc called with wrong message");
TaskbarWindowPreview *preview =
reinterpret_cast<TaskbarWindowPreview*>(aContext);
// Now we can make all the calls to mTaskbar
preview->UpdateTaskbarProgress();
preview->UpdateTaskbarProperties();
return PR_FALSE;
}
@ -282,7 +328,7 @@ TaskbarWindowPreview::DetachFromNSWindow() {
WindowHook &hook = GetWindowHook();
(void) hook.RemoveHook(WM_COMMAND, WindowHookProc, this);
(void) hook.RemoveMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
TaskbarProgressWindowHook, this);
TaskbarWindowHook, this);
TaskbarPreview::DetachFromNSWindow();
}

View File

@ -46,6 +46,7 @@
#include "nsITaskbarWindowPreview.h"
#include "nsITaskbarProgress.h"
#include "nsITaskbarOverlayIconController.h"
#include "TaskbarPreview.h"
#include <nsWeakReference.h>
@ -56,6 +57,7 @@ class TaskbarPreviewButton;
class TaskbarWindowPreview : public TaskbarPreview,
public nsITaskbarWindowPreview,
public nsITaskbarProgress,
public nsITaskbarOverlayIconController,
public nsSupportsWeakReference
{
public:
@ -65,6 +67,7 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSITASKBARWINDOWPREVIEW
NS_DECL_NSITASKBARPROGRESS
NS_DECL_NSITASKBAROVERLAYICONCONTROLLER
NS_FORWARD_NSITASKBARPREVIEW(TaskbarPreview::)
virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam);
@ -90,17 +93,22 @@ private:
// Called to update ITaskbarList4 dependent properties
nsresult UpdateTaskbarProgress();
nsresult UpdateOverlayIcon();
// The taskbar progress
TBPFLAG mState;
ULONGLONG mCurrentValue;
ULONGLONG mMaxValue;
// WindowHook procedure for hooking mWnd for taskbar progress stuff
static PRBool TaskbarProgressWindowHook(void *aContext,
HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam,
LRESULT *aResult);
// Taskbar overlay icon
HICON mOverlayIcon;
nsString mIconDescription;
// WindowHook procedure for hooking mWnd for taskbar progress and icon stuff
static PRBool TaskbarWindowHook(void *aContext,
HWND hWnd, UINT nMsg,
WPARAM wParam, LPARAM lParam,
LRESULT *aResult);
friend class TaskbarPreviewButton;
};

View File

@ -416,6 +416,16 @@ WinTaskbar::GetTaskbarProgress(nsIDocShell *shell, nsITaskbarProgress **_retval)
return CallQueryInterface(preview, _retval);
}
NS_IMETHODIMP
WinTaskbar::GetOverlayIconController(nsIDocShell *shell,
nsITaskbarOverlayIconController **_retval) {
nsCOMPtr<nsITaskbarWindowPreview> preview;
nsresult rv = GetTaskbarWindowPreview(shell, getter_AddRefs(preview));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(preview, _retval);
}
/* nsIJumpListBuilder createJumpListBuilder(); */
NS_IMETHODIMP
WinTaskbar::CreateJumpListBuilder(nsIJumpListBuilder * *aJumpListBuilder) {

View File

@ -2453,7 +2453,9 @@ NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
return NS_ERROR_NOT_AVAILABLE;
HCURSOR cursor;
rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
// No scaling
gfxIntSize size(0, 0);
rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, size, &cursor);
NS_ENSURE_SUCCESS(rv, rv);
mCursor = nsCursor(-1);

View File

@ -103,6 +103,18 @@ using namespace mozilla::layers;
static nsAutoPtr<PRUint8> sSharedSurfaceData;
static gfxIntSize sSharedSurfaceSize;
struct IconMetrics {
PRInt32 xMetric;
PRInt32 yMetric;
PRInt32 defaultSize;
};
// Corresponds 1:1 to the IconSizeType enum
static IconMetrics sIconMetrics[] = {
{SM_CXSMICON, SM_CYSMICON, 16}, // small icon
{SM_CXICON, SM_CYICON, 32} // regular icon
};
/**************************************************************
**************************************************************
**
@ -613,10 +625,22 @@ PRBool nsWindow::OnPaint(HDC aDC, PRUint32 aNestingLevel)
return result;
}
gfxIntSize nsWindowGfx::GetIconMetrics(IconSizeType aSizeType) {
PRInt32 width = ::GetSystemMetrics(sIconMetrics[aSizeType].xMetric);
PRInt32 height = ::GetSystemMetrics(sIconMetrics[aSizeType].yMetric);
if (width == 0 || height == 0) {
width = height = sIconMetrics[aSizeType].defaultSize;
}
return gfxIntSize(width, height);
}
nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer,
PRBool aIsCursor,
PRUint32 aHotspotX,
PRUint32 aHotspotY,
gfxIntSize aScaledSize,
HICON *aIcon) {
// Get the image data
@ -627,10 +651,42 @@ nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer,
if (!frame)
return NS_ERROR_NOT_AVAILABLE;
PRUint8 *data = frame->Data();
PRInt32 width = frame->Width();
PRInt32 height = frame->Height();
if (!width || !height)
return NS_ERROR_FAILURE;
PRUint8 *data;
if ((aScaledSize.width == 0 && aScaledSize.height == 0) ||
(aScaledSize.width == width && aScaledSize.height == height)) {
// We're not scaling the image. The data is simply what's in the frame.
data = frame->Data();
}
else {
NS_ENSURE_ARG(aScaledSize.width > 0);
NS_ENSURE_ARG(aScaledSize.height > 0);
// Draw a scaled version of the image to a temporary surface
nsRefPtr<gfxImageSurface> dest = new gfxImageSurface(aScaledSize,
gfxASurface::ImageFormatARGB32);
if (!dest)
return NS_ERROR_OUT_OF_MEMORY;
gfxContext ctx(dest);
// Set scaling
gfxFloat sw = (double) aScaledSize.width / width;
gfxFloat sh = (double) aScaledSize.height / height;
ctx.Scale(sw, sh);
// Paint a scaled image
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
ctx.SetSource(frame);
ctx.Paint();
data = dest->Data();
width = aScaledSize.width;
height = aScaledSize.height;
}
HBITMAP bmp = DataToBitmap(data, width, -height, 32);
PRUint8* a1data = Data32BitTo1Bit(data, width, height);

View File

@ -60,7 +60,12 @@ public:
static nsIntRegion ConvertHRGNToRegion(HRGN aRgn);
static nsresult CreateIcon(imgIContainer *aContainer, PRBool aIsCursor, PRUint32 aHotspotX, PRUint32 aHotspotY, HICON *aIcon);
enum IconSizeType {
kSmallIcon,
kRegularIcon
};
static gfxIntSize GetIconMetrics(IconSizeType aSizeType);
static nsresult CreateIcon(imgIContainer *aContainer, PRBool aIsCursor, PRUint32 aHotspotX, PRUint32 aHotspotY, gfxIntSize aScaledSize, HICON *aIcon);
private:
/**