mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
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:
parent
fdea173fa7
commit
79c05b8d5c
@ -140,6 +140,7 @@ XPIDLSRCS += nsIPrintSettingsWin.idl \
|
||||
nsITaskbarPreviewButton.idl \
|
||||
nsITaskbarProgress.idl \
|
||||
nsITaskbarPreviewButton.idl \
|
||||
nsITaskbarOverlayIconController.idl \
|
||||
nsIJumpListBuilder.idl \
|
||||
nsIJumpListItem.idl \
|
||||
$(NULL)
|
||||
|
72
widget/public/nsITaskbarOverlayIconController.idl
Normal file
72
widget/public/nsITaskbarOverlayIconController.idl
Normal 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);
|
||||
};
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user