Commit ba12dcb8 authored by Nico Weber's avatar Nico Weber

mac: Demo of most "modern" (anno 2012) Obj-C features now that we use the 10.12 SDK.

NSNumber literals, expression literals, container literals: e.g. in
base/mac/foundation_util.mm (expression literal),
base/mac/foundation_util_unittests.mm (NSNumber literal, container literal).
This is a compiler feature and we have used it for years.
https://clang.llvm.org/docs/ObjectiveCLiterals.html

@implementation instance variables, in translate_bubble_controller.h
(note that ivars referred to in the _unittest.mm need to stay in the .h).
This requires the "modern runtime". We could use this once we we shipped
64-bit chrome (m39, late 2014).

NSDictionary and NSArray subscripting, e.g. in service_process_util_mac.mm.
Note that for scoped_nsobject<NSArray>, you need to do ptr.get()[index].
(We could probably return a proxy object from scoped_nsobject::operator[]
to make that unnecessary, but that feels like it might be too clever.)
Custom @interfaces can add their own support for subscripting.
This has worked since the 10.8 SDK.

Generics, e.g. in translate_bubble_controller.h: NSDictionary<NSNumber*, NSView*>
instead of just NSDictionary.  This works only since the 10.11 SDK, and the
bots had an older SDK until erikchen's 10.12 SDK work completed late last year.

https://developer.apple.com/videos/play/wwdc2012/405/, click "slides", auth
See also https://developer.apple.com/library/content/releasenotes/ObjectiveC/ObjCAvailabilityIndex/index.html

We don't use property auto-synthesis because it's very magical. We build
with -Wobjc-missing-property-synthesis to make sure the compiler informs
us if we forget to synthesize a property in some way.

We don't use arc.

