Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: chrome/browser/ui/app_list/app_list_service_mac.mm

Issue 23072036: Adds an integration test for uninstalling app list search results. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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"
6
5 #include <ApplicationServices/ApplicationServices.h> 7 #include <ApplicationServices/ApplicationServices.h>
6 #import <Cocoa/Cocoa.h> 8 #import <Cocoa/Cocoa.h>
7 9
8 #include "apps/app_launcher.h" 10 #include "apps/app_launcher.h"
9 #include "apps/app_shim/app_shim_handler_mac.h"
10 #include "apps/app_shim/app_shim_mac.h" 11 #include "apps/app_shim/app_shim_mac.h"
11 #include "apps/pref_names.h" 12 #include "apps/pref_names.h"
12 #include "base/bind.h" 13 #include "base/bind.h"
13 #include "base/command_line.h" 14 #include "base/command_line.h"
14 #include "base/file_util.h" 15 #include "base/file_util.h"
15 #include "base/lazy_instance.h" 16 #include "base/lazy_instance.h"
16 #include "base/mac/scoped_nsobject.h"
17 #include "base/memory/singleton.h" 17 #include "base/memory/singleton.h"
18 #include "base/message_loop/message_loop.h" 18 #include "base/message_loop/message_loop.h"
19 #include "chrome/browser/browser_process.h" 19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/extensions/extension_service.h" 20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_system.h" 21 #include "chrome/browser/extensions/extension_system.h"
22 #include "chrome/browser/profiles/profile_manager.h" 22 #include "chrome/browser/profiles/profile_manager.h"
23 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h" 23 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
24 #include "chrome/browser/ui/app_list/app_list_service.h" 24 #include "chrome/browser/ui/app_list/app_list_service.h"
25 #include "chrome/browser/ui/app_list/app_list_service_impl.h" 25 #include "chrome/browser/ui/app_list/app_list_service_impl.h"
26 #include "chrome/browser/ui/app_list/app_list_view_delegate.h" 26 #include "chrome/browser/ui/app_list/app_list_view_delegate.h"
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 70
71 // Version of the app list shortcut version installed. 71 // Version of the app list shortcut version installed.
72 const int kShortcutVersion = 1; 72 const int kShortcutVersion = 1;
73 73
74 // Duration of show and hide animations. 74 // Duration of show and hide animations.
75 const NSTimeInterval kAnimationDuration = 0.2; 75 const NSTimeInterval kAnimationDuration = 0.2;
76 76
77 // Distance towards the screen edge that the app list moves from when showing. 77 // Distance towards the screen edge that the app list moves from when showing.
78 const CGFloat kDistanceMovedOnShow = 20; 78 const CGFloat kDistanceMovedOnShow = 20;
79 79
80 // AppListServiceMac manages global resources needed for the app list to
81 // operate, and controls when the app list is opened and closed.
82 class AppListServiceMac : public AppListServiceImpl,
83 public apps::AppShimHandler {
84 public:
85 virtual ~AppListServiceMac();
86
87 static AppListServiceMac* GetInstance() {
88 return Singleton<AppListServiceMac,
89 LeakySingletonTraits<AppListServiceMac> >::get();
90 }
91
92 void ShowWindowNearDock();
93
94 // AppListService overrides:
95 virtual void Init(Profile* initial_profile) OVERRIDE;
96 virtual void CreateForProfile(Profile* requested_profile) OVERRIDE;
97 virtual void ShowForProfile(Profile* requested_profile) OVERRIDE;
98 virtual void DismissAppList() OVERRIDE;
99 virtual bool IsAppListVisible() const OVERRIDE;
100 virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
101 virtual AppListControllerDelegate* CreateControllerDelegate() OVERRIDE;
102
103 // AppListServiceImpl overrides:
104 virtual void CreateShortcut() OVERRIDE;
105
106 // AppShimHandler overrides:
107 virtual void OnShimLaunch(apps::AppShimHandler::Host* host,
108 apps::AppShimLaunchType launch_type) OVERRIDE;
109 virtual void OnShimClose(apps::AppShimHandler::Host* host) OVERRIDE;
110 virtual void OnShimFocus(apps::AppShimHandler::Host* host,
111 apps::AppShimFocusType focus_type) OVERRIDE;
112 virtual void OnShimSetHidden(apps::AppShimHandler::Host* host,
113 bool hidden) OVERRIDE;
114 virtual void OnShimQuit(apps::AppShimHandler::Host* host) OVERRIDE;
115
116 private:
117 friend struct DefaultSingletonTraits<AppListServiceMac>;
118
119 AppListServiceMac();
120
121 base::scoped_nsobject<AppListWindowController> window_controller_;
122 base::scoped_nsobject<AppListAnimationController> animation_controller_;
123 base::scoped_nsobject<NSRunningApplication> previously_active_application_;
124 NSPoint last_start_origin_;
125
126 DISALLOW_COPY_AND_ASSIGN(AppListServiceMac);
127 };
128
129 class AppListControllerDelegateCocoa : public AppListControllerDelegate { 80 class AppListControllerDelegateCocoa : public AppListControllerDelegate {
130 public: 81 public:
131 AppListControllerDelegateCocoa(); 82 AppListControllerDelegateCocoa();
132 virtual ~AppListControllerDelegateCocoa(); 83 virtual ~AppListControllerDelegateCocoa();
133 84
134 private: 85 private:
135 // AppListControllerDelegate overrides: 86 // AppListControllerDelegate overrides:
136 virtual void DismissView() OVERRIDE; 87 virtual void DismissView() OVERRIDE;
137 virtual gfx::NativeWindow GetAppListWindow() OVERRIDE; 88 virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
138 virtual bool CanPin() OVERRIDE; 89 virtual bool CanPin() OVERRIDE;
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 Profile* profile, const extensions::Extension* extension, int event_flags) { 261 Profile* profile, const extensions::Extension* extension, int event_flags) {
311 LaunchApp(profile, extension, event_flags); 262 LaunchApp(profile, extension, event_flags);
312 } 263 }
313 264
314 void AppListControllerDelegateCocoa::LaunchApp( 265 void AppListControllerDelegateCocoa::LaunchApp(
315 Profile* profile, const extensions::Extension* extension, int event_flags) { 266 Profile* profile, const extensions::Extension* extension, int event_flags) {
316 chrome::OpenApplication(chrome::AppLaunchParams( 267 chrome::OpenApplication(chrome::AppLaunchParams(
317 profile, extension, NEW_FOREGROUND_TAB)); 268 profile, extension, NEW_FOREGROUND_TAB));
318 } 269 }
319 270
271 enum DockLocation {
272 DockLocationOtherDisplay,
273 DockLocationBottom,
274 DockLocationLeft,
275 DockLocationRight,
276 };
277
278 DockLocation DockLocationInDisplay(const gfx::Display& display) {
279 // Assume the dock occupies part of the work area either on the left, right or
280 // bottom of the display. Note in the autohide case, it is always 4 pixels.
281 const gfx::Rect work_area = display.work_area();
282 const gfx::Rect display_bounds = display.bounds();
283 if (work_area.bottom() != display_bounds.bottom())
284 return DockLocationBottom;
285
286 if (work_area.x() != display_bounds.x())
287 return DockLocationLeft;
288
289 if (work_area.right() != display_bounds.right())
290 return DockLocationRight;
291
292 return DockLocationOtherDisplay;
293 }
294
295 // If |work_area_edge| is too close to the |screen_edge| (e.g. autohide dock),
296 // adjust |anchor| away from the edge by a constant amount to reduce overlap and
297 // ensure the dock icon can still be clicked to dismiss the app list.
298 int AdjustPointForDynamicDock(int anchor, int screen_edge, int work_area_edge) {
299 const int kAutohideDockThreshold = 10;
300 const int kExtraDistance = 50; // A dock with 40 items is about this size.
301 if (abs(work_area_edge - screen_edge) > kAutohideDockThreshold)
302 return anchor;
303
304 return anchor +
305 (screen_edge < work_area_edge ? kExtraDistance : -kExtraDistance);
306 }
307
308 void GetAppListWindowOrigins(
309 NSWindow* window, NSPoint* target_origin, NSPoint* start_origin) {
310 gfx::Screen* const screen = gfx::Screen::GetScreenFor([window contentView]);
311 // Ensure y coordinates are flipped back into AppKit's coordinate system.
312 const CGFloat max_y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]);
313 if (!CGCursorIsVisible()) {
314 // If Chrome is the active application, display on the same display as
315 // Chrome's keyWindow since this will catch activations triggered, e.g, via
316 // WebStore install. If another application is active, OSX doesn't provide a
317 // reliable way to get the display in use. Fall back to the primary display
318 // since it has the menu bar and is likely to be correct, e.g., for
319 // activations from Spotlight.
320 const gfx::NativeView key_view = [[NSApp keyWindow] contentView];
321 const gfx::Rect work_area = key_view && [NSApp isActive] ?
322 screen->GetDisplayNearestWindow(key_view).work_area() :
323 screen->GetPrimaryDisplay().work_area();
324 *target_origin = NSMakePoint(work_area.x(), max_y - work_area.bottom());
325 *start_origin = *target_origin;
326 return;
327 }
328
329 gfx::Point anchor = screen->GetCursorScreenPoint();
330 const gfx::Display display = screen->GetDisplayNearestPoint(anchor);
331 const DockLocation dock_location = DockLocationInDisplay(display);
332 const gfx::Rect display_bounds = display.bounds();
333
334 if (dock_location == DockLocationOtherDisplay) {
335 // Just display at the bottom-left of the display the cursor is on.
336 *target_origin = NSMakePoint(display_bounds.x(),
337 max_y - display_bounds.bottom());
338 *start_origin = *target_origin;
339 return;
340 }
341
342 // Anchor the center of the window in a region that prevents the window
343 // showing outside of the work area.
344 const NSSize window_size = [window frame].size;
345 const gfx::Rect work_area = display.work_area();
346 gfx::Rect anchor_area = work_area;
347 anchor_area.Inset(window_size.width / 2, window_size.height / 2);
348 anchor.SetToMax(anchor_area.origin());
349 anchor.SetToMin(anchor_area.bottom_right());
350
351 // Move anchor to the dock, keeping the other axis aligned with the cursor.
352 switch (dock_location) {
353 case DockLocationBottom:
354 anchor.set_y(AdjustPointForDynamicDock(
355 anchor_area.bottom(), display_bounds.bottom(), work_area.bottom()));
356 break;
357 case DockLocationLeft:
358 anchor.set_x(AdjustPointForDynamicDock(
359 anchor_area.x(), display_bounds.x(), work_area.x()));
360 break;
361 case DockLocationRight:
362 anchor.set_x(AdjustPointForDynamicDock(
363 anchor_area.right(), display_bounds.right(), work_area.right()));
364 break;
365 default:
366 NOTREACHED();
367 }
368
369 *target_origin = NSMakePoint(anchor.x() - window_size.width / 2,
370 max_y - anchor.y() - window_size.height / 2);
371 *start_origin = *target_origin;
372
373 switch (dock_location) {
374 case DockLocationBottom:
375 start_origin->y -= kDistanceMovedOnShow;
376 break;
377 case DockLocationLeft:
378 start_origin->x -= kDistanceMovedOnShow;
379 break;
380 case DockLocationRight:
381 start_origin->x += kDistanceMovedOnShow;
382 break;
383 default:
384 NOTREACHED();
385 }
386 }
387
388 } // namespace
389
320 AppListServiceMac::AppListServiceMac() { 390 AppListServiceMac::AppListServiceMac() {
321 animation_controller_.reset([[AppListAnimationController alloc] init]); 391 animation_controller_.reset([[AppListAnimationController alloc] init]);
322 } 392 }
323 393
324 AppListServiceMac::~AppListServiceMac() {} 394 AppListServiceMac::~AppListServiceMac() {}
325 395
396 // static
397 AppListServiceMac* AppListServiceMac::GetInstance() {
398 return Singleton<AppListServiceMac,
399 LeakySingletonTraits<AppListServiceMac> >::get();
400 }
401
326 void AppListServiceMac::Init(Profile* initial_profile) { 402 void AppListServiceMac::Init(Profile* initial_profile) {
327 // On Mac, Init() is called multiple times for a process: any time there is no 403 // On Mac, Init() is called multiple times for a process: any time there is no
328 // browser window open and a new window is opened, and during process startup 404 // browser window open and a new window is opened, and during process startup
329 // to handle the silent launch case (e.g. for app shims). In the startup case, 405 // to handle the silent launch case (e.g. for app shims). In the startup case,
330 // a profile has not yet been determined so |initial_profile| will be NULL. 406 // a profile has not yet been determined so |initial_profile| will be NULL.
331 static bool init_called_with_profile = false; 407 static bool init_called_with_profile = false;
332 if (initial_profile && !init_called_with_profile) { 408 if (initial_profile && !init_called_with_profile) {
333 init_called_with_profile = true; 409 init_called_with_profile = true;
334 HandleCommandLineFlags(initial_profile); 410 HandleCommandLineFlags(initial_profile);
335 PrefService* local_state = g_browser_process->local_state(); 411 PrefService* local_state = g_browser_process->local_state();
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 void AppListServiceMac::OnShimClose(apps::AppShimHandler::Host* host) {} 526 void AppListServiceMac::OnShimClose(apps::AppShimHandler::Host* host) {}
451 527
452 void AppListServiceMac::OnShimFocus(apps::AppShimHandler::Host* host, 528 void AppListServiceMac::OnShimFocus(apps::AppShimHandler::Host* host,
453 apps::AppShimFocusType focus_type) {} 529 apps::AppShimFocusType focus_type) {}
454 530
455 void AppListServiceMac::OnShimSetHidden(apps::AppShimHandler::Host* host, 531 void AppListServiceMac::OnShimSetHidden(apps::AppShimHandler::Host* host,
456 bool hidden) {} 532 bool hidden) {}
457 533
458 void AppListServiceMac::OnShimQuit(apps::AppShimHandler::Host* host) {} 534 void AppListServiceMac::OnShimQuit(apps::AppShimHandler::Host* host) {}
459 535
460 enum DockLocation {
461 DockLocationOtherDisplay,
462 DockLocationBottom,
463 DockLocationLeft,
464 DockLocationRight,
465 };
466
467 DockLocation DockLocationInDisplay(const gfx::Display& display) {
468 // Assume the dock occupies part of the work area either on the left, right or
469 // bottom of the display. Note in the autohide case, it is always 4 pixels.
470 const gfx::Rect work_area = display.work_area();
471 const gfx::Rect display_bounds = display.bounds();
472 if (work_area.bottom() != display_bounds.bottom())
473 return DockLocationBottom;
474
475 if (work_area.x() != display_bounds.x())
476 return DockLocationLeft;
477
478 if (work_area.right() != display_bounds.right())
479 return DockLocationRight;
480
481 return DockLocationOtherDisplay;
482 }
483
484 // If |work_area_edge| is too close to the |screen_edge| (e.g. autohide dock),
485 // adjust |anchor| away from the edge by a constant amount to reduce overlap and
486 // ensure the dock icon can still be clicked to dismiss the app list.
487 int AdjustPointForDynamicDock(int anchor, int screen_edge, int work_area_edge) {
488 const int kAutohideDockThreshold = 10;
489 const int kExtraDistance = 50; // A dock with 40 items is about this size.
490 if (abs(work_area_edge - screen_edge) > kAutohideDockThreshold)
491 return anchor;
492
493 return anchor +
494 (screen_edge < work_area_edge ? kExtraDistance : -kExtraDistance);
495 }
496
497 void GetAppListWindowOrigins(
498 NSWindow* window, NSPoint* target_origin, NSPoint* start_origin) {
499 gfx::Screen* const screen = gfx::Screen::GetScreenFor([window contentView]);
500 // Ensure y coordinates are flipped back into AppKit's coordinate system.
501 const CGFloat max_y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]);
502 if (!CGCursorIsVisible()) {
503 // If Chrome is the active application, display on the same display as
504 // Chrome's keyWindow since this will catch activations triggered, e.g, via
505 // WebStore install. If another application is active, OSX doesn't provide a
506 // reliable way to get the display in use. Fall back to the primary display
507 // since it has the menu bar and is likely to be correct, e.g., for
508 // activations from Spotlight.
509 const gfx::NativeView key_view = [[NSApp keyWindow] contentView];
510 const gfx::Rect work_area = key_view && [NSApp isActive] ?
511 screen->GetDisplayNearestWindow(key_view).work_area() :
512 screen->GetPrimaryDisplay().work_area();
513 *target_origin = NSMakePoint(work_area.x(), max_y - work_area.bottom());
514 *start_origin = *target_origin;
515 return;
516 }
517
518 gfx::Point anchor = screen->GetCursorScreenPoint();
519 const gfx::Display display = screen->GetDisplayNearestPoint(anchor);
520 const DockLocation dock_location = DockLocationInDisplay(display);
521 const gfx::Rect display_bounds = display.bounds();
522
523 if (dock_location == DockLocationOtherDisplay) {
524 // Just display at the bottom-left of the display the cursor is on.
525 *target_origin = NSMakePoint(display_bounds.x(),
526 max_y - display_bounds.bottom());
527 *start_origin = *target_origin;
528 return;
529 }
530
531 // Anchor the center of the window in a region that prevents the window
532 // showing outside of the work area.
533 const NSSize window_size = [window frame].size;
534 const gfx::Rect work_area = display.work_area();
535 gfx::Rect anchor_area = work_area;
536 anchor_area.Inset(window_size.width / 2, window_size.height / 2);
537 anchor.SetToMax(anchor_area.origin());
538 anchor.SetToMin(anchor_area.bottom_right());
539
540 // Move anchor to the dock, keeping the other axis aligned with the cursor.
541 switch (dock_location) {
542 case DockLocationBottom:
543 anchor.set_y(AdjustPointForDynamicDock(
544 anchor_area.bottom(), display_bounds.bottom(), work_area.bottom()));
545 break;
546 case DockLocationLeft:
547 anchor.set_x(AdjustPointForDynamicDock(
548 anchor_area.x(), display_bounds.x(), work_area.x()));
549 break;
550 case DockLocationRight:
551 anchor.set_x(AdjustPointForDynamicDock(
552 anchor_area.right(), display_bounds.right(), work_area.right()));
553 break;
554 default:
555 NOTREACHED();
556 }
557
558 *target_origin = NSMakePoint(anchor.x() - window_size.width / 2,
559 max_y - anchor.y() - window_size.height / 2);
560 *start_origin = *target_origin;
561
562 switch (dock_location) {
563 case DockLocationBottom:
564 start_origin->y -= kDistanceMovedOnShow;
565 break;
566 case DockLocationLeft:
567 start_origin->x -= kDistanceMovedOnShow;
568 break;
569 case DockLocationRight:
570 start_origin->x += kDistanceMovedOnShow;
571 break;
572 default:
573 NOTREACHED();
574 }
575 }
576
577 void AppListServiceMac::ShowWindowNearDock() { 536 void AppListServiceMac::ShowWindowNearDock() {
578 NSWindow* window = GetAppListWindow(); 537 NSWindow* window = GetAppListWindow();
579 DCHECK(window); 538 DCHECK(window);
580 NSPoint target_origin; 539 NSPoint target_origin;
581 GetAppListWindowOrigins(window, &target_origin, &last_start_origin_); 540 GetAppListWindowOrigins(window, &target_origin, &last_start_origin_);
582 [window setFrameOrigin:last_start_origin_]; 541 [window setFrameOrigin:last_start_origin_];
583 542
584 // Before activating, see if an application other than Chrome is currently the 543 // Before activating, see if an application other than Chrome is currently the
585 // active application, so that it can be reactivated when dismissing. 544 // active application, so that it can be reactivated when dismissing.
586 previously_active_application_.reset([ActiveApplicationNotChrome() retain]); 545 previously_active_application_.reset([ActiveApplicationNotChrome() retain]);
587 546
588 [animation_controller_ animateWindow:[window_controller_ window] 547 [animation_controller_ animateWindow:[window_controller_ window]
589 targetOrigin:target_origin 548 targetOrigin:target_origin
590 closing:NO]; 549 closing:NO];
591 [window makeKeyAndOrderFront:nil]; 550 [window makeKeyAndOrderFront:nil];
592 [NSApp activateIgnoringOtherApps:YES]; 551 [NSApp activateIgnoringOtherApps:YES];
593 } 552 }
594 553
595 } // namespace 554 // static
555 AppListService* AppListService::Get() {
556 return AppListServiceMac::GetInstance();
557 }
558
559 // static
560 void AppListService::InitAll(Profile* initial_profile) {
561 Get()->Init(initial_profile);
562 }
596 563
597 @implementation AppListAnimationController 564 @implementation AppListAnimationController
598 565
599 - (BOOL)isClosing { 566 - (BOOL)isClosing {
600 return !!window_; 567 return !!window_;
601 } 568 }
602 569
603 - (void)animateWindow:(NSWindow*)window 570 - (void)animateWindow:(NSWindow*)window
604 targetOrigin:(NSPoint)targetOrigin 571 targetOrigin:(NSPoint)targetOrigin
605 closing:(BOOL)closing { 572 closing:(BOOL)closing {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 [animation_ startAnimation]; 604 [animation_ startAnimation];
638 } 605 }
639 606
640 - (void)animationDidEnd:(NSAnimation*)animation { 607 - (void)animationDidEnd:(NSAnimation*)animation {
641 [window_ close]; 608 [window_ close];
642 window_.reset(); 609 window_.reset();
643 animation_.reset(); 610 animation_.reset();
644 } 611 }
645 612
646 @end 613 @end
647
648 // static
649 AppListService* AppListService::Get() {
650 return AppListServiceMac::GetInstance();
651 }
652
653 // static
654 void AppListService::InitAll(Profile* initial_profile) {
655 Get()->Init(initial_profile);
656 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/app_list/app_list_service_mac.h ('k') | chrome/browser/ui/app_list/app_list_service_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698