| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/mac/dock.h" | 5 #import "chrome/browser/mac/dock.h" |
| 6 | 6 |
| 7 #include <ApplicationServices/ApplicationServices.h> | 7 #include <ApplicationServices/ApplicationServices.h> |
| 8 #import <Foundation/Foundation.h> | 8 #import <Foundation/Foundation.h> |
| 9 #include <CoreFoundation/CoreFoundation.h> | 9 #include <CoreFoundation/CoreFoundation.h> |
| 10 #include <signal.h> | 10 #include <signal.h> |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 } | 91 } |
| 92 | 92 |
| 93 NSDictionary* tile_data = [app objectForKey:kDockTileDataKey]; | 93 NSDictionary* tile_data = [app objectForKey:kDockTileDataKey]; |
| 94 if (![tile_data isKindOfClass:[NSDictionary class]]) { | 94 if (![tile_data isKindOfClass:[NSDictionary class]]) { |
| 95 LOG(ERROR) << "tile_data not NSDictionary"; | 95 LOG(ERROR) << "tile_data not NSDictionary"; |
| 96 return nil; | 96 return nil; |
| 97 } | 97 } |
| 98 | 98 |
| 99 NSDictionary* file_data = [tile_data objectForKey:kDockFileDataKey]; | 99 NSDictionary* file_data = [tile_data objectForKey:kDockFileDataKey]; |
| 100 if (![file_data isKindOfClass:[NSDictionary class]]) { | 100 if (![file_data isKindOfClass:[NSDictionary class]]) { |
| 101 LOG(ERROR) << "file_data not NSDictionary"; | 101 // Some apps (e.g. Dashboard) have no file data, but instead have a |
| 102 return nil; | 102 // special value for the tile-type key. For these, add an empty string to |
| 103 // align indexes with the source array. |
| 104 [app_paths addObject:@""]; |
| 105 continue; |
| 103 } | 106 } |
| 104 | 107 |
| 105 NSURL* url = NSURLCreateFromDictionary(file_data); | 108 NSURL* url = NSURLCreateFromDictionary(file_data); |
| 106 if (!url) { | 109 if (!url) { |
| 107 LOG(ERROR) << "no URL"; | 110 LOG(ERROR) << "no URL"; |
| 108 return nil; | 111 return nil; |
| 109 } | 112 } |
| 110 | 113 |
| 111 if (![url isFileURL]) { | 114 if (![url isFileURL]) { |
| 112 LOG(ERROR) << "non-file URL"; | 115 LOG(ERROR) << "non-file URL"; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 133 // Sending a SIGHUP to the Dock seems to be a more reliable way to get the | 136 // Sending a SIGHUP to the Dock seems to be a more reliable way to get the |
| 134 // replacement Dock process to read the newly written plist than using the | 137 // replacement Dock process to read the newly written plist than using the |
| 135 // equivalent of "launchctl stop" (even if followed by "launchctl start.") | 138 // equivalent of "launchctl stop" (even if followed by "launchctl start.") |
| 136 // Note that this is a potential race in that pid may no longer be valid or | 139 // Note that this is a potential race in that pid may no longer be valid or |
| 137 // may even have been reused. | 140 // may even have been reused. |
| 138 kill(pid, SIGHUP); | 141 kill(pid, SIGHUP); |
| 139 } | 142 } |
| 140 | 143 |
| 141 } // namespace | 144 } // namespace |
| 142 | 145 |
| 143 void AddIcon(NSString* installed_path, NSString* dmg_app_path) { | 146 AddIconStatus AddIcon(NSString* installed_path, NSString* dmg_app_path) { |
| 144 // ApplicationServices.framework/Frameworks/HIServices.framework contains an | 147 // ApplicationServices.framework/Frameworks/HIServices.framework contains an |
| 145 // undocumented function, CoreDockAddFileToDock, that is able to add items | 148 // undocumented function, CoreDockAddFileToDock, that is able to add items |
| 146 // to the Dock "live" without requiring a Dock restart. Under the hood, it | 149 // to the Dock "live" without requiring a Dock restart. Under the hood, it |
| 147 // communicates with the Dock via Mach IPC. It is available as of Mac OS X | 150 // communicates with the Dock via Mach IPC. It is available as of Mac OS X |
| 148 // 10.6. AddIcon could call CoreDockAddFileToDock if available, but | 151 // 10.6. AddIcon could call CoreDockAddFileToDock if available, but |
| 149 // CoreDockAddFileToDock seems to always to add the new Dock icon last, | 152 // CoreDockAddFileToDock seems to always to add the new Dock icon last, |
| 150 // where AddIcon takes care to position the icon appropriately. Based on | 153 // where AddIcon takes care to position the icon appropriately. Based on |
| 151 // disassembly, the signature of the undocumented function appears to be | 154 // disassembly, the signature of the undocumented function appears to be |
| 152 // extern "C" OSStatus CoreDockAddFileToDock(CFURLRef url, int); | 155 // extern "C" OSStatus CoreDockAddFileToDock(CFURLRef url, int); |
| 153 // The int argument doesn't appear to have any effect. It's not used as the | 156 // The int argument doesn't appear to have any effect. It's not used as the |
| 154 // position to place the icon as hoped. | 157 // position to place the icon as hoped. |
| 155 | 158 |
| 156 // There's enough potential allocation in this function to justify a | 159 // There's enough potential allocation in this function to justify a |
| 157 // distinct pool. | 160 // distinct pool. |
| 158 base::mac::ScopedNSAutoreleasePool autorelease_pool; | 161 base::mac::ScopedNSAutoreleasePool autorelease_pool; |
| 159 | 162 |
| 160 NSString* const kDockDomain = @"com.apple.dock"; | 163 NSString* const kDockDomain = @"com.apple.dock"; |
| 161 NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults]; | 164 NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults]; |
| 162 | 165 |
| 163 NSDictionary* dock_plist_const = | 166 NSDictionary* dock_plist_const = |
| 164 [user_defaults persistentDomainForName:kDockDomain]; | 167 [user_defaults persistentDomainForName:kDockDomain]; |
| 165 if (![dock_plist_const isKindOfClass:[NSDictionary class]]) { | 168 if (![dock_plist_const isKindOfClass:[NSDictionary class]]) { |
| 166 LOG(ERROR) << "dock_plist_const not NSDictionary"; | 169 LOG(ERROR) << "dock_plist_const not NSDictionary"; |
| 167 return; | 170 return IconAddFailure; |
| 168 } | 171 } |
| 169 NSMutableDictionary* dock_plist = | 172 NSMutableDictionary* dock_plist = |
| 170 [NSMutableDictionary dictionaryWithDictionary:dock_plist_const]; | 173 [NSMutableDictionary dictionaryWithDictionary:dock_plist_const]; |
| 171 | 174 |
| 172 NSString* const kDockPersistentAppsKey = @"persistent-apps"; | 175 NSString* const kDockPersistentAppsKey = @"persistent-apps"; |
| 173 NSArray* persistent_apps_const = | 176 NSArray* persistent_apps_const = |
| 174 [dock_plist objectForKey:kDockPersistentAppsKey]; | 177 [dock_plist objectForKey:kDockPersistentAppsKey]; |
| 175 if (![persistent_apps_const isKindOfClass:[NSArray class]]) { | 178 if (![persistent_apps_const isKindOfClass:[NSArray class]]) { |
| 176 LOG(ERROR) << "persistent_apps_const not NSArray"; | 179 LOG(ERROR) << "persistent_apps_const not NSArray"; |
| 177 return; | 180 return IconAddFailure; |
| 178 } | 181 } |
| 179 NSMutableArray* persistent_apps = | 182 NSMutableArray* persistent_apps = |
| 180 [NSMutableArray arrayWithArray:persistent_apps_const]; | 183 [NSMutableArray arrayWithArray:persistent_apps_const]; |
| 181 | 184 |
| 182 NSMutableArray* persistent_app_paths = PersistentAppPaths(persistent_apps); | 185 NSMutableArray* persistent_app_paths = PersistentAppPaths(persistent_apps); |
| 183 if (!persistent_app_paths) { | 186 if (!persistent_app_paths) { |
| 184 return; | 187 return IconAddFailure; |
| 185 } | 188 } |
| 186 | 189 |
| 187 NSUInteger already_installed_app_index = NSNotFound; | 190 NSUInteger already_installed_app_index = NSNotFound; |
| 188 NSUInteger app_index = NSNotFound; | 191 NSUInteger app_index = NSNotFound; |
| 189 for (NSUInteger index = 0; index < [persistent_apps count]; ++index) { | 192 for (NSUInteger index = 0; index < [persistent_apps count]; ++index) { |
| 190 NSString* app_path = [persistent_app_paths objectAtIndex:index]; | 193 NSString* app_path = [persistent_app_paths objectAtIndex:index]; |
| 191 if ([app_path isEqualToString:installed_path]) { | 194 if ([app_path isEqualToString:installed_path]) { |
| 192 // If the Dock already contains a reference to the newly installed | 195 // If the Dock already contains a reference to the newly installed |
| 193 // application, don't add another one. | 196 // application, don't add another one. |
| 194 already_installed_app_index = index; | 197 already_installed_app_index = index; |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 293 if (app_index == NSNotFound) { | 296 if (app_index == NSNotFound) { |
| 294 // Put the new application last in the Dock. | 297 // Put the new application last in the Dock. |
| 295 app_index = [persistent_apps count]; | 298 app_index = [persistent_apps count]; |
| 296 } | 299 } |
| 297 | 300 |
| 298 // Set up the new Dock tile. | 301 // Set up the new Dock tile. |
| 299 NSURL* url = [NSURL fileURLWithPath:installed_path isDirectory:YES]; | 302 NSURL* url = [NSURL fileURLWithPath:installed_path isDirectory:YES]; |
| 300 NSDictionary* url_dict = NSURLCopyDictionary(url); | 303 NSDictionary* url_dict = NSURLCopyDictionary(url); |
| 301 if (!url_dict) { | 304 if (!url_dict) { |
| 302 LOG(ERROR) << "couldn't create url_dict"; | 305 LOG(ERROR) << "couldn't create url_dict"; |
| 303 return; | 306 return IconAddFailure; |
| 304 } | 307 } |
| 305 | 308 |
| 306 NSDictionary* new_tile_data = | 309 NSDictionary* new_tile_data = |
| 307 [NSDictionary dictionaryWithObject:url_dict | 310 [NSDictionary dictionaryWithObject:url_dict |
| 308 forKey:kDockFileDataKey]; | 311 forKey:kDockFileDataKey]; |
| 309 NSDictionary* new_tile = | 312 NSDictionary* new_tile = |
| 310 [NSDictionary dictionaryWithObject:new_tile_data | 313 [NSDictionary dictionaryWithObject:new_tile_data |
| 311 forKey:kDockTileDataKey]; | 314 forKey:kDockTileDataKey]; |
| 312 | 315 |
| 313 // Add the new tile to the Dock. | 316 // Add the new tile to the Dock. |
| 314 [persistent_apps insertObject:new_tile atIndex:app_index]; | 317 [persistent_apps insertObject:new_tile atIndex:app_index]; |
| 315 [persistent_app_paths insertObject:installed_path atIndex:app_index]; | 318 [persistent_app_paths insertObject:installed_path atIndex:app_index]; |
| 316 made_change = true; | 319 made_change = true; |
| 317 } | 320 } |
| 318 | 321 |
| 319 // Verify that the arrays are still parallel. | 322 // Verify that the arrays are still parallel. |
| 320 DCHECK_EQ([persistent_apps count], [persistent_app_paths count]); | 323 DCHECK_EQ([persistent_apps count], [persistent_app_paths count]); |
| 321 | 324 |
| 322 if (!made_change) { | 325 if (!made_change) { |
| 323 // If no changes were made, there's no point in rewriting the Dock's | 326 // If no changes were made, there's no point in rewriting the Dock's |
| 324 // plist or restarting the Dock. | 327 // plist or restarting the Dock. |
| 325 return; | 328 return IconAlreadyPresent; |
| 326 } | 329 } |
| 327 | 330 |
| 328 // Rewrite the plist. | 331 // Rewrite the plist. |
| 329 [dock_plist setObject:persistent_apps forKey:kDockPersistentAppsKey]; | 332 [dock_plist setObject:persistent_apps forKey:kDockPersistentAppsKey]; |
| 330 [user_defaults setPersistentDomain:dock_plist forName:kDockDomain]; | 333 [user_defaults setPersistentDomain:dock_plist forName:kDockDomain]; |
| 331 | 334 |
| 332 Restart(); | 335 Restart(); |
| 336 return IconAddSuccess; |
| 333 } | 337 } |
| 334 | 338 |
| 335 } // namespace dock | 339 } // namespace dock |
| OLD | NEW |