summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-01 16:30:47 +0000
committeravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-01 16:30:47 +0000
commit6a7fb04b7475b355cb571c9aca6b192d2a96ca5f (patch)
tree189b6f31c49e34874d3308cbffb9beb6becd8b26
parentc702d70890ab023ce723dde7aea8c66adb7ef98e (diff)
downloadchromium_src-6a7fb04b7475b355cb571c9aca6b192d2a96ca5f.zip
chromium_src-6a7fb04b7475b355cb571c9aca6b192d2a96ca5f.tar.gz
chromium_src-6a7fb04b7475b355cb571c9aca6b192d2a96ca5f.tar.bz2
Add temporary download progress overlay to the dock icon for the Mac (real UI coming soon), and provide the hooks for the Win7 implementation.
BUG=http://crbug.com/8039 TEST=download; see progress in the dock icon Review URL: http://codereview.chromium.org/545157 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37698 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/cocoa/dock_icon.h30
-rw-r--r--chrome/browser/cocoa/dock_icon.mm221
-rw-r--r--chrome/browser/cocoa/download_util_mac.mm11
-rw-r--r--chrome/browser/download/download_manager.cc38
-rw-r--r--chrome/browser/download/download_manager.h3
-rw-r--r--chrome/browser/download/download_util.cc8
-rw-r--r--chrome/browser/download/download_util.h9
-rwxr-xr-xchrome/chrome_browser.gypi2
8 files changed, 322 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/dock_icon.h b/chrome/browser/cocoa/dock_icon.h
new file mode 100644
index 0000000..4a96537
--- /dev/null
+++ b/chrome/browser/cocoa/dock_icon.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+// A class representing the dock icon of the Chromium app. It's its own class
+// since several parts of the app want to manipulate the display of the dock
+// icon.
+@interface DockIcon : NSObject {
+}
+
++ (DockIcon*)sharedDockIcon;
+
+// Updates the icon. Use the setters below to set the details first.
+- (void)updateIcon;
+
+// Download progress ///////////////////////////////////////////////////////////
+
+// Indicates how many downloads are in progress.
+- (void)setDownloads:(int)downloads;
+
+// Indicates whether the progress indicator should be in an indeterminate state
+// or not.
+- (void)setIndeterminate:(BOOL)indeterminate;
+
+// Indicates the amount of progress made of the download. Ranges from [0..1].
+- (void)setProgress:(float)progress;
+
+@end
diff --git a/chrome/browser/cocoa/dock_icon.mm b/chrome/browser/cocoa/dock_icon.mm
new file mode 100644
index 0000000..2b2b77e
--- /dev/null
+++ b/chrome/browser/cocoa/dock_icon.mm
@@ -0,0 +1,221 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/cocoa/dock_icon.h"
+
+#include "base/scoped_nsobject.h"
+
+// The fraction of the size of the dock icon that the badge is.
+static const float kBadgeFraction = 0.4f;
+
+// The indentation of the badge.
+static const float kBadgeIndent = 5.0f;
+
+// A view that draws our dock tile.
+@interface DockTileView : NSView {
+ @private
+ int downloads_;
+ BOOL indeterminate_;
+ float progress_;
+}
+
+// Indicates how many downloads are in progress.
+@property (nonatomic) int downloads;
+
+// Indicates whether the progress indicator should be in an indeterminate state
+// or not.
+@property (nonatomic) BOOL indeterminate;
+
+// Indicates the amount of progress made of the download. Ranges from [0..1].
+@property (nonatomic) float progress;
+
+@end
+
+@implementation DockTileView
+
+@synthesize downloads = downloads_;
+@synthesize indeterminate = indeterminate_;
+@synthesize progress = progress_;
+
+- (void)drawRect:(NSRect)dirtyRect {
+ NSImage* appIcon = [[NSApplication sharedApplication] applicationIconImage];
+ [appIcon drawInRect:[self bounds]
+ fromRect:NSZeroRect
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+
+ if (downloads_ == 0)
+ return;
+
+ NSRect badgeRect = [self bounds];
+ badgeRect.size.height = (int)(kBadgeFraction * badgeRect.size.height);
+ int newWidth = kBadgeFraction * badgeRect.size.width;
+ badgeRect.origin.x = badgeRect.size.width - newWidth;
+ badgeRect.size.width = newWidth;
+
+ CGFloat badgeRadius = NSMidY(badgeRect);
+
+ badgeRect.origin.x -= kBadgeIndent;
+ badgeRect.origin.y += kBadgeIndent;
+
+ NSPoint badgeCenter = NSMakePoint(NSMidX(badgeRect),
+ NSMidY(badgeRect));
+
+ // Background
+ NSColor* backgroundColor = [NSColor colorWithCalibratedRed:0.85
+ green:0.85
+ blue:0.85
+ alpha:1.0];
+ NSColor* backgroundHighlight =
+ [backgroundColor blendedColorWithFraction:0.85
+ ofColor:[NSColor whiteColor]];
+ scoped_nsobject<NSGradient> backgroundGradient(
+ [[NSGradient alloc] initWithStartingColor:backgroundHighlight
+ endingColor:backgroundColor]);
+ NSBezierPath* badgeEdge = [NSBezierPath bezierPathWithOvalInRect:badgeRect];
+ [NSGraphicsContext saveGraphicsState];
+ [badgeEdge addClip];
+ [backgroundGradient drawFromCenter:badgeCenter
+ radius:0.0
+ toCenter:badgeCenter
+ radius:badgeRadius
+ options:0];
+ [NSGraphicsContext restoreGraphicsState];
+
+ // Slice
+ if (!indeterminate_) {
+ NSColor* sliceColor = [NSColor colorWithCalibratedRed:0.45
+ green:0.8
+ blue:0.25
+ alpha:1.0];
+ NSColor* sliceHighlight =
+ [sliceColor blendedColorWithFraction:0.4
+ ofColor:[NSColor whiteColor]];
+ scoped_nsobject<NSGradient> sliceGradient(
+ [[NSGradient alloc] initWithStartingColor:sliceHighlight
+ endingColor:sliceColor]);
+ NSBezierPath* progressSlice;
+ if (progress_ >= 1.0) {
+ progressSlice = [NSBezierPath bezierPathWithOvalInRect:badgeRect];
+ } else {
+ CGFloat endAngle = 90.0 - 360.0 * progress_;
+ if (endAngle < 0.0)
+ endAngle += 360.0;
+ progressSlice = [NSBezierPath bezierPath];
+ [progressSlice moveToPoint:badgeCenter];
+ [progressSlice appendBezierPathWithArcWithCenter:badgeCenter
+ radius:badgeRadius
+ startAngle:90.0
+ endAngle:endAngle
+ clockwise:YES];
+ [progressSlice closePath];
+ }
+ [NSGraphicsContext saveGraphicsState];
+ [progressSlice addClip];
+ [sliceGradient drawFromCenter:badgeCenter
+ radius:0.0
+ toCenter:badgeCenter
+ radius:badgeRadius
+ options:0];
+ [NSGraphicsContext restoreGraphicsState];
+ }
+
+ // Edge
+ [NSGraphicsContext saveGraphicsState];
+ [[NSColor whiteColor] set];
+ scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+ [shadow setShadowOffset:NSMakeSize(0, -2)];
+ [shadow setShadowBlurRadius:2];
+ [shadow set];
+ [badgeEdge setLineWidth:2];
+ [badgeEdge stroke];
+ [NSGraphicsContext restoreGraphicsState];
+
+ // Download count
+ scoped_nsobject<NSNumberFormatter> formatter(
+ [[NSNumberFormatter alloc] init]);
+ NSString* countString =
+ [formatter stringFromNumber:[NSNumber numberWithInt:downloads_]];
+
+ scoped_nsobject<NSShadow> countShadow([[NSShadow alloc] init]);
+ [countShadow setShadowBlurRadius:3.0];
+ [countShadow setShadowColor:[NSColor whiteColor]];
+ [countShadow setShadowOffset:NSMakeSize(0.0, 0.0)];
+ NSMutableDictionary* countAttrsDict =
+ [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ [NSColor blackColor], NSForegroundColorAttributeName,
+ countShadow.get(), NSShadowAttributeName,
+ nil];
+ CGFloat countFontSize = badgeRadius;
+ NSSize countSize = NSZeroSize;
+ scoped_nsobject<NSAttributedString> countAttrString;
+ while (1) {
+ NSFont* countFont = [NSFont fontWithName:@"Helvetica-Bold"
+ size:countFontSize];
+ [countAttrsDict setObject:countFont forKey:NSFontAttributeName];
+ countAttrString.reset(
+ [[NSAttributedString alloc] initWithString:countString
+ attributes:countAttrsDict]);
+ countSize = [countAttrString size];
+ if (countSize.width > badgeRadius * 1.5) {
+ countFontSize -= 1.0;
+ } else {
+ break;
+ }
+ }
+
+ NSPoint countOrigin = badgeCenter;
+ countOrigin.x -= countSize.width / 2;
+ countOrigin.y -= countSize.height / 2.2; // tweak; otherwise too low
+
+ [countAttrString.get() drawAtPoint:countOrigin];
+}
+
+@end
+
+
+@implementation DockIcon
+
++ (DockIcon*)sharedDockIcon {
+ static DockIcon* icon;
+ if (!icon) {
+ NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
+
+ scoped_nsobject<DockTileView> dockTileView([[DockTileView alloc] init]);
+ [dockTile setContentView:dockTileView];
+
+ icon = [[DockIcon alloc] init];
+ }
+
+ return icon;
+}
+
+- (void)updateIcon {
+ NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
+
+ [dockTile display];
+}
+
+- (void)setDownloads:(int)downloads {
+ NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
+ DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
+
+ [dockTileView setDownloads:downloads];
+}
+
+- (void)setIndeterminate:(BOOL)indeterminate {
+ NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
+ DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
+
+ [dockTileView setIndeterminate:indeterminate];
+}
+
+- (void)setProgress:(float)progress {
+ NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
+ DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
+
+ [dockTileView setProgress:progress];
+}
+
+@end
diff --git a/chrome/browser/cocoa/download_util_mac.mm b/chrome/browser/cocoa/download_util_mac.mm
index 479ab7f..3c77f08 100644
--- a/chrome/browser/cocoa/download_util_mac.mm
+++ b/chrome/browser/cocoa/download_util_mac.mm
@@ -8,6 +8,7 @@
#include "app/gfx/native_widget_types.h"
#include "base/sys_string_conversions.h"
+#import "chrome/browser/cocoa/dock_icon.h"
#include "chrome/browser/download/download_manager.h"
#include "skia/ext/skia_utils_mac.h"
@@ -68,4 +69,14 @@ void DragDownload(const DownloadItem* download,
slideBack:YES];
}
+void UpdateAppIconDownloadProgress(int download_count,
+ bool progress_known,
+ float progress) {
+ DockIcon* dock_icon = [DockIcon sharedDockIcon];
+ [dock_icon setDownloads:download_count];
+ [dock_icon setIndeterminate:!progress_known];
+ [dock_icon setProgress:progress];
+ [dock_icon updateIcon];
+}
+
} // namespace download_util
diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc
index c327944..252b43c 100644
--- a/chrome/browser/download/download_manager.cc
+++ b/chrome/browser/download/download_manager.cc
@@ -789,6 +789,8 @@ void DownloadManager::ContinueStartDownload(DownloadCreateInfo* info,
NewCallback(this, &DownloadManager::OnCreateDownloadEntryComplete));
}
}
+
+ UpdateAppIcon();
}
// Convenience function for updating the history service for a download.
@@ -833,6 +835,7 @@ void DownloadManager::UpdateDownload(int32 download_id, int64 size) {
download->Update(size);
UpdateHistoryForDownload(download);
}
+ UpdateAppIcon();
}
void DownloadManager::DownloadFinished(int32 download_id, int64 size) {
@@ -865,6 +868,8 @@ void DownloadManager::DownloadFinished(int32 download_id, int64 size) {
UpdateHistoryForDownload(download);
}
+ UpdateAppIcon();
+
// If this a dangerous download not yet validated by the user, don't do
// anything. When the user notifies us, it will trigger a call to
// ProceedWithFinishedDangerousDownload.
@@ -1018,6 +1023,7 @@ void DownloadManager::DownloadCancelled(int32 download_id) {
DownloadCancelledInternal(download_id,
download->render_process_id(),
download->request_id());
+ UpdateAppIcon();
}
void DownloadManager::DownloadCancelledInternal(int download_id,
@@ -1071,6 +1077,36 @@ bool DownloadManager::IsDangerous(const FilePath& file_name) {
return IsExecutableFile(file_name);
}
+void DownloadManager::UpdateAppIcon() {
+ int64 total_bytes = 0;
+ int64 received_bytes = 0;
+ int download_count = 0;
+ bool progress_known = true;
+
+ for (DownloadMap::iterator i = in_progress_.begin();
+ i != in_progress_.end();
+ ++i) {
+ ++download_count;
+ const DownloadItem* item = i->second;
+ if (item->total_bytes() > 0) {
+ total_bytes += item->total_bytes();
+ received_bytes += item->received_bytes();
+ } else {
+ // This download didn't specify a Content-Length, so the combined progress
+ // bar neeeds to be indeterminate.
+ progress_known = false;
+ }
+ }
+
+ float progress = 0;
+ if (progress_known && download_count)
+ progress = (float)received_bytes / total_bytes;
+
+ download_util::UpdateAppIconDownloadProgress(download_count,
+ progress_known,
+ progress);
+}
+
void DownloadManager::RenameDownload(DownloadItem* download,
const FilePath& new_path) {
download->Rename(new_path);
@@ -1640,6 +1676,8 @@ void DownloadManager::OnCreateDownloadEntryComplete(DownloadCreateInfo info,
UpdateHistoryForDownload(download);
download->UpdateObservers();
}
+
+ UpdateAppIcon();
}
// Called when the history service has retrieved the list of downloads that
diff --git a/chrome/browser/download/download_manager.h b/chrome/browser/download/download_manager.h
index b562bc2..4d7a709 100644
--- a/chrome/browser/download/download_manager.h
+++ b/chrome/browser/download/download_manager.h
@@ -600,6 +600,9 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
// Checks whether a file represents a risk if downloaded.
bool IsDangerous(const FilePath& file_name);
+ // Updates the app icon about the overall download progress.
+ void UpdateAppIcon();
+
// Changes the paths and file name of the specified |download|, propagating
// the change to the history system.
void RenameDownload(DownloadItem* download, const FilePath& new_path);
diff --git a/chrome/browser/download/download_util.cc b/chrome/browser/download/download_util.cc
index 711c24c..48cb86f 100644
--- a/chrome/browser/download/download_util.cc
+++ b/chrome/browser/download/download_util.cc
@@ -400,4 +400,12 @@ std::wstring GetProgressStatusText(DownloadItem* download) {
amount, time_remaining);
}
+#if !defined(OS_MACOSX)
+void UpdateAppIconDownloadProgress(int download_count,
+ bool progress_known,
+ float progress) {
+ // Win7 Superbar wants some pixel lovin! http://crbug.com/8039
+}
+#endif
+
} // namespace download_util
diff --git a/chrome/browser/download/download_util.h b/chrome/browser/download/download_util.h
index 93114fe..f14be9a 100644
--- a/chrome/browser/download/download_util.h
+++ b/chrome/browser/download/download_util.h
@@ -144,6 +144,15 @@ DictionaryValue* CreateDownloadItemValue(DownloadItem* download, int id);
// Get the localized status text for an in-progress download.
std::wstring GetProgressStatusText(DownloadItem* download);
+// Update the application icon to indicate overall download progress.
+// |download_count| is the number of downloads currently in progress. If
+// |progress_known| is false, then at least one download is of indeterminate
+// size and |progress| is invalid, otherwise |progress| indicates the overall
+// download progress (float value from 0..1).
+void UpdateAppIconDownloadProgress(int download_count,
+ bool progress_known,
+ float progress);
+
} // namespace download_util
#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_UTIL_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 06ca294..33976a9 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -432,6 +432,8 @@
'browser/cocoa/custom_home_pages_model.mm',
'browser/cocoa/delayedmenu_button.h',
'browser/cocoa/delayedmenu_button.mm',
+ 'browser/cocoa/dock_icon.h',
+ 'browser/cocoa/dock_icon.mm',
'browser/cocoa/download_item_button.h',
'browser/cocoa/download_item_button.mm',
'browser/cocoa/download_item_cell.h',