widget/cocoa/nsMacDockSupport.mm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/cocoa/nsMacDockSupport.mm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,178 @@
     1.4 +/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#import <Cocoa/Cocoa.h>
    1.10 +
    1.11 +#include "nsComponentManagerUtils.h"
    1.12 +#include "nsMacDockSupport.h"
    1.13 +#include "nsObjCExceptions.h"
    1.14 +
    1.15 +NS_IMPL_ISUPPORTS(nsMacDockSupport, nsIMacDockSupport, nsITaskbarProgress)
    1.16 +
    1.17 +nsMacDockSupport::nsMacDockSupport()
    1.18 +: mAppIcon(nil)
    1.19 +, mProgressBackground(nil)
    1.20 +, mProgressState(STATE_NO_PROGRESS)
    1.21 +, mProgressFraction(0.0)
    1.22 +{
    1.23 +  mProgressTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
    1.24 +}
    1.25 +
    1.26 +nsMacDockSupport::~nsMacDockSupport()
    1.27 +{
    1.28 +  if (mAppIcon) {
    1.29 +    [mAppIcon release];
    1.30 +    mAppIcon = nil;
    1.31 +  }
    1.32 +  if (mProgressBackground) {
    1.33 +    [mProgressBackground release];
    1.34 +    mProgressBackground = nil;
    1.35 +  }
    1.36 +  if (mProgressTimer) {
    1.37 +    mProgressTimer->Cancel();
    1.38 +    mProgressTimer = nullptr;
    1.39 +  }
    1.40 +}
    1.41 +
    1.42 +NS_IMETHODIMP
    1.43 +nsMacDockSupport::GetDockMenu(nsIStandaloneNativeMenu ** aDockMenu)
    1.44 +{
    1.45 +  *aDockMenu = nullptr;
    1.46 +
    1.47 +  if (mDockMenu)
    1.48 +    return mDockMenu->QueryInterface(NS_GET_IID(nsIStandaloneNativeMenu),
    1.49 +                                     reinterpret_cast<void **>(aDockMenu));
    1.50 +  return NS_OK;
    1.51 +}
    1.52 +
    1.53 +NS_IMETHODIMP
    1.54 +nsMacDockSupport::SetDockMenu(nsIStandaloneNativeMenu * aDockMenu)
    1.55 +{
    1.56 +  nsresult rv;
    1.57 +  mDockMenu = do_QueryInterface(aDockMenu, &rv);
    1.58 +  return rv;
    1.59 +}
    1.60 +
    1.61 +NS_IMETHODIMP
    1.62 +nsMacDockSupport::ActivateApplication(bool aIgnoreOtherApplications)
    1.63 +{
    1.64 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
    1.65 +
    1.66 +  [[NSApplication sharedApplication] activateIgnoringOtherApps:aIgnoreOtherApplications];
    1.67 +  return NS_OK;
    1.68 +
    1.69 +  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
    1.70 +}
    1.71 +
    1.72 +NS_IMETHODIMP
    1.73 +nsMacDockSupport::SetBadgeText(const nsAString& aBadgeText)
    1.74 +{
    1.75 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
    1.76 +
    1.77 +  NSDockTile *tile = [[NSApplication sharedApplication] dockTile];
    1.78 +  mBadgeText = aBadgeText;
    1.79 +  if (aBadgeText.IsEmpty())
    1.80 +    [tile setBadgeLabel: nil];
    1.81 +  else
    1.82 +    [tile setBadgeLabel:[NSString stringWithCharacters:reinterpret_cast<const unichar*>(mBadgeText.get())
    1.83 +                                                length:mBadgeText.Length()]];
    1.84 +  return NS_OK;
    1.85 +
    1.86 +  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
    1.87 +}
    1.88 +
    1.89 +NS_IMETHODIMP
    1.90 +nsMacDockSupport::GetBadgeText(nsAString& aBadgeText)
    1.91 +{
    1.92 +  aBadgeText = mBadgeText;
    1.93 +  return NS_OK;
    1.94 +}
    1.95 +
    1.96 +NS_IMETHODIMP
    1.97 +nsMacDockSupport::SetProgressState(nsTaskbarProgressState aState,
    1.98 +                                   uint64_t aCurrentValue,
    1.99 +                                   uint64_t aMaxValue)
   1.100 +{
   1.101 +  NS_ENSURE_ARG_RANGE(aState, 0, STATE_PAUSED);
   1.102 +  if (aState == STATE_NO_PROGRESS || aState == STATE_INDETERMINATE) {
   1.103 +    NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG);
   1.104 +    NS_ENSURE_TRUE(aMaxValue == 0, NS_ERROR_INVALID_ARG);
   1.105 +  }
   1.106 +  if (aCurrentValue > aMaxValue) {
   1.107 +    return NS_ERROR_ILLEGAL_VALUE;
   1.108 +  }
   1.109 +
   1.110 +  mProgressState = aState;
   1.111 +  if (aMaxValue == 0) {
   1.112 +    mProgressFraction = 0;
   1.113 +  } else {
   1.114 +    mProgressFraction = (double)aCurrentValue / aMaxValue;
   1.115 +  }
   1.116 +
   1.117 +  if (mProgressState == STATE_NORMAL || mProgressState == STATE_INDETERMINATE) {
   1.118 +    int perSecond = 8; // Empirically determined, see bug 848792 
   1.119 +    mProgressTimer->InitWithFuncCallback(RedrawIconCallback, this, 1000 / perSecond,
   1.120 +      nsITimer::TYPE_REPEATING_SLACK);
   1.121 +    return NS_OK;
   1.122 +  } else {
   1.123 +    mProgressTimer->Cancel();
   1.124 +    return RedrawIcon();
   1.125 +  }
   1.126 +}
   1.127 +
   1.128 +// static
   1.129 +void nsMacDockSupport::RedrawIconCallback(nsITimer* aTimer, void* aClosure)
   1.130 +{
   1.131 +  static_cast<nsMacDockSupport*>(aClosure)->RedrawIcon();
   1.132 +}
   1.133 +
   1.134 +// Return whether to draw progress
   1.135 +bool nsMacDockSupport::InitProgress()
   1.136 +{
   1.137 +  if (mProgressState != STATE_NORMAL && mProgressState != STATE_INDETERMINATE) {
   1.138 +    return false;
   1.139 +  }
   1.140 +
   1.141 +  if (!mAppIcon) {
   1.142 +    mProgressTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
   1.143 +    mAppIcon = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
   1.144 +    mProgressBackground = [mAppIcon copyWithZone:nil];
   1.145 +    mTheme = new nsNativeThemeCocoa();
   1.146 +
   1.147 +    NSSize sz = [mProgressBackground size];
   1.148 +    mProgressBounds = CGRectMake(sz.width * 1/32, sz.height * 3/32,
   1.149 +                                 sz.width * 30/32, sz.height * 4/32);
   1.150 +    [mProgressBackground lockFocus];
   1.151 +    [[NSColor whiteColor] set];
   1.152 +    NSRectFill(NSRectFromCGRect(mProgressBounds));
   1.153 +    [mProgressBackground unlockFocus];
   1.154 +  }
   1.155 +  return true;
   1.156 +}
   1.157 +
   1.158 +nsresult
   1.159 +nsMacDockSupport::RedrawIcon()
   1.160 +{
   1.161 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   1.162 +
   1.163 +  if (InitProgress()) {
   1.164 +    // TODO: - Implement ERROR and PAUSED states?
   1.165 +    NSImage *icon = [mProgressBackground copyWithZone:nil];
   1.166 +    bool isIndeterminate = (mProgressState != STATE_NORMAL);
   1.167 +
   1.168 +    [icon lockFocus];
   1.169 +    CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
   1.170 +    mTheme->DrawProgress(ctx, mProgressBounds, isIndeterminate,
   1.171 +      true, mProgressFraction, 1.0, NULL);
   1.172 +    [icon unlockFocus];
   1.173 +    [NSApp setApplicationIconImage:icon];
   1.174 +    [icon release];
   1.175 +  } else {
   1.176 +    [NSApp setApplicationIconImage:mAppIcon];
   1.177 +  }
   1.178 +
   1.179 +  return NS_OK;
   1.180 +  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   1.181 +}

mercurial