1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/platform_util.h"
7 #import <Cocoa/Cocoa.h>
9 #include "base/apple/foundation_util.h"
10 #include "base/apple/osstatus_logging.h"
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/functional/bind.h"
15 #include "base/logging.h"
16 #include "base/strings/sys_string_conversions.h"
17 #include "chrome/browser/platform_util_internal.h"
18 #include "content/public/browser/browser_task_traits.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/common/content_switches.h"
21 #include "net/base/mac/url_conversions.h"
22 #include "ui/views/widget/widget.h"
25 namespace platform_util {
27 // Returns true if revealing file paths in the Finder should be skipped
28 // because it's not needed while running a test.
29 bool WorkspacePathRevealDisabledForTest() {
30 // Note: the kTestType switch is only added on browser tests, but not unit
31 // tests. Unit tests need to add the switch manually:
33 // base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
34 // command_line->AppendSwitch(switches::kTestType);
36 return base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType);
39 void ShowItemInFolder(Profile* profile, const base::FilePath& full_path) {
40 DCHECK([NSThread isMainThread]);
41 NSURL* url = base::apple::FilePathToNSURL(full_path);
43 // The Finder creates a new window on each `full_path` reveal. Skip
44 // revealing the path during testing to avoid an avalanche of new
46 if (WorkspacePathRevealDisabledForTest()) {
50 [[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:@[ url ]];
53 void OpenFileOnMainThread(const base::FilePath& full_path) {
54 DCHECK([NSThread isMainThread]);
55 NSURL* url = base::apple::FilePathToNSURL(full_path);
59 [[NSWorkspace sharedWorkspace]
61 configuration:[NSWorkspaceOpenConfiguration configuration]
62 completionHandler:nil];
67 void PlatformOpenVerifiedItem(const base::FilePath& path, OpenItemType type) {
70 content::GetUIThreadTaskRunner({})->PostTask(
71 FROM_HERE, base::BindOnce(&OpenFileOnMainThread, path));
74 NSURL* url = base::apple::FilePathToNSURL(path);
78 // Note that there exists a TOCTOU race between the time that |path| was
79 // verified as being a directory and when NSWorkspace invokes Finder (or
80 // alternative) to open |path_string|.
81 [[NSWorkspace sharedWorkspace] openURL:url];
86 } // namespace internal
88 void OpenExternal(const GURL& url) {
89 DCHECK([NSThread isMainThread]);
90 NSURL* ns_url = net::NSURLWithGURL(url);
91 if (!ns_url || ![[NSWorkspace sharedWorkspace] openURL:ns_url])
92 LOG(WARNING) << "NSWorkspace failed to open URL " << url;
95 gfx::NativeWindow GetTopLevel(gfx::NativeView view) {
96 return gfx::NativeWindow([view.GetNativeNSView() window]);
99 gfx::NativeView GetViewForWindow(gfx::NativeWindow native_window) {
100 NSWindow* window = native_window.GetNativeNSWindow();
102 DCHECK([window contentView]);
103 return gfx::NativeView([window contentView]);
106 gfx::NativeView GetParent(gfx::NativeView view) {
107 return gfx::NativeView(nil);
110 bool IsWindowActive(gfx::NativeWindow native_window) {
111 // If |window| is a doppelganger NSWindow being used to track an NSWindow that
112 // is being hosted in another process, then use the views::Widget interface to
114 views::Widget* widget =
115 views::Widget::GetWidgetForNativeWindow(native_window);
117 return widget->IsActive();
119 NSWindow* window = native_window.GetNativeNSWindow();
120 return [window isKeyWindow] || [window isMainWindow];
123 void ActivateWindow(gfx::NativeWindow native_window) {
124 views::Widget* widget =
125 views::Widget::GetWidgetForNativeWindow(native_window);
127 return widget->Activate();
129 NSWindow* window = native_window.GetNativeNSWindow();
130 [window makeKeyAndOrderFront:nil];
133 bool IsVisible(gfx::NativeView native_view) {
134 views::Widget* widget = views::Widget::GetWidgetForNativeView(native_view);
136 return widget->IsVisible();
138 // A reasonable approximation of how you'd expect this to behave.
139 NSView* view = native_view.GetNativeNSView();
141 ![view isHiddenOrHasHiddenAncestor] &&
143 [[view window] isVisible]);
146 bool IsSwipeTrackingFromScrollEventsEnabled() {
147 return NSEvent.swipeTrackingFromScrollEventsEnabled;
150 NSWindow* GetActiveWindow() {
151 return [NSApp keyWindow];
154 } // namespace platform_util