widget/windows/TaskbarWindowPreview.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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

mercurial