widget/cocoa/nsMacDockSupport.mm

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:c1791a1f1858
1 /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #import <Cocoa/Cocoa.h>
7
8 #include "nsComponentManagerUtils.h"
9 #include "nsMacDockSupport.h"
10 #include "nsObjCExceptions.h"
11
12 NS_IMPL_ISUPPORTS(nsMacDockSupport, nsIMacDockSupport, nsITaskbarProgress)
13
14 nsMacDockSupport::nsMacDockSupport()
15 : mAppIcon(nil)
16 , mProgressBackground(nil)
17 , mProgressState(STATE_NO_PROGRESS)
18 , mProgressFraction(0.0)
19 {
20 mProgressTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
21 }
22
23 nsMacDockSupport::~nsMacDockSupport()
24 {
25 if (mAppIcon) {
26 [mAppIcon release];
27 mAppIcon = nil;
28 }
29 if (mProgressBackground) {
30 [mProgressBackground release];
31 mProgressBackground = nil;
32 }
33 if (mProgressTimer) {
34 mProgressTimer->Cancel();
35 mProgressTimer = nullptr;
36 }
37 }
38
39 NS_IMETHODIMP
40 nsMacDockSupport::GetDockMenu(nsIStandaloneNativeMenu ** aDockMenu)
41 {
42 *aDockMenu = nullptr;
43
44 if (mDockMenu)
45 return mDockMenu->QueryInterface(NS_GET_IID(nsIStandaloneNativeMenu),
46 reinterpret_cast<void **>(aDockMenu));
47 return NS_OK;
48 }
49
50 NS_IMETHODIMP
51 nsMacDockSupport::SetDockMenu(nsIStandaloneNativeMenu * aDockMenu)
52 {
53 nsresult rv;
54 mDockMenu = do_QueryInterface(aDockMenu, &rv);
55 return rv;
56 }
57
58 NS_IMETHODIMP
59 nsMacDockSupport::ActivateApplication(bool aIgnoreOtherApplications)
60 {
61 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
62
63 [[NSApplication sharedApplication] activateIgnoringOtherApps:aIgnoreOtherApplications];
64 return NS_OK;
65
66 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
67 }
68
69 NS_IMETHODIMP
70 nsMacDockSupport::SetBadgeText(const nsAString& aBadgeText)
71 {
72 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
73
74 NSDockTile *tile = [[NSApplication sharedApplication] dockTile];
75 mBadgeText = aBadgeText;
76 if (aBadgeText.IsEmpty())
77 [tile setBadgeLabel: nil];
78 else
79 [tile setBadgeLabel:[NSString stringWithCharacters:reinterpret_cast<const unichar*>(mBadgeText.get())
80 length:mBadgeText.Length()]];
81 return NS_OK;
82
83 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
84 }
85
86 NS_IMETHODIMP
87 nsMacDockSupport::GetBadgeText(nsAString& aBadgeText)
88 {
89 aBadgeText = mBadgeText;
90 return NS_OK;
91 }
92
93 NS_IMETHODIMP
94 nsMacDockSupport::SetProgressState(nsTaskbarProgressState aState,
95 uint64_t aCurrentValue,
96 uint64_t aMaxValue)
97 {
98 NS_ENSURE_ARG_RANGE(aState, 0, STATE_PAUSED);
99 if (aState == STATE_NO_PROGRESS || aState == STATE_INDETERMINATE) {
100 NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG);
101 NS_ENSURE_TRUE(aMaxValue == 0, NS_ERROR_INVALID_ARG);
102 }
103 if (aCurrentValue > aMaxValue) {
104 return NS_ERROR_ILLEGAL_VALUE;
105 }
106
107 mProgressState = aState;
108 if (aMaxValue == 0) {
109 mProgressFraction = 0;
110 } else {
111 mProgressFraction = (double)aCurrentValue / aMaxValue;
112 }
113
114 if (mProgressState == STATE_NORMAL || mProgressState == STATE_INDETERMINATE) {
115 int perSecond = 8; // Empirically determined, see bug 848792
116 mProgressTimer->InitWithFuncCallback(RedrawIconCallback, this, 1000 / perSecond,
117 nsITimer::TYPE_REPEATING_SLACK);
118 return NS_OK;
119 } else {
120 mProgressTimer->Cancel();
121 return RedrawIcon();
122 }
123 }
124
125 // static
126 void nsMacDockSupport::RedrawIconCallback(nsITimer* aTimer, void* aClosure)
127 {
128 static_cast<nsMacDockSupport*>(aClosure)->RedrawIcon();
129 }
130
131 // Return whether to draw progress
132 bool nsMacDockSupport::InitProgress()
133 {
134 if (mProgressState != STATE_NORMAL && mProgressState != STATE_INDETERMINATE) {
135 return false;
136 }
137
138 if (!mAppIcon) {
139 mProgressTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
140 mAppIcon = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
141 mProgressBackground = [mAppIcon copyWithZone:nil];
142 mTheme = new nsNativeThemeCocoa();
143
144 NSSize sz = [mProgressBackground size];
145 mProgressBounds = CGRectMake(sz.width * 1/32, sz.height * 3/32,
146 sz.width * 30/32, sz.height * 4/32);
147 [mProgressBackground lockFocus];
148 [[NSColor whiteColor] set];
149 NSRectFill(NSRectFromCGRect(mProgressBounds));
150 [mProgressBackground unlockFocus];
151 }
152 return true;
153 }
154
155 nsresult
156 nsMacDockSupport::RedrawIcon()
157 {
158 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
159
160 if (InitProgress()) {
161 // TODO: - Implement ERROR and PAUSED states?
162 NSImage *icon = [mProgressBackground copyWithZone:nil];
163 bool isIndeterminate = (mProgressState != STATE_NORMAL);
164
165 [icon lockFocus];
166 CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
167 mTheme->DrawProgress(ctx, mProgressBounds, isIndeterminate,
168 true, mProgressFraction, 1.0, NULL);
169 [icon unlockFocus];
170 [NSApp setApplicationIconImage:icon];
171 [icon release];
172 } else {
173 [NSApp setApplicationIconImage:mAppIcon];
174 }
175
176 return NS_OK;
177 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
178 }

mercurial