| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/ui/app_list/app_list_service_mac.h" | 5 #import "chrome/browser/ui/app_list/app_list_service_mac.h" |
| 6 | 6 |
| 7 #include <ApplicationServices/ApplicationServices.h> | 7 #include <ApplicationServices/ApplicationServices.h> |
| 8 #import <Cocoa/Cocoa.h> | 8 #import <Cocoa/Cocoa.h> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 #include "chrome/common/pref_names.h" | 36 #include "chrome/common/pref_names.h" |
| 37 #include "chrome/grit/google_chrome_strings.h" | 37 #include "chrome/grit/google_chrome_strings.h" |
| 38 #include "content/public/browser/browser_thread.h" | 38 #include "content/public/browser/browser_thread.h" |
| 39 #include "extensions/browser/extension_system.h" | 39 #include "extensions/browser/extension_system.h" |
| 40 #include "extensions/common/manifest_handlers/file_handler_info.h" | 40 #include "extensions/common/manifest_handlers/file_handler_info.h" |
| 41 #include "grit/chrome_unscaled_resources.h" | 41 #include "grit/chrome_unscaled_resources.h" |
| 42 #include "net/base/url_util.h" | 42 #include "net/base/url_util.h" |
| 43 #import "ui/app_list/cocoa/app_list_view_controller.h" | 43 #import "ui/app_list/cocoa/app_list_view_controller.h" |
| 44 #import "ui/app_list/cocoa/app_list_window_controller.h" | 44 #import "ui/app_list/cocoa/app_list_window_controller.h" |
| 45 #include "ui/app_list/search_box_model.h" | 45 #include "ui/app_list/search_box_model.h" |
| 46 #import "ui/base/cocoa/window_animator.h" |
| 46 #include "ui/base/l10n/l10n_util.h" | 47 #include "ui/base/l10n/l10n_util.h" |
| 47 #include "ui/base/resource/resource_bundle.h" | 48 #include "ui/base/resource/resource_bundle.h" |
| 48 #include "ui/gfx/display.h" | 49 #include "ui/gfx/display.h" |
| 49 #include "ui/gfx/screen.h" | 50 #include "ui/gfx/screen.h" |
| 50 | 51 |
| 51 namespace gfx { | 52 namespace gfx { |
| 52 class ImageSkia; | 53 class ImageSkia; |
| 53 } | 54 } |
| 54 | 55 |
| 55 // Controller for animations that show or hide the app list. | |
| 56 @interface AppListAnimationController : NSObject<NSAnimationDelegate> { | |
| 57 @private | |
| 58 // When closing, the window to close. Retained until the animation ends. | |
| 59 base::scoped_nsobject<NSWindow> window_; | |
| 60 // The animation started and owned by |self|. Reset when the animation ends. | |
| 61 base::scoped_nsobject<NSViewAnimation> animation_; | |
| 62 } | |
| 63 | |
| 64 // Returns whether |window_| is scheduled to be closed when the animation ends. | |
| 65 - (BOOL)isClosing; | |
| 66 | |
| 67 // Animate |window| to show or close it, after cancelling any current animation. | |
| 68 // Translates from the current location to |targetOrigin| and fades in or out. | |
| 69 - (void)animateWindow:(NSWindow*)window | |
| 70 targetOrigin:(NSPoint)targetOrigin | |
| 71 closing:(BOOL)closing; | |
| 72 | |
| 73 // Called on the UI thread once the animation has completed to reset the | |
| 74 // animation state, close the window (if it is a close animation), and possibly | |
| 75 // terminate Chrome. | |
| 76 - (void)cleanupOnUIThread; | |
| 77 | |
| 78 @end | |
| 79 | |
| 80 namespace { | 56 namespace { |
| 81 | 57 |
| 82 // Version of the app list shortcut version installed. | 58 // Version of the app list shortcut version installed. |
| 83 const int kShortcutVersion = 2; | 59 const int kShortcutVersion = 2; |
| 84 | 60 |
| 85 // Duration of show and hide animations. | |
| 86 const NSTimeInterval kAnimationDuration = 0.2; | |
| 87 | |
| 88 // Distance towards the screen edge that the app list moves from when showing. | 61 // Distance towards the screen edge that the app list moves from when showing. |
| 89 const CGFloat kDistanceMovedOnShow = 20; | 62 const CGFloat kDistanceMovedOnShow = 20; |
| 90 | 63 |
| 91 web_app::ShortcutInfo GetAppListShortcutInfo( | 64 web_app::ShortcutInfo GetAppListShortcutInfo( |
| 92 const base::FilePath& profile_path) { | 65 const base::FilePath& profile_path) { |
| 93 web_app::ShortcutInfo shortcut_info; | 66 web_app::ShortcutInfo shortcut_info; |
| 94 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); | 67 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); |
| 95 if (channel == chrome::VersionInfo::CHANNEL_CANARY) { | 68 if (channel == chrome::VersionInfo::CHANNEL_CANARY) { |
| 96 shortcut_info.title = | 69 shortcut_info.title = |
| 97 l10n_util::GetStringUTF16(IDS_APP_LIST_SHORTCUT_NAME_CANARY); | 70 l10n_util::GetStringUTF16(IDS_APP_LIST_SHORTCUT_NAME_CANARY); |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 cursor, | 231 cursor, |
| 259 target_origin, | 232 target_origin, |
| 260 start_origin); | 233 start_origin); |
| 261 } | 234 } |
| 262 | 235 |
| 263 } // namespace | 236 } // namespace |
| 264 | 237 |
| 265 AppListServiceMac::AppListServiceMac() | 238 AppListServiceMac::AppListServiceMac() |
| 266 : profile_(NULL), | 239 : profile_(NULL), |
| 267 controller_delegate_(new AppListControllerDelegateImpl(this)) { | 240 controller_delegate_(new AppListControllerDelegateImpl(this)) { |
| 268 animation_controller_.reset([[AppListAnimationController alloc] init]); | 241 animation_controller_.reset([[WindowAnimationController alloc] init]); |
| 269 } | 242 } |
| 270 | 243 |
| 271 AppListServiceMac::~AppListServiceMac() {} | 244 AppListServiceMac::~AppListServiceMac() {} |
| 272 | 245 |
| 273 // static | 246 // static |
| 274 AppListServiceMac* AppListServiceMac::GetInstance() { | 247 AppListServiceMac* AppListServiceMac::GetInstance() { |
| 275 return Singleton<AppListServiceMac, | 248 return Singleton<AppListServiceMac, |
| 276 LeakySingletonTraits<AppListServiceMac> >::get(); | 249 LeakySingletonTraits<AppListServiceMac> >::get(); |
| 277 } | 250 } |
| 278 | 251 |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 else | 386 else |
| 414 previously_active_application_.reset(); | 387 previously_active_application_.reset(); |
| 415 | 388 |
| 416 // If activation is successful, the app list will lose main status and try to | 389 // If activation is successful, the app list will lose main status and try to |
| 417 // close itself again. It can't be closed in this runloop iteration without | 390 // close itself again. It can't be closed in this runloop iteration without |
| 418 // OSX deciding to raise the next Chrome window, and _then_ activating the | 391 // OSX deciding to raise the next Chrome window, and _then_ activating the |
| 419 // application on top. This also occurs if no activation option is given. | 392 // application on top. This also occurs if no activation option is given. |
| 420 if ([prior_app activateWithOptions:NSApplicationActivateIgnoringOtherApps]) | 393 if ([prior_app activateWithOptions:NSApplicationActivateIgnoringOtherApps]) |
| 421 return; | 394 return; |
| 422 | 395 |
| 396 base::Closure callback(base::Bind(&apps::AppShimHandler::MaybeTerminate)); |
| 423 [animation_controller_ animateWindow:[window_controller_ window] | 397 [animation_controller_ animateWindow:[window_controller_ window] |
| 424 targetOrigin:last_start_origin_ | 398 targetOrigin:last_start_origin_ |
| 425 closing:YES]; | 399 closing:YES |
| 400 callback:callback]; |
| 426 } | 401 } |
| 427 | 402 |
| 428 void AppListServiceMac::ShowForCustomLauncherPage(Profile* profile) { | 403 void AppListServiceMac::ShowForCustomLauncherPage(Profile* profile) { |
| 429 NOTIMPLEMENTED(); | 404 NOTIMPLEMENTED(); |
| 430 } | 405 } |
| 431 | 406 |
| 432 bool AppListServiceMac::IsAppListVisible() const { | 407 bool AppListServiceMac::IsAppListVisible() const { |
| 433 return [[window_controller_ window] isVisible] && | 408 return [[window_controller_ window] isVisible] && |
| 434 ![animation_controller_ isClosing]; | 409 ![animation_controller_ isClosing]; |
| 435 } | 410 } |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 523 NSPoint target_origin; | 498 NSPoint target_origin; |
| 524 GetAppListWindowOrigins(window, &target_origin, &last_start_origin_); | 499 GetAppListWindowOrigins(window, &target_origin, &last_start_origin_); |
| 525 [window setFrameOrigin:last_start_origin_]; | 500 [window setFrameOrigin:last_start_origin_]; |
| 526 | 501 |
| 527 // Before activating, see if an application other than Chrome is currently the | 502 // Before activating, see if an application other than Chrome is currently the |
| 528 // active application, so that it can be reactivated when dismissing. | 503 // active application, so that it can be reactivated when dismissing. |
| 529 previously_active_application_.reset([ActiveApplicationNotChrome() retain]); | 504 previously_active_application_.reset([ActiveApplicationNotChrome() retain]); |
| 530 | 505 |
| 531 [animation_controller_ animateWindow:[window_controller_ window] | 506 [animation_controller_ animateWindow:[window_controller_ window] |
| 532 targetOrigin:target_origin | 507 targetOrigin:target_origin |
| 533 closing:NO]; | 508 closing:NO |
| 509 callback:base::Closure()]; |
| 534 [window makeKeyAndOrderFront:nil]; | 510 [window makeKeyAndOrderFront:nil]; |
| 535 [NSApp activateIgnoringOtherApps:YES]; | 511 [NSApp activateIgnoringOtherApps:YES]; |
| 536 RecordAppListLaunch(); | 512 RecordAppListLaunch(); |
| 537 } | 513 } |
| 538 | 514 |
| 539 void AppListServiceMac::WindowAnimationDidEnd() { | |
| 540 [animation_controller_ cleanupOnUIThread]; | |
| 541 } | |
| 542 | |
| 543 // static | 515 // static |
| 544 AppListService* AppListService::Get(chrome::HostDesktopType desktop_type) { | 516 AppListService* AppListService::Get(chrome::HostDesktopType desktop_type) { |
| 545 return AppListServiceMac::GetInstance(); | 517 return AppListServiceMac::GetInstance(); |
| 546 } | 518 } |
| 547 | 519 |
| 548 // static | 520 // static |
| 549 void AppListService::InitAll(Profile* initial_profile, | 521 void AppListService::InitAll(Profile* initial_profile, |
| 550 const base::FilePath& profile_path) { | 522 const base::FilePath& profile_path) { |
| 551 AppListServiceMac::GetInstance()->InitWithProfilePath(initial_profile, | 523 AppListServiceMac::GetInstance()->InitWithProfilePath(initial_profile, |
| 552 profile_path); | 524 profile_path); |
| 553 } | 525 } |
| 554 | |
| 555 @implementation AppListAnimationController | |
| 556 | |
| 557 - (BOOL)isClosing { | |
| 558 return !!window_; | |
| 559 } | |
| 560 | |
| 561 - (void)animateWindow:(NSWindow*)window | |
| 562 targetOrigin:(NSPoint)targetOrigin | |
| 563 closing:(BOOL)closing { | |
| 564 // First, stop the existing animation, if there is one. | |
| 565 [animation_ stopAnimation]; | |
| 566 | |
| 567 NSRect targetFrame = [window frame]; | |
| 568 targetFrame.origin = targetOrigin; | |
| 569 | |
| 570 // NSViewAnimation has a quirk when setting the curve to NSAnimationEaseOut | |
| 571 // where it attempts to auto-reverse the animation. FadeOut becomes FadeIn | |
| 572 // (good), but FrameKey is also switched (bad). So |targetFrame| needs to be | |
| 573 // put on the StartFrameKey when using NSAnimationEaseOut for showing. | |
| 574 NSArray* animationArray = @[ | |
| 575 @{ | |
| 576 NSViewAnimationTargetKey : window, | |
| 577 NSViewAnimationEffectKey : NSViewAnimationFadeOutEffect, | |
| 578 (closing ? NSViewAnimationEndFrameKey : NSViewAnimationStartFrameKey) : | |
| 579 [NSValue valueWithRect:targetFrame] | |
| 580 } | |
| 581 ]; | |
| 582 animation_.reset( | |
| 583 [[NSViewAnimation alloc] initWithViewAnimations:animationArray]); | |
| 584 [animation_ setDuration:kAnimationDuration]; | |
| 585 [animation_ setDelegate:self]; | |
| 586 | |
| 587 if (closing) { | |
| 588 [animation_ setAnimationCurve:NSAnimationEaseIn]; | |
| 589 window_.reset([window retain]); | |
| 590 } else { | |
| 591 [window setAlphaValue:0.0f]; | |
| 592 [animation_ setAnimationCurve:NSAnimationEaseOut]; | |
| 593 window_.reset(); | |
| 594 } | |
| 595 // This once used a threaded animation, but AppKit would too often ignore | |
| 596 // -[NSView canDrawConcurrently:] and just redraw whole view hierarchies on | |
| 597 // the animation thread anyway, creating a minefield of race conditions. | |
| 598 // Non-threaded means the animation isn't as smooth and doesn't begin unless | |
| 599 // the UI runloop has spun up (after profile loading). | |
| 600 [animation_ setAnimationBlockingMode:NSAnimationNonblocking]; | |
| 601 | |
| 602 [animation_ startAnimation]; | |
| 603 } | |
| 604 | |
| 605 - (void)cleanupOnUIThread { | |
| 606 bool closing = [self isClosing]; | |
| 607 [window_ close]; | |
| 608 window_.reset(); | |
| 609 animation_.reset(); | |
| 610 | |
| 611 if (closing) | |
| 612 apps::AppShimHandler::MaybeTerminate(); | |
| 613 } | |
| 614 | |
| 615 - (void)animationDidEnd:(NSAnimation*)animation { | |
| 616 content::BrowserThread::PostTask( | |
| 617 content::BrowserThread::UI, | |
| 618 FROM_HERE, | |
| 619 base::Bind(&AppListServiceMac::WindowAnimationDidEnd, | |
| 620 base::Unretained(AppListServiceMac::GetInstance()))); | |
| 621 } | |
| 622 | |
| 623 @end | |
| OLD | NEW |