widget/windows/TaskbarWindowPreview.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* vim: se cin sw=2 ts=2 et : */
     2 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     3  *
     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"
    15 #include "nsWindow.h"
    16 #include "nsWindowGfx.h"
    18 namespace mozilla {
    19 namespace widget {
    21 namespace {
    22 bool WindowHookProc(void *aContext, HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT *aResult)
    23 {
    24   TaskbarWindowPreview *preview = reinterpret_cast<TaskbarWindowPreview*>(aContext);
    25   *aResult = preview->WndProc(nMsg, wParam, lParam);
    26   return true;
    27 }
    28 }
    30 NS_IMPL_ISUPPORTS(TaskbarWindowPreview, nsITaskbarWindowPreview,
    31                   nsITaskbarProgress, nsITaskbarOverlayIconController,
    32                   nsISupportsWeakReference)
    34 /**
    35  * These correspond directly to the states defined in nsITaskbarProgress.idl, so
    36  * they should be kept in sync.
    37  */
    38 static TBPFLAG sNativeStates[] =
    39 {
    40   TBPF_NOPROGRESS,
    41   TBPF_INDETERMINATE,
    42   TBPF_NORMAL,
    43   TBPF_ERROR,
    44   TBPF_PAUSED
    45 };
    47 TaskbarWindowPreview::TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
    48   : TaskbarPreview(aTaskbar, aController, aHWND, aShell),
    49     mCustomDrawing(false),
    50     mHaveButtons(false),
    51     mState(TBPF_NOPROGRESS),
    52     mCurrentValue(0),
    53     mMaxValue(0),
    54     mOverlayIcon(nullptr)
    55 {
    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;
    64   }
    66   WindowHook &hook = GetWindowHook();
    67   if (!CanMakeTaskbarCalls())
    68     hook.AddMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
    69                     TaskbarWindowHook, this);
    70 }
    72 TaskbarWindowPreview::~TaskbarWindowPreview() {
    73   if (mOverlayIcon) {
    74     ::DestroyIcon(mOverlayIcon);
    75     mOverlayIcon = nullptr;
    76   }
    78   if (IsWindowAvailable()) {
    79     DetachFromNSWindow();
    80   } else {
    81     mWnd = nullptr;
    82   }
    83 }
    85 nsresult
    86 TaskbarWindowPreview::ShowActive(bool active) {
    87   return FAILED(mTaskbar->ActivateTab(active ? mWnd : nullptr))
    88        ? NS_ERROR_FAILURE
    89        : NS_OK;
    91 }
    93 HWND &
    94 TaskbarWindowPreview::PreviewWindow() {
    95   return mWnd;
    96 }
    98 nsresult
    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]));
   105   if (!button) {
   106     // Lost reference
   107     button = new TaskbarPreviewButton(this, index);
   108     if (!button) {
   109       return NS_ERROR_OUT_OF_MEMORY;
   110     }
   111     mWeakButtons[index] = do_GetWeakReference(button);
   112   }
   114   if (!mHaveButtons) {
   115     mHaveButtons = true;
   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;
   122     }
   123   }
   124   button.forget(_retVal);
   125   return NS_OK;
   126 }
   128 NS_IMETHODIMP
   129 TaskbarWindowPreview::SetEnableCustomDrawing(bool aEnable) {
   130   if (aEnable == mCustomDrawing)
   131     return NS_OK;
   132   mCustomDrawing = aEnable;
   133   TaskbarPreview::EnableCustomDrawing(mWnd, aEnable);
   135   WindowHook &hook = GetWindowHook();
   136   if (aEnable) {
   137     (void) hook.AddHook(WM_DWMSENDICONICTHUMBNAIL, WindowHookProc, this);
   138     (void) hook.AddHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP, WindowHookProc, this);
   139   } else {
   140     (void) hook.RemoveHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP, WindowHookProc, this);
   141     (void) hook.RemoveHook(WM_DWMSENDICONICTHUMBNAIL, WindowHookProc, this);
   142   }
   143   return NS_OK;
   144 }
   146 NS_IMETHODIMP
   147 TaskbarWindowPreview::GetEnableCustomDrawing(bool *aEnable) {
   148   *aEnable = mCustomDrawing;
   149   return NS_OK;
   150 }
   152 NS_IMETHODIMP
   153 TaskbarWindowPreview::SetProgressState(nsTaskbarProgressState aState,
   154                                        uint64_t aCurrentValue,
   155                                        uint64_t aMaxValue)
   156 {
   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);
   165   }
   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;
   176 }
   178 NS_IMETHODIMP
   179 TaskbarWindowPreview::SetOverlayIcon(imgIContainer* aStatusIcon,
   180                                      const nsAString& aStatusDescription) {
   181   nsresult rv;
   182   if (aStatusIcon) {
   183     // The image shouldn't be animated
   184     bool isAnimated;
   185     rv = aStatusIcon->GetAnimated(&isAnimated);
   186     NS_ENSURE_SUCCESS(rv, rv);
   187     NS_ENSURE_FALSE(isAnimated, NS_ERROR_INVALID_ARG);
   188   }
   190   HICON hIcon = nullptr;
   191   if (aStatusIcon) {
   192     rv = nsWindowGfx::CreateIcon(aStatusIcon, false, 0, 0,
   193                                  nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon),
   194                                  &hIcon);
   195     NS_ENSURE_SUCCESS(rv, rv);
   196   }
   198   if (mOverlayIcon)
   199     ::DestroyIcon(mOverlayIcon);
   200   mOverlayIcon = hIcon;
   201   mIconDescription = aStatusDescription;
   203   // Only update if we can
   204   return CanMakeTaskbarCalls() ? UpdateOverlayIcon() : NS_OK;
   205 }
   207 nsresult
   208 TaskbarWindowPreview::UpdateTaskbarProperties() {
   209   if (mHaveButtons) {
   210     if (FAILED(mTaskbar->ThumbBarAddButtons(mWnd, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS, mThumbButtons)))
   211       return NS_ERROR_FAILURE;
   212   }
   213   nsresult rv = UpdateTaskbarProgress();
   214   NS_ENSURE_SUCCESS(rv, rv);
   215   rv = UpdateOverlayIcon();
   216   NS_ENSURE_SUCCESS(rv, rv);
   217   return TaskbarPreview::UpdateTaskbarProperties();
   218 }
   220 nsresult
   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;
   228 }
   230 nsresult
   231 TaskbarWindowPreview::UpdateOverlayIcon() {
   232   HRESULT hr = mTaskbar->SetOverlayIcon(mWnd, mOverlayIcon,
   233                                         mIconDescription.get());
   234   return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
   235 }
   237 LRESULT
   238 TaskbarWindowPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
   239   nsRefPtr<TaskbarWindowPreview> kungFuDeathGrip(this);
   240   switch (nMsg) {
   241     case WM_COMMAND:
   242       {
   243         uint32_t id = LOWORD(wParam);
   244         uint32_t index = id;
   245         nsCOMPtr<nsITaskbarPreviewButton> button;
   246         nsresult rv = GetButton(index, getter_AddRefs(button));
   247         if (NS_SUCCEEDED(rv))
   248           mController->OnClick(button);
   249       }
   250       return 0;
   251   }
   252   return TaskbarPreview::WndProc(nMsg, wParam, lParam);
   253 }
   255 /* static */
   256 bool
   257 TaskbarWindowPreview::TaskbarWindowHook(void *aContext,
   258                                         HWND hWnd, UINT nMsg,
   259                                         WPARAM wParam, LPARAM lParam,
   260                                         LRESULT *aResult)
   261 {
   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();
   268   return false;
   269 }
   271 nsresult
   272 TaskbarWindowPreview::Enable() {
   273   nsresult rv = TaskbarPreview::Enable();
   274   NS_ENSURE_SUCCESS(rv, rv);
   276   return FAILED(mTaskbar->AddTab(mWnd))
   277        ? NS_ERROR_FAILURE
   278        : NS_OK;
   279 }
   281 nsresult
   282 TaskbarWindowPreview::Disable() {
   283   nsresult rv = TaskbarPreview::Disable();
   284   NS_ENSURE_SUCCESS(rv, rv);
   286   return FAILED(mTaskbar->DeleteTab(mWnd))
   287        ? NS_ERROR_FAILURE
   288        : NS_OK;
   289 }
   291 void
   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();
   302 }
   304 nsresult
   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;
   310   return NS_OK;
   311 }
   313 nsresult
   314 TaskbarWindowPreview::UpdateButton(uint32_t index) {
   315   if (index >= nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS)
   316     return NS_ERROR_INVALID_ARG;
   317   if (mVisible) {
   318     if (FAILED(mTaskbar->ThumbBarUpdateButtons(mWnd, 1, &mThumbButtons[index])))
   319       return NS_ERROR_FAILURE;
   320   }
   321   return NS_OK;
   322 }
   324 } // namespace widget
   325 } // namespace mozilla

mercurial