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 |