Bug: 324079
Change-Id: I78659ed47829fe73c2b87cce43a83ec36deb87e8
Reviewed-on: https://chromium-review.googlesource.com/884011
Commit-Queue: Nico Weber <thakis@chromium.org>
Reviewed-by: default avatarElly Fong-Jones <ellyjones@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#531990}
parent f5f8cf9f
...@@ -88,7 +88,7 @@ bool IsBackgroundOnlyProcess() { ...@@ -88,7 +88,7 @@ bool IsBackgroundOnlyProcess() {
// bundle dictionary. It needs to look at the actual running .app's // bundle dictionary. It needs to look at the actual running .app's
// Info.plist to access its LSUIElement property. // Info.plist to access its LSUIElement property.
NSDictionary* info_dictionary = [base::mac::MainBundle() infoDictionary]; NSDictionary* info_dictionary = [base::mac::MainBundle() infoDictionary];
return [[info_dictionary objectForKey:@"LSUIElement"] boolValue] != NO; return [info_dictionary[@"LSUIElement"] boolValue] != NO;
} }
FilePath PathForFrameworkBundleResource(CFStringRef resourceName) { FilePath PathForFrameworkBundleResource(CFStringRef resourceName) {
...@@ -116,12 +116,12 @@ bool GetSearchPathDirectory(NSSearchPathDirectory directory, ...@@ -116,12 +116,12 @@ bool GetSearchPathDirectory(NSSearchPathDirectory directory,
NSSearchPathDomainMask domain_mask, NSSearchPathDomainMask domain_mask,
FilePath* result) { FilePath* result) {
DCHECK(result); DCHECK(result);
NSArray* dirs = NSArray<NSString*>* dirs =
NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES); NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES);
if ([dirs count] < 1) { if ([dirs count] < 1) {
return false; return false;
} }
*result = NSStringToFilePath([dirs objectAtIndex:0]); *result = NSStringToFilePath(dirs[0]);
return true; return true;
} }
...@@ -434,7 +434,7 @@ std::string GetValueFromDictionaryErrorMessage( ...@@ -434,7 +434,7 @@ std::string GetValueFromDictionaryErrorMessage(
NSString* FilePathToNSString(const FilePath& path) { NSString* FilePathToNSString(const FilePath& path) {
if (path.empty()) if (path.empty())
return nil; return nil;
return [NSString stringWithUTF8String:path.value().c_str()]; return @(path.value().c_str()); // @() does UTF8 conversion.
} }
FilePath NSStringToFilePath(NSString* str) { FilePath NSStringToFilePath(NSString* str) {
......
...@@ -164,16 +164,14 @@ TEST(FoundationUtilTest, CFCast) { ...@@ -164,16 +164,14 @@ TEST(FoundationUtilTest, CFCast) {
TEST(FoundationUtilTest, ObjCCast) { TEST(FoundationUtilTest, ObjCCast) {
ScopedNSAutoreleasePool pool; ScopedNSAutoreleasePool pool;
id test_array = [NSArray array]; id test_array = @[];
id test_array_mutable = [NSMutableArray array]; id test_array_mutable = [NSMutableArray array];
id test_data = [NSData data]; id test_data = [NSData data];
id test_data_mutable = [NSMutableData dataWithCapacity:10]; id test_data_mutable = [NSMutableData dataWithCapacity:10];
id test_date = [NSDate date]; id test_date = [NSDate date];
id test_dict = id test_dict = @{ @"meaning" : @42 };
[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:42]
forKey:@"meaning"];
id test_dict_mutable = [NSMutableDictionary dictionaryWithCapacity:10]; id test_dict_mutable = [NSMutableDictionary dictionaryWithCapacity:10];
id test_number = [NSNumber numberWithInt:42]; id test_number = @42;
id test_null = [NSNull null]; id test_null = [NSNull null];
id test_set = [NSSet setWithObject:@"string object"]; id test_set = [NSSet setWithObject:@"string object"];
id test_set_mutable = [NSMutableSet setWithCapacity:10]; id test_set_mutable = [NSMutableSet setWithCapacity:10];
......
...@@ -96,8 +96,8 @@ LSSharedFileListItemRef GetLoginItemForApp() { ...@@ -96,8 +96,8 @@ LSSharedFileListItemRef GetLoginItemForApp() {
NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]]; NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]];
for(NSUInteger i = 0; i < [login_items_array count]; ++i) { for(NSUInteger i = 0; i < [login_items_array count]; ++i) {
LSSharedFileListItemRef item = reinterpret_cast<LSSharedFileListItemRef>( LSSharedFileListItemRef item =
[login_items_array objectAtIndex:i]); reinterpret_cast<LSSharedFileListItemRef>(login_items_array[i]);
CFURLRef item_url_ref = NULL; CFURLRef item_url_ref = NULL;
// It seems that LSSharedFileListItemResolve() can return NULL in // It seems that LSSharedFileListItemResolve() can return NULL in
......
...@@ -97,13 +97,13 @@ NSMutableArray* PersistentAppPaths(NSArray* persistent_apps) { ...@@ -97,13 +97,13 @@ NSMutableArray* PersistentAppPaths(NSArray* persistent_apps) {
return nil; return nil;
} }
NSDictionary* tile_data = [app objectForKey:kDockTileDataKey]; NSDictionary* tile_data = app[kDockTileDataKey];
if (![tile_data isKindOfClass:[NSDictionary class]]) { if (![tile_data isKindOfClass:[NSDictionary class]]) {
LOG(ERROR) << "tile_data not NSDictionary"; LOG(ERROR) << "tile_data not NSDictionary";
return nil; return nil;
} }
NSDictionary* file_data = [tile_data objectForKey:kDockFileDataKey]; NSDictionary* file_data = tile_data[kDockFileDataKey];
if (![file_data isKindOfClass:[NSDictionary class]]) { if (![file_data isKindOfClass:[NSDictionary class]]) {
// Some apps (e.g. Dashboard) have no file data, but instead have a // Some apps (e.g. Dashboard) have no file data, but instead have a
// special value for the tile-type key. For these, add an empty string to // special value for the tile-type key. For these, add an empty string to
......
...@@ -277,7 +277,7 @@ const CGFloat kFrameColorDarkUpperBound = 0.33; ...@@ -277,7 +277,7 @@ const CGFloat kFrameColorDarkUpperBound = 0.33;
attributes:@{ attributes:@{
NSForegroundColorAttributeName : foregroundColor, NSForegroundColorAttributeName : foregroundColor,
NSParagraphStyleAttributeName : paragraphStyle, NSParagraphStyleAttributeName : paragraphStyle,
NSKernAttributeName : [NSNumber numberWithFloat:kTitleKern] NSKernAttributeName : @(kTitleKern),
}]); }]);
[button_ setAttributedTitle:attributedTitle]; [button_ setAttributedTitle:attributedTitle];
[button_ sizeToFit]; [button_ sizeToFit];
......
...@@ -16,9 +16,7 @@ ...@@ -16,9 +16,7 @@
@class BrowserWindowController; @class BrowserWindowController;
class LanguageComboboxModel;
class TranslateBubbleModel; class TranslateBubbleModel;
class TranslateDenialComboboxModel;
namespace content { namespace content {
class WebContents; class WebContents;
...@@ -30,49 +28,12 @@ class WebContents; ...@@ -30,49 +28,12 @@ class WebContents;
// revert this, and configure the translate setting. // revert this, and configure the translate setting.
@interface TranslateBubbleController @interface TranslateBubbleController
: OmniboxDecorationBubbleController<NSTextViewDelegate> { : OmniboxDecorationBubbleController<NSTextViewDelegate> {
@private
content::WebContents* webContents_;
std::unique_ptr<TranslateBubbleModel> model_;
// The views of each state. The keys are TranslateBubbleModel::ViewState, // The views of each state. The keys are TranslateBubbleModel::ViewState,
// and the values are NSView*. // and the values are NSView*.
base::scoped_nsobject<NSDictionary> views_; base::scoped_nsobject<NSDictionary<NSNumber*, NSView*>> views_;
// The 'Done' or 'Translate' button on the advanced (option) panel.
NSButton* advancedDoneButton_;
// The 'Cancel' button on the advanced (option) panel.
NSButton* advancedCancelButton_;
// The 'Always translate' checkbox on the before panel.
// This is nil when the current WebContents is in an incognito window.
NSButton* beforeAlwaysTranslateCheckbox_;
// The 'Always translate' checkbox on the advanced (option) panel.
// This is nil when the current WebContents is in an incognito window.
NSButton* advancedAlwaysTranslateCheckbox_;
// The 'Try again' button on the error panel. // The 'Try again' button on the error panel.
NSButton* tryAgainButton_; NSButton* tryAgainButton_;
// The '[x]' close button on the upper right side of the before panel.
NSButton* closeButton_;
// The combobox model which is used to deny translation at the view before
// translate.
std::unique_ptr<TranslateDenialComboboxModel> translateDenialComboboxModel_;
// The combobox model for source languages on the advanced (option) panel.
std::unique_ptr<LanguageComboboxModel> sourceLanguageComboboxModel_;
// The combobox model for target languages on the advanced (option) panel.
std::unique_ptr<LanguageComboboxModel> targetLanguageComboboxModel_;
// Whether the translation is actually executed once at least.
BOOL translateExecuted_;
// The state of the 'Always ...' checkboxes.
BOOL shouldAlwaysTranslate_;
} }
@property(readonly, nonatomic) const content::WebContents* webContents; @property(readonly, nonatomic) const content::WebContents* webContents;
......
...@@ -134,7 +134,44 @@ const CGFloat kContentWidth = kWindowWidth - 2 * kFramePadding; ...@@ -134,7 +134,44 @@ const CGFloat kContentWidth = kWindowWidth - 2 * kFramePadding;
atIndex:(NSUInteger)charIndex; atIndex:(NSUInteger)charIndex;
@end @end
@implementation TranslateBubbleController @implementation TranslateBubbleController {
@private
content::WebContents* webContents_;
std::unique_ptr<TranslateBubbleModel> model_;
// The 'Done' or 'Translate' button on the advanced (option) panel.
NSButton* advancedDoneButton_;
// The 'Cancel' button on the advanced (option) panel.
NSButton* advancedCancelButton_;
// The 'Always translate' checkbox on the before panel.
// This is nil when the current WebContents is in an incognito window.
NSButton* beforeAlwaysTranslateCheckbox_;
// The 'Always translate' checkbox on the advanced (option) panel.
// This is nil when the current WebContents is in an incognito window.
NSButton* advancedAlwaysTranslateCheckbox_;
// The '[x]' close button on the upper right side of the before panel.
NSButton* closeButton_;
// The combobox model which is used to deny translation at the view before
// translate.
std::unique_ptr<TranslateDenialComboboxModel> translateDenialComboboxModel_;
// The combobox model for source languages on the advanced (option) panel.
std::unique_ptr<LanguageComboboxModel> sourceLanguageComboboxModel_;
// The combobox model for target languages on the advanced (option) panel.
std::unique_ptr<LanguageComboboxModel> targetLanguageComboboxModel_;
// Whether the translation is actually executed once at least.
BOOL translateExecuted_;
// The state of the 'Always ...' checkboxes.
BOOL shouldAlwaysTranslate_;
}
@synthesize webContents = webContents_; @synthesize webContents = webContents_;
......
...@@ -124,7 +124,7 @@ bool GetServiceProcessData(std::string* version, base::ProcessId* pid) { ...@@ -124,7 +124,7 @@ bool GetServiceProcessData(std::string* version, base::ProcessId* pid) {
// to be a service process of some sort registered with launchd. // to be a service process of some sort registered with launchd.
if (version) { if (version) {
*version = "0"; *version = "0";
NSString* exe_path = [launchd_conf objectForKey:@ LAUNCH_JOBKEY_PROGRAM]; NSString* exe_path = launchd_conf.get()[@LAUNCH_JOBKEY_PROGRAM];
if (exe_path) { if (exe_path) {
NSString* bundle_path = [[[exe_path stringByDeletingLastPathComponent] NSString* bundle_path = [[[exe_path stringByDeletingLastPathComponent]
stringByDeletingLastPathComponent] stringByDeletingLastPathComponent]
...@@ -151,7 +151,7 @@ bool GetServiceProcessData(std::string* version, base::ProcessId* pid) { ...@@ -151,7 +151,7 @@ bool GetServiceProcessData(std::string* version, base::ProcessId* pid) {
} }
if (pid) { if (pid) {
*pid = -1; *pid = -1;
NSNumber* ns_pid = [launchd_conf objectForKey:@ LAUNCH_JOBKEY_PID]; NSNumber* ns_pid = launchd_conf.get()[@LAUNCH_JOBKEY_PID];
if (ns_pid) { if (ns_pid) {
*pid = [ns_pid intValue]; *pid = [ns_pid intValue];
} }
...@@ -242,13 +242,12 @@ CFDictionaryRef CreateServiceProcessLaunchdPlist(base::CommandLine* cmd_line, ...@@ -242,13 +242,12 @@ CFDictionaryRef CreateServiceProcessLaunchdPlist(base::CommandLine* cmd_line,
forKey:GetServiceProcessLaunchDSocketKey()]; forKey:GetServiceProcessLaunchDSocketKey()];
// See the man page for launchd.plist. // See the man page for launchd.plist.
NSMutableDictionary* launchd_plist = NSMutableDictionary* launchd_plist = [@{
[[NSMutableDictionary alloc] initWithObjectsAndKeys: @LAUNCH_JOBKEY_LABEL : GetServiceProcessLaunchDLabel(),
GetServiceProcessLaunchDLabel(), @LAUNCH_JOBKEY_LABEL, @LAUNCH_JOBKEY_PROGRAM : program,
program, @LAUNCH_JOBKEY_PROGRAM, @LAUNCH_JOBKEY_PROGRAMARGUMENTS : ns_args,
ns_args, @LAUNCH_JOBKEY_PROGRAMARGUMENTS, @LAUNCH_JOBKEY_SOCKETS : sockets,
sockets, @LAUNCH_JOBKEY_SOCKETS, } mutableCopy];
nil];
if (for_auto_launch) { if (for_auto_launch) {
// We want the service process to be able to exit if there are no services // We want the service process to be able to exit if there are no services
...@@ -256,15 +255,12 @@ CFDictionaryRef CreateServiceProcessLaunchdPlist(base::CommandLine* cmd_line, ...@@ -256,15 +255,12 @@ CFDictionaryRef CreateServiceProcessLaunchdPlist(base::CommandLine* cmd_line,
// relaunch the service automatically in any other case than exiting // relaunch the service automatically in any other case than exiting
// cleanly with a 0 return code. // cleanly with a 0 return code.
NSDictionary* keep_alive = NSDictionary* keep_alive =
[NSDictionary @{ @LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT : @NO };
dictionaryWithObject:[NSNumber numberWithBool:NO] NSDictionary* auto_launchd_plist = @{
forKey:@LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT]; @LAUNCH_JOBKEY_RUNATLOAD : @YES,
NSDictionary* auto_launchd_plist = @LAUNCH_JOBKEY_KEEPALIVE : keep_alive,
[[NSDictionary alloc] initWithObjectsAndKeys: @LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE : @kServiceProcessSessionType
[NSNumber numberWithBool:YES], @LAUNCH_JOBKEY_RUNATLOAD, };
keep_alive, @LAUNCH_JOBKEY_KEEPALIVE,
@kServiceProcessSessionType, @LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE,
nil];
[launchd_plist addEntriesFromDictionary:auto_launchd_plist]; [launchd_plist addEntriesFromDictionary:auto_launchd_plist];
} }
return reinterpret_cast<CFDictionaryRef>(launchd_plist); return reinterpret_cast<CFDictionaryRef>(launchd_plist);
...@@ -293,7 +289,7 @@ bool ServiceProcessState::RemoveFromAutoRun() { ...@@ -293,7 +289,7 @@ bool ServiceProcessState::RemoveFromAutoRun() {
bool ServiceProcessState::StateData::WatchExecutable() { bool ServiceProcessState::StateData::WatchExecutable() {
base::mac::ScopedNSAutoreleasePool pool; base::mac::ScopedNSAutoreleasePool pool;
NSDictionary* ns_launchd_conf = base::mac::CFToNSCast(launchd_conf); NSDictionary* ns_launchd_conf = base::mac::CFToNSCast(launchd_conf);
NSString* exe_path = [ns_launchd_conf objectForKey:@ LAUNCH_JOBKEY_PROGRAM]; NSString* exe_path = ns_launchd_conf[@LAUNCH_JOBKEY_PROGRAM];
if (!exe_path) { if (!exe_path) {
DLOG(ERROR) << "No " LAUNCH_JOBKEY_PROGRAM; DLOG(ERROR) << "No " LAUNCH_JOBKEY_PROGRAM;
return false; return false;
...@@ -409,11 +405,11 @@ void ExecFilePathWatcherCallback::NotifyPathChanged(const base::FilePath& path, ...@@ -409,11 +405,11 @@ void ExecFilePathWatcherCallback::NotifyPathChanged(const base::FilePath& path,
NSURL* new_path = [executable_fsref_ filePathURL]; NSURL* new_path = [executable_fsref_ filePathURL];
DCHECK([new_path isFileURL]); DCHECK([new_path isFileURL]);
NSString* ns_new_path = [new_path path]; NSString* ns_new_path = [new_path path];
[ns_plist setObject:ns_new_path forKey:@ LAUNCH_JOBKEY_PROGRAM]; ns_plist[@LAUNCH_JOBKEY_PROGRAM] = ns_new_path;
base::scoped_nsobject<NSMutableArray> args([[ns_plist base::scoped_nsobject<NSMutableArray> args(
objectForKey:@LAUNCH_JOBKEY_PROGRAMARGUMENTS] mutableCopy]); [ns_plist[@LAUNCH_JOBKEY_PROGRAMARGUMENTS] mutableCopy]);
[args replaceObjectAtIndex:0 withObject:ns_new_path]; args[0] = ns_new_path;
[ns_plist setObject:args forKey:@ LAUNCH_JOBKEY_PROGRAMARGUMENTS]; ns_plist[@LAUNCH_JOBKEY_PROGRAMARGUMENTS] = args;
if (!Launchd::GetInstance()->WritePlistToFile(Launchd::User, if (!Launchd::GetInstance()->WritePlistToFile(Launchd::User,
Launchd::Agent, Launchd::Agent,
name, name,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment