summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa
diff options
context:
space:
mode:
authorthomasvl@chromium.org <thomasvl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-28 16:40:39 +0000
committerthomasvl@chromium.org <thomasvl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-28 16:40:39 +0000
commit7a3bdc0069b8ae1ed6eb115999878cee5cfa9360 (patch)
tree75bb0ee47dcfade7689c00a843e8f516a1d78cb1 /chrome/browser/cocoa
parent7911717865f60ebb922f07d1cf45249b9717cb00 (diff)
downloadchromium_src-7a3bdc0069b8ae1ed6eb115999878cee5cfa9360.zip
chromium_src-7a3bdc0069b8ae1ed6eb115999878cee5cfa9360.tar.gz
chromium_src-7a3bdc0069b8ae1ed6eb115999878cee5cfa9360.tar.bz2
Add background_tile_view for tiling an image as UI background (about box needed it)
Added restart_browser as a helper like Views helper for putting up a request for the user to restart. Added a new string needed for Mac style alerts to go with the existing restart string. Make Mac Chromium use a custom about box. Give Chromium and Google Chrome an about box that matches the one on other platforms Use all the existing UI strings for the about box so we get credits, copy rights, etc. TEST=New aboutbox for Chromium and Google Chrome. About box should be fully l10n and size as needed. Chrome update messaging should more match windows and be localized. BUG=13219,19020 Review URL: http://codereview.chromium.org/173606 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24737 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r--chrome/browser/cocoa/about_window_controller.h23
-rw-r--r--chrome/browser/cocoa/about_window_controller.mm351
-rw-r--r--chrome/browser/cocoa/about_window_controller_unittest.mm11
-rw-r--r--chrome/browser/cocoa/background_tile_view.h22
-rw-r--r--chrome/browser/cocoa/background_tile_view.mm32
-rw-r--r--chrome/browser/cocoa/background_tile_view_unittest.mm44
-rw-r--r--chrome/browser/cocoa/restart_browser.h21
-rw-r--r--chrome/browser/cocoa/restart_browser.mm67
8 files changed, 511 insertions, 60 deletions
diff --git a/chrome/browser/cocoa/about_window_controller.h b/chrome/browser/cocoa/about_window_controller.h
index 2117365..f9c7528 100644
--- a/chrome/browser/cocoa/about_window_controller.h
+++ b/chrome/browser/cocoa/about_window_controller.h
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_COCOA_ABOUT_WINDOW_CONTROLLER_MAC_H_
-#define CHROME_BROWSER_COCOA_ABOUT_WINDOW_CONTROLLER_MAC_H_
+#ifndef CHROME_BROWSER_COCOA_ABOUT_WINDOW_CONTROLLER_H_
+#define CHROME_BROWSER_COCOA_ABOUT_WINDOW_CONTROLLER_H_
#import <Cocoa/Cocoa.h>
+#include "base/scoped_nsobject.h"
#import "chrome/app/keystone_glue.h"
-@class AppController;
+@class BackgroundTileView;
// A window controller that handles the branded (Chrome.app) about
// window. The branded about window has a few features beyond the
@@ -18,12 +19,19 @@
@interface AboutWindowController : NSWindowController<KeystoneGlueCallbacks> {
@private
IBOutlet NSTextField* version_;
- IBOutlet NSTextField* upToDate_;
- IBOutlet NSTextField* updateCompleted_;
+ IBOutlet BackgroundTileView* backgroundView_;
+ IBOutlet NSImageView* logoView_;
+ IBOutlet NSTextField* legalBlock_;
+ IBOutlet NSView* updateBlock_; // Holds everything related to updates
IBOutlet NSProgressIndicator* spinner_;
+ IBOutlet NSImageView* updateStatusIndicator_;
+ IBOutlet NSTextField* updateText_;
IBOutlet NSButton* updateNowButton_;
BOOL updateTriggered_; // Has an update ever been triggered?
+
+ // The version we got told about by Keystone
+ scoped_nsobject<NSString> newVersionAvailable_;
}
// Trigger an update right now, as initiated by a button.
@@ -34,12 +42,11 @@
@interface AboutWindowController (JustForTesting)
- (NSButton*)updateButton;
-- (NSTextField*)upToDateTextField;
-- (NSTextField*)updateCompletedTextField;
+- (NSTextField*)updateText;
@end
// NSNotification sent when the about window is closed.
extern NSString* const kUserClosedAboutNotification;
-#endif
+#endif // CHROME_BROWSER_COCOA_ABOUT_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/about_window_controller.mm b/chrome/browser/cocoa/about_window_controller.mm
index d9ea076..5280c26 100644
--- a/chrome/browser/cocoa/about_window_controller.mm
+++ b/chrome/browser/cocoa/about_window_controller.mm
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
#include "base/file_version_info.h"
#include "base/logging.h"
#include "base/mac_util.h"
@@ -10,15 +11,170 @@
#include "base/sys_string_conversions.h"
#import "chrome/app/keystone_glue.h"
#import "chrome/browser/cocoa/about_window_controller.h"
+#import "chrome/browser/cocoa/background_tile_view.h"
+#include "chrome/browser/cocoa/restart_browser.h"
+#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "grit/locale_settings.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
NSString* const kUserClosedAboutNotification =
@"kUserClosedAboutNotification";
@interface AboutWindowController (Private)
- (KeystoneGlue*)defaultKeystoneGlue;
+- (void)startProgressMessageID:(uint32_t)messageID;
+- (void)startProgressMessage:(NSString*)message;
+- (void)stopProgressMessage:(NSString*)message imageID:(uint32_t)imageID;
@end
+namespace {
+
+// Keystone doesn't give us error numbers on some results, so we just make
+// our own for reporting in the UI.
+const int kUpdateInstallFailed = 128;
+const int kUpdateInstallFailedToStart = 129;
+
+void AttributedStringAppendString(NSMutableAttributedString* attr_str,
+ NSString* str) {
+ // You might think doing [[attr_str mutableString] appendString:str] would
+ // work, but it causes any trailing style to get extened, meaning as we
+ // append links, they grow to include the new text, not what we want.
+ NSAttributedString* new_attr_str =
+ [[[NSAttributedString alloc] initWithString:str] autorelease];
+ [attr_str appendAttributedString:new_attr_str];
+}
+
+void AttributedStringAppendHyperlink(NSMutableAttributedString* attr_str,
+ NSString* text, NSString* url_str) {
+
+ // Figure out the range of the text we're adding and add the text.
+ NSRange range = NSMakeRange([attr_str length], [text length]);
+ AttributedStringAppendString(attr_str, text);
+
+ // Add the link
+ [attr_str addAttribute:NSLinkAttributeName value:url_str range:range];
+
+ // Blue and underlined
+ [attr_str addAttribute:NSForegroundColorAttributeName
+ value:[NSColor blueColor]
+ range:range];
+ [attr_str addAttribute:NSUnderlineStyleAttributeName
+ value:[NSNumber numberWithInt:NSSingleUnderlineStyle]
+ range:range];
+}
+
+NSAttributedString* BuildLegalTextBlock() {
+ // Windows builds this up in a very complex way, we're just trying to model
+ // it the best we can to get all the information in (they actually do it
+ // but created Labels and Links that they carefully place to make it appear
+ // to be a paragraph of text).
+ // src/chrome/browser/views/about_chrome_view.cc AboutChromeView::Init()
+
+ NSMutableAttributedString* legal_block =
+ [[[NSMutableAttributedString alloc] init] autorelease];
+ [legal_block beginEditing];
+
+ NSString* copyright = l10n_util::GetNSString(IDS_ABOUT_VERSION_COPYRIGHT);
+ AttributedStringAppendString(legal_block, copyright);
+
+ // These are the markers directly in IDS_ABOUT_VERSION_LICENSE
+ NSString* kBeginLinkChr = @"BEGIN_LINK_CHR";
+ NSString* kBeginLinkOss = @"BEGIN_LINK_OSS";
+ NSString* kEndLinkChr = @"END_LINK_CHR";
+ NSString* kEndLinkOss = @"END_LINK_OSS";
+ // The CHR link should go to here
+ NSString* kChromiumProject = l10n_util::GetNSString(IDS_CHROMIUM_PROJECT_URL);
+ // The OSS link should go to here
+ NSString* kAcknowledgements = @"about:credits";
+
+ // Now fetch the license string and deal with the markers
+
+ NSString* license = l10n_util::GetNSString(IDS_ABOUT_VERSION_LICENSE);
+
+ NSRange begin_chr = [license rangeOfString:kBeginLinkChr];
+ NSRange begin_oss = [license rangeOfString:kBeginLinkOss];
+ NSRange end_chr = [license rangeOfString:kEndLinkChr];
+ NSRange end_oss = [license rangeOfString:kEndLinkOss];
+ DCHECK(begin_chr.location != NSNotFound);
+ DCHECK(begin_oss.location != NSNotFound);
+ DCHECK(end_chr.location != NSNotFound);
+ DCHECK(end_oss.location != NSNotFound);
+
+ // We don't know which link will come first, so we have to deal with things
+ // like this:
+ // [text][begin][text][end][text][start][text][end][text]
+
+ bool chromium_link_first = begin_chr.location < begin_oss.location;
+
+ NSRange* begin1 = &begin_chr;
+ NSRange* begin2 = &begin_oss;
+ NSRange* end1 = &end_chr;
+ NSRange* end2 = &end_oss;
+ NSString* link1 = kChromiumProject;
+ NSString* link2 = kAcknowledgements;
+ if (!chromium_link_first) {
+ // OSS came first, switch!
+ begin2 = &begin_chr;
+ begin1 = &begin_oss;
+ end2 = &end_chr;
+ end1 = &end_oss;
+ link2 = kChromiumProject;
+ link1 = kAcknowledgements;
+ }
+
+ NSString *sub_str;
+
+ AttributedStringAppendString(legal_block, @"\n");
+ sub_str = [license substringWithRange:NSMakeRange(0, begin1->location)];
+ AttributedStringAppendString(legal_block, sub_str);
+ sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*begin1),
+ end1->location -
+ NSMaxRange(*begin1))];
+ AttributedStringAppendHyperlink(legal_block, sub_str, link1);
+ sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*end1),
+ begin2->location -
+ NSMaxRange(*end1))];
+ AttributedStringAppendString(legal_block, sub_str);
+ sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*begin2),
+ end2->location -
+ NSMaxRange(*begin2))];
+ AttributedStringAppendHyperlink(legal_block, sub_str, link2);
+ sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*end2),
+ [license length] -
+ NSMaxRange(*end2))];
+ AttributedStringAppendString(legal_block, sub_str);
+
+#if defined(GOOGLE_CHROME_BUILD)
+ // Terms of service is only valid for Google Chrome
+
+ // The url within terms should point here:
+ NSString* kTOS = @"about:terms";
+ // Following Window. There is one marker in the string for where the terms
+ // link goes, but the text of the link comes from a second string resources.
+ std::vector<size_t> url_offsets;
+ std::wstring w_about_terms = l10n_util::GetStringF(IDS_ABOUT_TERMS_OF_SERVICE,
+ std::wstring(),
+ std::wstring(),
+ &url_offsets);
+ DCHECK_EQ(url_offsets.size(), 1U);
+ NSString* about_terms = base::SysWideToNSString(w_about_terms);
+ NSString* terms_link_text = l10n_util::GetNSString(IDS_TERMS_OF_SERVICE);
+
+ AttributedStringAppendString(legal_block, @"\n");
+ sub_str = [about_terms substringToIndex:url_offsets[0]];
+ AttributedStringAppendString(legal_block, sub_str);
+ AttributedStringAppendHyperlink(legal_block, terms_link_text, kTOS);
+ sub_str = [about_terms substringFromIndex:url_offsets[0]];
+ AttributedStringAppendString(legal_block, sub_str);
+#endif // defined(GOOGLE_CHROME_BUILD)
+
+ [legal_block endEditing];
+ return legal_block;
+}
+
+} // namespace
@implementation AboutWindowController
@@ -33,45 +189,133 @@ NSString* const kUserClosedAboutNotification =
// Set our current version.
scoped_ptr<FileVersionInfo> version_info(
FileVersionInfo::CreateFileVersionInfoForCurrentModule());
- NSString* version = base::SysWideToNSString(version_info->file_version());
- [version_ setStringValue:version];
+ std::wstring version(version_info->product_version());
+#if !defined(GOOGLE_CHROME_BUILD)
+ // Yes, Windows does this raw since it is only in Chromium builds
+ // src/chrome/browser/views/about_chrome_view.cc AboutChromeView::Init()
+ version += L" (";
+ version += version_info->last_change();
+ version += L")";
+#endif
+ NSString* nsversion = base::SysWideToNSString(version);
+ [version_ setStringValue:nsversion];
+
+ // Put the two images into the ui
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* backgroundImage = rb.GetNSImageNamed(IDR_ABOUT_BACKGROUND_COLOR);
+ DCHECK(backgroundImage);
+ [backgroundView_ setTileImage:backgroundImage];
+ NSImage* logoImage = rb.GetNSImageNamed(IDR_ABOUT_BACKGROUND);
+ DCHECK(logoImage);
+ [logoView_ setImage:logoImage];
+
+ // Put the legal text into
+ [legalBlock_ setAttributedStringValue:BuildLegalTextBlock()];
+
+ KeystoneGlue* keystone = [self defaultKeystoneGlue];
+ CGFloat updateShift = 0.0;
+ if (keystone) {
+ // Initiate an update check.
+ if ([keystone checkForUpdate:self]) {
+ [self startProgressMessageID:IDS_UPGRADE_CHECK_STARTED];
+ }
+ } else {
+ // Hide all the update UI
+ [updateBlock_ setHidden:YES];
+ // Figure out the amount we're removing by taking about the update block
+ // (and it's spacing).
+ updateShift = NSMinY([legalBlock_ frame]) - NSMinY([updateBlock_ frame]);
+ }
- // Localize the update now button.
- NSString* updateNow = base::SysWideToNSString(
- l10n_util::GetString(IDS_ABOUT_CHROME_UPDATE_CHECK));
- [updateNowButton_ setStringValue:updateNow];
+ // Adjust the sizes/locations.
- // TODO(jrg): localize the rest of the elements:
- // - "Google Chrome" string at top
- // - copyright string at bottom
+ CGFloat legalShift =
+ [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:legalBlock_];
- // Initiate an update check.
- if ([[self defaultKeystoneGlue] checkForUpdate:self])
- [spinner_ startAnimation:self];
+ NSRect rect = [legalBlock_ frame];
+ rect.origin.y -= updateShift;
+ [legalBlock_ setFrame:rect];
+
+ rect = [backgroundView_ frame];
+ rect.origin.y = rect.origin.y - updateShift + legalShift;
+ [backgroundView_ setFrame:rect];
+
+ NSWindow* window = [self window];
+ [[window contentView] setAutoresizesSubviews:NO];
+ rect = [window frame];
+ rect.size.height = rect.size.height - updateShift + legalShift;
+ [window setFrame:rect display:NO];
+ [[window contentView] setAutoresizesSubviews:YES];
}
- (KeystoneGlue*)defaultKeystoneGlue {
return [KeystoneGlue defaultKeystoneGlue];
}
+- (void)startProgressMessageID:(uint32_t)messageID {
+ NSString* message = l10n_util::GetNSStringWithFixup(messageID);
+ [self startProgressMessage:message];
+}
+
+- (void)startProgressMessage:(NSString*)message {
+ [updateStatusIndicator_ setHidden:YES];
+ [spinner_ setHidden:NO];
+ [spinner_ startAnimation:self];
+
+ [updateText_ setStringValue:message];
+}
+
+- (void)stopProgressMessage:(NSString*)message imageID:(uint32_t)imageID {
+ [spinner_ stopAnimation:self];
+ [spinner_ setHidden:YES];
+ if (imageID) {
+ [updateStatusIndicator_ setHidden:NO];
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* statusImage = rb.GetNSImageNamed(imageID);
+ DCHECK(statusImage);
+ [updateStatusIndicator_ setImage:statusImage];
+ }
+
+ [updateText_ setStringValue:message];
+}
+
// Callback from KeystoneGlue; implementation of KeystoneGlueCallbacks protocol.
// Warning: latest version may be nil if not set in server config.
- (void)upToDateCheckCompleted:(BOOL)updatesAvailable
latestVersion:(NSString*)latestVersion {
- [spinner_ stopAnimation:self];
-
- // If an update is available, be sure to enable the "update now" button.
- NSString* display = @"No updates are available.";
+ uint32_t imageID;
+ NSString* message;
if (updatesAvailable) {
+ newVersionAvailable_.reset([latestVersion copy]);
+
+ // Window UI doesn't put the version number in the string.
+ imageID = IDR_UPDATE_AVAILABLE;
+ message =
+ l10n_util::GetNSStringF(IDS_UPGRADE_AVAILABLE,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
[updateNowButton_ setEnabled:YES];
- // TODO(jrg): IDS_UPGRADE_AVAILABLE seems close but there is no facility
- // for specifying a verision in the update string. Do we care?
- display = latestVersion ?
- [NSString stringWithFormat:@"Version %@ is available for update.",
- latestVersion] :
- @"A new version is available.";
+ } else {
+ // NOTE: This is can be a lie, Keystone does not provide us with an error if
+ // it was not able to reach the server. So we can't completely map to the
+ // Windows UI.
+
+ // Keystone does not provide the version number when we are up to date so to
+ // maintain the UI, we just go fetch our version and call it good.
+ scoped_ptr<FileVersionInfo> version_info(
+ FileVersionInfo::CreateFileVersionInfoForCurrentModule());
+ std::wstring version(version_info->product_version());
+
+ // TODO: We really should check to see if what is on disk is newer then what
+ // is running and report it as such. (Windows has some messages that can
+ // help with this.) http://crbug.com/13165
+
+ imageID = IDR_UPDATE_UPTODATE;
+ message =
+ l10n_util::GetNSStringF(IDS_UPGRADE_ALREADY_UP_TO_DATE,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
+ WideToUTF16(version));
}
- [upToDate_ setStringValue:display];
+ [self stopProgressMessage:message imageID:imageID];
}
- (void)windowWillClose:(NSNotification*)notification {
@@ -90,32 +334,51 @@ NSString* const kUserClosedAboutNotification =
// Callback from KeystoneGlue; implementation of KeystoneGlueCallbacks protocol.
- (void)updateCompleted:(BOOL)successful installs:(int)installs {
- [spinner_ stopAnimation:self];
- // TODO(jrg): localize. No current string really says this.
- NSString* display = ((successful && installs) ?
- @"Update completed! Please restart Chrome." :
- @"Self update failed.");
- [updateCompleted_ setStringValue:display];
-
- // Allow a second chance.
- if (!(successful && installs))
+ uint32_t imageID;
+ NSString* message;
+ if (successful && installs) {
+ imageID = IDR_UPDATE_UPTODATE;
+ if ([newVersionAvailable_.get() length]) {
+ message =
+ l10n_util::GetNSStringF(IDS_UPGRADE_SUCCESSFUL,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
+ base::SysNSStringToUTF16(
+ newVersionAvailable_.get()));
+ } else {
+ message =
+ l10n_util::GetNSStringF(IDS_UPGRADE_SUCCESSFUL_NOVERSION,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ }
+
+ // Tell the user to restart their browser.
+ restart_browser::RequestRestart(nil);
+
+ } else {
+ imageID = IDR_UPDATE_FAIL;
+ message =
+ l10n_util::GetNSStringF(IDS_UPGRADE_ERROR,
+ IntToString16(kUpdateInstallFailed));
+
+ // Allow a second chance.
[updateNowButton_ setEnabled:YES];
+ }
+
+ [self stopProgressMessage:message imageID:imageID];
}
- (IBAction)updateNow:(id)sender {
updateTriggered_ = YES;
+
// Don't let someone click "Update Now" twice!
[updateNowButton_ setEnabled:NO];
- [spinner_ startAnimation:self];
if ([[self defaultKeystoneGlue] startUpdate:self]) {
// Clear any previous error message from the throbber area.
- [updateCompleted_ setStringValue:@""];
- [spinner_ startAnimation:self];
+ [self startProgressMessageID:IDS_UPGRADE_STARTED];
} else {
- // TODO(jrg): localize.
- // IDS_UPGRADE_ERROR doesn't work here; we don't have an error number, and
- // "server not available" is too specific.
- [updateCompleted_ setStringValue:@"Failed to start updates."];
+ NSString* message =
+ l10n_util::GetNSStringF(IDS_UPGRADE_ERROR,
+ IntToString16(kUpdateInstallFailedToStart));
+ [self stopProgressMessage:message imageID:IDR_UPDATE_FAIL];
}
}
@@ -123,12 +386,8 @@ NSString* const kUserClosedAboutNotification =
return updateNowButton_;
}
-- (NSTextField*)upToDateTextField {
- return upToDate_;
-}
-
-- (NSTextField*)updateCompletedTextField {
- return updateCompleted_;
+- (NSTextField*)updateText {
+ return updateText_;
}
@end
diff --git a/chrome/browser/cocoa/about_window_controller_unittest.mm b/chrome/browser/cocoa/about_window_controller_unittest.mm
index 1f1ad54..462824d 100644
--- a/chrome/browser/cocoa/about_window_controller_unittest.mm
+++ b/chrome/browser/cocoa/about_window_controller_unittest.mm
@@ -46,17 +46,16 @@ TEST_F(AboutWindowControllerTest, TestButton) {
// Doesn't confirm correctness, but does confirm something happens.
TEST_F(AboutWindowControllerTest, TestCallbacks) {
- NSString *upToDate = [[about_window_controller_ upToDateTextField]
+ NSString *lastText = [[about_window_controller_ updateText]
stringValue];
[about_window_controller_ upToDateCheckCompleted:NO latestVersion:@"foo"];
- ASSERT_FALSE([upToDate isEqual:[[about_window_controller_ upToDateTextField]
+ ASSERT_FALSE([lastText isEqual:[[about_window_controller_ updateText]
stringValue]]);
- NSString *completed = [[about_window_controller_ updateCompletedTextField]
- stringValue];
+ lastText = [[about_window_controller_ updateText] stringValue];
[about_window_controller_ updateCompleted:NO installs:0];
- ASSERT_FALSE([completed isEqual:[[about_window_controller_
- updateCompletedTextField] stringValue]]);
+ ASSERT_FALSE([lastText isEqual:[[about_window_controller_
+ updateText] stringValue]]);
}
} // namespace
diff --git a/chrome/browser/cocoa/background_tile_view.h b/chrome/browser/cocoa/background_tile_view.h
new file mode 100644
index 0000000..3f4454e
--- /dev/null
+++ b/chrome/browser/cocoa/background_tile_view.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_COCOA_BACKGROUND_TILE_VIEW_H_
+#define CHROME_BROWSER_COCOA_BACKGROUND_TILE_VIEW_H_
+
+#import <Cocoa/Cocoa.h>
+
+// A custom view that draws a image tiled as the background. This isn't meant
+// to be used where themes might be need, and is for other windows (about box).
+
+@interface BackgroundTileView : NSView {
+ @private
+ BOOL showsDivider_;
+ NSImage* tileImage_;
+}
+
+@property(retain) NSImage* tileImage;
+@end
+
+#endif // CHROME_BROWSER_COCOA_BACKGROUND_TILE_VIEW_H_
diff --git a/chrome/browser/cocoa/background_tile_view.mm b/chrome/browser/cocoa/background_tile_view.mm
new file mode 100644
index 0000000..cab5046
--- /dev/null
+++ b/chrome/browser/cocoa/background_tile_view.mm
@@ -0,0 +1,32 @@
+// Copyright (c) 2009 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.
+
+#include "chrome/browser/cocoa/background_tile_view.h"
+
+@implementation BackgroundTileView
+@synthesize tileImage = tileImage_;
+
+- (void)setTileImage:(NSImage*)tileImage {
+ [tileImage_ autorelease];
+ tileImage_ = [tileImage retain];
+ [self setNeedsDisplay:YES];
+}
+
+- (void)drawRect:(NSRect)rect {
+ // Tile within the view, so set the phase to start at the view bottom.
+ NSPoint phase = NSMakePoint(0.0, NSMinY([self frame]));
+ [[NSGraphicsContext currentContext] setPatternPhase:phase];
+
+ if (tileImage_) {
+ NSColor *color = [NSColor colorWithPatternImage:tileImage_];
+ [color set];
+ } else {
+ // Something to catch the missing image
+ [[NSColor magentaColor] set];
+ }
+
+ NSRectFill([self bounds]);
+}
+
+@end
diff --git a/chrome/browser/cocoa/background_tile_view_unittest.mm b/chrome/browser/cocoa/background_tile_view_unittest.mm
new file mode 100644
index 0000000..d225fca
--- /dev/null
+++ b/chrome/browser/cocoa/background_tile_view_unittest.mm
@@ -0,0 +1,44 @@
+// Copyright (c) 2009 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>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/cocoa/background_tile_view.h"
+#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class BackgroundTileViewTest : public testing::Test {
+ public:
+ BackgroundTileViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 30);
+ view_.reset([[BackgroundTileView alloc] initWithFrame:frame]);
+ [cocoa_helper_.contentView() addSubview:view_.get()];
+ }
+
+ CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc...
+ scoped_nsobject<BackgroundTileView> view_;
+};
+
+// Test adding/removing from the view hierarchy, mostly to ensure nothing
+// leaks or crashes.
+TEST_F(BackgroundTileViewTest, AddRemove) {
+ EXPECT_EQ(cocoa_helper_.contentView(), [view_ superview]);
+ [view_.get() removeFromSuperview];
+ EXPECT_FALSE([view_ superview]);
+}
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(BackgroundTileViewTest, Display) {
+ // Without image set.
+ [view_ display];
+ // And now with an image.
+ NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"];
+ [view_ setTileImage:image];
+ [view_ display];
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/restart_browser.h b/chrome/browser/cocoa/restart_browser.h
new file mode 100644
index 0000000..1d6ab41
--- /dev/null
+++ b/chrome/browser/cocoa/restart_browser.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_COCOA_RESTART_BROWSER_H_
+#define CHROME_BROWSER_COCOA_RESTART_BROWSER_H_
+
+#import <Cocoa/Cocoa.h>
+
+// This is a functional match for chrome/browser/views/restart_message_box
+// so any code that needs to ask for a browser restart has something like what
+// the Windows code has.
+namespace restart_browser {
+
+// Puts up an alert telling the user to restart their browser. The alert
+// will be hung off |parent| or global otherise.
+void RequestRestart(NSWindow* parent);
+
+} // namespace restart_browser
+
+#endif // CHROME_BROWSER_COCOA_RESTART_BROWSER_H_
diff --git a/chrome/browser/cocoa/restart_browser.mm b/chrome/browser/cocoa/restart_browser.mm
new file mode 100644
index 0000000..9a17f04
--- /dev/null
+++ b/chrome/browser/cocoa/restart_browser.mm
@@ -0,0 +1,67 @@
+// Copyright (c) 2009 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.
+
+#include "app/l10n_util_mac.h"
+#import "chrome/browser/cocoa/restart_browser.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/app_strings.h"
+
+// Helper to clean up after the notification that the alert was dismissed.
+@interface RestartHelper : NSObject {
+ @private
+ NSAlert* alert_;
+}
+- (NSAlert*)alert;
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo;
+@end
+
+@implementation RestartHelper
+
+- (NSAlert*)alert {
+ alert_ = [[NSAlert alloc] init];
+ return alert_;
+}
+
+- (void)dealloc {
+ [alert_ release];
+ [super dealloc];
+}
+
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ // Nothing to do, just clean up
+ [self autorelease];
+}
+
+@end
+
+namespace restart_browser {
+
+void RequestRestart(NSWindow* parent) {
+ NSString* title =
+ l10n_util::GetNSStringFWithFixup(IDS_PLEASE_RESTART_BROWSER,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ NSString* text =
+ l10n_util::GetNSStringWithFixup(IDS_OPTIONS_RESTART_REQUIRED);
+ NSString* okBtn = l10n_util::GetNSStringWithFixup(IDS_APP_OK);
+
+ RestartHelper* helper = [[RestartHelper alloc] init];
+
+ NSAlert* alert = [helper alert];
+ [alert setAlertStyle:NSCriticalAlertStyle];
+ [alert setMessageText:title];
+ [alert setInformativeText:text];
+ [alert addButtonWithTitle:okBtn];
+
+ [alert beginSheetModalForWindow:parent
+ modalDelegate:helper
+ didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+} // namespace restart_browser