summaryrefslogtreecommitdiffstats
path: root/base/mac_util.mm
diff options
context:
space:
mode:
authordimich@chromium.org <dimich@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-27 17:55:54 +0000
committerdimich@chromium.org <dimich@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-27 17:55:54 +0000
commit91484afdf575b8dd68ba92238338085f8758dbcd (patch)
tree6e1b831f09cf9a910211eb515c91ce320589aae6 /base/mac_util.mm
parentd852274be5cd2157e9519c9dc587e29a091032fa (diff)
downloadchromium_src-91484afdf575b8dd68ba92238338085f8758dbcd.zip
chromium_src-91484afdf575b8dd68ba92238338085f8758dbcd.tar.gz
chromium_src-91484afdf575b8dd68ba92238338085f8758dbcd.tar.bz2
Re-land. Fixed previous errors.
Implement OSX version for "Start on Login" for background-enabled extensions. When user installs first background-enabled extension we set Chrome to be a hidden "Login Item", and when user uninstalls the last one, we remove Chrome from the "Login Items List". Login Items are the apps that are listed in Systempreferences->Accounts->Login Items, or which have a "Open on Login" check for their Dock icon. Since we manipulate the user-faced UI item here, we try to do it in a way that will likely not interfere with user settings. Most typically, users do not use 'hidden' property, so if we ever encounter setting w/o this property, we won't override. Also there is a hidden preference used to remember the fact that Chrome changed the settings earlier - to avoid override on uninstall of the last persistent app in opposite case. Using the same bit that user can manipulate separately and perhaps even knows about is beneficial since it provides for unified place to "start Chrome on Login" and reduces confusion. Implementation for Login Items List access uses LSSharedFileList API that is available starting 10.5, which I think is our minimal supported version of OSX. BUG=43382 TEST=none Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=57569 Reverted Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=57614 Reverted Review URL: http://codereview.chromium.org/3163029 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57699 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/mac_util.mm')
-rw-r--r--base/mac_util.mm149
1 files changed, 149 insertions, 0 deletions
diff --git a/base/mac_util.mm b/base/mac_util.mm
index 8b0d481..fa25501 100644
--- a/base/mac_util.mm
+++ b/base/mac_util.mm
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/scoped_cftyperef.h"
+#include "base/scoped_nsobject.h"
#include "base/sys_string_conversions.h"
namespace {
@@ -49,6 +50,78 @@ void SetUIMode() {
SetSystemUIMode(desired_mode, desired_options);
}
+bool WasLaunchedAsLoginItem() {
+ ProcessSerialNumber psn = { 0, kCurrentProcess };
+
+ scoped_nsobject<NSDictionary> process_info(
+ reinterpret_cast<const NSDictionary*>(
+ ProcessInformationCopyDictionary(&psn,
+ kProcessDictionaryIncludeAllInformationMask)));
+
+ long long temp = [[process_info objectForKey:@"ParentPSN"] longLongValue];
+ ProcessSerialNumber parent_psn =
+ { (temp >> 32) & 0x00000000FFFFFFFFLL, temp & 0x00000000FFFFFFFFLL };
+
+ scoped_nsobject<NSDictionary> parent_info(
+ reinterpret_cast<const NSDictionary*>(
+ ProcessInformationCopyDictionary(&parent_psn,
+ kProcessDictionaryIncludeAllInformationMask)));
+
+ // Check that creator process code is that of loginwindow.
+ BOOL result =
+ [[parent_info objectForKey:@"FileCreator"] isEqualToString:@"lgnw"];
+
+ return result == YES;
+}
+
+// Looks into Shared File Lists corresponding to Login Items for the item
+// representing the current application. If such an item is found, returns
+// retained reference to it. Caller is responsible for releasing the reference.
+LSSharedFileListItemRef GetLoginItemForApp() {
+ scoped_cftyperef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+ NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+ if (!login_items.get()) {
+ LOG(ERROR) << "Couldn't get a Login Items list.";
+ return NULL;
+ }
+
+ scoped_nsobject<NSArray> login_items_array(reinterpret_cast<const NSArray*>(
+ LSSharedFileListCopySnapshot(login_items, NULL)));
+
+ NSURL* url = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
+
+ for(NSUInteger i = 0; i < [login_items_array count]; ++i) {
+ LSSharedFileListItemRef item = reinterpret_cast<LSSharedFileListItemRef>(
+ [login_items_array objectAtIndex:i]);
+ CFURLRef item_url_ref = NULL;
+
+ if (LSSharedFileListItemResolve(item, 0, &item_url_ref, NULL) == noErr) {
+ scoped_cftyperef<CFURLRef> item_url(item_url_ref);
+ if (CFEqual(item_url, url)) {
+ CFRetain(item);
+ return item;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+// kLSSharedFileListLoginItemHidden is supported on
+// 10.5, but missing from the 10.5 headers.
+// http://openradar.appspot.com/6482251
+static NSString* kLSSharedFileListLoginItemHidden =
+ @"com.apple.loginitem.HideOnLaunch";
+
+bool IsHiddenLoginItem(LSSharedFileListItemRef item) {
+ scoped_cftyperef<CFBooleanRef> hidden(reinterpret_cast<CFBooleanRef>(
+ LSSharedFileListItemCopyProperty(item,
+ reinterpret_cast<CFStringRef>(kLSSharedFileListLoginItemHidden))));
+
+ return hidden && hidden == kCFBooleanTrue;
+}
+
} // end namespace
namespace mac_util {
@@ -515,4 +588,80 @@ CGImageRef CopyNSImageToCGImage(NSImage* image) {
return CGBitmapContextCreateImage(context);
}
+bool CheckLoginItemStatus(bool* is_hidden) {
+ scoped_cftyperef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+ if (!item.get())
+ return false;
+
+ if (is_hidden)
+ *is_hidden = IsHiddenLoginItem(item);
+
+ return true;
+}
+
+void AddToLoginItems(bool hide_on_startup) {
+ scoped_cftyperef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+ if (item.get() && (IsHiddenLoginItem(item) == hide_on_startup)) {
+ return; // Already is a login item with required hide flag.
+ }
+
+ scoped_cftyperef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+ NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+ if (!login_items.get()) {
+ LOG(ERROR) << "Couldn't get a Login Items list.";
+ return;
+ }
+
+ // Remove the old item, it has wrong hide flag, we'll create a new one.
+ if (item.get()) {
+ LSSharedFileListItemRemove(login_items, item);
+ }
+
+ NSURL* url = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
+
+ BOOL hide = hide_on_startup ? YES : NO;
+ NSDictionary* properties =
+ [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:hide]
+ forKey:kLSSharedFileListLoginItemHidden];
+
+ scoped_cftyperef<LSSharedFileListItemRef> new_item;
+ new_item.reset(LSSharedFileListInsertItemURL(
+ login_items, kLSSharedFileListItemLast, NULL, NULL,
+ reinterpret_cast<CFURLRef>(url),
+ reinterpret_cast<CFDictionaryRef>(properties), NULL));
+
+ if (!new_item.get()) {
+ LOG(ERROR) << "Couldn't insert current app into Login Items list.";
+ }
+}
+
+void RemoveFromLoginItems() {
+ scoped_cftyperef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+ if (!item.get())
+ return;
+
+ scoped_cftyperef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+ NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+ if (!login_items.get()) {
+ LOG(ERROR) << "Couldn't get a Login Items list.";
+ return;
+ }
+
+ LSSharedFileListItemRemove(login_items, item);
+}
+
+bool WasLaunchedAsHiddenLoginItem() {
+ if (!WasLaunchedAsLoginItem())
+ return false;
+
+ scoped_cftyperef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+ if (!item.get()) {
+ LOG(ERROR) << "Process launched at Login but can't access Login Item List.";
+ return false;
+ }
+ return IsHiddenLoginItem(item);
+}
+
} // namespace mac_util