Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* vim: se cin sw=2 ts=2 et : */ |
michael@0 | 2 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
michael@0 | 3 | * |
michael@0 | 4 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 7 | |
michael@0 | 8 | #include "mozilla/ArrayUtils.h" |
michael@0 | 9 | |
michael@0 | 10 | #include <nsITaskbarPreviewController.h> |
michael@0 | 11 | #include "TaskbarWindowPreview.h" |
michael@0 | 12 | #include "WindowHook.h" |
michael@0 | 13 | #include "nsUXThemeData.h" |
michael@0 | 14 | #include "TaskbarPreviewButton.h" |
michael@0 | 15 | #include "nsWindow.h" |
michael@0 | 16 | #include "nsWindowGfx.h" |
michael@0 | 17 | |
michael@0 | 18 | namespace mozilla { |
michael@0 | 19 | namespace widget { |
michael@0 | 20 | |
michael@0 | 21 | namespace { |
michael@0 | 22 | bool WindowHookProc(void *aContext, HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT *aResult) |
michael@0 | 23 | { |
michael@0 | 24 | TaskbarWindowPreview *preview = reinterpret_cast<TaskbarWindowPreview*>(aContext); |
michael@0 | 25 | *aResult = preview->WndProc(nMsg, wParam, lParam); |
michael@0 | 26 | return true; |
michael@0 | 27 | } |
michael@0 | 28 | } |
michael@0 | 29 | |
michael@0 | 30 | NS_IMPL_ISUPPORTS(TaskbarWindowPreview, nsITaskbarWindowPreview, |
michael@0 | 31 | nsITaskbarProgress, nsITaskbarOverlayIconController, |
michael@0 | 32 | nsISupportsWeakReference) |
michael@0 | 33 | |
michael@0 | 34 | /** |
michael@0 | 35 | * These correspond directly to the states defined in nsITaskbarProgress.idl, so |
michael@0 | 36 | * they should be kept in sync. |
michael@0 | 37 | */ |
michael@0 | 38 | static TBPFLAG sNativeStates[] = |
michael@0 | 39 | { |
michael@0 | 40 | TBPF_NOPROGRESS, |
michael@0 | 41 | TBPF_INDETERMINATE, |
michael@0 | 42 | TBPF_NORMAL, |
michael@0 | 43 | TBPF_ERROR, |
michael@0 | 44 | TBPF_PAUSED |
michael@0 | 45 | }; |
michael@0 | 46 | |
michael@0 | 47 | TaskbarWindowPreview::TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell) |
michael@0 | 48 | : TaskbarPreview(aTaskbar, aController, aHWND, aShell), |
michael@0 | 49 | mCustomDrawing(false), |
michael@0 | 50 | mHaveButtons(false), |
michael@0 | 51 | mState(TBPF_NOPROGRESS), |
michael@0 | 52 | mCurrentValue(0), |
michael@0 | 53 | mMaxValue(0), |
michael@0 | 54 | mOverlayIcon(nullptr) |
michael@0 | 55 | { |
michael@0 | 56 | // Window previews are visible by default |
michael@0 | 57 | (void) SetVisible(true); |
michael@0 | 58 | |
michael@0 | 59 | memset(mThumbButtons, 0, sizeof mThumbButtons); |
michael@0 | 60 | for (int32_t i = 0; i < nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS; i++) { |
michael@0 | 61 | mThumbButtons[i].dwMask = THB_FLAGS | THB_ICON | THB_TOOLTIP; |
michael@0 | 62 | mThumbButtons[i].iId = i; |
michael@0 | 63 | mThumbButtons[i].dwFlags = THBF_HIDDEN; |
michael@0 | 64 | } |
michael@0 | 65 | |
michael@0 | 66 | WindowHook &hook = GetWindowHook(); |
michael@0 | 67 | if (!CanMakeTaskbarCalls()) |
michael@0 | 68 | hook.AddMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(), |
michael@0 | 69 | TaskbarWindowHook, this); |
michael@0 | 70 | } |
michael@0 | 71 | |
michael@0 | 72 | TaskbarWindowPreview::~TaskbarWindowPreview() { |
michael@0 | 73 | if (mOverlayIcon) { |
michael@0 | 74 | ::DestroyIcon(mOverlayIcon); |
michael@0 | 75 | mOverlayIcon = nullptr; |
michael@0 | 76 | } |
michael@0 | 77 | |
michael@0 | 78 | if (IsWindowAvailable()) { |
michael@0 | 79 | DetachFromNSWindow(); |
michael@0 | 80 | } else { |
michael@0 | 81 | mWnd = nullptr; |
michael@0 | 82 | } |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | nsresult |
michael@0 | 86 | TaskbarWindowPreview::ShowActive(bool active) { |
michael@0 | 87 | return FAILED(mTaskbar->ActivateTab(active ? mWnd : nullptr)) |
michael@0 | 88 | ? NS_ERROR_FAILURE |
michael@0 | 89 | : NS_OK; |
michael@0 | 90 | |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | HWND & |
michael@0 | 94 | TaskbarWindowPreview::PreviewWindow() { |
michael@0 | 95 | return mWnd; |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | nsresult |
michael@0 | 99 | TaskbarWindowPreview::GetButton(uint32_t index, nsITaskbarPreviewButton **_retVal) { |
michael@0 | 100 | if (index >= nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS) |
michael@0 | 101 | return NS_ERROR_INVALID_ARG; |
michael@0 | 102 | |
michael@0 | 103 | nsCOMPtr<nsITaskbarPreviewButton> button(do_QueryReferent(mWeakButtons[index])); |
michael@0 | 104 | |
michael@0 | 105 | if (!button) { |
michael@0 | 106 | // Lost reference |
michael@0 | 107 | button = new TaskbarPreviewButton(this, index); |
michael@0 | 108 | if (!button) { |
michael@0 | 109 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 110 | } |
michael@0 | 111 | mWeakButtons[index] = do_GetWeakReference(button); |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | if (!mHaveButtons) { |
michael@0 | 115 | mHaveButtons = true; |
michael@0 | 116 | |
michael@0 | 117 | WindowHook &hook = GetWindowHook(); |
michael@0 | 118 | (void) hook.AddHook(WM_COMMAND, WindowHookProc, this); |
michael@0 | 119 | |
michael@0 | 120 | if (mVisible && FAILED(mTaskbar->ThumbBarAddButtons(mWnd, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS, mThumbButtons))) { |
michael@0 | 121 | return NS_ERROR_FAILURE; |
michael@0 | 122 | } |
michael@0 | 123 | } |
michael@0 | 124 | button.forget(_retVal); |
michael@0 | 125 | return NS_OK; |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | NS_IMETHODIMP |
michael@0 | 129 | TaskbarWindowPreview::SetEnableCustomDrawing(bool aEnable) { |
michael@0 | 130 | if (aEnable == mCustomDrawing) |
michael@0 | 131 | return NS_OK; |
michael@0 | 132 | mCustomDrawing = aEnable; |
michael@0 | 133 | TaskbarPreview::EnableCustomDrawing(mWnd, aEnable); |
michael@0 | 134 | |
michael@0 | 135 | WindowHook &hook = GetWindowHook(); |
michael@0 | 136 | if (aEnable) { |
michael@0 | 137 | (void) hook.AddHook(WM_DWMSENDICONICTHUMBNAIL, WindowHookProc, this); |
michael@0 | 138 | (void) hook.AddHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP, WindowHookProc, this); |
michael@0 | 139 | } else { |
michael@0 | 140 | (void) hook.RemoveHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP, WindowHookProc, this); |
michael@0 | 141 | (void) hook.RemoveHook(WM_DWMSENDICONICTHUMBNAIL, WindowHookProc, this); |
michael@0 | 142 | } |
michael@0 | 143 | return NS_OK; |
michael@0 | 144 | } |
michael@0 | 145 | |
michael@0 | 146 | NS_IMETHODIMP |
michael@0 | 147 | TaskbarWindowPreview::GetEnableCustomDrawing(bool *aEnable) { |
michael@0 | 148 | *aEnable = mCustomDrawing; |
michael@0 | 149 | return NS_OK; |
michael@0 | 150 | } |
michael@0 | 151 | |
michael@0 | 152 | NS_IMETHODIMP |
michael@0 | 153 | TaskbarWindowPreview::SetProgressState(nsTaskbarProgressState aState, |
michael@0 | 154 | uint64_t aCurrentValue, |
michael@0 | 155 | uint64_t aMaxValue) |
michael@0 | 156 | { |
michael@0 | 157 | NS_ENSURE_ARG_RANGE(aState, |
michael@0 | 158 | nsTaskbarProgressState(0), |
michael@0 | 159 | nsTaskbarProgressState(ArrayLength(sNativeStates) - 1)); |
michael@0 | 160 | |
michael@0 | 161 | TBPFLAG nativeState = sNativeStates[aState]; |
michael@0 | 162 | if (nativeState == TBPF_NOPROGRESS || nativeState == TBPF_INDETERMINATE) { |
michael@0 | 163 | NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG); |
michael@0 | 164 | NS_ENSURE_TRUE(aMaxValue == 0, NS_ERROR_INVALID_ARG); |
michael@0 | 165 | } |
michael@0 | 166 | |
michael@0 | 167 | if (aCurrentValue > aMaxValue) |
michael@0 | 168 | return NS_ERROR_ILLEGAL_VALUE; |
michael@0 | 169 | |
michael@0 | 170 | mState = nativeState; |
michael@0 | 171 | mCurrentValue = aCurrentValue; |
michael@0 | 172 | mMaxValue = aMaxValue; |
michael@0 | 173 | |
michael@0 | 174 | // Only update if we can |
michael@0 | 175 | return CanMakeTaskbarCalls() ? UpdateTaskbarProgress() : NS_OK; |
michael@0 | 176 | } |
michael@0 | 177 | |
michael@0 | 178 | NS_IMETHODIMP |
michael@0 | 179 | TaskbarWindowPreview::SetOverlayIcon(imgIContainer* aStatusIcon, |
michael@0 | 180 | const nsAString& aStatusDescription) { |
michael@0 | 181 | nsresult rv; |
michael@0 | 182 | if (aStatusIcon) { |
michael@0 | 183 | // The image shouldn't be animated |
michael@0 | 184 | bool isAnimated; |
michael@0 | 185 | rv = aStatusIcon->GetAnimated(&isAnimated); |
michael@0 | 186 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 187 | NS_ENSURE_FALSE(isAnimated, NS_ERROR_INVALID_ARG); |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | HICON hIcon = nullptr; |
michael@0 | 191 | if (aStatusIcon) { |
michael@0 | 192 | rv = nsWindowGfx::CreateIcon(aStatusIcon, false, 0, 0, |
michael@0 | 193 | nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon), |
michael@0 | 194 | &hIcon); |
michael@0 | 195 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 196 | } |
michael@0 | 197 | |
michael@0 | 198 | if (mOverlayIcon) |
michael@0 | 199 | ::DestroyIcon(mOverlayIcon); |
michael@0 | 200 | mOverlayIcon = hIcon; |
michael@0 | 201 | mIconDescription = aStatusDescription; |
michael@0 | 202 | |
michael@0 | 203 | // Only update if we can |
michael@0 | 204 | return CanMakeTaskbarCalls() ? UpdateOverlayIcon() : NS_OK; |
michael@0 | 205 | } |
michael@0 | 206 | |
michael@0 | 207 | nsresult |
michael@0 | 208 | TaskbarWindowPreview::UpdateTaskbarProperties() { |
michael@0 | 209 | if (mHaveButtons) { |
michael@0 | 210 | if (FAILED(mTaskbar->ThumbBarAddButtons(mWnd, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS, mThumbButtons))) |
michael@0 | 211 | return NS_ERROR_FAILURE; |
michael@0 | 212 | } |
michael@0 | 213 | nsresult rv = UpdateTaskbarProgress(); |
michael@0 | 214 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 215 | rv = UpdateOverlayIcon(); |
michael@0 | 216 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 217 | return TaskbarPreview::UpdateTaskbarProperties(); |
michael@0 | 218 | } |
michael@0 | 219 | |
michael@0 | 220 | nsresult |
michael@0 | 221 | TaskbarWindowPreview::UpdateTaskbarProgress() { |
michael@0 | 222 | HRESULT hr = mTaskbar->SetProgressState(mWnd, mState); |
michael@0 | 223 | if (SUCCEEDED(hr) && mState != TBPF_NOPROGRESS && |
michael@0 | 224 | mState != TBPF_INDETERMINATE) |
michael@0 | 225 | hr = mTaskbar->SetProgressValue(mWnd, mCurrentValue, mMaxValue); |
michael@0 | 226 | |
michael@0 | 227 | return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE; |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | nsresult |
michael@0 | 231 | TaskbarWindowPreview::UpdateOverlayIcon() { |
michael@0 | 232 | HRESULT hr = mTaskbar->SetOverlayIcon(mWnd, mOverlayIcon, |
michael@0 | 233 | mIconDescription.get()); |
michael@0 | 234 | return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE; |
michael@0 | 235 | } |
michael@0 | 236 | |
michael@0 | 237 | LRESULT |
michael@0 | 238 | TaskbarWindowPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) { |
michael@0 | 239 | nsRefPtr<TaskbarWindowPreview> kungFuDeathGrip(this); |
michael@0 | 240 | switch (nMsg) { |
michael@0 | 241 | case WM_COMMAND: |
michael@0 | 242 | { |
michael@0 | 243 | uint32_t id = LOWORD(wParam); |
michael@0 | 244 | uint32_t index = id; |
michael@0 | 245 | nsCOMPtr<nsITaskbarPreviewButton> button; |
michael@0 | 246 | nsresult rv = GetButton(index, getter_AddRefs(button)); |
michael@0 | 247 | if (NS_SUCCEEDED(rv)) |
michael@0 | 248 | mController->OnClick(button); |
michael@0 | 249 | } |
michael@0 | 250 | return 0; |
michael@0 | 251 | } |
michael@0 | 252 | return TaskbarPreview::WndProc(nMsg, wParam, lParam); |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | /* static */ |
michael@0 | 256 | bool |
michael@0 | 257 | TaskbarWindowPreview::TaskbarWindowHook(void *aContext, |
michael@0 | 258 | HWND hWnd, UINT nMsg, |
michael@0 | 259 | WPARAM wParam, LPARAM lParam, |
michael@0 | 260 | LRESULT *aResult) |
michael@0 | 261 | { |
michael@0 | 262 | NS_ASSERTION(nMsg == nsAppShell::GetTaskbarButtonCreatedMessage(), |
michael@0 | 263 | "Window hook proc called with wrong message"); |
michael@0 | 264 | TaskbarWindowPreview *preview = |
michael@0 | 265 | reinterpret_cast<TaskbarWindowPreview*>(aContext); |
michael@0 | 266 | // Now we can make all the calls to mTaskbar |
michael@0 | 267 | preview->UpdateTaskbarProperties(); |
michael@0 | 268 | return false; |
michael@0 | 269 | } |
michael@0 | 270 | |
michael@0 | 271 | nsresult |
michael@0 | 272 | TaskbarWindowPreview::Enable() { |
michael@0 | 273 | nsresult rv = TaskbarPreview::Enable(); |
michael@0 | 274 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 275 | |
michael@0 | 276 | return FAILED(mTaskbar->AddTab(mWnd)) |
michael@0 | 277 | ? NS_ERROR_FAILURE |
michael@0 | 278 | : NS_OK; |
michael@0 | 279 | } |
michael@0 | 280 | |
michael@0 | 281 | nsresult |
michael@0 | 282 | TaskbarWindowPreview::Disable() { |
michael@0 | 283 | nsresult rv = TaskbarPreview::Disable(); |
michael@0 | 284 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 285 | |
michael@0 | 286 | return FAILED(mTaskbar->DeleteTab(mWnd)) |
michael@0 | 287 | ? NS_ERROR_FAILURE |
michael@0 | 288 | : NS_OK; |
michael@0 | 289 | } |
michael@0 | 290 | |
michael@0 | 291 | void |
michael@0 | 292 | TaskbarWindowPreview::DetachFromNSWindow() { |
michael@0 | 293 | // Remove the hooks we have for drawing |
michael@0 | 294 | SetEnableCustomDrawing(false); |
michael@0 | 295 | |
michael@0 | 296 | WindowHook &hook = GetWindowHook(); |
michael@0 | 297 | (void) hook.RemoveHook(WM_COMMAND, WindowHookProc, this); |
michael@0 | 298 | (void) hook.RemoveMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(), |
michael@0 | 299 | TaskbarWindowHook, this); |
michael@0 | 300 | |
michael@0 | 301 | TaskbarPreview::DetachFromNSWindow(); |
michael@0 | 302 | } |
michael@0 | 303 | |
michael@0 | 304 | nsresult |
michael@0 | 305 | TaskbarWindowPreview::UpdateButtons() { |
michael@0 | 306 | NS_ASSERTION(mVisible, "UpdateButtons called on invisible preview"); |
michael@0 | 307 | |
michael@0 | 308 | if (FAILED(mTaskbar->ThumbBarUpdateButtons(mWnd, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS, mThumbButtons))) |
michael@0 | 309 | return NS_ERROR_FAILURE; |
michael@0 | 310 | return NS_OK; |
michael@0 | 311 | } |
michael@0 | 312 | |
michael@0 | 313 | nsresult |
michael@0 | 314 | TaskbarWindowPreview::UpdateButton(uint32_t index) { |
michael@0 | 315 | if (index >= nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS) |
michael@0 | 316 | return NS_ERROR_INVALID_ARG; |
michael@0 | 317 | if (mVisible) { |
michael@0 | 318 | if (FAILED(mTaskbar->ThumbBarUpdateButtons(mWnd, 1, &mThumbButtons[index]))) |
michael@0 | 319 | return NS_ERROR_FAILURE; |
michael@0 | 320 | } |
michael@0 | 321 | return NS_OK; |
michael@0 | 322 | } |
michael@0 | 323 | |
michael@0 | 324 | } // namespace widget |
michael@0 | 325 | } // namespace mozilla |
michael@0 | 326 |