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
, LPARAM lParam
, LRESULT
*aResult
)
24 TaskbarWindowPreview
*preview
= reinterpret_cast<TaskbarWindowPreview
*>(aContext
);
25 *aResult
= preview
->WndProc(nMsg
, wParam
, lParam
);
30 NS_IMPL_ISUPPORTS(TaskbarWindowPreview
, nsITaskbarWindowPreview
,
31 nsITaskbarProgress
, nsITaskbarOverlayIconController
,
32 nsISupportsWeakReference
)
35 * These correspond directly to the states defined in nsITaskbarProgress.idl, so
36 * they should be kept in sync.
38 static TBPFLAG sNativeStates
[] =
47 TaskbarWindowPreview::TaskbarWindowPreview(ITaskbarList4
*aTaskbar
, nsITaskbarPreviewController
*aController
, HWND aHWND
, nsIDocShell
*aShell
)
48 : TaskbarPreview(aTaskbar
, aController
, aHWND
, aShell
),
49 mCustomDrawing(false),
51 mState(TBPF_NOPROGRESS
),
56 // Window previews are visible by default
57 (void) SetVisible(true);
59 memset(mThumbButtons
, 0, sizeof mThumbButtons
);
60 for (int32_t i
= 0; i
< nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
; i
++) {
61 mThumbButtons
[i
].dwMask
= THB_FLAGS
| THB_ICON
| THB_TOOLTIP
;
62 mThumbButtons
[i
].iId
= i
;
63 mThumbButtons
[i
].dwFlags
= THBF_HIDDEN
;
66 WindowHook
&hook
= GetWindowHook();
67 if (!CanMakeTaskbarCalls())
68 hook
.AddMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
69 TaskbarWindowHook
, this);
72 TaskbarWindowPreview::~TaskbarWindowPreview() {
74 ::DestroyIcon(mOverlayIcon
);
75 mOverlayIcon
= nullptr;
78 if (IsWindowAvailable()) {
86 TaskbarWindowPreview::ShowActive(bool active
) {
87 return FAILED(mTaskbar
->ActivateTab(active
? mWnd
: nullptr))
94 TaskbarWindowPreview::PreviewWindow() {
99 TaskbarWindowPreview::GetButton(uint32_t index
, nsITaskbarPreviewButton
**_retVal
) {
100 if (index
>= nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
)
101 return NS_ERROR_INVALID_ARG
;
103 nsCOMPtr
<nsITaskbarPreviewButton
> button(do_QueryReferent(mWeakButtons
[index
]));
107 button
= new TaskbarPreviewButton(this, index
);
109 return NS_ERROR_OUT_OF_MEMORY
;
111 mWeakButtons
[index
] = do_GetWeakReference(button
);
117 WindowHook
&hook
= GetWindowHook();
118 (void) hook
.AddHook(WM_COMMAND
, WindowHookProc
, this);
120 if (mVisible
&& FAILED(mTaskbar
->ThumbBarAddButtons(mWnd
, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
, mThumbButtons
))) {
121 return NS_ERROR_FAILURE
;
124 button
.forget(_retVal
);
129 TaskbarWindowPreview::SetEnableCustomDrawing(bool aEnable
) {
130 if (aEnable
== mCustomDrawing
)
132 mCustomDrawing
= aEnable
;
133 TaskbarPreview::EnableCustomDrawing(mWnd
, aEnable
);
135 WindowHook
&hook
= GetWindowHook();
137 (void) hook
.AddHook(WM_DWMSENDICONICTHUMBNAIL
, WindowHookProc
, this);
138 (void) hook
.AddHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP
, WindowHookProc
, this);
140 (void) hook
.RemoveHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP
, WindowHookProc
, this);
141 (void) hook
.RemoveHook(WM_DWMSENDICONICTHUMBNAIL
, WindowHookProc
, this);
147 TaskbarWindowPreview::GetEnableCustomDrawing(bool *aEnable
) {
148 *aEnable
= mCustomDrawing
;
153 TaskbarWindowPreview::SetProgressState(nsTaskbarProgressState aState
,
154 uint64_t aCurrentValue
,
157 NS_ENSURE_ARG_RANGE(aState
,
158 nsTaskbarProgressState(0),
159 nsTaskbarProgressState(ArrayLength(sNativeStates
) - 1));
161 TBPFLAG nativeState
= sNativeStates
[aState
];
162 if (nativeState
== TBPF_NOPROGRESS
|| nativeState
== TBPF_INDETERMINATE
) {
163 NS_ENSURE_TRUE(aCurrentValue
== 0, NS_ERROR_INVALID_ARG
);
164 NS_ENSURE_TRUE(aMaxValue
== 0, NS_ERROR_INVALID_ARG
);
167 if (aCurrentValue
> aMaxValue
)
168 return NS_ERROR_ILLEGAL_VALUE
;
170 mState
= nativeState
;
171 mCurrentValue
= aCurrentValue
;
172 mMaxValue
= aMaxValue
;
174 // Only update if we can
175 return CanMakeTaskbarCalls() ? UpdateTaskbarProgress() : NS_OK
;
179 TaskbarWindowPreview::SetOverlayIcon(imgIContainer
* aStatusIcon
,
180 const nsAString
& aStatusDescription
) {
183 // The image shouldn't be animated
185 rv
= aStatusIcon
->GetAnimated(&isAnimated
);
186 NS_ENSURE_SUCCESS(rv
, rv
);
187 NS_ENSURE_FALSE(isAnimated
, NS_ERROR_INVALID_ARG
);
190 HICON hIcon
= nullptr;
192 rv
= nsWindowGfx::CreateIcon(aStatusIcon
, false, 0, 0,
193 nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon
),
195 NS_ENSURE_SUCCESS(rv
, rv
);
199 ::DestroyIcon(mOverlayIcon
);
200 mOverlayIcon
= hIcon
;
201 mIconDescription
= aStatusDescription
;
203 // Only update if we can
204 return CanMakeTaskbarCalls() ? UpdateOverlayIcon() : NS_OK
;
208 TaskbarWindowPreview::UpdateTaskbarProperties() {
210 if (FAILED(mTaskbar
->ThumbBarAddButtons(mWnd
, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
, mThumbButtons
)))
211 return NS_ERROR_FAILURE
;
213 nsresult rv
= UpdateTaskbarProgress();
214 NS_ENSURE_SUCCESS(rv
, rv
);
215 rv
= UpdateOverlayIcon();
216 NS_ENSURE_SUCCESS(rv
, rv
);
217 return TaskbarPreview::UpdateTaskbarProperties();
221 TaskbarWindowPreview::UpdateTaskbarProgress() {
222 HRESULT hr
= mTaskbar
->SetProgressState(mWnd
, mState
);
223 if (SUCCEEDED(hr
) && mState
!= TBPF_NOPROGRESS
&&
224 mState
!= TBPF_INDETERMINATE
)
225 hr
= mTaskbar
->SetProgressValue(mWnd
, mCurrentValue
, mMaxValue
);
227 return SUCCEEDED(hr
) ? NS_OK
: NS_ERROR_FAILURE
;
231 TaskbarWindowPreview::UpdateOverlayIcon() {
232 HRESULT hr
= mTaskbar
->SetOverlayIcon(mWnd
, mOverlayIcon
,
233 mIconDescription
.get());
234 return SUCCEEDED(hr
) ? NS_OK
: NS_ERROR_FAILURE
;
238 TaskbarWindowPreview::WndProc(UINT nMsg
, WPARAM wParam
, LPARAM lParam
) {
239 nsRefPtr
<TaskbarWindowPreview
> kungFuDeathGrip(this);
243 uint32_t id
= LOWORD(wParam
);
245 nsCOMPtr
<nsITaskbarPreviewButton
> button
;
246 nsresult rv
= GetButton(index
, getter_AddRefs(button
));
247 if (NS_SUCCEEDED(rv
))
248 mController
->OnClick(button
);
252 return TaskbarPreview::WndProc(nMsg
, wParam
, lParam
);
257 TaskbarWindowPreview::TaskbarWindowHook(void *aContext
,
258 HWND hWnd
, UINT nMsg
,
259 WPARAM wParam
, LPARAM lParam
,
262 NS_ASSERTION(nMsg
== nsAppShell::GetTaskbarButtonCreatedMessage(),
263 "Window hook proc called with wrong message");
264 TaskbarWindowPreview
*preview
=
265 reinterpret_cast<TaskbarWindowPreview
*>(aContext
);
266 // Now we can make all the calls to mTaskbar
267 preview
->UpdateTaskbarProperties();
272 TaskbarWindowPreview::Enable() {
273 nsresult rv
= TaskbarPreview::Enable();
274 NS_ENSURE_SUCCESS(rv
, rv
);
276 return FAILED(mTaskbar
->AddTab(mWnd
))
282 TaskbarWindowPreview::Disable() {
283 nsresult rv
= TaskbarPreview::Disable();
284 NS_ENSURE_SUCCESS(rv
, rv
);
286 return FAILED(mTaskbar
->DeleteTab(mWnd
))
292 TaskbarWindowPreview::DetachFromNSWindow() {
293 // Remove the hooks we have for drawing
294 SetEnableCustomDrawing(false);
296 WindowHook
&hook
= GetWindowHook();
297 (void) hook
.RemoveHook(WM_COMMAND
, WindowHookProc
, this);
298 (void) hook
.RemoveMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
299 TaskbarWindowHook
, this);
301 TaskbarPreview::DetachFromNSWindow();
305 TaskbarWindowPreview::UpdateButtons() {
306 NS_ASSERTION(mVisible
, "UpdateButtons called on invisible preview");
308 if (FAILED(mTaskbar
->ThumbBarUpdateButtons(mWnd
, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
, mThumbButtons
)))
309 return NS_ERROR_FAILURE
;
314 TaskbarWindowPreview::UpdateButton(uint32_t index
) {
315 if (index
>= nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS
)
316 return NS_ERROR_INVALID_ARG
;
318 if (FAILED(mTaskbar
->ThumbBarUpdateButtons(mWnd
, 1, &mThumbButtons
[index
])))
319 return NS_ERROR_FAILURE
;
324 } // namespace widget
325 } // namespace mozilla