/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #import #include "nsComponentManagerUtils.h" #include "nsMacDockSupport.h" #include "nsObjCExceptions.h" // For 10.4 (this is actually identical to 10.5's code) static inline NSRect NSRectFromCGRect( CGRect cgrect ) { union ConversionUnion { NSRect ns; CGRect cg; }; return ((union ConversionUnion *)&cgrect)->ns; } NS_IMPL_ISUPPORTS(nsMacDockSupport, nsIMacDockSupport, nsITaskbarProgress) nsMacDockSupport::nsMacDockSupport() : mAppIcon(nil) , mProgressBackground(nil) , mProgressState(STATE_NO_PROGRESS) , mProgressFraction(0.0) { mProgressTimer = do_CreateInstance(NS_TIMER_CONTRACTID); } nsMacDockSupport::~nsMacDockSupport() { if (mAppIcon) { [mAppIcon release]; mAppIcon = nil; } if (mProgressBackground) { [mProgressBackground release]; mProgressBackground = nil; } if (mProgressTimer) { mProgressTimer->Cancel(); mProgressTimer = nullptr; } } NS_IMETHODIMP nsMacDockSupport::GetDockMenu(nsIStandaloneNativeMenu ** aDockMenu) { *aDockMenu = nullptr; if (mDockMenu) return mDockMenu->QueryInterface(NS_GET_IID(nsIStandaloneNativeMenu), reinterpret_cast(aDockMenu)); return NS_OK; } NS_IMETHODIMP nsMacDockSupport::SetDockMenu(nsIStandaloneNativeMenu * aDockMenu) { nsresult rv; mDockMenu = do_QueryInterface(aDockMenu, &rv); return rv; } NS_IMETHODIMP nsMacDockSupport::ActivateApplication(bool aIgnoreOtherApplications) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; [[NSApplication sharedApplication] activateIgnoringOtherApps:aIgnoreOtherApplications]; return NS_OK; NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; } NS_IMETHODIMP nsMacDockSupport::SetBadgeText(const nsAString& aBadgeText) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; #if(0) NSDockTile *tile = [[NSApplication sharedApplication] dockTile]; mBadgeText = aBadgeText; if (aBadgeText.IsEmpty()) [tile setBadgeLabel: nil]; else [tile setBadgeLabel:[NSString stringWithCharacters:reinterpret_cast(mBadgeText.get()) length:mBadgeText.Length()]]; return NS_OK; #else // There is no NSDockTile class in 10.4, so this does nothing. mBadgeText = aBadgeText; NS_WARNING("10.4 does not have NSDockTile"); #endif NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; } NS_IMETHODIMP nsMacDockSupport::GetBadgeText(nsAString& aBadgeText) { aBadgeText = mBadgeText; return NS_OK; } NS_IMETHODIMP nsMacDockSupport::SetProgressState(nsTaskbarProgressState aState, uint64_t aCurrentValue, uint64_t aMaxValue) { NS_ENSURE_ARG_RANGE(aState, 0, STATE_PAUSED); if (aState == STATE_NO_PROGRESS || aState == STATE_INDETERMINATE) { NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG); NS_ENSURE_TRUE(aMaxValue == 0, NS_ERROR_INVALID_ARG); } if (aCurrentValue > aMaxValue) { return NS_ERROR_ILLEGAL_VALUE; } mProgressState = aState; if (aMaxValue == 0) { mProgressFraction = 0; } else { mProgressFraction = (double)aCurrentValue / aMaxValue; } if (mProgressState == STATE_NORMAL || mProgressState == STATE_INDETERMINATE) { int perSecond = 8; // Empirically determined, see bug 848792 mProgressTimer->InitWithFuncCallback(RedrawIconCallback, this, 1000 / perSecond, nsITimer::TYPE_REPEATING_SLACK); return NS_OK; } else { mProgressTimer->Cancel(); return RedrawIcon(); } } // static void nsMacDockSupport::RedrawIconCallback(nsITimer* aTimer, void* aClosure) { static_cast(aClosure)->RedrawIcon(); } // Return whether to draw progress bool nsMacDockSupport::InitProgress() { if (mProgressState != STATE_NORMAL && mProgressState != STATE_INDETERMINATE) { return false; } if (!mAppIcon) { mProgressTimer = do_CreateInstance(NS_TIMER_CONTRACTID); mAppIcon = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; mProgressBackground = [mAppIcon copyWithZone:nil]; mTheme = new nsNativeThemeCocoa(); NSSize sz = [mProgressBackground size]; mProgressBounds = CGRectMake(sz.width * 1/32, sz.height * 3/32, sz.width * 30/32, sz.height * 4/32); [mProgressBackground lockFocus]; [[NSColor whiteColor] set]; NSRectFill(NSRectFromCGRect(mProgressBounds)); [mProgressBackground unlockFocus]; } return true; } nsresult nsMacDockSupport::RedrawIcon() { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; if (InitProgress()) { // TODO: - Implement ERROR and PAUSED states? NSImage *icon = [mProgressBackground copyWithZone:nil]; bool isIndeterminate = (mProgressState != STATE_NORMAL); [icon lockFocus]; CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; mTheme->DrawProgress(ctx, mProgressBounds, isIndeterminate, true, mProgressFraction, 1.0, NULL); [icon unlockFocus]; [NSApp setApplicationIconImage:icon]; [icon release]; } else { [NSApp setApplicationIconImage:mAppIcon]; } return NS_OK; NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; }