1 /* vim: se cin sw=2 ts=2 et : */
2 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/ArrayUtils.h"
10 #include <nsITaskbarPreviewController.h>
11 #include "TaskbarWindowPreview.h"
12 #include "WindowHook.h"
13 #include "nsUXThemeData.h"
14 #include "TaskbarPreviewButton.h"
16 #include "nsWindowGfx.h"
22 bool WindowHookProc(void* aContext
, HWND hWnd
, UINT nMsg
, WPARAM wParam
,
23 LPARAM lParam
, LRESULT
* aResult
) {
24 TaskbarWindowPreview
* preview
=
25 reinterpret_cast<TaskbarWindowPreview
*>(aContext
);
26 *aResult
= preview
->WndProc(nMsg
, wParam
, lParam
);
31 NS_IMPL_ISUPPORTS(TaskbarWindowPreview
, nsITaskbarWindowPreview
,
32 nsITaskbarProgress
, nsITaskbarOverlayIconController
,
33 nsISupportsWeakReference
)
36 * These correspond directly to the states defined in nsITaskbarProgress.idl, so
37 * they should be kept in sync.
39 static TBPFLAG sNativeStates
[] = {TBPF_NOPROGRESS
, TBPF_INDETERMINATE
,
40 TBPF_NORMAL
, TBPF_ERROR
, TBPF_PAUSED
};
42 TaskbarWindowPreview::TaskbarWindowPreview(
43 ITaskbarList4
* aTaskbar
, nsITaskbarPreviewController
* aController
,
44 HWND aHWND
, nsIDocShell
* aShell
)
45 : TaskbarPreview(aTaskbar
, aController
, aHWND
, aShell
),
46 mCustomDrawing(false),
48 mState(TBPF_NOPROGRESS
),
51 mOverlayIcon(nullptr) {
52 // Window previews are visible by default
53 (void)SetVisible(true);
55 memset(mThumbButtons
, 0, sizeof mThumbButtons
);
56 for (int32_t i
= 0; i
< nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
; i
++) {
57 mThumbButtons
[i
].dwMask
= THB_FLAGS
| THB_ICON
| THB_TOOLTIP
;
58 mThumbButtons
[i
].iId
= i
;
59 mThumbButtons
[i
].dwFlags
= THBF_HIDDEN
;
63 TaskbarWindowPreview::~TaskbarWindowPreview() {
65 ::DestroyIcon(mOverlayIcon
);
66 mOverlayIcon
= nullptr;
69 // We need to clean up a hook associated with the "this" pointer.
72 if (IsWindowAvailable()) {
79 nsresult
TaskbarWindowPreview::Init() {
80 nsresult rv
= TaskbarPreview::Init();
85 if (CanMakeTaskbarCalls()) {
89 WindowHook
* hook
= GetWindowHook();
91 return NS_ERROR_NOT_AVAILABLE
;
94 return hook
->AddMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
95 TaskbarWindowHook
, this);
98 nsresult
TaskbarWindowPreview::ShowActive(bool active
) {
99 return FAILED(mTaskbar
->ActivateTab(active
? mWnd
: nullptr))
104 HWND
& TaskbarWindowPreview::PreviewWindow() { return mWnd
; }
106 nsresult
TaskbarWindowPreview::GetButton(uint32_t index
,
107 nsITaskbarPreviewButton
** _retVal
) {
108 if (index
>= nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
)
109 return NS_ERROR_INVALID_ARG
;
111 nsCOMPtr
<nsITaskbarPreviewButton
> button(
112 do_QueryReferent(mWeakButtons
[index
]));
116 button
= new TaskbarPreviewButton(this, index
);
118 return NS_ERROR_OUT_OF_MEMORY
;
120 mWeakButtons
[index
] = do_GetWeakReference(button
);
126 WindowHook
* hook
= GetWindowHook();
128 return NS_ERROR_NOT_AVAILABLE
;
130 (void)hook
->AddHook(WM_COMMAND
, WindowHookProc
, this);
132 if (mVisible
&& FAILED(mTaskbar
->ThumbBarAddButtons(
133 mWnd
, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
,
135 return NS_ERROR_FAILURE
;
138 button
.forget(_retVal
);
143 TaskbarWindowPreview::SetEnableCustomDrawing(bool aEnable
) {
144 if (aEnable
== mCustomDrawing
) return NS_OK
;
146 WindowHook
* hook
= GetWindowHook();
148 return NS_ERROR_NOT_AVAILABLE
;
151 mCustomDrawing
= aEnable
;
152 TaskbarPreview::EnableCustomDrawing(mWnd
, aEnable
);
155 (void)hook
->AddHook(WM_DWMSENDICONICTHUMBNAIL
, WindowHookProc
, this);
156 (void)hook
->AddHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP
, WindowHookProc
,
159 (void)hook
->RemoveHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP
, WindowHookProc
,
161 (void)hook
->RemoveHook(WM_DWMSENDICONICTHUMBNAIL
, WindowHookProc
, this);
167 TaskbarWindowPreview::GetEnableCustomDrawing(bool* aEnable
) {
168 *aEnable
= mCustomDrawing
;
173 TaskbarWindowPreview::SetProgressState(nsTaskbarProgressState aState
,
174 uint64_t aCurrentValue
,
175 uint64_t aMaxValue
) {
176 NS_ENSURE_ARG_RANGE(aState
, nsTaskbarProgressState(0),
177 nsTaskbarProgressState(ArrayLength(sNativeStates
) - 1));
179 TBPFLAG nativeState
= sNativeStates
[aState
];
180 if (nativeState
== TBPF_NOPROGRESS
|| nativeState
== TBPF_INDETERMINATE
) {
181 NS_ENSURE_TRUE(aCurrentValue
== 0, NS_ERROR_INVALID_ARG
);
182 NS_ENSURE_TRUE(aMaxValue
== 0, NS_ERROR_INVALID_ARG
);
185 if (aCurrentValue
> aMaxValue
) return NS_ERROR_ILLEGAL_VALUE
;
187 mState
= nativeState
;
188 mCurrentValue
= aCurrentValue
;
189 mMaxValue
= aMaxValue
;
191 // Only update if we can
192 return CanMakeTaskbarCalls() ? UpdateTaskbarProgress() : NS_OK
;
196 TaskbarWindowPreview::SetOverlayIcon(imgIContainer
* aStatusIcon
,
197 const nsAString
& aStatusDescription
) {
200 // The image shouldn't be animated
202 rv
= aStatusIcon
->GetAnimated(&isAnimated
);
203 NS_ENSURE_SUCCESS(rv
, rv
);
204 NS_ENSURE_FALSE(isAnimated
, NS_ERROR_INVALID_ARG
);
207 HICON hIcon
= nullptr;
209 rv
= nsWindowGfx::CreateIcon(
210 aStatusIcon
, false, LayoutDeviceIntPoint(),
211 nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon
), &hIcon
);
212 NS_ENSURE_SUCCESS(rv
, rv
);
215 if (mOverlayIcon
) ::DestroyIcon(mOverlayIcon
);
216 mOverlayIcon
= hIcon
;
217 mIconDescription
= aStatusDescription
;
219 // Only update if we can
220 return CanMakeTaskbarCalls() ? UpdateOverlayIcon() : NS_OK
;
223 nsresult
TaskbarWindowPreview::UpdateTaskbarProperties() {
225 if (FAILED(mTaskbar
->ThumbBarAddButtons(
226 mWnd
, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
, mThumbButtons
)))
227 return NS_ERROR_FAILURE
;
229 nsresult rv
= UpdateTaskbarProgress();
230 NS_ENSURE_SUCCESS(rv
, rv
);
231 rv
= UpdateOverlayIcon();
232 NS_ENSURE_SUCCESS(rv
, rv
);
233 return TaskbarPreview::UpdateTaskbarProperties();
236 nsresult
TaskbarWindowPreview::UpdateTaskbarProgress() {
237 HRESULT hr
= mTaskbar
->SetProgressState(mWnd
, mState
);
238 if (SUCCEEDED(hr
) && mState
!= TBPF_NOPROGRESS
&&
239 mState
!= TBPF_INDETERMINATE
)
240 hr
= mTaskbar
->SetProgressValue(mWnd
, mCurrentValue
, mMaxValue
);
242 return SUCCEEDED(hr
) ? NS_OK
: NS_ERROR_FAILURE
;
245 nsresult
TaskbarWindowPreview::UpdateOverlayIcon() {
247 mTaskbar
->SetOverlayIcon(mWnd
, mOverlayIcon
, mIconDescription
.get());
248 return SUCCEEDED(hr
) ? NS_OK
: NS_ERROR_FAILURE
;
252 TaskbarWindowPreview::WndProc(UINT nMsg
, WPARAM wParam
, LPARAM lParam
) {
253 RefPtr
<TaskbarWindowPreview
> kungFuDeathGrip(this);
256 uint32_t id
= LOWORD(wParam
);
258 nsCOMPtr
<nsITaskbarPreviewButton
> button
;
259 nsresult rv
= GetButton(index
, getter_AddRefs(button
));
260 if (NS_SUCCEEDED(rv
)) mController
->OnClick(button
);
264 return TaskbarPreview::WndProc(nMsg
, wParam
, lParam
);
268 bool TaskbarWindowPreview::TaskbarWindowHook(void* aContext
, HWND hWnd
,
269 UINT nMsg
, WPARAM wParam
,
270 LPARAM lParam
, LRESULT
* aResult
) {
271 NS_ASSERTION(nMsg
== nsAppShell::GetTaskbarButtonCreatedMessage(),
272 "Window hook proc called with wrong message");
273 TaskbarWindowPreview
* preview
=
274 reinterpret_cast<TaskbarWindowPreview
*>(aContext
);
275 // Now we can make all the calls to mTaskbar
276 preview
->UpdateTaskbarProperties();
280 nsresult
TaskbarWindowPreview::Enable() {
281 nsresult rv
= TaskbarPreview::Enable();
282 NS_ENSURE_SUCCESS(rv
, rv
);
284 return FAILED(mTaskbar
->AddTab(mWnd
)) ? NS_ERROR_FAILURE
: NS_OK
;
287 nsresult
TaskbarWindowPreview::Disable() {
288 nsresult rv
= TaskbarPreview::Disable();
289 NS_ENSURE_SUCCESS(rv
, rv
);
291 return FAILED(mTaskbar
->DeleteTab(mWnd
)) ? NS_ERROR_FAILURE
: NS_OK
;
294 void TaskbarWindowPreview::DetachFromNSWindow() {
295 // Remove the hooks we have for drawing
296 SetEnableCustomDrawing(false);
298 if (WindowHook
* hook
= GetWindowHook()) {
299 (void)hook
->RemoveHook(WM_COMMAND
, WindowHookProc
, this);
300 (void)hook
->RemoveMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
301 TaskbarWindowHook
, this);
303 TaskbarPreview::DetachFromNSWindow();
306 nsresult
TaskbarWindowPreview::UpdateButtons() {
307 NS_ASSERTION(mVisible
, "UpdateButtons called on invisible preview");
309 if (FAILED(mTaskbar
->ThumbBarUpdateButtons(
310 mWnd
, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
, mThumbButtons
)))
311 return NS_ERROR_FAILURE
;
315 nsresult
TaskbarWindowPreview::UpdateButton(uint32_t index
) {
316 if (index
>= nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
)
317 return NS_ERROR_INVALID_ARG
;
319 if (FAILED(mTaskbar
->ThumbBarUpdateButtons(mWnd
, 1, &mThumbButtons
[index
])))
320 return NS_ERROR_FAILURE
;
325 } // namespace widget
326 } // namespace mozilla