views_content_client_main_parts_mac.mm 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #import <Cocoa/Cocoa.h>
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/callback.h"
  8. #include "base/files/file_path.h"
  9. #include "base/mac/scoped_nsobject.h"
  10. #include "base/path_service.h"
  11. #include "content/public/browser/context_factory.h"
  12. #include "content/public/common/content_paths.h"
  13. #include "content/public/common/result_codes.h"
  14. #include "content/shell/browser/shell_application_mac.h"
  15. #include "content/shell/browser/shell_browser_context.h"
  16. #include "ui/views/test/test_views_delegate.h"
  17. #include "ui/views_content_client/views_content_client.h"
  18. #include "ui/views_content_client/views_content_client_main_parts.h"
  19. // A simple NSApplicationDelegate that provides a basic mainMenu and can
  20. // activate a task when the application has finished loading.
  21. @interface ViewsContentClientAppController : NSObject<NSApplicationDelegate> {
  22. @private
  23. base::OnceClosure _onApplicationDidFinishLaunching;
  24. }
  25. // Set the task to run after receiving -applicationDidFinishLaunching:.
  26. - (void)setOnApplicationDidFinishLaunching:(base::OnceClosure)task;
  27. @end
  28. namespace ui {
  29. namespace {
  30. class ViewsContentClientMainPartsMac : public ViewsContentClientMainParts {
  31. public:
  32. explicit ViewsContentClientMainPartsMac(
  33. ViewsContentClient* views_content_client);
  34. ViewsContentClientMainPartsMac(const ViewsContentClientMainPartsMac&) =
  35. delete;
  36. ViewsContentClientMainPartsMac& operator=(
  37. const ViewsContentClientMainPartsMac&) = delete;
  38. ~ViewsContentClientMainPartsMac() override;
  39. // content::BrowserMainParts:
  40. int PreMainMessageLoopRun() override;
  41. private:
  42. base::scoped_nsobject<ViewsContentClientAppController> app_controller_;
  43. };
  44. ViewsContentClientMainPartsMac::ViewsContentClientMainPartsMac(
  45. ViewsContentClient* views_content_client)
  46. : ViewsContentClientMainParts(views_content_client) {
  47. // Cache the child process path to avoid triggering an AssertIOAllowed.
  48. base::FilePath child_process_exe;
  49. base::PathService::Get(content::CHILD_PROCESS_EXE, &child_process_exe);
  50. app_controller_.reset([[ViewsContentClientAppController alloc] init]);
  51. [[NSApplication sharedApplication] setDelegate:app_controller_];
  52. }
  53. int ViewsContentClientMainPartsMac::PreMainMessageLoopRun() {
  54. ViewsContentClientMainParts::PreMainMessageLoopRun();
  55. views_delegate()->set_context_factory(content::GetContextFactory());
  56. // On Mac, the task must be deferred to applicationDidFinishLaunching. If not,
  57. // the widget can activate, but (even if configured) the mainMenu won't be
  58. // ready to switch over in the OSX UI, so it will look strange.
  59. NSWindow* window_context = nil;
  60. [app_controller_
  61. setOnApplicationDidFinishLaunching:
  62. base::BindOnce(&ViewsContentClient::OnPreMainMessageLoopRun,
  63. base::Unretained(views_content_client()),
  64. base::Unretained(browser_context()),
  65. base::Unretained(window_context))];
  66. return content::RESULT_CODE_NORMAL_EXIT;
  67. }
  68. ViewsContentClientMainPartsMac::~ViewsContentClientMainPartsMac() {
  69. [[NSApplication sharedApplication] setDelegate:nil];
  70. }
  71. } // namespace
  72. // static
  73. std::unique_ptr<ViewsContentClientMainParts>
  74. ViewsContentClientMainParts::Create(ViewsContentClient* views_content_client) {
  75. return std::make_unique<ViewsContentClientMainPartsMac>(views_content_client);
  76. }
  77. // static
  78. void ViewsContentClientMainParts::PreBrowserMain() {
  79. // Simply instantiating an instance of ShellCrApplication serves to register
  80. // it as the application class. Do make sure that no other code has done this
  81. // first, though.
  82. CHECK_EQ(NSApp, nil);
  83. [ShellCrApplication sharedApplication];
  84. }
  85. } // namespace ui
  86. @implementation ViewsContentClientAppController
  87. - (void)setOnApplicationDidFinishLaunching:(base::OnceClosure)task {
  88. _onApplicationDidFinishLaunching = std::move(task);
  89. }
  90. - (void)applicationDidFinishLaunching:(NSNotification*)aNotification {
  91. // To get key events, the application needs to have an activation policy.
  92. // Unbundled apps (i.e. those without an Info.plist) default to
  93. // NSApplicationActivationPolicyProhibited.
  94. [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
  95. // Create a basic mainMenu object using the executable filename.
  96. base::scoped_nsobject<NSMenu> mainMenu([[NSMenu alloc] initWithTitle:@""]);
  97. NSMenuItem* appMenuItem =
  98. [mainMenu addItemWithTitle:@"" action:NULL keyEquivalent:@""];
  99. [NSApp setMainMenu:mainMenu];
  100. base::scoped_nsobject<NSMenu> appMenu([[NSMenu alloc] initWithTitle:@""]);
  101. NSString* appName = [[NSProcessInfo processInfo] processName];
  102. // TODO(tapted): Localize "Quit" if this is ever used for a released binary.
  103. // At the time of writing, ui_strings.grd has "Close" but not "Quit".
  104. NSString* quitTitle = [@"Quit " stringByAppendingString:appName];
  105. [appMenu addItemWithTitle:quitTitle
  106. action:@selector(terminate:)
  107. keyEquivalent:@"q"];
  108. [appMenuItem setSubmenu:appMenu];
  109. CHECK([NSApp isKindOfClass:[ShellCrApplication class]]);
  110. std::move(_onApplicationDidFinishLaunching).Run();
  111. }
  112. @end