1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/platform_util.h"
#import <Cocoa/Cocoa.h>
#include "base/apple/foundation_util.h"
#include "base/apple/osstatus_logging.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/strings/sys_string_conversions.h"
#include "chrome/browser/platform_util_internal.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "net/base/apple/url_conversions.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/mac/coordinate_conversion.h"
#include "ui/views/widget/widget.h"
#include "url/gurl.h"
namespace platform_util {
// Returns true if revealing file paths in the Finder should be skipped
// because it's not needed while running a test.
bool WorkspacePathRevealDisabledForTest() {
// Note: the kTestType switch is only added on browser tests, but not unit
// tests. Unit tests need to add the switch manually:
//
// base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
// command_line->AppendSwitch(switches::kTestType);
//
return base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType);
}
void ShowItemInFolder(Profile* profile, const base::FilePath& full_path) {
DCHECK([NSThread isMainThread]);
// The Finder creates a new window on each `full_path` reveal. Skip
// revealing the path during testing to avoid an avalanche of new
// Finder windows.
if (WorkspacePathRevealDisabledForTest() ||
!internal::AreShellOperationsAllowed()) {
return;
}
NSURL* url = base::apple::FilePathToNSURL(full_path);
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:@[ url ]];
}
void OpenFileOnMainThread(const base::FilePath& full_path) {
DCHECK([NSThread isMainThread]);
NSURL* url = base::apple::FilePathToNSURL(full_path);
if (!url)
return;
[[NSWorkspace sharedWorkspace]
openURL:url
configuration:[NSWorkspaceOpenConfiguration configuration]
completionHandler:nil];
}
namespace internal {
void PlatformOpenVerifiedItem(const base::FilePath& path, OpenItemType type) {
switch (type) {
case OPEN_FILE:
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&OpenFileOnMainThread, path));
return;
case OPEN_FOLDER:
NSURL* url = base::apple::FilePathToNSURL(path);
if (!url)
return;
// Note that there exists a TOCTOU race between the time that |path| was
// verified as being a directory and when NSWorkspace invokes Finder (or
// alternative) to open |path_string|.
[[NSWorkspace sharedWorkspace] openURL:url];
return;
}
}
} // namespace internal
void OpenExternal(const GURL& url) {
DCHECK([NSThread isMainThread]);
NSURL* ns_url = net::NSURLWithGURL(url);
if (!ns_url || ![[NSWorkspace sharedWorkspace] openURL:ns_url]) {
LOG(WARNING) << "NSWorkspace failed to open URL " << url;
}
}
gfx::NativeWindow GetTopLevel(gfx::NativeView view) {
return gfx::NativeWindow([view.GetNativeNSView() window]);
}
gfx::NativeView GetViewForWindow(gfx::NativeWindow native_window) {
NSWindow* window = native_window.GetNativeNSWindow();
DCHECK(window);
DCHECK([window contentView]);
return gfx::NativeView([window contentView]);
}
gfx::NativeView GetParent(gfx::NativeView view) {
return gfx::NativeView(nil);
}
bool IsWindowActive(gfx::NativeWindow native_window) {
// If |window| is a doppelganger NSWindow being used to track an NSWindow that
// is being hosted in another process, then use the views::Widget interface to
// interact with it.
views::Widget* widget =
views::Widget::GetWidgetForNativeWindow(native_window);
if (widget)
return widget->IsActive();
NSWindow* window = native_window.GetNativeNSWindow();
return [window isKeyWindow] || [window isMainWindow];
}
void ActivateWindow(gfx::NativeWindow native_window) {
views::Widget* widget =
views::Widget::GetWidgetForNativeWindow(native_window);
if (widget)
return widget->Activate();
NSWindow* window = native_window.GetNativeNSWindow();
[window makeKeyAndOrderFront:nil];
}
bool IsVisible(gfx::NativeView native_view) {
views::Widget* widget = views::Widget::GetWidgetForNativeView(native_view);
if (widget)
return widget->IsVisible();
// A reasonable approximation of how you'd expect this to behave.
NSView* view = native_view.GetNativeNSView();
return (view &&
![view isHiddenOrHasHiddenAncestor] &&
[view window] &&
[[view window] isVisible]);
}
bool IsSwipeTrackingFromScrollEventsEnabled() {
return NSEvent.swipeTrackingFromScrollEventsEnabled;
}
gfx::NativeWindow GetActiveWindow() {
return gfx::NativeWindow(NSApp.keyWindow);
}
gfx::Rect GetWindowScreenBounds(gfx::NativeWindow window) {
return gfx::ScreenRectFromNSRect([window.GetNativeNSWindow() frame]);
}
} // namespace platform_util
|