2014-10-31 18:17:05 +00:00
|
|
|
// Copyright (c) 2013 GitHub, Inc.
|
2014-04-25 09:49:37 +00:00
|
|
|
// Use of this source code is governed by the MIT license that can be
|
2013-04-12 07:04:46 +00:00
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2014-03-16 00:30:26 +00:00
|
|
|
#include "atom/browser/native_window_mac.h"
|
2013-04-12 07:04:46 +00:00
|
|
|
|
2017-10-05 22:57:27 +00:00
|
|
|
#include <AvailabilityMacros.h>
|
2018-05-02 11:43:45 +00:00
|
|
|
#include <objc/objc-runtime.h>
|
2018-04-19 07:41:36 +00:00
|
|
|
|
2016-10-26 00:55:34 +00:00
|
|
|
#include <string>
|
2013-04-15 16:25:08 +00:00
|
|
|
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
#include "atom/browser/native_browser_view_mac.h"
|
2018-04-24 08:23:08 +00:00
|
|
|
#include "atom/browser/ui/cocoa/atom_native_widget_mac.h"
|
2018-04-19 07:53:12 +00:00
|
|
|
#include "atom/browser/ui/cocoa/atom_ns_window.h"
|
2018-04-19 07:01:19 +00:00
|
|
|
#include "atom/browser/ui/cocoa/atom_ns_window_delegate.h"
|
2018-04-19 07:41:36 +00:00
|
|
|
#include "atom/browser/ui/cocoa/atom_preview_item.h"
|
2017-02-28 20:29:23 +00:00
|
|
|
#include "atom/browser/ui/cocoa/atom_touch_bar.h"
|
2018-05-02 06:39:43 +00:00
|
|
|
#include "atom/browser/ui/cocoa/root_view_mac.h"
|
2016-05-25 23:25:51 +00:00
|
|
|
#include "atom/browser/window_list.h"
|
2014-03-16 00:30:26 +00:00
|
|
|
#include "atom/common/options_switches.h"
|
2014-05-15 07:19:02 +00:00
|
|
|
#include "base/mac/mac_util.h"
|
2016-04-03 02:59:21 +00:00
|
|
|
#include "base/mac/scoped_cftyperef.h"
|
2014-05-15 07:19:02 +00:00
|
|
|
#include "base/strings/sys_string_conversions.h"
|
2015-05-04 04:06:03 +00:00
|
|
|
#include "brightray/browser/inspectable_web_contents.h"
|
|
|
|
#include "brightray/browser/inspectable_web_contents_view.h"
|
2015-04-13 12:10:51 +00:00
|
|
|
#include "content/public/browser/browser_accessibility_state.h"
|
2014-06-23 13:51:42 +00:00
|
|
|
#include "native_mate/dictionary.h"
|
2016-04-02 12:17:38 +00:00
|
|
|
#include "skia/ext/skia_utils_mac.h"
|
2015-10-20 23:33:43 +00:00
|
|
|
#include "ui/gfx/skia_util.h"
|
2018-03-07 16:40:36 +00:00
|
|
|
#include "ui/gl/gpu_switching_manager.h"
|
2018-04-24 10:00:44 +00:00
|
|
|
#include "ui/views/background.h"
|
2018-04-24 11:08:14 +00:00
|
|
|
#include "ui/views/cocoa/bridged_native_widget.h"
|
2018-04-19 06:26:34 +00:00
|
|
|
#include "ui/views/widget/widget.h"
|
2013-04-12 07:04:46 +00:00
|
|
|
|
2018-07-10 04:09:46 +00:00
|
|
|
// This view always takes the size of its superview. It is intended to be used
|
|
|
|
// as a NSWindow's contentView. It is needed because NSWindow's implementation
|
|
|
|
// explicitly resizes the contentView at inopportune times.
|
|
|
|
@interface FullSizeContentView : NSView
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation FullSizeContentView
|
|
|
|
|
|
|
|
// This method is directly called by NSWindow during a window resize on OSX
|
|
|
|
// 10.10.0, beta 2. We must override it to prevent the content view from
|
|
|
|
// shrinking.
|
|
|
|
- (void)setFrameSize:(NSSize)size {
|
|
|
|
if ([self superview])
|
|
|
|
size = [[self superview] bounds].size;
|
|
|
|
[super setFrameSize:size];
|
|
|
|
}
|
|
|
|
|
|
|
|
// The contentView gets moved around during certain full-screen operations.
|
|
|
|
// This is less than ideal, and should eventually be removed.
|
|
|
|
- (void)viewDidMoveToSuperview {
|
|
|
|
[self setFrame:[[self superview] bounds]];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2017-06-06 22:18:22 +00:00
|
|
|
// Custom Quit, Minimize and Full Screen button container for frameless
|
|
|
|
// windows.
|
|
|
|
@interface CustomWindowButtonView : NSView {
|
2017-06-05 19:55:39 +00:00
|
|
|
@private
|
|
|
|
BOOL mouse_inside_;
|
|
|
|
}
|
2017-03-17 20:18:05 +00:00
|
|
|
@end
|
|
|
|
|
2017-06-06 22:18:22 +00:00
|
|
|
@implementation CustomWindowButtonView
|
2017-03-17 20:18:05 +00:00
|
|
|
|
|
|
|
- (id)initWithFrame:(NSRect)frame {
|
2017-06-05 18:08:05 +00:00
|
|
|
self = [super initWithFrame:frame];
|
|
|
|
|
2017-06-06 22:22:15 +00:00
|
|
|
NSButton* close_button = [NSWindow standardWindowButton:NSWindowCloseButton
|
|
|
|
forStyleMask:NSTitledWindowMask];
|
|
|
|
NSButton* miniaturize_button =
|
|
|
|
[NSWindow standardWindowButton:NSWindowMiniaturizeButton
|
|
|
|
forStyleMask:NSTitledWindowMask];
|
|
|
|
NSButton* zoom_button = [NSWindow standardWindowButton:NSWindowZoomButton
|
2017-06-06 22:19:53 +00:00
|
|
|
forStyleMask:NSTitledWindowMask];
|
2017-06-06 22:22:15 +00:00
|
|
|
|
|
|
|
CGFloat x = 0;
|
|
|
|
const CGFloat space_between = 20;
|
|
|
|
|
|
|
|
[close_button setFrameOrigin:NSMakePoint(x, 0)];
|
|
|
|
x += space_between;
|
|
|
|
[self addSubview:close_button];
|
|
|
|
|
|
|
|
[miniaturize_button setFrameOrigin:NSMakePoint(x, 0)];
|
|
|
|
x += space_between;
|
|
|
|
[self addSubview:miniaturize_button];
|
|
|
|
|
|
|
|
[zoom_button setFrameOrigin:NSMakePoint(x, 0)];
|
|
|
|
x += space_between;
|
|
|
|
[self addSubview:zoom_button];
|
|
|
|
|
|
|
|
const auto last_button_frame = zoom_button.frame;
|
|
|
|
[self setFrameSize:NSMakeSize(last_button_frame.origin.x +
|
|
|
|
last_button_frame.size.width,
|
|
|
|
last_button_frame.size.height)];
|
|
|
|
|
|
|
|
mouse_inside_ = NO;
|
2017-06-06 22:19:53 +00:00
|
|
|
[self setNeedsDisplayForButtons];
|
2017-06-05 18:08:05 +00:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2017-06-06 22:22:15 +00:00
|
|
|
- (void)viewDidMoveToWindow {
|
|
|
|
if (!self.window) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stay in upper left corner.
|
|
|
|
const CGFloat top_margin = 3;
|
|
|
|
const CGFloat left_margin = 7;
|
|
|
|
[self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
|
|
|
|
[self setFrameOrigin:NSMakePoint(left_margin, self.window.frame.size.height -
|
|
|
|
self.frame.size.height -
|
|
|
|
top_margin)];
|
|
|
|
}
|
|
|
|
|
2017-06-05 18:08:05 +00:00
|
|
|
- (BOOL)_mouseInGroup:(NSButton*)button {
|
2017-06-05 19:55:39 +00:00
|
|
|
return mouse_inside_;
|
2017-03-17 20:18:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)updateTrackingAreas {
|
2017-06-06 22:22:15 +00:00
|
|
|
auto tracking_area = [[[NSTrackingArea alloc]
|
|
|
|
initWithRect:NSZeroRect
|
|
|
|
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways |
|
|
|
|
NSTrackingInVisibleRect
|
|
|
|
owner:self
|
|
|
|
userInfo:nil] autorelease];
|
|
|
|
[self addTrackingArea:tracking_area];
|
2017-03-17 20:18:05 +00:00
|
|
|
}
|
|
|
|
|
2017-06-05 18:08:05 +00:00
|
|
|
- (void)mouseEntered:(NSEvent*)event {
|
|
|
|
[super mouseEntered:event];
|
2017-06-05 19:55:39 +00:00
|
|
|
mouse_inside_ = YES;
|
2017-06-05 18:08:05 +00:00
|
|
|
[self setNeedsDisplayForButtons];
|
2017-03-17 20:18:05 +00:00
|
|
|
}
|
|
|
|
|
2017-06-05 18:08:05 +00:00
|
|
|
- (void)mouseExited:(NSEvent*)event {
|
|
|
|
[super mouseExited:event];
|
2017-06-05 19:55:39 +00:00
|
|
|
mouse_inside_ = NO;
|
2017-06-05 18:08:05 +00:00
|
|
|
[self setNeedsDisplayForButtons];
|
2017-03-17 20:18:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setNeedsDisplayForButtons {
|
2017-06-05 18:08:05 +00:00
|
|
|
for (NSView* subview in self.subviews) {
|
2017-06-05 19:55:39 +00:00
|
|
|
[subview setHidden:!mouse_inside_];
|
2017-06-05 18:08:05 +00:00
|
|
|
[subview setNeedsDisplay:YES];
|
|
|
|
}
|
2017-03-17 20:18:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2017-10-05 22:57:27 +00:00
|
|
|
#if !defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER)
|
2017-03-31 17:20:02 +00:00
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
enum { NSWindowTabbingModeDisallowed = 2 };
|
2017-03-31 17:20:02 +00:00
|
|
|
|
2017-03-30 13:13:49 +00:00
|
|
|
@interface NSWindow (SierraSDK)
|
|
|
|
- (void)setTabbingMode:(NSInteger)mode;
|
2017-03-31 17:20:02 +00:00
|
|
|
- (void)setTabbingIdentifier:(NSString*)identifier;
|
2017-09-13 19:15:14 +00:00
|
|
|
- (void)addTabbedWindow:(NSWindow*)window ordered:(NSWindowOrderingMode)ordered;
|
2017-08-21 04:46:10 +00:00
|
|
|
- (IBAction)selectPreviousTab:(id)sender;
|
|
|
|
- (IBAction)selectNextTab:(id)sender;
|
|
|
|
- (IBAction)mergeAllWindows:(id)sender;
|
|
|
|
- (IBAction)moveTabToNewWindow:(id)sender;
|
|
|
|
- (IBAction)toggleTabBar:(id)sender;
|
2017-03-30 13:13:49 +00:00
|
|
|
@end
|
|
|
|
|
2017-10-05 22:57:27 +00:00
|
|
|
#endif
|
2017-03-31 17:20:02 +00:00
|
|
|
|
2014-09-17 07:58:08 +00:00
|
|
|
@interface AtomProgressBar : NSProgressIndicator
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation AtomProgressBar
|
|
|
|
|
|
|
|
- (void)drawRect:(NSRect)dirtyRect {
|
|
|
|
if (self.style != NSProgressIndicatorBarStyle)
|
|
|
|
return;
|
|
|
|
// Draw edges of rounded rect.
|
|
|
|
NSRect rect = NSInsetRect([self bounds], 1.0, 1.0);
|
2014-09-18 08:17:49 +00:00
|
|
|
CGFloat radius = rect.size.height / 2;
|
2018-04-20 18:47:04 +00:00
|
|
|
NSBezierPath* bezier_path = [NSBezierPath bezierPathWithRoundedRect:rect
|
|
|
|
xRadius:radius
|
|
|
|
yRadius:radius];
|
2014-09-18 08:17:49 +00:00
|
|
|
[bezier_path setLineWidth:2.0];
|
|
|
|
[[NSColor grayColor] set];
|
|
|
|
[bezier_path stroke];
|
2014-09-17 07:58:08 +00:00
|
|
|
|
|
|
|
// Fill the rounded rect.
|
2014-09-18 08:17:49 +00:00
|
|
|
rect = NSInsetRect(rect, 2.0, 2.0);
|
|
|
|
radius = rect.size.height / 2;
|
2018-04-20 18:47:04 +00:00
|
|
|
bezier_path = [NSBezierPath bezierPathWithRoundedRect:rect
|
|
|
|
xRadius:radius
|
|
|
|
yRadius:radius];
|
2014-09-18 08:17:49 +00:00
|
|
|
[bezier_path setLineWidth:1.0];
|
|
|
|
[bezier_path addClip];
|
2014-09-17 07:58:08 +00:00
|
|
|
|
|
|
|
// Calculate the progress width.
|
2018-04-20 18:47:04 +00:00
|
|
|
rect.size.width =
|
|
|
|
floor(rect.size.width * ([self doubleValue] / [self maxValue]));
|
2014-09-17 07:58:08 +00:00
|
|
|
|
|
|
|
// Fill the progress bar with color blue.
|
|
|
|
[[NSColor colorWithSRGBRed:0.2 green:0.6 blue:1 alpha:1] set];
|
|
|
|
NSRectFill(rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2016-06-17 01:54:50 +00:00
|
|
|
namespace mate {
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
template <>
|
2016-06-17 01:54:50 +00:00
|
|
|
struct Converter<atom::NativeWindowMac::TitleBarStyle> {
|
2018-04-20 18:47:04 +00:00
|
|
|
static bool FromV8(v8::Isolate* isolate,
|
|
|
|
v8::Handle<v8::Value> val,
|
2016-06-17 01:54:50 +00:00
|
|
|
atom::NativeWindowMac::TitleBarStyle* out) {
|
|
|
|
std::string title_bar_style;
|
|
|
|
if (!ConvertFromV8(isolate, val, &title_bar_style))
|
|
|
|
return false;
|
|
|
|
if (title_bar_style == "hidden") {
|
|
|
|
*out = atom::NativeWindowMac::HIDDEN;
|
2018-02-20 17:09:54 +00:00
|
|
|
} else if (title_bar_style == "hiddenInset") {
|
2016-09-02 22:45:20 +00:00
|
|
|
*out = atom::NativeWindowMac::HIDDEN_INSET;
|
2017-06-05 20:30:08 +00:00
|
|
|
} else if (title_bar_style == "customButtonsOnHover") {
|
|
|
|
*out = atom::NativeWindowMac::CUSTOM_BUTTONS_ON_HOVER;
|
2016-06-17 01:54:50 +00:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace mate
|
|
|
|
|
2013-04-12 07:04:46 +00:00
|
|
|
namespace atom {
|
|
|
|
|
2018-05-02 11:43:45 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
bool IsFramelessWindow(NSView* view) {
|
|
|
|
NativeWindow* window = [static_cast<AtomNSWindow*>([view window]) shell];
|
|
|
|
return window && !window->has_frame();
|
|
|
|
}
|
|
|
|
|
|
|
|
IMP original_set_frame_size = nullptr;
|
|
|
|
IMP original_view_did_move_to_superview = nullptr;
|
|
|
|
|
|
|
|
// This method is directly called by NSWindow during a window resize on OSX
|
|
|
|
// 10.10.0, beta 2. We must override it to prevent the content view from
|
|
|
|
// shrinking.
|
|
|
|
void SetFrameSize(NSView* self, SEL _cmd, NSSize size) {
|
|
|
|
if (!IsFramelessWindow(self)) {
|
|
|
|
auto original =
|
|
|
|
reinterpret_cast<decltype(&SetFrameSize)>(original_set_frame_size);
|
|
|
|
return original(self, _cmd, size);
|
|
|
|
}
|
|
|
|
// For frameless window, resize the view to cover full window.
|
|
|
|
if ([self superview])
|
|
|
|
size = [[self superview] bounds].size;
|
|
|
|
auto super_impl = reinterpret_cast<decltype(&SetFrameSize)>(
|
|
|
|
[[self superclass] instanceMethodForSelector:_cmd]);
|
|
|
|
super_impl(self, _cmd, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The contentView gets moved around during certain full-screen operations.
|
|
|
|
// This is less than ideal, and should eventually be removed.
|
|
|
|
void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
|
|
|
|
if (!IsFramelessWindow(self)) {
|
|
|
|
// [BridgedContentView viewDidMoveToSuperview];
|
|
|
|
auto original = reinterpret_cast<decltype(&ViewDidMoveToSuperview)>(
|
|
|
|
original_view_did_move_to_superview);
|
2018-05-02 12:36:51 +00:00
|
|
|
if (original)
|
|
|
|
original(self, _cmd);
|
|
|
|
return;
|
2018-05-02 11:43:45 +00:00
|
|
|
}
|
|
|
|
[self setFrame:[[self superview] bounds]];
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2018-04-08 11:20:43 +00:00
|
|
|
NativeWindowMac::NativeWindowMac(const mate::Dictionary& options,
|
|
|
|
NativeWindow* parent)
|
2018-05-21 22:18:38 +00:00
|
|
|
: NativeWindow(options, parent), root_view_(new RootViewMac(this)) {
|
2014-01-06 10:58:30 +00:00
|
|
|
int width = 800, height = 600;
|
2015-11-13 05:58:31 +00:00
|
|
|
options.Get(options::kWidth, &width);
|
|
|
|
options.Get(options::kHeight, &height);
|
2013-04-12 07:04:46 +00:00
|
|
|
|
2016-12-20 21:49:35 +00:00
|
|
|
NSRect main_screen_rect = [[[NSScreen screens] firstObject] frame];
|
2018-04-24 08:23:08 +00:00
|
|
|
gfx::Rect bounds(round((NSWidth(main_screen_rect) - width) / 2),
|
2018-05-01 04:58:42 +00:00
|
|
|
round((NSHeight(main_screen_rect) - height) / 2), width,
|
2018-04-24 08:23:08 +00:00
|
|
|
height);
|
2013-09-11 10:10:28 +00:00
|
|
|
|
2018-04-24 10:00:44 +00:00
|
|
|
options.Get(options::kResizable, &resizable_);
|
|
|
|
options.Get(options::kTitleBarStyle, &title_bar_style_);
|
|
|
|
options.Get(options::kZoomToPageWidth, &zoom_to_page_width_);
|
|
|
|
options.Get(options::kFullscreenWindowTitle, &fullscreen_window_title_);
|
|
|
|
options.Get(options::kSimpleFullScreen, &always_simple_fullscreen_);
|
2015-05-06 14:08:24 +00:00
|
|
|
|
2016-01-18 22:46:35 +00:00
|
|
|
bool minimizable = true;
|
|
|
|
options.Get(options::kMinimizable, &minimizable);
|
2016-01-23 07:51:52 +00:00
|
|
|
|
2016-01-22 21:24:33 +00:00
|
|
|
bool maximizable = true;
|
|
|
|
options.Get(options::kMaximizable, &maximizable);
|
|
|
|
|
2016-01-18 22:46:35 +00:00
|
|
|
bool closable = true;
|
|
|
|
options.Get(options::kClosable, &closable);
|
|
|
|
|
2017-03-30 20:47:11 +00:00
|
|
|
std::string tabbingIdentifier;
|
|
|
|
options.Get(options::kTabbingIdentifier, &tabbingIdentifier);
|
2017-03-27 14:15:17 +00:00
|
|
|
|
2015-11-19 08:39:45 +00:00
|
|
|
std::string windowType;
|
|
|
|
options.Get(options::kType, &windowType);
|
|
|
|
|
|
|
|
bool useStandardWindow = true;
|
|
|
|
// eventually deprecate separate "standardWindow" option in favor of
|
|
|
|
// standard / textured window types
|
|
|
|
options.Get(options::kStandardWindow, &useStandardWindow);
|
|
|
|
if (windowType == "textured") {
|
|
|
|
useStandardWindow = false;
|
|
|
|
}
|
|
|
|
|
2017-06-05 19:50:18 +00:00
|
|
|
NSUInteger styleMask = NSTitledWindowMask;
|
2018-06-20 09:34:04 +00:00
|
|
|
if (@available(macOS 10.10, *)) {
|
|
|
|
if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER &&
|
|
|
|
(!useStandardWindow || transparent() || !has_frame())) {
|
|
|
|
styleMask = NSFullSizeContentViewWindowMask;
|
|
|
|
}
|
2017-06-05 19:50:18 +00:00
|
|
|
}
|
2016-01-18 22:46:35 +00:00
|
|
|
if (minimizable) {
|
|
|
|
styleMask |= NSMiniaturizableWindowMask;
|
|
|
|
}
|
2016-01-23 10:23:18 +00:00
|
|
|
if (closable) {
|
|
|
|
styleMask |= NSClosableWindowMask;
|
2016-01-18 22:46:35 +00:00
|
|
|
}
|
2016-06-17 01:54:50 +00:00
|
|
|
if (title_bar_style_ != NORMAL) {
|
2016-05-17 06:48:14 +00:00
|
|
|
// The window without titlebar is treated the same with frameless window.
|
|
|
|
set_has_frame(false);
|
|
|
|
}
|
2015-08-05 04:46:32 +00:00
|
|
|
if (!useStandardWindow || transparent() || !has_frame()) {
|
2015-05-06 14:08:24 +00:00
|
|
|
styleMask |= NSTexturedBackgroundWindowMask;
|
|
|
|
}
|
2015-12-21 18:55:23 +00:00
|
|
|
|
2018-04-24 08:23:08 +00:00
|
|
|
// Create views::Widget and assign window_ with it.
|
|
|
|
// TODO(zcbenz): Get rid of the window_ in future.
|
|
|
|
views::Widget::InitParams params;
|
|
|
|
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
|
|
|
params.bounds = bounds;
|
|
|
|
params.delegate = this;
|
|
|
|
params.type = views::Widget::InitParams::TYPE_WINDOW;
|
2018-05-02 12:28:28 +00:00
|
|
|
params.native_widget = new AtomNativeWidgetMac(this, styleMask, widget());
|
2018-04-25 07:05:43 +00:00
|
|
|
widget()->Init(params);
|
|
|
|
window_ = static_cast<AtomNSWindow*>(widget()->GetNativeWindow());
|
2018-04-24 08:23:08 +00:00
|
|
|
|
2015-08-05 04:46:32 +00:00
|
|
|
[window_ setEnableLargerThanScreen:enable_larger_than_screen()];
|
2013-09-11 10:10:28 +00:00
|
|
|
|
2015-03-25 10:51:29 +00:00
|
|
|
window_delegate_.reset([[AtomNSWindowDelegate alloc] initWithShell:this]);
|
|
|
|
[window_ setDelegate:window_delegate_];
|
2014-03-15 11:28:23 +00:00
|
|
|
|
2016-06-20 05:49:24 +00:00
|
|
|
// Only use native parent window for non-modal windows.
|
|
|
|
if (parent && !is_modal()) {
|
2017-05-01 20:21:05 +00:00
|
|
|
SetParentWindow(parent);
|
2016-06-19 03:06:08 +00:00
|
|
|
}
|
|
|
|
|
2015-08-05 04:46:32 +00:00
|
|
|
if (transparent()) {
|
2016-01-19 23:24:16 +00:00
|
|
|
// Setting the background color to clear will also hide the shadow.
|
2014-12-23 19:17:56 +00:00
|
|
|
[window_ setBackgroundColor:[NSColor clearColor]];
|
|
|
|
}
|
2015-04-25 02:35:28 +00:00
|
|
|
|
2015-11-19 08:39:45 +00:00
|
|
|
if (windowType == "desktop") {
|
|
|
|
[window_ setLevel:kCGDesktopWindowLevel - 1];
|
2015-11-20 05:06:42 +00:00
|
|
|
[window_ setDisableKeyOrMainWindow:YES];
|
2018-04-20 18:47:04 +00:00
|
|
|
[window_ setCollectionBehavior:(NSWindowCollectionBehaviorCanJoinAllSpaces |
|
|
|
|
NSWindowCollectionBehaviorStationary |
|
|
|
|
NSWindowCollectionBehaviorIgnoresCycle)];
|
2015-11-19 08:39:45 +00:00
|
|
|
}
|
|
|
|
|
2016-06-13 08:10:28 +00:00
|
|
|
bool focusable;
|
|
|
|
if (options.Get(options::kFocusable, &focusable) && !focusable)
|
|
|
|
[window_ setDisableKeyOrMainWindow:YES];
|
|
|
|
|
2016-06-17 02:02:37 +00:00
|
|
|
if (transparent() || !has_frame()) {
|
2018-06-20 09:34:04 +00:00
|
|
|
if (@available(macOS 10.10, *)) {
|
|
|
|
// Don't show title bar.
|
|
|
|
[window_ setTitlebarAppearsTransparent:YES];
|
|
|
|
[window_ setTitleVisibility:NSWindowTitleHidden];
|
|
|
|
}
|
2016-06-17 01:54:50 +00:00
|
|
|
// Remove non-transparent corners, see http://git.io/vfonD.
|
2015-04-18 12:08:22 +00:00
|
|
|
[window_ setOpaque:NO];
|
2016-06-17 01:54:50 +00:00
|
|
|
}
|
2014-12-23 19:17:56 +00:00
|
|
|
|
2017-03-30 20:46:34 +00:00
|
|
|
// Create a tab only if tabbing identifier is specified and window has
|
|
|
|
// a native title bar.
|
2017-03-30 20:47:11 +00:00
|
|
|
if (tabbingIdentifier.empty() || transparent() || !has_frame()) {
|
2018-04-17 23:45:26 +00:00
|
|
|
if (@available(macOS 10.12, *)) {
|
2017-03-30 20:46:34 +00:00
|
|
|
[window_ setTabbingMode:NSWindowTabbingModeDisallowed];
|
|
|
|
}
|
|
|
|
} else {
|
2018-04-17 23:45:26 +00:00
|
|
|
if (@available(macOS 10.12, *)) {
|
2017-03-30 20:47:11 +00:00
|
|
|
[window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbingIdentifier)];
|
2017-03-27 14:15:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-19 04:19:22 +00:00
|
|
|
// Hide the title bar background
|
|
|
|
if (title_bar_style_ != NORMAL) {
|
2018-06-20 09:34:04 +00:00
|
|
|
if (@available(macOS 10.10, *)) {
|
|
|
|
[window_ setTitlebarAppearsTransparent:YES];
|
|
|
|
}
|
2017-11-19 04:00:01 +00:00
|
|
|
}
|
|
|
|
|
2017-11-19 04:19:22 +00:00
|
|
|
// Hide the title bar.
|
2017-11-19 04:00:01 +00:00
|
|
|
if (title_bar_style_ == HIDDEN_INSET) {
|
2018-06-20 09:34:04 +00:00
|
|
|
if (@available(macOS 10.10, *)) {
|
|
|
|
base::scoped_nsobject<NSToolbar> toolbar(
|
|
|
|
[[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
|
|
|
|
[toolbar setShowsBaselineSeparator:NO];
|
|
|
|
[window_ setToolbar:toolbar];
|
|
|
|
} else {
|
|
|
|
[window_ enableWindowButtonsOffset];
|
|
|
|
[window_ setWindowButtonsOffset:NSMakePoint(12, 10)];
|
|
|
|
}
|
2015-09-14 12:15:41 +00:00
|
|
|
}
|
|
|
|
|
2018-04-24 10:00:44 +00:00
|
|
|
// Resize to content bounds.
|
2014-05-15 07:19:02 +00:00
|
|
|
bool use_content_size = false;
|
2015-11-13 05:58:31 +00:00
|
|
|
options.Get(options::kUseContentSize, &use_content_size);
|
2018-04-24 10:00:44 +00:00
|
|
|
if (!has_frame() || use_content_size)
|
|
|
|
SetContentSize(gfx::Size(width, height));
|
2017-08-13 06:28:33 +00:00
|
|
|
|
2014-03-15 11:28:23 +00:00
|
|
|
// Enable the NSView to accept first mouse event.
|
|
|
|
bool acceptsFirstMouse = false;
|
2015-11-13 05:58:31 +00:00
|
|
|
options.Get(options::kAcceptFirstMouse, &acceptsFirstMouse);
|
2015-04-27 03:47:26 +00:00
|
|
|
[window_ setAcceptsFirstMouse:acceptsFirstMouse];
|
2013-04-12 07:04:46 +00:00
|
|
|
|
2015-04-27 04:08:22 +00:00
|
|
|
// Disable auto-hiding cursor.
|
|
|
|
bool disableAutoHideCursor = false;
|
2015-11-13 05:58:31 +00:00
|
|
|
options.Get(options::kDisableAutoHideCursor, &disableAutoHideCursor);
|
2015-04-27 04:08:22 +00:00
|
|
|
[window_ setDisableAutoHideCursor:disableAutoHideCursor];
|
|
|
|
|
2016-01-25 07:02:43 +00:00
|
|
|
// Use an NSEvent monitor to listen for the wheel event.
|
|
|
|
BOOL __block began = NO;
|
|
|
|
wheel_event_monitor_ = [NSEvent
|
2018-04-20 18:47:04 +00:00
|
|
|
addLocalMonitorForEventsMatchingMask:NSScrollWheelMask
|
|
|
|
handler:^(NSEvent* event) {
|
|
|
|
if ([[event window] windowNumber] !=
|
|
|
|
[window_ windowNumber])
|
|
|
|
return event;
|
|
|
|
|
|
|
|
if (!began && (([event phase] ==
|
|
|
|
NSEventPhaseMayBegin) ||
|
|
|
|
([event phase] ==
|
|
|
|
NSEventPhaseBegan))) {
|
|
|
|
this->NotifyWindowScrollTouchBegin();
|
|
|
|
began = YES;
|
|
|
|
} else if (began &&
|
|
|
|
(([event phase] ==
|
|
|
|
NSEventPhaseEnded) ||
|
|
|
|
([event phase] ==
|
|
|
|
NSEventPhaseCancelled))) {
|
|
|
|
this->NotifyWindowScrollTouchEnd();
|
|
|
|
began = NO;
|
|
|
|
}
|
|
|
|
return event;
|
|
|
|
}];
|
2016-01-21 17:40:21 +00:00
|
|
|
|
2016-06-08 20:56:45 +00:00
|
|
|
// Set maximizable state last to ensure zoom button does not get reset
|
|
|
|
// by calls to other APIs.
|
2016-08-04 23:47:03 +00:00
|
|
|
SetMaximizable(maximizable);
|
2018-04-10 08:30:46 +00:00
|
|
|
|
2018-05-08 07:02:57 +00:00
|
|
|
// Default content view.
|
|
|
|
SetContentView(new views::View());
|
2018-07-10 04:09:46 +00:00
|
|
|
AddContentViewLayers();
|
2018-04-08 11:20:43 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 04:58:42 +00:00
|
|
|
NativeWindowMac::~NativeWindowMac() {
|
|
|
|
[NSEvent removeMonitor:wheel_event_monitor_];
|
|
|
|
}
|
|
|
|
|
2018-05-08 03:51:27 +00:00
|
|
|
void NativeWindowMac::SetContentView(views::View* view) {
|
2018-05-02 06:39:43 +00:00
|
|
|
views::View* root_view = GetContentsView();
|
2018-05-08 03:51:27 +00:00
|
|
|
if (content_view())
|
|
|
|
root_view->RemoveChildView(content_view());
|
2018-05-01 04:58:42 +00:00
|
|
|
|
2018-05-08 03:51:27 +00:00
|
|
|
set_content_view(view);
|
|
|
|
root_view->AddChildView(content_view());
|
2018-05-01 04:58:42 +00:00
|
|
|
|
2018-05-02 06:39:43 +00:00
|
|
|
if (buttons_view_) {
|
|
|
|
// Ensure the buttons view are always floated on the top.
|
|
|
|
[buttons_view_ removeFromSuperview];
|
|
|
|
[[window_ contentView] addSubview:buttons_view_];
|
2018-05-01 04:58:42 +00:00
|
|
|
}
|
2018-05-02 06:39:43 +00:00
|
|
|
|
|
|
|
root_view->Layout();
|
2018-05-01 04:58:42 +00:00
|
|
|
}
|
|
|
|
|
2013-04-12 07:04:46 +00:00
|
|
|
void NativeWindowMac::Close() {
|
2016-06-20 05:49:24 +00:00
|
|
|
// When this is a sheet showing, performClose won't work.
|
|
|
|
if (is_modal() && parent() && IsVisible()) {
|
2016-09-07 22:24:37 +00:00
|
|
|
[parent()->GetNativeWindow() endSheet:window_];
|
2016-06-20 05:49:24 +00:00
|
|
|
CloseImmediately();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-25 23:25:51 +00:00
|
|
|
if (!IsClosable()) {
|
|
|
|
WindowList::WindowCloseCancelled(this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-04-11 04:45:48 +00:00
|
|
|
[window_ performClose:nil];
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
2013-05-01 08:12:00 +00:00
|
|
|
void NativeWindowMac::CloseImmediately() {
|
2014-04-11 04:45:48 +00:00
|
|
|
[window_ close];
|
2013-05-01 08:12:00 +00:00
|
|
|
}
|
|
|
|
|
2013-04-12 07:04:46 +00:00
|
|
|
void NativeWindowMac::Focus(bool focus) {
|
2013-10-03 01:39:17 +00:00
|
|
|
if (!IsVisible())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (focus) {
|
2013-05-25 07:08:58 +00:00
|
|
|
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
2014-04-11 04:45:48 +00:00
|
|
|
[window_ makeKeyAndOrderFront:nil];
|
2013-05-25 07:08:58 +00:00
|
|
|
} else {
|
2014-04-11 04:45:48 +00:00
|
|
|
[window_ orderBack:nil];
|
2013-05-25 07:08:58 +00:00
|
|
|
}
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
2013-05-16 14:56:52 +00:00
|
|
|
bool NativeWindowMac::IsFocused() {
|
2014-04-11 04:45:48 +00:00
|
|
|
return [window_ isKeyWindow];
|
2013-05-16 14:56:52 +00:00
|
|
|
}
|
|
|
|
|
2013-04-12 07:04:46 +00:00
|
|
|
void NativeWindowMac::Show() {
|
2016-06-20 05:49:24 +00:00
|
|
|
if (is_modal() && parent()) {
|
2016-09-29 18:49:24 +00:00
|
|
|
if ([window_ sheetParent] == nil)
|
|
|
|
[parent()->GetNativeWindow() beginSheet:window_
|
2018-04-20 18:47:04 +00:00
|
|
|
completionHandler:^(NSModalResponse){
|
|
|
|
}];
|
2016-06-20 05:49:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-09-14 05:43:22 +00:00
|
|
|
|
2017-05-01 20:10:48 +00:00
|
|
|
// Reattach the window to the parent to actually show it.
|
|
|
|
if (parent())
|
|
|
|
InternalSetParentWindow(parent(), true);
|
2016-06-20 05:49:24 +00:00
|
|
|
|
2014-12-28 01:41:13 +00:00
|
|
|
// This method is supposed to put focus on window, however if the app does not
|
|
|
|
// have focus then "makeKeyAndOrderFront" will only show the window.
|
|
|
|
[NSApp activateIgnoringOtherApps:YES];
|
|
|
|
|
2014-10-17 14:51:20 +00:00
|
|
|
[window_ makeKeyAndOrderFront:nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
void NativeWindowMac::ShowInactive() {
|
2017-05-01 21:01:48 +00:00
|
|
|
// Reattach the window to the parent to actually show it.
|
|
|
|
if (parent())
|
|
|
|
InternalSetParentWindow(parent(), true);
|
2017-09-14 05:43:22 +00:00
|
|
|
|
2014-09-09 06:47:04 +00:00
|
|
|
[window_ orderFrontRegardless];
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void NativeWindowMac::Hide() {
|
2016-06-20 05:49:24 +00:00
|
|
|
if (is_modal() && parent()) {
|
|
|
|
[window_ orderOut:nil];
|
|
|
|
[parent()->GetNativeWindow() endSheet:window_];
|
|
|
|
return;
|
|
|
|
}
|
2017-09-14 05:43:22 +00:00
|
|
|
|
2017-05-01 20:10:48 +00:00
|
|
|
// Deattach the window from the parent before.
|
|
|
|
if (parent())
|
|
|
|
InternalSetParentWindow(parent(), false);
|
2016-06-20 05:49:24 +00:00
|
|
|
|
2014-04-11 04:45:48 +00:00
|
|
|
[window_ orderOut:nil];
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
2013-10-03 00:27:59 +00:00
|
|
|
bool NativeWindowMac::IsVisible() {
|
2014-04-11 04:45:48 +00:00
|
|
|
return [window_ isVisible];
|
2013-10-03 00:27:59 +00:00
|
|
|
}
|
|
|
|
|
2016-06-17 08:38:44 +00:00
|
|
|
bool NativeWindowMac::IsEnabled() {
|
2016-06-20 05:49:24 +00:00
|
|
|
return [window_ attachedSheet] == nil;
|
2016-06-17 08:38:44 +00:00
|
|
|
}
|
|
|
|
|
2018-02-06 13:21:53 +00:00
|
|
|
void NativeWindowMac::SetEnabled(bool enable) {
|
2018-02-06 13:30:33 +00:00
|
|
|
if (enable) {
|
2018-04-20 18:47:04 +00:00
|
|
|
[window_ beginSheet:window_
|
|
|
|
completionHandler:^(NSModalResponse returnCode) {
|
|
|
|
NSLog(@"modal enabled");
|
|
|
|
return;
|
|
|
|
}];
|
2018-02-06 13:21:53 +00:00
|
|
|
} else {
|
2018-04-20 18:47:04 +00:00
|
|
|
[window_ endSheet:[window_ attachedSheet]];
|
2018-02-06 13:21:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-12 07:04:46 +00:00
|
|
|
void NativeWindowMac::Maximize() {
|
2016-04-22 23:15:00 +00:00
|
|
|
if (IsMaximized())
|
|
|
|
return;
|
|
|
|
|
2014-04-11 04:45:48 +00:00
|
|
|
[window_ zoom:nil];
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void NativeWindowMac::Unmaximize() {
|
2016-04-22 23:15:00 +00:00
|
|
|
if (!IsMaximized())
|
|
|
|
return;
|
|
|
|
|
2014-04-11 04:45:48 +00:00
|
|
|
[window_ zoom:nil];
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
2014-06-28 01:17:37 +00:00
|
|
|
bool NativeWindowMac::IsMaximized() {
|
2016-03-05 06:39:13 +00:00
|
|
|
if (([window_ styleMask] & NSResizableWindowMask) != 0) {
|
|
|
|
return [window_ isZoomed];
|
|
|
|
} else {
|
|
|
|
NSRect rectScreen = [[NSScreen mainScreen] visibleFrame];
|
|
|
|
NSRect rectWindow = [window_ frame];
|
|
|
|
return (rectScreen.origin.x == rectWindow.origin.x &&
|
|
|
|
rectScreen.origin.y == rectWindow.origin.y &&
|
|
|
|
rectScreen.size.width == rectWindow.size.width &&
|
|
|
|
rectScreen.size.height == rectWindow.size.height);
|
|
|
|
}
|
2014-05-14 21:58:49 +00:00
|
|
|
}
|
|
|
|
|
2013-04-12 07:04:46 +00:00
|
|
|
void NativeWindowMac::Minimize() {
|
2014-04-11 04:45:48 +00:00
|
|
|
[window_ miniaturize:nil];
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void NativeWindowMac::Restore() {
|
2014-04-11 04:45:48 +00:00
|
|
|
[window_ deminiaturize:nil];
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
2014-07-26 05:58:26 +00:00
|
|
|
bool NativeWindowMac::IsMinimized() {
|
|
|
|
return [window_ isMiniaturized];
|
|
|
|
}
|
|
|
|
|
2014-11-25 06:34:14 +00:00
|
|
|
void NativeWindowMac::SetFullScreen(bool fullscreen) {
|
2013-06-04 10:15:03 +00:00
|
|
|
if (fullscreen == IsFullscreen())
|
2013-04-12 07:04:46 +00:00
|
|
|
return;
|
|
|
|
|
2018-01-19 14:27:36 +00:00
|
|
|
[window_ toggleFullScreenMode:nil];
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
2015-04-21 13:35:36 +00:00
|
|
|
bool NativeWindowMac::IsFullscreen() const {
|
2014-04-11 04:45:48 +00:00
|
|
|
return [window_ styleMask] & NSFullScreenWindowMask;
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
2016-01-15 04:54:12 +00:00
|
|
|
void NativeWindowMac::SetBounds(const gfx::Rect& bounds, bool animate) {
|
2016-07-11 07:44:42 +00:00
|
|
|
// Do nothing if in fullscreen mode.
|
|
|
|
if (IsFullscreen())
|
|
|
|
return;
|
|
|
|
|
2016-07-07 11:02:18 +00:00
|
|
|
// Check size constraints since setFrame does not check it.
|
|
|
|
gfx::Size size = bounds.size();
|
|
|
|
size.SetToMax(GetMinimumSize());
|
|
|
|
gfx::Size max_size = GetMaximumSize();
|
|
|
|
if (!max_size.IsEmpty())
|
|
|
|
size.SetToMin(max_size);
|
|
|
|
|
|
|
|
NSRect cocoa_bounds = NSMakeRect(bounds.x(), 0, size.width(), size.height());
|
2015-05-01 14:40:46 +00:00
|
|
|
// Flip coordinates based on the primary screen.
|
2016-12-20 21:49:35 +00:00
|
|
|
NSScreen* screen = [[NSScreen screens] firstObject];
|
2018-04-20 18:47:04 +00:00
|
|
|
cocoa_bounds.origin.y = NSHeight([screen frame]) - size.height() - bounds.y();
|
2015-05-01 14:40:46 +00:00
|
|
|
|
2016-01-15 04:54:12 +00:00
|
|
|
[window_ setFrame:cocoa_bounds display:YES animate:animate];
|
2015-05-01 10:50:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gfx::Rect NativeWindowMac::GetBounds() {
|
2015-05-01 14:40:46 +00:00
|
|
|
NSRect frame = [window_ frame];
|
2015-05-04 04:06:03 +00:00
|
|
|
gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame));
|
2016-12-20 21:49:35 +00:00
|
|
|
NSScreen* screen = [[NSScreen screens] firstObject];
|
2015-05-04 04:06:03 +00:00
|
|
|
bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame));
|
|
|
|
return bounds;
|
2015-05-01 10:50:53 +00:00
|
|
|
}
|
|
|
|
|
2015-10-05 08:19:01 +00:00
|
|
|
void NativeWindowMac::SetContentSizeConstraints(
|
|
|
|
const extensions::SizeConstraints& size_constraints) {
|
2015-10-06 07:15:23 +00:00
|
|
|
auto convertSize = [this](const gfx::Size& size) {
|
|
|
|
// Our frameless window still has titlebar attached, so setting contentSize
|
|
|
|
// will result in actual content size being larger.
|
|
|
|
if (!has_frame()) {
|
|
|
|
NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
|
2018-05-02 12:28:28 +00:00
|
|
|
NSRect content = [window_ originalContentRectForFrameRect:frame];
|
2015-10-06 07:15:23 +00:00
|
|
|
return content.size;
|
|
|
|
} else {
|
|
|
|
return NSMakeSize(size.width(), size.height());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-04-11 04:45:48 +00:00
|
|
|
NSView* content = [window_ contentView];
|
2015-10-05 08:19:01 +00:00
|
|
|
if (size_constraints.HasMinimumSize()) {
|
2015-10-06 07:15:23 +00:00
|
|
|
NSSize min_size = convertSize(size_constraints.GetMinimumSize());
|
2015-10-05 12:09:29 +00:00
|
|
|
[window_ setContentMinSize:[content convertSize:min_size toView:nil]];
|
2015-10-05 08:19:01 +00:00
|
|
|
}
|
|
|
|
if (size_constraints.HasMaximumSize()) {
|
2015-10-06 07:15:23 +00:00
|
|
|
NSSize max_size = convertSize(size_constraints.GetMaximumSize());
|
2015-10-05 12:09:29 +00:00
|
|
|
[window_ setContentMaxSize:[content convertSize:max_size toView:nil]];
|
2015-10-05 08:19:01 +00:00
|
|
|
}
|
|
|
|
NativeWindow::SetContentSizeConstraints(size_constraints);
|
2013-04-18 07:38:04 +00:00
|
|
|
}
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
void NativeWindowMac::MoveTop() {
|
2018-04-03 13:04:32 +00:00
|
|
|
[window_ orderWindow:NSWindowAbove relativeTo:0];
|
|
|
|
}
|
2018-04-24 10:00:44 +00:00
|
|
|
|
2013-04-12 07:04:46 +00:00
|
|
|
void NativeWindowMac::SetResizable(bool resizable) {
|
2016-01-23 11:12:19 +00:00
|
|
|
SetStyleMask(resizable, NSResizableWindowMask);
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
2013-04-18 07:38:04 +00:00
|
|
|
bool NativeWindowMac::IsResizable() {
|
2014-04-11 04:45:48 +00:00
|
|
|
return [window_ styleMask] & NSResizableWindowMask;
|
2013-04-18 07:38:04 +00:00
|
|
|
}
|
|
|
|
|
2016-05-22 23:50:50 +00:00
|
|
|
void NativeWindowMac::SetAspectRatio(double aspect_ratio,
|
2016-05-23 01:36:05 +00:00
|
|
|
const gfx::Size& extra_size) {
|
2016-07-11 07:43:01 +00:00
|
|
|
NativeWindow::SetAspectRatio(aspect_ratio, extra_size);
|
2016-05-22 23:50:50 +00:00
|
|
|
|
2016-07-11 07:43:01 +00:00
|
|
|
// Reset the behaviour to default if aspect_ratio is set to 0 or less.
|
|
|
|
if (aspect_ratio > 0.0)
|
|
|
|
[window_ setAspectRatio:NSMakeSize(aspect_ratio, 1.0)];
|
|
|
|
else
|
|
|
|
[window_ setResizeIncrements:NSMakeSize(1.0, 1.0)];
|
2016-05-22 23:50:50 +00:00
|
|
|
}
|
|
|
|
|
2016-10-26 00:47:22 +00:00
|
|
|
void NativeWindowMac::PreviewFile(const std::string& path,
|
|
|
|
const std::string& display_name) {
|
2018-04-19 07:41:36 +00:00
|
|
|
preview_item_.reset([[AtomPreviewItem alloc]
|
|
|
|
initWithURL:[NSURL fileURLWithPath:base::SysUTF8ToNSString(path)]
|
|
|
|
title:base::SysUTF8ToNSString(display_name)]);
|
|
|
|
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
|
2016-10-12 01:08:01 +00:00
|
|
|
}
|
|
|
|
|
2016-11-21 18:30:13 +00:00
|
|
|
void NativeWindowMac::CloseFilePreview() {
|
|
|
|
if ([QLPreviewPanel sharedPreviewPanelExists]) {
|
|
|
|
[[QLPreviewPanel sharedPreviewPanel] close];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-18 22:46:35 +00:00
|
|
|
void NativeWindowMac::SetMovable(bool movable) {
|
|
|
|
[window_ setMovable:movable];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NativeWindowMac::IsMovable() {
|
|
|
|
return [window_ isMovable];
|
|
|
|
}
|
|
|
|
|
|
|
|
void NativeWindowMac::SetMinimizable(bool minimizable) {
|
2016-01-23 11:12:19 +00:00
|
|
|
SetStyleMask(minimizable, NSMiniaturizableWindowMask);
|
2016-01-18 22:46:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool NativeWindowMac::IsMinimizable() {
|
|
|
|
return [window_ styleMask] & NSMiniaturizableWindowMask;
|
|
|
|
}
|
|
|
|
|
2016-01-22 21:24:33 +00:00
|
|
|
void NativeWindowMac::SetMaximizable(bool maximizable) {
|
|
|
|
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:maximizable];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NativeWindowMac::IsMaximizable() {
|
|
|
|
return [[window_ standardWindowButton:NSWindowZoomButton] isEnabled];
|
|
|
|
}
|
|
|
|
|
2016-01-23 07:47:37 +00:00
|
|
|
void NativeWindowMac::SetFullScreenable(bool fullscreenable) {
|
2018-04-20 18:47:04 +00:00
|
|
|
SetCollectionBehavior(fullscreenable,
|
|
|
|
NSWindowCollectionBehaviorFullScreenPrimary);
|
2016-01-23 11:12:19 +00:00
|
|
|
// On EL Capitan this flag is required to hide fullscreen button.
|
2018-04-20 18:47:04 +00:00
|
|
|
SetCollectionBehavior(!fullscreenable,
|
|
|
|
NSWindowCollectionBehaviorFullScreenAuxiliary);
|
2016-01-22 21:24:33 +00:00
|
|
|
}
|
|
|
|
|
2016-01-23 07:47:37 +00:00
|
|
|
bool NativeWindowMac::IsFullScreenable() {
|
2016-01-23 11:12:19 +00:00
|
|
|
NSUInteger collectionBehavior = [window_ collectionBehavior];
|
|
|
|
return collectionBehavior & NSWindowCollectionBehaviorFullScreenPrimary;
|
2016-01-22 21:24:33 +00:00
|
|
|
}
|
|
|
|
|
2016-01-18 22:46:35 +00:00
|
|
|
void NativeWindowMac::SetClosable(bool closable) {
|
2016-01-23 11:12:19 +00:00
|
|
|
SetStyleMask(closable, NSClosableWindowMask);
|
2016-01-18 22:46:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool NativeWindowMac::IsClosable() {
|
|
|
|
return [window_ styleMask] & NSClosableWindowMask;
|
|
|
|
}
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
void NativeWindowMac::SetAlwaysOnTop(bool top,
|
|
|
|
const std::string& level,
|
|
|
|
int relativeLevel,
|
|
|
|
std::string* error) {
|
2016-09-22 16:22:28 +00:00
|
|
|
int windowLevel = NSNormalWindowLevel;
|
2017-01-25 04:08:08 +00:00
|
|
|
CGWindowLevel maxWindowLevel = CGWindowLevelForKey(kCGMaximumWindowLevelKey);
|
2017-01-27 03:12:10 +00:00
|
|
|
CGWindowLevel minWindowLevel = CGWindowLevelForKey(kCGMinimumWindowLevelKey);
|
2017-02-07 17:32:40 +00:00
|
|
|
|
2016-09-22 16:22:28 +00:00
|
|
|
if (top) {
|
|
|
|
if (level == "floating") {
|
|
|
|
windowLevel = NSFloatingWindowLevel;
|
|
|
|
} else if (level == "torn-off-menu") {
|
|
|
|
windowLevel = NSTornOffMenuWindowLevel;
|
|
|
|
} else if (level == "modal-panel") {
|
|
|
|
windowLevel = NSModalPanelWindowLevel;
|
|
|
|
} else if (level == "main-menu") {
|
|
|
|
windowLevel = NSMainMenuWindowLevel;
|
|
|
|
} else if (level == "status") {
|
|
|
|
windowLevel = NSStatusWindowLevel;
|
|
|
|
} else if (level == "pop-up-menu") {
|
|
|
|
windowLevel = NSPopUpMenuWindowLevel;
|
|
|
|
} else if (level == "screen-saver") {
|
|
|
|
windowLevel = NSScreenSaverWindowLevel;
|
|
|
|
} else if (level == "dock") {
|
2016-12-06 21:48:40 +00:00
|
|
|
// Deprecated by macOS, but kept for backwards compatibility
|
2016-09-22 16:22:28 +00:00
|
|
|
windowLevel = NSDockWindowLevel;
|
|
|
|
}
|
|
|
|
}
|
2017-01-24 04:36:09 +00:00
|
|
|
|
|
|
|
NSInteger newLevel = windowLevel + relativeLevel;
|
2017-01-27 03:12:10 +00:00
|
|
|
if (newLevel >= minWindowLevel && newLevel <= maxWindowLevel) {
|
2017-01-24 04:36:09 +00:00
|
|
|
[window_ setLevel:newLevel];
|
|
|
|
} else {
|
2018-04-20 18:47:04 +00:00
|
|
|
*error = std::string([
|
|
|
|
[NSString stringWithFormat:@"relativeLevel must be between %d and %d",
|
|
|
|
minWindowLevel, maxWindowLevel] UTF8String]);
|
2017-01-24 04:36:09 +00:00
|
|
|
}
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
2013-04-18 07:38:04 +00:00
|
|
|
bool NativeWindowMac::IsAlwaysOnTop() {
|
2016-09-22 16:41:06 +00:00
|
|
|
return [window_ level] != NSNormalWindowLevel;
|
2013-04-18 07:38:04 +00:00
|
|
|
}
|
|
|
|
|
2013-05-10 12:34:05 +00:00
|
|
|
void NativeWindowMac::Center() {
|
2014-04-11 04:45:48 +00:00
|
|
|
[window_ center];
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
2017-02-14 03:41:24 +00:00
|
|
|
void NativeWindowMac::Invalidate() {
|
|
|
|
[window_ flushWindow];
|
2017-02-14 19:09:15 +00:00
|
|
|
[[window_ contentView] setNeedsDisplay:YES];
|
2017-02-14 03:41:24 +00:00
|
|
|
}
|
|
|
|
|
2013-04-12 07:04:46 +00:00
|
|
|
void NativeWindowMac::SetTitle(const std::string& title) {
|
2018-06-20 09:34:04 +00:00
|
|
|
// For macOS <= 10.9, the setTitleVisibility API is not available, we have
|
|
|
|
// to avoid calling setTitle for frameless window.
|
|
|
|
if (!base::mac::IsAtLeastOS10_10() && (transparent() || !has_frame()))
|
|
|
|
return;
|
|
|
|
|
2016-06-17 01:54:50 +00:00
|
|
|
[window_ setTitle:base::SysUTF8ToNSString(title)];
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
2013-04-18 06:30:05 +00:00
|
|
|
std::string NativeWindowMac::GetTitle() {
|
2018-04-20 18:47:04 +00:00
|
|
|
return base::SysNSStringToUTF8([window_ title]);
|
2018-06-20 09:34:04 +00:00
|
|
|
;
|
2013-04-18 06:30:05 +00:00
|
|
|
}
|
|
|
|
|
2013-04-12 07:04:46 +00:00
|
|
|
void NativeWindowMac::FlashFrame(bool flash) {
|
|
|
|
if (flash) {
|
|
|
|
attention_request_id_ = [NSApp requestUserAttention:NSInformationalRequest];
|
|
|
|
} else {
|
|
|
|
[NSApp cancelUserAttentionRequest:attention_request_id_];
|
|
|
|
attention_request_id_ = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
void NativeWindowMac::SetSkipTaskbar(bool skip) {}
|
2014-06-16 02:29:51 +00:00
|
|
|
|
2017-08-13 06:28:33 +00:00
|
|
|
void NativeWindowMac::SetSimpleFullScreen(bool simple_fullscreen) {
|
|
|
|
NSWindow* window = GetNativeWindow();
|
|
|
|
|
|
|
|
if (simple_fullscreen && !is_simple_fullscreen_) {
|
|
|
|
is_simple_fullscreen_ = true;
|
|
|
|
|
|
|
|
// Take note of the current window size
|
|
|
|
original_frame_ = [window frame];
|
|
|
|
|
|
|
|
simple_fullscreen_options_ = [NSApp currentSystemPresentationOptions];
|
2017-09-12 18:27:30 +00:00
|
|
|
simple_fullscreen_mask_ = [window styleMask];
|
2017-08-13 06:28:33 +00:00
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
// We can simulate the pre-Lion fullscreen by auto-hiding the dock and menu
|
|
|
|
// bar
|
2017-08-13 06:28:33 +00:00
|
|
|
NSApplicationPresentationOptions options =
|
|
|
|
NSApplicationPresentationAutoHideDock +
|
|
|
|
NSApplicationPresentationAutoHideMenuBar;
|
|
|
|
[NSApp setPresentationOptions:options];
|
|
|
|
|
|
|
|
was_maximizable_ = IsMaximizable();
|
|
|
|
was_movable_ = IsMovable();
|
|
|
|
|
|
|
|
NSRect fullscreenFrame = [window.screen frame];
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
if (!fullscreen_window_title()) {
|
2017-08-13 06:28:33 +00:00
|
|
|
// Hide the titlebar
|
|
|
|
SetStyleMask(false, NSTitledWindowMask);
|
|
|
|
|
|
|
|
// Resize the window to accomodate the _entire_ screen size
|
2018-04-20 18:47:04 +00:00
|
|
|
fullscreenFrame.size.height -=
|
|
|
|
[[[NSApplication sharedApplication] mainMenu] menuBarHeight];
|
2017-08-13 06:28:33 +00:00
|
|
|
} else {
|
|
|
|
// No need to hide the title, but we should still hide the window buttons
|
|
|
|
[[window standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
|
|
|
[[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
|
|
|
[[window standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
|
|
|
}
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
[window setFrame:fullscreenFrame display:YES animate:YES];
|
2017-08-13 06:28:33 +00:00
|
|
|
|
2017-09-12 18:27:30 +00:00
|
|
|
// Fullscreen windows can't be resized, minimized, maximized, or moved
|
|
|
|
SetMinimizable(false);
|
|
|
|
SetResizable(false);
|
|
|
|
SetMaximizable(false);
|
|
|
|
SetMovable(false);
|
2017-08-13 06:28:33 +00:00
|
|
|
} else if (!simple_fullscreen && is_simple_fullscreen_) {
|
|
|
|
is_simple_fullscreen_ = false;
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
if (!fullscreen_window_title()) {
|
2017-08-13 06:28:33 +00:00
|
|
|
// Restore the titlebar
|
|
|
|
SetStyleMask(true, NSTitledWindowMask);
|
|
|
|
} else {
|
|
|
|
// Show the window buttons
|
|
|
|
[[window standardWindowButton:NSWindowZoomButton] setHidden:NO];
|
|
|
|
[[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:NO];
|
|
|
|
[[window standardWindowButton:NSWindowCloseButton] setHidden:NO];
|
|
|
|
}
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
[window setFrame:original_frame_ display:YES animate:YES];
|
2017-08-13 06:28:33 +00:00
|
|
|
|
|
|
|
[NSApp setPresentationOptions:simple_fullscreen_options_];
|
2017-09-12 18:27:30 +00:00
|
|
|
|
|
|
|
// Restore original style mask
|
|
|
|
ScopedDisableResize disable_resize;
|
|
|
|
[window_ setStyleMask:simple_fullscreen_mask_];
|
|
|
|
|
2017-08-13 06:28:33 +00:00
|
|
|
// Restore window manipulation abilities
|
2017-09-12 18:27:30 +00:00
|
|
|
SetMaximizable(was_maximizable_);
|
|
|
|
SetMovable(was_movable_);
|
2017-08-13 06:28:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NativeWindowMac::IsSimpleFullScreen() {
|
|
|
|
return is_simple_fullscreen_;
|
|
|
|
}
|
|
|
|
|
2013-04-12 07:04:46 +00:00
|
|
|
void NativeWindowMac::SetKiosk(bool kiosk) {
|
2014-06-09 05:04:59 +00:00
|
|
|
if (kiosk && !is_kiosk_) {
|
|
|
|
kiosk_options_ = [NSApp currentSystemPresentationOptions];
|
2013-04-12 07:04:46 +00:00
|
|
|
NSApplicationPresentationOptions options =
|
|
|
|
NSApplicationPresentationHideDock +
|
2013-09-11 20:23:17 +00:00
|
|
|
NSApplicationPresentationHideMenuBar +
|
2013-04-12 07:04:46 +00:00
|
|
|
NSApplicationPresentationDisableAppleMenu +
|
|
|
|
NSApplicationPresentationDisableProcessSwitching +
|
|
|
|
NSApplicationPresentationDisableForceQuit +
|
|
|
|
NSApplicationPresentationDisableSessionTermination +
|
|
|
|
NSApplicationPresentationDisableHideApplication;
|
|
|
|
[NSApp setPresentationOptions:options];
|
|
|
|
is_kiosk_ = true;
|
2017-01-13 23:04:51 +00:00
|
|
|
was_fullscreen_ = IsFullscreen();
|
2018-04-20 18:47:04 +00:00
|
|
|
if (!was_fullscreen_)
|
|
|
|
SetFullScreen(true);
|
2014-06-09 05:04:59 +00:00
|
|
|
} else if (!kiosk && is_kiosk_) {
|
|
|
|
is_kiosk_ = false;
|
2018-04-20 18:47:04 +00:00
|
|
|
if (!was_fullscreen_)
|
|
|
|
SetFullScreen(false);
|
2014-06-09 05:04:59 +00:00
|
|
|
[NSApp setPresentationOptions:kiosk_options_];
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NativeWindowMac::IsKiosk() {
|
|
|
|
return is_kiosk_;
|
|
|
|
}
|
|
|
|
|
2018-03-06 04:21:47 +00:00
|
|
|
void NativeWindowMac::SetBackgroundColor(SkColor color) {
|
2018-04-24 11:08:14 +00:00
|
|
|
base::ScopedCFTypeRef<CGColorRef> cgcolor(
|
|
|
|
skia::CGColorCreateFromSkColor(color));
|
|
|
|
// views::Widget adds a layer for the content view.
|
|
|
|
auto* bridge = views::NativeWidgetMac::GetBridgeForNativeWindow(window_);
|
|
|
|
NSView* compositor_superview =
|
2018-05-01 04:58:42 +00:00
|
|
|
static_cast<ui::AcceleratedWidgetMacNSView*>(bridge)
|
|
|
|
->AcceleratedWidgetGetNSView();
|
2018-04-24 11:08:14 +00:00
|
|
|
[[compositor_superview layer] setBackgroundColor:cgcolor];
|
|
|
|
// When using WebContents as content view, the contentView also has layer.
|
|
|
|
if ([[window_ contentView] wantsLayer])
|
|
|
|
[[[window_ contentView] layer] setBackgroundColor:cgcolor];
|
2015-10-23 03:35:33 +00:00
|
|
|
}
|
|
|
|
|
2016-01-23 00:15:49 +00:00
|
|
|
void NativeWindowMac::SetHasShadow(bool has_shadow) {
|
|
|
|
[window_ setHasShadow:has_shadow];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NativeWindowMac::HasShadow() {
|
|
|
|
return [window_ hasShadow];
|
|
|
|
}
|
|
|
|
|
2017-09-29 02:26:02 +00:00
|
|
|
void NativeWindowMac::SetOpacity(const double opacity) {
|
|
|
|
[window_ setAlphaValue:opacity];
|
|
|
|
}
|
|
|
|
|
2017-10-02 15:08:10 +00:00
|
|
|
double NativeWindowMac::GetOpacity() {
|
|
|
|
return [window_ alphaValue];
|
|
|
|
}
|
|
|
|
|
2014-05-27 06:15:34 +00:00
|
|
|
void NativeWindowMac::SetRepresentedFilename(const std::string& filename) {
|
|
|
|
[window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)];
|
|
|
|
}
|
|
|
|
|
2014-07-18 13:42:26 +00:00
|
|
|
std::string NativeWindowMac::GetRepresentedFilename() {
|
|
|
|
return base::SysNSStringToUTF8([window_ representedFilename]);
|
|
|
|
}
|
|
|
|
|
2014-05-27 06:15:34 +00:00
|
|
|
void NativeWindowMac::SetDocumentEdited(bool edited) {
|
|
|
|
[window_ setDocumentEdited:edited];
|
|
|
|
}
|
|
|
|
|
2014-07-24 07:48:33 +00:00
|
|
|
bool NativeWindowMac::IsDocumentEdited() {
|
|
|
|
return [window_ isDocumentEdited];
|
|
|
|
}
|
|
|
|
|
2018-04-09 10:35:05 +00:00
|
|
|
void NativeWindowMac::SetIgnoreMouseEvents(bool ignore, bool forward) {
|
2015-12-06 02:14:54 +00:00
|
|
|
[window_ setIgnoresMouseEvents:ignore];
|
2018-04-09 10:35:05 +00:00
|
|
|
|
|
|
|
if (!ignore) {
|
|
|
|
SetForwardMouseMessages(NO);
|
|
|
|
} else {
|
|
|
|
SetForwardMouseMessages(forward);
|
|
|
|
}
|
2015-12-06 02:14:54 +00:00
|
|
|
}
|
|
|
|
|
2016-06-22 08:40:01 +00:00
|
|
|
void NativeWindowMac::SetContentProtection(bool enable) {
|
2018-04-20 18:47:04 +00:00
|
|
|
[window_
|
|
|
|
setSharingType:enable ? NSWindowSharingNone : NSWindowSharingReadOnly];
|
2016-06-22 08:40:01 +00:00
|
|
|
}
|
|
|
|
|
2018-03-06 06:04:40 +00:00
|
|
|
void NativeWindowMac::SetBrowserView(NativeBrowserView* view) {
|
|
|
|
if (browser_view()) {
|
|
|
|
[browser_view()->GetInspectableWebContentsView()->GetNativeView()
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
removeFromSuperview];
|
2018-03-06 06:04:40 +00:00
|
|
|
set_browser_view(nullptr);
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
}
|
|
|
|
|
2018-03-06 06:04:40 +00:00
|
|
|
if (!view) {
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-06 06:04:40 +00:00
|
|
|
set_browser_view(view);
|
|
|
|
auto* native_view = view->GetInspectableWebContentsView()->GetNativeView();
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
[[window_ contentView] addSubview:native_view
|
|
|
|
positioned:NSWindowAbove
|
|
|
|
relativeTo:nil];
|
|
|
|
native_view.hidden = NO;
|
|
|
|
}
|
|
|
|
|
2017-05-01 20:10:48 +00:00
|
|
|
void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
|
2017-05-01 20:21:05 +00:00
|
|
|
InternalSetParentWindow(parent, IsVisible());
|
2017-05-01 20:10:48 +00:00
|
|
|
}
|
|
|
|
|
2017-05-23 09:41:59 +00:00
|
|
|
gfx::NativeView NativeWindowMac::GetNativeView() const {
|
2018-03-06 04:31:12 +00:00
|
|
|
return [window_ contentView];
|
2017-03-14 11:56:24 +00:00
|
|
|
}
|
|
|
|
|
2017-09-14 05:43:22 +00:00
|
|
|
gfx::NativeWindow NativeWindowMac::GetNativeWindow() const {
|
2014-04-11 04:45:48 +00:00
|
|
|
return window_;
|
2013-05-03 11:31:24 +00:00
|
|
|
}
|
|
|
|
|
2017-05-23 09:41:59 +00:00
|
|
|
gfx::AcceleratedWidget NativeWindowMac::GetAcceleratedWidget() const {
|
2018-04-12 20:20:37 +00:00
|
|
|
return gfx::kNullAcceleratedWidget;
|
2016-01-07 20:38:35 +00:00
|
|
|
}
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
void NativeWindowMac::SetProgressBar(double progress,
|
|
|
|
const NativeWindow::ProgressState state) {
|
2014-09-17 07:58:08 +00:00
|
|
|
NSDockTile* dock_tile = [NSApp dockTile];
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
// For the first time API invoked, we need to create a ContentView in
|
|
|
|
// DockTile.
|
2017-03-30 20:12:14 +00:00
|
|
|
if (dock_tile.contentView == nullptr) {
|
2014-09-17 07:58:08 +00:00
|
|
|
NSImageView* image_view = [[NSImageView alloc] init];
|
|
|
|
[image_view setImage:[NSApp applicationIconImage]];
|
|
|
|
[dock_tile setContentView:image_view];
|
2016-06-16 21:57:23 +00:00
|
|
|
}
|
2014-09-17 07:58:08 +00:00
|
|
|
|
2016-06-16 21:57:23 +00:00
|
|
|
if ([[dock_tile.contentView subviews] count] == 0) {
|
2014-09-17 07:58:08 +00:00
|
|
|
NSProgressIndicator* progress_indicator = [[AtomProgressBar alloc]
|
|
|
|
initWithFrame:NSMakeRect(0.0f, 0.0f, dock_tile.size.width, 15.0)];
|
|
|
|
[progress_indicator setStyle:NSProgressIndicatorBarStyle];
|
|
|
|
[progress_indicator setIndeterminate:NO];
|
|
|
|
[progress_indicator setBezeled:YES];
|
|
|
|
[progress_indicator setMinValue:0];
|
|
|
|
[progress_indicator setMaxValue:1];
|
|
|
|
[progress_indicator setHidden:NO];
|
2016-06-16 21:57:23 +00:00
|
|
|
[dock_tile.contentView addSubview:progress_indicator];
|
2014-09-17 07:58:08 +00:00
|
|
|
}
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
NSProgressIndicator* progress_indicator = static_cast<NSProgressIndicator*>(
|
|
|
|
[[[dock_tile contentView] subviews] objectAtIndex:0]);
|
2014-09-17 07:58:08 +00:00
|
|
|
if (progress < 0) {
|
|
|
|
[progress_indicator setHidden:YES];
|
|
|
|
} else if (progress > 1) {
|
2014-09-21 10:56:03 +00:00
|
|
|
[progress_indicator setHidden:NO];
|
2014-09-17 07:58:08 +00:00
|
|
|
[progress_indicator setIndeterminate:YES];
|
2014-09-21 10:56:03 +00:00
|
|
|
[progress_indicator setDoubleValue:1];
|
2014-09-17 07:58:08 +00:00
|
|
|
} else {
|
2014-09-21 10:56:03 +00:00
|
|
|
[progress_indicator setHidden:NO];
|
2014-09-17 07:58:08 +00:00
|
|
|
[progress_indicator setDoubleValue:progress];
|
|
|
|
}
|
|
|
|
[dock_tile display];
|
|
|
|
}
|
|
|
|
|
2015-02-11 01:14:26 +00:00
|
|
|
void NativeWindowMac::SetOverlayIcon(const gfx::Image& overlay,
|
2018-04-20 18:47:04 +00:00
|
|
|
const std::string& description) {}
|
2015-02-07 19:56:03 +00:00
|
|
|
|
2015-03-26 06:18:37 +00:00
|
|
|
void NativeWindowMac::SetVisibleOnAllWorkspaces(bool visible) {
|
2016-01-23 11:12:19 +00:00
|
|
|
SetCollectionBehavior(visible, NSWindowCollectionBehaviorCanJoinAllSpaces);
|
2015-03-26 06:18:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool NativeWindowMac::IsVisibleOnAllWorkspaces() {
|
2015-03-27 11:41:07 +00:00
|
|
|
NSUInteger collectionBehavior = [window_ collectionBehavior];
|
|
|
|
return collectionBehavior & NSWindowCollectionBehaviorCanJoinAllSpaces;
|
2015-03-26 06:18:37 +00:00
|
|
|
}
|
|
|
|
|
2016-11-28 19:38:40 +00:00
|
|
|
void NativeWindowMac::SetAutoHideCursor(bool auto_hide) {
|
|
|
|
[window_ setDisableAutoHideCursor:!auto_hide];
|
|
|
|
}
|
|
|
|
|
2017-08-21 04:46:10 +00:00
|
|
|
void NativeWindowMac::SelectPreviousTab() {
|
2018-04-17 23:45:26 +00:00
|
|
|
if (@available(macOS 10.12, *)) {
|
2017-08-21 04:46:10 +00:00
|
|
|
[window_ selectPreviousTab:nil];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NativeWindowMac::SelectNextTab() {
|
2018-04-17 23:45:26 +00:00
|
|
|
if (@available(macOS 10.12, *)) {
|
2017-08-21 04:46:10 +00:00
|
|
|
[window_ selectNextTab:nil];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NativeWindowMac::MergeAllWindows() {
|
2018-04-17 23:45:26 +00:00
|
|
|
if (@available(macOS 10.12, *)) {
|
2017-08-21 04:46:10 +00:00
|
|
|
[window_ mergeAllWindows:nil];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NativeWindowMac::MoveTabToNewWindow() {
|
2018-04-17 23:45:26 +00:00
|
|
|
if (@available(macOS 10.12, *)) {
|
2017-08-21 04:46:10 +00:00
|
|
|
[window_ moveTabToNewWindow:nil];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NativeWindowMac::ToggleTabBar() {
|
2018-04-17 23:45:26 +00:00
|
|
|
if (@available(macOS 10.12, *)) {
|
2017-08-21 04:46:10 +00:00
|
|
|
[window_ toggleTabBar:nil];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-27 21:00:42 +00:00
|
|
|
bool NativeWindowMac::AddTabbedWindow(NativeWindow* window) {
|
2018-04-24 08:23:08 +00:00
|
|
|
if (window_ == window->GetNativeWindow()) {
|
2018-02-27 21:00:42 +00:00
|
|
|
return false;
|
2018-02-26 22:47:36 +00:00
|
|
|
} else {
|
2018-04-17 23:45:26 +00:00
|
|
|
if (@available(macOS 10.12, *))
|
2018-02-26 22:47:36 +00:00
|
|
|
[window_ addTabbedWindow:window->GetNativeWindow() ordered:NSWindowAbove];
|
2017-09-13 19:15:14 +00:00
|
|
|
}
|
2018-02-27 21:00:42 +00:00
|
|
|
return true;
|
2017-09-13 19:15:14 +00:00
|
|
|
}
|
|
|
|
|
2016-11-07 20:22:41 +00:00
|
|
|
void NativeWindowMac::SetVibrancy(const std::string& type) {
|
2018-06-20 09:34:04 +00:00
|
|
|
if (@available(macOS 10.10, *)) {
|
|
|
|
NSView* vibrant_view = [window_ vibrantView];
|
2016-11-07 20:22:41 +00:00
|
|
|
|
2018-06-20 09:34:04 +00:00
|
|
|
if (type.empty()) {
|
|
|
|
if (background_color_before_vibrancy_) {
|
|
|
|
[window_ setBackgroundColor:background_color_before_vibrancy_];
|
|
|
|
[window_ setTitlebarAppearsTransparent:transparency_before_vibrancy_];
|
|
|
|
}
|
|
|
|
if (vibrant_view == nil)
|
|
|
|
return;
|
2016-11-10 10:59:25 +00:00
|
|
|
|
2018-06-20 09:34:04 +00:00
|
|
|
[vibrant_view removeFromSuperview];
|
|
|
|
[window_ setVibrantView:nil];
|
|
|
|
ui::GpuSwitchingManager::SetTransparent(transparent());
|
2016-11-10 10:59:25 +00:00
|
|
|
|
2018-06-20 09:34:04 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-11-10 10:59:25 +00:00
|
|
|
|
2018-06-20 09:34:04 +00:00
|
|
|
background_color_before_vibrancy_.reset([[window_ backgroundColor] retain]);
|
|
|
|
transparency_before_vibrancy_ = [window_ titlebarAppearsTransparent];
|
|
|
|
ui::GpuSwitchingManager::SetTransparent(true);
|
2018-02-12 18:38:37 +00:00
|
|
|
|
2018-06-20 09:34:04 +00:00
|
|
|
if (title_bar_style_ != NORMAL) {
|
|
|
|
[window_ setTitlebarAppearsTransparent:YES];
|
|
|
|
[window_ setBackgroundColor:[NSColor clearColor]];
|
|
|
|
}
|
2018-02-12 18:38:37 +00:00
|
|
|
|
2018-06-20 09:34:04 +00:00
|
|
|
NSVisualEffectView* effect_view = (NSVisualEffectView*)vibrant_view;
|
|
|
|
if (effect_view == nil) {
|
|
|
|
effect_view = [[[NSVisualEffectView alloc]
|
|
|
|
initWithFrame:[[window_ contentView] bounds]] autorelease];
|
|
|
|
[window_ setVibrantView:(NSView*)effect_view];
|
|
|
|
|
|
|
|
[effect_view
|
|
|
|
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
|
|
|
[effect_view setBlendingMode:NSVisualEffectBlendingModeBehindWindow];
|
|
|
|
[effect_view setState:NSVisualEffectStateActive];
|
|
|
|
[[window_ contentView] addSubview:effect_view
|
|
|
|
positioned:NSWindowBelow
|
|
|
|
relativeTo:nil];
|
|
|
|
}
|
2016-11-07 20:22:41 +00:00
|
|
|
|
2018-06-20 09:34:04 +00:00
|
|
|
NSVisualEffectMaterial vibrancyType = NSVisualEffectMaterialLight;
|
2016-11-07 20:22:41 +00:00
|
|
|
|
2018-06-20 09:34:04 +00:00
|
|
|
if (type == "appearance-based") {
|
|
|
|
vibrancyType = NSVisualEffectMaterialAppearanceBased;
|
|
|
|
} else if (type == "light") {
|
|
|
|
vibrancyType = NSVisualEffectMaterialLight;
|
|
|
|
} else if (type == "dark") {
|
|
|
|
vibrancyType = NSVisualEffectMaterialDark;
|
|
|
|
} else if (type == "titlebar") {
|
|
|
|
vibrancyType = NSVisualEffectMaterialTitlebar;
|
|
|
|
}
|
2016-11-07 20:22:41 +00:00
|
|
|
|
2018-06-20 09:34:04 +00:00
|
|
|
if (@available(macOS 10.11, *)) {
|
|
|
|
// TODO(kevinsawicki): Use NSVisualEffectMaterial* constants directly once
|
|
|
|
// they are available in the minimum SDK version
|
|
|
|
if (type == "selection") {
|
|
|
|
// NSVisualEffectMaterialSelection
|
|
|
|
vibrancyType = static_cast<NSVisualEffectMaterial>(4);
|
|
|
|
} else if (type == "menu") {
|
|
|
|
// NSVisualEffectMaterialMenu
|
|
|
|
vibrancyType = static_cast<NSVisualEffectMaterial>(5);
|
|
|
|
} else if (type == "popover") {
|
|
|
|
// NSVisualEffectMaterialPopover
|
|
|
|
vibrancyType = static_cast<NSVisualEffectMaterial>(6);
|
|
|
|
} else if (type == "sidebar") {
|
|
|
|
// NSVisualEffectMaterialSidebar
|
|
|
|
vibrancyType = static_cast<NSVisualEffectMaterial>(7);
|
|
|
|
} else if (type == "medium-light") {
|
|
|
|
// NSVisualEffectMaterialMediumLight
|
|
|
|
vibrancyType = static_cast<NSVisualEffectMaterial>(8);
|
|
|
|
} else if (type == "ultra-dark") {
|
|
|
|
// NSVisualEffectMaterialUltraDark
|
|
|
|
vibrancyType = static_cast<NSVisualEffectMaterial>(9);
|
|
|
|
}
|
2016-11-07 20:22:41 +00:00
|
|
|
}
|
2018-06-19 15:06:41 +00:00
|
|
|
|
2018-06-20 09:34:04 +00:00
|
|
|
[effect_view setMaterial:vibrancyType];
|
|
|
|
}
|
2016-11-07 20:22:41 +00:00
|
|
|
}
|
|
|
|
|
2017-03-01 00:14:02 +00:00
|
|
|
void NativeWindowMac::SetTouchBar(
|
|
|
|
const std::vector<mate::PersistentDictionary>& items) {
|
2018-04-20 10:23:21 +00:00
|
|
|
if (@available(macOS 10.12.2, *)) {
|
|
|
|
touch_bar_.reset([[AtomTouchBar alloc]
|
|
|
|
initWithDelegate:window_delegate_.get()
|
|
|
|
window:this
|
|
|
|
settings:items]);
|
|
|
|
[window_ setTouchBar:nil];
|
|
|
|
}
|
2016-11-27 11:54:12 +00:00
|
|
|
}
|
|
|
|
|
2017-03-01 00:08:12 +00:00
|
|
|
void NativeWindowMac::RefreshTouchBarItem(const std::string& item_id) {
|
2018-04-20 10:23:21 +00:00
|
|
|
if (@available(macOS 10.12.2, *)) {
|
|
|
|
if (touch_bar_ && [window_ touchBar])
|
|
|
|
[touch_bar_ refreshTouchBarItem:[window_ touchBar] id:item_id];
|
|
|
|
}
|
2016-12-16 06:24:51 +00:00
|
|
|
}
|
|
|
|
|
2018-04-19 07:12:11 +00:00
|
|
|
void NativeWindowMac::SetEscapeTouchBarItem(
|
|
|
|
const mate::PersistentDictionary& item) {
|
2018-04-20 10:23:21 +00:00
|
|
|
if (@available(macOS 10.12.2, *)) {
|
|
|
|
if (touch_bar_ && [window_ touchBar])
|
|
|
|
[touch_bar_ setEscapeTouchBarItem:item forTouchBar:[window_ touchBar]];
|
|
|
|
}
|
2017-03-27 00:22:52 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 06:09:38 +00:00
|
|
|
gfx::Rect NativeWindowMac::ContentBoundsToWindowBounds(
|
|
|
|
const gfx::Rect& bounds) const {
|
|
|
|
if (has_frame()) {
|
|
|
|
gfx::Rect window_bounds(
|
|
|
|
[window_ frameRectForContentRect:bounds.ToCGRect()]);
|
|
|
|
int frame_height = window_bounds.height() - bounds.height();
|
|
|
|
window_bounds.set_y(window_bounds.y() - frame_height);
|
|
|
|
return window_bounds;
|
|
|
|
} else {
|
|
|
|
return bounds;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx::Rect NativeWindowMac::WindowBoundsToContentBounds(
|
|
|
|
const gfx::Rect& bounds) const {
|
|
|
|
if (has_frame()) {
|
|
|
|
gfx::Rect content_bounds(
|
|
|
|
[window_ contentRectForFrameRect:bounds.ToCGRect()]);
|
|
|
|
int frame_height = bounds.height() - content_bounds.height();
|
|
|
|
content_bounds.set_y(content_bounds.y() + frame_height);
|
|
|
|
return content_bounds;
|
|
|
|
} else {
|
|
|
|
return bounds;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-24 10:00:44 +00:00
|
|
|
bool NativeWindowMac::CanResize() const {
|
|
|
|
return resizable_;
|
|
|
|
}
|
|
|
|
|
2018-05-02 06:39:43 +00:00
|
|
|
views::View* NativeWindowMac::GetContentsView() {
|
|
|
|
return root_view_.get();
|
|
|
|
}
|
|
|
|
|
2018-07-10 04:09:46 +00:00
|
|
|
void NativeWindowMac::AddContentViewLayers() {
|
|
|
|
// Make sure the bottom corner is rounded for non-modal windows:
|
|
|
|
// http://crbug.com/396264. But do not enable it on OS X 10.9 for transparent
|
|
|
|
// window, otherwise a semi-transparent frame would show.
|
|
|
|
if (!(transparent() && base::mac::IsOS10_9()) && !is_modal()) {
|
|
|
|
base::scoped_nsobject<CALayer> background_layer([[CALayer alloc] init]);
|
|
|
|
[background_layer
|
|
|
|
setAutoresizingMask:kCALayerWidthSizable | kCALayerHeightSizable];
|
|
|
|
[[window_ contentView] setLayer:background_layer];
|
|
|
|
[[window_ contentView] setWantsLayer:YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!has_frame()) {
|
|
|
|
// In OSX 10.10, adding subviews to the root view for the NSView hierarchy
|
|
|
|
// produces warnings. To eliminate the warnings, we resize the contentView
|
|
|
|
// to fill the window, and add subviews to that.
|
|
|
|
// http://crbug.com/380412
|
|
|
|
if (!original_set_frame_size) {
|
|
|
|
Class cl = [[window_ contentView] class];
|
|
|
|
original_set_frame_size = class_replaceMethod(
|
|
|
|
cl, @selector(setFrameSize:), (IMP)SetFrameSize, "v@:{_NSSize=ff}");
|
|
|
|
original_view_did_move_to_superview =
|
|
|
|
class_replaceMethod(cl, @selector(viewDidMoveToSuperview),
|
|
|
|
(IMP)ViewDidMoveToSuperview, "v@:");
|
|
|
|
[[window_ contentView] viewDidMoveToWindow];
|
|
|
|
}
|
|
|
|
|
|
|
|
// The fullscreen button should always be hidden for frameless window.
|
|
|
|
[[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
|
|
|
|
|
|
|
|
if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER) {
|
|
|
|
buttons_view_.reset(
|
|
|
|
[[CustomWindowButtonView alloc] initWithFrame:NSZeroRect]);
|
|
|
|
[[window_ contentView] addSubview:buttons_view_];
|
|
|
|
} else {
|
|
|
|
if (title_bar_style_ != NORMAL) {
|
|
|
|
if (base::mac::IsOS10_9()) {
|
|
|
|
ShowWindowButton(NSWindowZoomButton);
|
|
|
|
ShowWindowButton(NSWindowMiniaturizeButton);
|
|
|
|
ShowWindowButton(NSWindowCloseButton);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hide the window buttons.
|
|
|
|
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
|
|
|
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
|
|
|
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Some third-party macOS utilities check the zoom button's enabled state to
|
|
|
|
// determine whether to show custom UI on hover, so we disable it here to
|
|
|
|
// prevent them from doing so in a frameless app window.
|
|
|
|
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
void NativeWindowMac::InternalSetParentWindow(NativeWindow* parent,
|
|
|
|
bool attach) {
|
2017-09-14 05:43:22 +00:00
|
|
|
if (is_modal())
|
|
|
|
return;
|
|
|
|
|
|
|
|
NativeWindow::SetParentWindow(parent);
|
|
|
|
|
|
|
|
// Do not remove/add if we are already properly attached.
|
|
|
|
if (attach && parent && [window_ parentWindow] == parent->GetNativeWindow())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Remove current parent window.
|
|
|
|
if ([window_ parentWindow])
|
|
|
|
[[window_ parentWindow] removeChildWindow:window_];
|
|
|
|
|
|
|
|
// Set new parent window.
|
|
|
|
// Note that this method will force the window to become visible.
|
|
|
|
if (parent && attach)
|
|
|
|
[parent->GetNativeWindow() addChildWindow:window_ ordered:NSWindowAbove];
|
|
|
|
}
|
|
|
|
|
2018-06-20 09:34:04 +00:00
|
|
|
void NativeWindowMac::ShowWindowButton(NSWindowButton button) {
|
|
|
|
auto view = [window_ standardWindowButton:button];
|
|
|
|
[view.superview addSubview:view positioned:NSWindowAbove relativeTo:nil];
|
|
|
|
}
|
|
|
|
|
2018-04-09 10:35:05 +00:00
|
|
|
void NativeWindowMac::SetForwardMouseMessages(bool forward) {
|
|
|
|
[window_ setAcceptsMouseMovedEvents:forward];
|
|
|
|
}
|
|
|
|
|
2018-07-10 04:09:46 +00:00
|
|
|
void NativeWindowMac::OverrideNSWindowContentView() {
|
|
|
|
// When using `views::Widget` to hold WebContents, Chromium would use
|
|
|
|
// `BridgedContentView` as content view, which does not support draggable
|
|
|
|
// regions. In order to make draggable regions work, we have to replace the
|
|
|
|
// content view with a simple NSView.
|
|
|
|
container_view_.reset([[FullSizeContentView alloc] init]);
|
|
|
|
[container_view_
|
|
|
|
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
|
|
|
[container_view_ setFrame:[[[window_ contentView] superview] bounds]];
|
|
|
|
[window_ setContentView:container_view_];
|
|
|
|
AddContentViewLayers();
|
|
|
|
}
|
|
|
|
|
2016-01-23 11:12:19 +00:00
|
|
|
void NativeWindowMac::SetStyleMask(bool on, NSUInteger flag) {
|
2016-08-15 20:14:19 +00:00
|
|
|
// Changing the styleMask of a frameless windows causes it to change size so
|
|
|
|
// we explicitly disable resizing while setting it.
|
|
|
|
ScopedDisableResize disable_resize;
|
|
|
|
|
2016-08-04 23:47:03 +00:00
|
|
|
bool was_maximizable = IsMaximizable();
|
2016-01-23 11:12:19 +00:00
|
|
|
if (on)
|
|
|
|
[window_ setStyleMask:[window_ styleMask] | flag];
|
|
|
|
else
|
|
|
|
[window_ setStyleMask:[window_ styleMask] & (~flag)];
|
|
|
|
// Change style mask will make the zoom button revert to default, probably
|
2016-06-18 13:26:26 +00:00
|
|
|
// a bug of Cocoa or macOS.
|
2016-08-04 23:47:03 +00:00
|
|
|
SetMaximizable(was_maximizable);
|
2016-01-23 11:12:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void NativeWindowMac::SetCollectionBehavior(bool on, NSUInteger flag) {
|
2016-08-04 23:47:03 +00:00
|
|
|
bool was_maximizable = IsMaximizable();
|
2016-01-23 11:12:19 +00:00
|
|
|
if (on)
|
|
|
|
[window_ setCollectionBehavior:[window_ collectionBehavior] | flag];
|
|
|
|
else
|
|
|
|
[window_ setCollectionBehavior:[window_ collectionBehavior] & (~flag)];
|
|
|
|
// Change collectionBehavior will make the zoom button revert to default,
|
2016-06-18 13:26:26 +00:00
|
|
|
// probably a bug of Cocoa or macOS.
|
2016-08-04 23:47:03 +00:00
|
|
|
SetMaximizable(was_maximizable);
|
2016-01-23 11:12:19 +00:00
|
|
|
}
|
|
|
|
|
2013-04-12 07:04:46 +00:00
|
|
|
// static
|
2018-04-08 11:20:43 +00:00
|
|
|
NativeWindow* NativeWindow::Create(const mate::Dictionary& options,
|
|
|
|
NativeWindow* parent) {
|
|
|
|
return new NativeWindowMac(options, parent);
|
2013-04-12 07:04:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace atom
|