native_window_mac.mm 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462
  1. // Copyright (c) 2013 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/browser/native_window_mac.h"
  5. #include <AvailabilityMacros.h>
  6. #include <objc/objc-runtime.h>
  7. #include <string>
  8. #include "atom/browser/native_browser_view_mac.h"
  9. #include "atom/browser/ui/cocoa/atom_native_widget_mac.h"
  10. #include "atom/browser/ui/cocoa/atom_ns_window.h"
  11. #include "atom/browser/ui/cocoa/atom_ns_window_delegate.h"
  12. #include "atom/browser/ui/cocoa/atom_preview_item.h"
  13. #include "atom/browser/ui/cocoa/atom_touch_bar.h"
  14. #include "atom/browser/ui/cocoa/root_view_mac.h"
  15. #include "atom/browser/window_list.h"
  16. #include "atom/common/options_switches.h"
  17. #include "base/mac/mac_util.h"
  18. #include "base/mac/scoped_cftyperef.h"
  19. #include "base/strings/sys_string_conversions.h"
  20. #include "brightray/browser/inspectable_web_contents.h"
  21. #include "brightray/browser/inspectable_web_contents_view.h"
  22. #include "content/public/browser/browser_accessibility_state.h"
  23. #include "native_mate/dictionary.h"
  24. #include "skia/ext/skia_utils_mac.h"
  25. #include "ui/gfx/skia_util.h"
  26. #include "ui/gl/gpu_switching_manager.h"
  27. #include "ui/views/background.h"
  28. #include "ui/views/cocoa/bridged_native_widget.h"
  29. #include "ui/views/widget/widget.h"
  30. // This view always takes the size of its superview. It is intended to be used
  31. // as a NSWindow's contentView. It is needed because NSWindow's implementation
  32. // explicitly resizes the contentView at inopportune times.
  33. @interface FullSizeContentView : NSView
  34. @end
  35. @implementation FullSizeContentView
  36. // This method is directly called by NSWindow during a window resize on OSX
  37. // 10.10.0, beta 2. We must override it to prevent the content view from
  38. // shrinking.
  39. - (void)setFrameSize:(NSSize)size {
  40. if ([self superview])
  41. size = [[self superview] bounds].size;
  42. [super setFrameSize:size];
  43. }
  44. // The contentView gets moved around during certain full-screen operations.
  45. // This is less than ideal, and should eventually be removed.
  46. - (void)viewDidMoveToSuperview {
  47. [self setFrame:[[self superview] bounds]];
  48. }
  49. @end
  50. // Custom Quit, Minimize and Full Screen button container for frameless
  51. // windows.
  52. @interface CustomWindowButtonView : NSView {
  53. @private
  54. BOOL mouse_inside_;
  55. }
  56. @end
  57. @implementation CustomWindowButtonView
  58. - (id)initWithFrame:(NSRect)frame {
  59. self = [super initWithFrame:frame];
  60. NSButton* close_button = [NSWindow standardWindowButton:NSWindowCloseButton
  61. forStyleMask:NSTitledWindowMask];
  62. NSButton* miniaturize_button =
  63. [NSWindow standardWindowButton:NSWindowMiniaturizeButton
  64. forStyleMask:NSWindowStyleMaskTitled];
  65. CGFloat x = 0;
  66. const CGFloat space_between = 20;
  67. [close_button setFrameOrigin:NSMakePoint(x, 0)];
  68. x += space_between;
  69. [self addSubview:close_button];
  70. [miniaturize_button setFrameOrigin:NSMakePoint(x, 0)];
  71. x += space_between;
  72. [self addSubview:miniaturize_button];
  73. const auto last_button_frame = miniaturize_button.frame;
  74. [self setFrameSize:NSMakeSize(last_button_frame.origin.x +
  75. last_button_frame.size.width,
  76. last_button_frame.size.height)];
  77. mouse_inside_ = NO;
  78. [self setNeedsDisplayForButtons];
  79. return self;
  80. }
  81. - (void)viewDidMoveToWindow {
  82. if (!self.window) {
  83. return;
  84. }
  85. // Stay in upper left corner.
  86. const CGFloat top_margin = 3;
  87. const CGFloat left_margin = 7;
  88. [self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
  89. [self setFrameOrigin:NSMakePoint(left_margin, self.window.frame.size.height -
  90. self.frame.size.height -
  91. top_margin)];
  92. }
  93. - (BOOL)_mouseInGroup:(NSButton*)button {
  94. return mouse_inside_;
  95. }
  96. - (void)updateTrackingAreas {
  97. auto tracking_area = [[[NSTrackingArea alloc]
  98. initWithRect:NSZeroRect
  99. options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways |
  100. NSTrackingInVisibleRect
  101. owner:self
  102. userInfo:nil] autorelease];
  103. [self addTrackingArea:tracking_area];
  104. }
  105. - (void)mouseEntered:(NSEvent*)event {
  106. [super mouseEntered:event];
  107. mouse_inside_ = YES;
  108. [self setNeedsDisplayForButtons];
  109. }
  110. - (void)mouseExited:(NSEvent*)event {
  111. [super mouseExited:event];
  112. mouse_inside_ = NO;
  113. [self setNeedsDisplayForButtons];
  114. }
  115. - (void)setNeedsDisplayForButtons {
  116. for (NSView* subview in self.subviews) {
  117. [subview setHidden:!mouse_inside_];
  118. [subview setNeedsDisplay:YES];
  119. }
  120. }
  121. @end
  122. #if !defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER)
  123. enum { NSWindowTabbingModeDisallowed = 2 };
  124. @interface NSWindow (SierraSDK)
  125. - (void)setTabbingMode:(NSInteger)mode;
  126. - (void)setTabbingIdentifier:(NSString*)identifier;
  127. - (void)addTabbedWindow:(NSWindow*)window ordered:(NSWindowOrderingMode)ordered;
  128. - (IBAction)selectPreviousTab:(id)sender;
  129. - (IBAction)selectNextTab:(id)sender;
  130. - (IBAction)mergeAllWindows:(id)sender;
  131. - (IBAction)moveTabToNewWindow:(id)sender;
  132. - (IBAction)toggleTabBar:(id)sender;
  133. @end
  134. #endif
  135. @interface AtomProgressBar : NSProgressIndicator
  136. @end
  137. @implementation AtomProgressBar
  138. - (void)drawRect:(NSRect)dirtyRect {
  139. if (self.style != NSProgressIndicatorBarStyle)
  140. return;
  141. // Draw edges of rounded rect.
  142. NSRect rect = NSInsetRect([self bounds], 1.0, 1.0);
  143. CGFloat radius = rect.size.height / 2;
  144. NSBezierPath* bezier_path = [NSBezierPath bezierPathWithRoundedRect:rect
  145. xRadius:radius
  146. yRadius:radius];
  147. [bezier_path setLineWidth:2.0];
  148. [[NSColor grayColor] set];
  149. [bezier_path stroke];
  150. // Fill the rounded rect.
  151. rect = NSInsetRect(rect, 2.0, 2.0);
  152. radius = rect.size.height / 2;
  153. bezier_path = [NSBezierPath bezierPathWithRoundedRect:rect
  154. xRadius:radius
  155. yRadius:radius];
  156. [bezier_path setLineWidth:1.0];
  157. [bezier_path addClip];
  158. // Calculate the progress width.
  159. rect.size.width =
  160. floor(rect.size.width * ([self doubleValue] / [self maxValue]));
  161. // Fill the progress bar with color blue.
  162. [[NSColor colorWithSRGBRed:0.2 green:0.6 blue:1 alpha:1] set];
  163. NSRectFill(rect);
  164. }
  165. @end
  166. namespace mate {
  167. template <>
  168. struct Converter<atom::NativeWindowMac::TitleBarStyle> {
  169. static bool FromV8(v8::Isolate* isolate,
  170. v8::Handle<v8::Value> val,
  171. atom::NativeWindowMac::TitleBarStyle* out) {
  172. std::string title_bar_style;
  173. if (!ConvertFromV8(isolate, val, &title_bar_style))
  174. return false;
  175. if (title_bar_style == "hidden") {
  176. *out = atom::NativeWindowMac::HIDDEN;
  177. } else if (title_bar_style == "hiddenInset") {
  178. *out = atom::NativeWindowMac::HIDDEN_INSET;
  179. } else if (title_bar_style == "customButtonsOnHover") {
  180. *out = atom::NativeWindowMac::CUSTOM_BUTTONS_ON_HOVER;
  181. } else {
  182. return false;
  183. }
  184. return true;
  185. }
  186. };
  187. } // namespace mate
  188. namespace atom {
  189. namespace {
  190. bool IsFramelessWindow(NSView* view) {
  191. NativeWindow* window = [static_cast<AtomNSWindow*>([view window]) shell];
  192. return window && !window->has_frame();
  193. }
  194. IMP original_set_frame_size = nullptr;
  195. IMP original_view_did_move_to_superview = nullptr;
  196. // This method is directly called by NSWindow during a window resize on OSX
  197. // 10.10.0, beta 2. We must override it to prevent the content view from
  198. // shrinking.
  199. void SetFrameSize(NSView* self, SEL _cmd, NSSize size) {
  200. if (!IsFramelessWindow(self)) {
  201. auto original =
  202. reinterpret_cast<decltype(&SetFrameSize)>(original_set_frame_size);
  203. return original(self, _cmd, size);
  204. }
  205. // For frameless window, resize the view to cover full window.
  206. if ([self superview])
  207. size = [[self superview] bounds].size;
  208. auto super_impl = reinterpret_cast<decltype(&SetFrameSize)>(
  209. [[self superclass] instanceMethodForSelector:_cmd]);
  210. super_impl(self, _cmd, size);
  211. }
  212. // The contentView gets moved around during certain full-screen operations.
  213. // This is less than ideal, and should eventually be removed.
  214. void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
  215. if (!IsFramelessWindow(self)) {
  216. // [BridgedContentView viewDidMoveToSuperview];
  217. auto original = reinterpret_cast<decltype(&ViewDidMoveToSuperview)>(
  218. original_view_did_move_to_superview);
  219. if (original)
  220. original(self, _cmd);
  221. return;
  222. }
  223. [self setFrame:[[self superview] bounds]];
  224. }
  225. } // namespace
  226. NativeWindowMac::NativeWindowMac(const mate::Dictionary& options,
  227. NativeWindow* parent)
  228. : NativeWindow(options, parent), root_view_(new RootViewMac(this)) {
  229. int width = 800, height = 600;
  230. options.Get(options::kWidth, &width);
  231. options.Get(options::kHeight, &height);
  232. NSRect main_screen_rect = [[[NSScreen screens] firstObject] frame];
  233. gfx::Rect bounds(round((NSWidth(main_screen_rect) - width) / 2),
  234. round((NSHeight(main_screen_rect) - height) / 2), width,
  235. height);
  236. options.Get(options::kResizable, &resizable_);
  237. options.Get(options::kTitleBarStyle, &title_bar_style_);
  238. options.Get(options::kZoomToPageWidth, &zoom_to_page_width_);
  239. options.Get(options::kFullscreenWindowTitle, &fullscreen_window_title_);
  240. options.Get(options::kSimpleFullScreen, &always_simple_fullscreen_);
  241. bool minimizable = true;
  242. options.Get(options::kMinimizable, &minimizable);
  243. bool maximizable = true;
  244. options.Get(options::kMaximizable, &maximizable);
  245. bool closable = true;
  246. options.Get(options::kClosable, &closable);
  247. std::string tabbingIdentifier;
  248. options.Get(options::kTabbingIdentifier, &tabbingIdentifier);
  249. std::string windowType;
  250. options.Get(options::kType, &windowType);
  251. bool useStandardWindow = true;
  252. // eventually deprecate separate "standardWindow" option in favor of
  253. // standard / textured window types
  254. options.Get(options::kStandardWindow, &useStandardWindow);
  255. if (windowType == "textured") {
  256. useStandardWindow = false;
  257. }
  258. NSUInteger styleMask = NSTitledWindowMask;
  259. if (@available(macOS 10.10, *)) {
  260. if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER &&
  261. (!useStandardWindow || transparent() || !has_frame())) {
  262. styleMask = NSFullSizeContentViewWindowMask;
  263. }
  264. }
  265. if (minimizable) {
  266. styleMask |= NSMiniaturizableWindowMask;
  267. }
  268. if (closable) {
  269. styleMask |= NSClosableWindowMask;
  270. }
  271. if (title_bar_style_ != NORMAL) {
  272. // The window without titlebar is treated the same with frameless window.
  273. set_has_frame(false);
  274. }
  275. if (!useStandardWindow || transparent() || !has_frame()) {
  276. styleMask |= NSTexturedBackgroundWindowMask;
  277. }
  278. if (resizable_) {
  279. styleMask |= NSResizableWindowMask;
  280. }
  281. // Create views::Widget and assign window_ with it.
  282. // TODO(zcbenz): Get rid of the window_ in future.
  283. views::Widget::InitParams params;
  284. params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  285. params.bounds = bounds;
  286. params.delegate = this;
  287. params.type = views::Widget::InitParams::TYPE_WINDOW;
  288. params.native_widget = new AtomNativeWidgetMac(this, styleMask, widget());
  289. widget()->Init(params);
  290. window_ = static_cast<AtomNSWindow*>(widget()->GetNativeWindow());
  291. [window_ setEnableLargerThanScreen:enable_larger_than_screen()];
  292. window_delegate_.reset([[AtomNSWindowDelegate alloc] initWithShell:this]);
  293. [window_ setDelegate:window_delegate_];
  294. // Only use native parent window for non-modal windows.
  295. if (parent && !is_modal()) {
  296. SetParentWindow(parent);
  297. }
  298. if (transparent()) {
  299. // Setting the background color to clear will also hide the shadow.
  300. [window_ setBackgroundColor:[NSColor clearColor]];
  301. }
  302. if (windowType == "desktop") {
  303. [window_ setLevel:kCGDesktopWindowLevel - 1];
  304. [window_ setDisableKeyOrMainWindow:YES];
  305. [window_ setCollectionBehavior:(NSWindowCollectionBehaviorCanJoinAllSpaces |
  306. NSWindowCollectionBehaviorStationary |
  307. NSWindowCollectionBehaviorIgnoresCycle)];
  308. }
  309. bool focusable;
  310. if (options.Get(options::kFocusable, &focusable) && !focusable)
  311. [window_ setDisableKeyOrMainWindow:YES];
  312. if (transparent() || !has_frame()) {
  313. if (@available(macOS 10.10, *)) {
  314. // Don't show title bar.
  315. [window_ setTitlebarAppearsTransparent:YES];
  316. [window_ setTitleVisibility:NSWindowTitleHidden];
  317. }
  318. // Remove non-transparent corners, see http://git.io/vfonD.
  319. [window_ setOpaque:NO];
  320. }
  321. // Create a tab only if tabbing identifier is specified and window has
  322. // a native title bar.
  323. if (tabbingIdentifier.empty() || transparent() || !has_frame()) {
  324. if (@available(macOS 10.12, *)) {
  325. [window_ setTabbingMode:NSWindowTabbingModeDisallowed];
  326. }
  327. } else {
  328. if (@available(macOS 10.12, *)) {
  329. [window_ setTabbingIdentifier:base::SysUTF8ToNSString(tabbingIdentifier)];
  330. }
  331. }
  332. // Hide the title bar background
  333. if (title_bar_style_ != NORMAL) {
  334. if (@available(macOS 10.10, *)) {
  335. [window_ setTitlebarAppearsTransparent:YES];
  336. }
  337. }
  338. // Hide the title bar.
  339. if (title_bar_style_ == HIDDEN_INSET) {
  340. if (@available(macOS 10.10, *)) {
  341. base::scoped_nsobject<NSToolbar> toolbar(
  342. [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
  343. [toolbar setShowsBaselineSeparator:NO];
  344. [window_ setToolbar:toolbar];
  345. } else {
  346. [window_ enableWindowButtonsOffset];
  347. [window_ setWindowButtonsOffset:NSMakePoint(12, 10)];
  348. }
  349. }
  350. // Resize to content bounds.
  351. bool use_content_size = false;
  352. options.Get(options::kUseContentSize, &use_content_size);
  353. if (!has_frame() || use_content_size)
  354. SetContentSize(gfx::Size(width, height));
  355. // Enable the NSView to accept first mouse event.
  356. bool acceptsFirstMouse = false;
  357. options.Get(options::kAcceptFirstMouse, &acceptsFirstMouse);
  358. [window_ setAcceptsFirstMouse:acceptsFirstMouse];
  359. // Disable auto-hiding cursor.
  360. bool disableAutoHideCursor = false;
  361. options.Get(options::kDisableAutoHideCursor, &disableAutoHideCursor);
  362. [window_ setDisableAutoHideCursor:disableAutoHideCursor];
  363. // Use an NSEvent monitor to listen for the wheel event.
  364. BOOL __block began = NO;
  365. wheel_event_monitor_ = [NSEvent
  366. addLocalMonitorForEventsMatchingMask:NSScrollWheelMask
  367. handler:^(NSEvent* event) {
  368. if ([[event window] windowNumber] !=
  369. [window_ windowNumber])
  370. return event;
  371. if (!began && (([event phase] ==
  372. NSEventPhaseMayBegin) ||
  373. ([event phase] ==
  374. NSEventPhaseBegan))) {
  375. this->NotifyWindowScrollTouchBegin();
  376. began = YES;
  377. } else if (began &&
  378. (([event phase] ==
  379. NSEventPhaseEnded) ||
  380. ([event phase] ==
  381. NSEventPhaseCancelled))) {
  382. this->NotifyWindowScrollTouchEnd();
  383. began = NO;
  384. }
  385. return event;
  386. }];
  387. // Set maximizable state last to ensure zoom button does not get reset
  388. // by calls to other APIs.
  389. SetMaximizable(maximizable);
  390. // Default content view.
  391. SetContentView(new views::View());
  392. AddContentViewLayers();
  393. original_frame_ = [window_ frame];
  394. original_level_ = [window_ level];
  395. }
  396. NativeWindowMac::~NativeWindowMac() {
  397. if (wheel_event_monitor_)
  398. [NSEvent removeMonitor:wheel_event_monitor_];
  399. }
  400. void NativeWindowMac::SetContentView(views::View* view) {
  401. views::View* root_view = GetContentsView();
  402. if (content_view())
  403. root_view->RemoveChildView(content_view());
  404. set_content_view(view);
  405. root_view->AddChildView(content_view());
  406. if (buttons_view_) {
  407. // Ensure the buttons view are always floated on the top.
  408. [buttons_view_ removeFromSuperview];
  409. [[window_ contentView] addSubview:buttons_view_];
  410. }
  411. root_view->Layout();
  412. }
  413. void NativeWindowMac::Close() {
  414. // When this is a sheet showing, performClose won't work.
  415. if (is_modal() && parent() && IsVisible()) {
  416. [parent()->GetNativeWindow() endSheet:window_];
  417. CloseImmediately();
  418. return;
  419. }
  420. if (!IsClosable()) {
  421. WindowList::WindowCloseCancelled(this);
  422. return;
  423. }
  424. [window_ performClose:nil];
  425. }
  426. void NativeWindowMac::CloseImmediately() {
  427. // Remove event monitor before destroying window, otherwise the monitor may
  428. // call its callback after window has been destroyed.
  429. if (wheel_event_monitor_) {
  430. [NSEvent removeMonitor:wheel_event_monitor_];
  431. wheel_event_monitor_ = nil;
  432. }
  433. // Retain the child window before closing it. If the last reference to the
  434. // NSWindow goes away inside -[NSWindow close], then bad stuff can happen.
  435. // See e.g. http://crbug.com/616701.
  436. base::scoped_nsobject<NSWindow> child_window(window_,
  437. base::scoped_policy::RETAIN);
  438. [window_ close];
  439. }
  440. void NativeWindowMac::Focus(bool focus) {
  441. if (!IsVisible())
  442. return;
  443. if (focus) {
  444. [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
  445. [window_ makeKeyAndOrderFront:nil];
  446. } else {
  447. [window_ orderBack:nil];
  448. }
  449. }
  450. bool NativeWindowMac::IsFocused() {
  451. return [window_ isKeyWindow];
  452. }
  453. void NativeWindowMac::Show() {
  454. if (is_modal() && parent()) {
  455. if ([window_ sheetParent] == nil)
  456. [parent()->GetNativeWindow() beginSheet:window_
  457. completionHandler:^(NSModalResponse){
  458. }];
  459. return;
  460. }
  461. // Reattach the window to the parent to actually show it.
  462. if (parent())
  463. InternalSetParentWindow(parent(), true);
  464. // This method is supposed to put focus on window, however if the app does not
  465. // have focus then "makeKeyAndOrderFront" will only show the window.
  466. [NSApp activateIgnoringOtherApps:YES];
  467. [window_ makeKeyAndOrderFront:nil];
  468. }
  469. void NativeWindowMac::ShowInactive() {
  470. // Reattach the window to the parent to actually show it.
  471. if (parent())
  472. InternalSetParentWindow(parent(), true);
  473. [window_ orderFrontRegardless];
  474. }
  475. void NativeWindowMac::Hide() {
  476. if (is_modal() && parent()) {
  477. [window_ orderOut:nil];
  478. [parent()->GetNativeWindow() endSheet:window_];
  479. return;
  480. }
  481. // Deattach the window from the parent before.
  482. if (parent())
  483. InternalSetParentWindow(parent(), false);
  484. [window_ orderOut:nil];
  485. }
  486. bool NativeWindowMac::IsVisible() {
  487. return [window_ isVisible];
  488. }
  489. bool NativeWindowMac::IsEnabled() {
  490. return [window_ attachedSheet] == nil;
  491. }
  492. void NativeWindowMac::SetEnabled(bool enable) {
  493. if (enable) {
  494. [window_ endSheet:[window_ attachedSheet]];
  495. } else {
  496. [window_ beginSheet:window_
  497. completionHandler:^(NSModalResponse returnCode) {
  498. NSLog(@"modal enabled");
  499. return;
  500. }];
  501. }
  502. }
  503. void NativeWindowMac::Maximize() {
  504. if (IsMaximized())
  505. return;
  506. [window_ zoom:nil];
  507. }
  508. void NativeWindowMac::Unmaximize() {
  509. if (!IsMaximized())
  510. return;
  511. [window_ zoom:nil];
  512. }
  513. bool NativeWindowMac::IsMaximized() {
  514. if (([window_ styleMask] & NSResizableWindowMask) != 0) {
  515. return [window_ isZoomed];
  516. } else {
  517. NSRect rectScreen = [[NSScreen mainScreen] visibleFrame];
  518. NSRect rectWindow = [window_ frame];
  519. return (rectScreen.origin.x == rectWindow.origin.x &&
  520. rectScreen.origin.y == rectWindow.origin.y &&
  521. rectScreen.size.width == rectWindow.size.width &&
  522. rectScreen.size.height == rectWindow.size.height);
  523. }
  524. }
  525. void NativeWindowMac::Minimize() {
  526. [window_ miniaturize:nil];
  527. }
  528. void NativeWindowMac::Restore() {
  529. [window_ deminiaturize:nil];
  530. }
  531. bool NativeWindowMac::IsMinimized() {
  532. return [window_ isMiniaturized];
  533. }
  534. void NativeWindowMac::SetFullScreen(bool fullscreen) {
  535. if (fullscreen == IsFullscreen())
  536. return;
  537. [window_ toggleFullScreenMode:nil];
  538. }
  539. bool NativeWindowMac::IsFullscreen() const {
  540. return [window_ styleMask] & NSFullScreenWindowMask;
  541. }
  542. void NativeWindowMac::SetBounds(const gfx::Rect& bounds, bool animate) {
  543. // Do nothing if in fullscreen mode.
  544. if (IsFullscreen())
  545. return;
  546. // Check size constraints since setFrame does not check it.
  547. gfx::Size size = bounds.size();
  548. size.SetToMax(GetMinimumSize());
  549. gfx::Size max_size = GetMaximumSize();
  550. if (!max_size.IsEmpty())
  551. size.SetToMin(max_size);
  552. NSRect cocoa_bounds = NSMakeRect(bounds.x(), 0, size.width(), size.height());
  553. // Flip coordinates based on the primary screen.
  554. NSScreen* screen = [[NSScreen screens] firstObject];
  555. cocoa_bounds.origin.y = NSHeight([screen frame]) - size.height() - bounds.y();
  556. [window_ setFrame:cocoa_bounds display:YES animate:animate];
  557. }
  558. gfx::Rect NativeWindowMac::GetBounds() {
  559. NSRect frame = [window_ frame];
  560. gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame));
  561. NSScreen* screen = [[NSScreen screens] firstObject];
  562. bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame));
  563. return bounds;
  564. }
  565. void NativeWindowMac::SetContentSizeConstraints(
  566. const extensions::SizeConstraints& size_constraints) {
  567. auto convertSize = [this](const gfx::Size& size) {
  568. // Our frameless window still has titlebar attached, so setting contentSize
  569. // will result in actual content size being larger.
  570. if (!has_frame()) {
  571. NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
  572. NSRect content = [window_ originalContentRectForFrameRect:frame];
  573. return content.size;
  574. } else {
  575. return NSMakeSize(size.width(), size.height());
  576. }
  577. };
  578. NSView* content = [window_ contentView];
  579. if (size_constraints.HasMinimumSize()) {
  580. NSSize min_size = convertSize(size_constraints.GetMinimumSize());
  581. [window_ setContentMinSize:[content convertSize:min_size toView:nil]];
  582. }
  583. if (size_constraints.HasMaximumSize()) {
  584. NSSize max_size = convertSize(size_constraints.GetMaximumSize());
  585. [window_ setContentMaxSize:[content convertSize:max_size toView:nil]];
  586. }
  587. NativeWindow::SetContentSizeConstraints(size_constraints);
  588. }
  589. void NativeWindowMac::MoveTop() {
  590. [window_ orderWindow:NSWindowAbove relativeTo:0];
  591. }
  592. void NativeWindowMac::SetResizable(bool resizable) {
  593. SetStyleMask(resizable, NSResizableWindowMask);
  594. }
  595. bool NativeWindowMac::IsResizable() {
  596. return [window_ styleMask] & NSResizableWindowMask;
  597. }
  598. void NativeWindowMac::SetAspectRatio(double aspect_ratio,
  599. const gfx::Size& extra_size) {
  600. NativeWindow::SetAspectRatio(aspect_ratio, extra_size);
  601. // Reset the behaviour to default if aspect_ratio is set to 0 or less.
  602. if (aspect_ratio > 0.0)
  603. [window_ setAspectRatio:NSMakeSize(aspect_ratio, 1.0)];
  604. else
  605. [window_ setResizeIncrements:NSMakeSize(1.0, 1.0)];
  606. }
  607. void NativeWindowMac::PreviewFile(const std::string& path,
  608. const std::string& display_name) {
  609. preview_item_.reset([[AtomPreviewItem alloc]
  610. initWithURL:[NSURL fileURLWithPath:base::SysUTF8ToNSString(path)]
  611. title:base::SysUTF8ToNSString(display_name)]);
  612. [[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
  613. }
  614. void NativeWindowMac::CloseFilePreview() {
  615. if ([QLPreviewPanel sharedPreviewPanelExists]) {
  616. [[QLPreviewPanel sharedPreviewPanel] close];
  617. }
  618. }
  619. void NativeWindowMac::SetMovable(bool movable) {
  620. [window_ setMovable:movable];
  621. }
  622. bool NativeWindowMac::IsMovable() {
  623. return [window_ isMovable];
  624. }
  625. void NativeWindowMac::SetMinimizable(bool minimizable) {
  626. SetStyleMask(minimizable, NSMiniaturizableWindowMask);
  627. }
  628. bool NativeWindowMac::IsMinimizable() {
  629. return [window_ styleMask] & NSMiniaturizableWindowMask;
  630. }
  631. void NativeWindowMac::SetMaximizable(bool maximizable) {
  632. [[window_ standardWindowButton:NSWindowZoomButton] setEnabled:maximizable];
  633. }
  634. bool NativeWindowMac::IsMaximizable() {
  635. return [[window_ standardWindowButton:NSWindowZoomButton] isEnabled];
  636. }
  637. void NativeWindowMac::SetFullScreenable(bool fullscreenable) {
  638. SetCollectionBehavior(fullscreenable,
  639. NSWindowCollectionBehaviorFullScreenPrimary);
  640. // On EL Capitan this flag is required to hide fullscreen button.
  641. SetCollectionBehavior(!fullscreenable,
  642. NSWindowCollectionBehaviorFullScreenAuxiliary);
  643. }
  644. bool NativeWindowMac::IsFullScreenable() {
  645. NSUInteger collectionBehavior = [window_ collectionBehavior];
  646. return collectionBehavior & NSWindowCollectionBehaviorFullScreenPrimary;
  647. }
  648. void NativeWindowMac::SetClosable(bool closable) {
  649. SetStyleMask(closable, NSClosableWindowMask);
  650. }
  651. bool NativeWindowMac::IsClosable() {
  652. return [window_ styleMask] & NSClosableWindowMask;
  653. }
  654. void NativeWindowMac::SetAlwaysOnTop(bool top,
  655. const std::string& level,
  656. int relativeLevel,
  657. std::string* error) {
  658. int windowLevel = NSNormalWindowLevel;
  659. CGWindowLevel maxWindowLevel = CGWindowLevelForKey(kCGMaximumWindowLevelKey);
  660. CGWindowLevel minWindowLevel = CGWindowLevelForKey(kCGMinimumWindowLevelKey);
  661. if (top) {
  662. if (level == "floating") {
  663. windowLevel = NSFloatingWindowLevel;
  664. } else if (level == "torn-off-menu") {
  665. windowLevel = NSTornOffMenuWindowLevel;
  666. } else if (level == "modal-panel") {
  667. windowLevel = NSModalPanelWindowLevel;
  668. } else if (level == "main-menu") {
  669. windowLevel = NSMainMenuWindowLevel;
  670. } else if (level == "status") {
  671. windowLevel = NSStatusWindowLevel;
  672. } else if (level == "pop-up-menu") {
  673. windowLevel = NSPopUpMenuWindowLevel;
  674. } else if (level == "screen-saver") {
  675. windowLevel = NSScreenSaverWindowLevel;
  676. } else if (level == "dock") {
  677. // Deprecated by macOS, but kept for backwards compatibility
  678. windowLevel = NSDockWindowLevel;
  679. }
  680. }
  681. NSInteger newLevel = windowLevel + relativeLevel;
  682. if (newLevel >= minWindowLevel && newLevel <= maxWindowLevel) {
  683. [window_ setLevel:newLevel];
  684. } else {
  685. *error = std::string([
  686. [NSString stringWithFormat:@"relativeLevel must be between %d and %d",
  687. minWindowLevel, maxWindowLevel] UTF8String]);
  688. }
  689. }
  690. bool NativeWindowMac::IsAlwaysOnTop() {
  691. return [window_ level] != NSNormalWindowLevel;
  692. }
  693. void NativeWindowMac::Center() {
  694. [window_ center];
  695. }
  696. void NativeWindowMac::Invalidate() {
  697. [window_ flushWindow];
  698. [[window_ contentView] setNeedsDisplay:YES];
  699. }
  700. void NativeWindowMac::SetTitle(const std::string& title) {
  701. // For macOS <= 10.9, the setTitleVisibility API is not available, we have
  702. // to avoid calling setTitle for frameless window.
  703. if (!base::mac::IsAtLeastOS10_10() && (transparent() || !has_frame()))
  704. return;
  705. [window_ setTitle:base::SysUTF8ToNSString(title)];
  706. }
  707. std::string NativeWindowMac::GetTitle() {
  708. return base::SysNSStringToUTF8([window_ title]);
  709. ;
  710. }
  711. void NativeWindowMac::FlashFrame(bool flash) {
  712. if (flash) {
  713. attention_request_id_ = [NSApp requestUserAttention:NSInformationalRequest];
  714. } else {
  715. [NSApp cancelUserAttentionRequest:attention_request_id_];
  716. attention_request_id_ = 0;
  717. }
  718. }
  719. void NativeWindowMac::SetSkipTaskbar(bool skip) {}
  720. void NativeWindowMac::SetSimpleFullScreen(bool simple_fullscreen) {
  721. NSWindow* window = GetNativeWindow();
  722. if (simple_fullscreen && !is_simple_fullscreen_) {
  723. is_simple_fullscreen_ = true;
  724. // Take note of the current window size and level
  725. original_frame_ = [window frame];
  726. original_level_ = [window level];
  727. simple_fullscreen_options_ = [NSApp currentSystemPresentationOptions];
  728. simple_fullscreen_mask_ = [window styleMask];
  729. // We can simulate the pre-Lion fullscreen by auto-hiding the dock and menu
  730. // bar
  731. NSApplicationPresentationOptions options =
  732. NSApplicationPresentationAutoHideDock +
  733. NSApplicationPresentationAutoHideMenuBar;
  734. [NSApp setPresentationOptions:options];
  735. was_maximizable_ = IsMaximizable();
  736. was_movable_ = IsMovable();
  737. NSRect fullscreenFrame = [window.screen frame];
  738. // If our app has dock hidden, set the window level higher so another app's
  739. // menu bar doesn't appear on top of our fullscreen app.
  740. if ([[NSRunningApplication currentApplication] activationPolicy] !=
  741. NSApplicationActivationPolicyRegular) {
  742. window.level = NSPopUpMenuWindowLevel;
  743. }
  744. if (!fullscreen_window_title()) {
  745. // Hide the titlebar
  746. SetStyleMask(false, NSTitledWindowMask);
  747. // Resize the window to accomodate the _entire_ screen size
  748. fullscreenFrame.size.height -=
  749. [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
  750. } else {
  751. // No need to hide the title, but we should still hide the window buttons
  752. [[window standardWindowButton:NSWindowZoomButton] setHidden:YES];
  753. [[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
  754. [[window standardWindowButton:NSWindowCloseButton] setHidden:YES];
  755. }
  756. [window setFrame:fullscreenFrame display:YES animate:YES];
  757. // Fullscreen windows can't be resized, minimized, maximized, or moved
  758. SetMinimizable(false);
  759. SetResizable(false);
  760. SetMaximizable(false);
  761. SetMovable(false);
  762. } else if (!simple_fullscreen && is_simple_fullscreen_) {
  763. is_simple_fullscreen_ = false;
  764. if (!fullscreen_window_title()) {
  765. // Restore the titlebar
  766. SetStyleMask(true, NSTitledWindowMask);
  767. } else {
  768. // Show the window buttons
  769. [[window standardWindowButton:NSWindowZoomButton] setHidden:NO];
  770. [[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:NO];
  771. [[window standardWindowButton:NSWindowCloseButton] setHidden:NO];
  772. }
  773. [window setFrame:original_frame_ display:YES animate:YES];
  774. window.level = original_level_;
  775. [NSApp setPresentationOptions:simple_fullscreen_options_];
  776. // Restore original style mask
  777. ScopedDisableResize disable_resize;
  778. [window_ setStyleMask:simple_fullscreen_mask_];
  779. // Restore window manipulation abilities
  780. SetMaximizable(was_maximizable_);
  781. SetMovable(was_movable_);
  782. }
  783. }
  784. bool NativeWindowMac::IsSimpleFullScreen() {
  785. return is_simple_fullscreen_;
  786. }
  787. void NativeWindowMac::SetKiosk(bool kiosk) {
  788. if (kiosk && !is_kiosk_) {
  789. kiosk_options_ = [NSApp currentSystemPresentationOptions];
  790. NSApplicationPresentationOptions options =
  791. NSApplicationPresentationHideDock +
  792. NSApplicationPresentationHideMenuBar +
  793. NSApplicationPresentationDisableAppleMenu +
  794. NSApplicationPresentationDisableProcessSwitching +
  795. NSApplicationPresentationDisableForceQuit +
  796. NSApplicationPresentationDisableSessionTermination +
  797. NSApplicationPresentationDisableHideApplication;
  798. [NSApp setPresentationOptions:options];
  799. is_kiosk_ = true;
  800. was_fullscreen_ = IsFullscreen();
  801. if (!was_fullscreen_)
  802. SetFullScreen(true);
  803. } else if (!kiosk && is_kiosk_) {
  804. is_kiosk_ = false;
  805. if (!was_fullscreen_)
  806. SetFullScreen(false);
  807. [NSApp setPresentationOptions:kiosk_options_];
  808. }
  809. }
  810. bool NativeWindowMac::IsKiosk() {
  811. return is_kiosk_;
  812. }
  813. void NativeWindowMac::SetBackgroundColor(SkColor color) {
  814. base::ScopedCFTypeRef<CGColorRef> cgcolor(
  815. skia::CGColorCreateFromSkColor(color));
  816. // views::Widget adds a layer for the content view.
  817. auto* bridge = views::NativeWidgetMac::GetBridgeForNativeWindow(window_);
  818. NSView* compositor_superview =
  819. static_cast<ui::AcceleratedWidgetMacNSView*>(bridge)
  820. ->AcceleratedWidgetGetNSView();
  821. [[compositor_superview layer] setBackgroundColor:cgcolor];
  822. // When using WebContents as content view, the contentView also has layer.
  823. if ([[window_ contentView] wantsLayer])
  824. [[[window_ contentView] layer] setBackgroundColor:cgcolor];
  825. }
  826. void NativeWindowMac::SetHasShadow(bool has_shadow) {
  827. [window_ setHasShadow:has_shadow];
  828. }
  829. bool NativeWindowMac::HasShadow() {
  830. return [window_ hasShadow];
  831. }
  832. void NativeWindowMac::SetOpacity(const double opacity) {
  833. [window_ setAlphaValue:opacity];
  834. }
  835. double NativeWindowMac::GetOpacity() {
  836. return [window_ alphaValue];
  837. }
  838. void NativeWindowMac::SetRepresentedFilename(const std::string& filename) {
  839. [window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)];
  840. }
  841. std::string NativeWindowMac::GetRepresentedFilename() {
  842. return base::SysNSStringToUTF8([window_ representedFilename]);
  843. }
  844. void NativeWindowMac::SetDocumentEdited(bool edited) {
  845. [window_ setDocumentEdited:edited];
  846. }
  847. bool NativeWindowMac::IsDocumentEdited() {
  848. return [window_ isDocumentEdited];
  849. }
  850. void NativeWindowMac::SetIgnoreMouseEvents(bool ignore, bool forward) {
  851. [window_ setIgnoresMouseEvents:ignore];
  852. if (!ignore) {
  853. SetForwardMouseMessages(NO);
  854. } else {
  855. SetForwardMouseMessages(forward);
  856. }
  857. }
  858. void NativeWindowMac::SetContentProtection(bool enable) {
  859. [window_
  860. setSharingType:enable ? NSWindowSharingNone : NSWindowSharingReadOnly];
  861. }
  862. void NativeWindowMac::SetBrowserView(NativeBrowserView* view) {
  863. [CATransaction begin];
  864. [CATransaction setDisableActions:YES];
  865. if (browser_view()) {
  866. [browser_view()->GetInspectableWebContentsView()->GetNativeView()
  867. removeFromSuperview];
  868. set_browser_view(nullptr);
  869. }
  870. if (!view) {
  871. [CATransaction commit];
  872. return;
  873. }
  874. set_browser_view(view);
  875. auto* native_view = view->GetInspectableWebContentsView()->GetNativeView();
  876. [[window_ contentView] addSubview:native_view
  877. positioned:NSWindowAbove
  878. relativeTo:nil];
  879. native_view.hidden = NO;
  880. [CATransaction commit];
  881. }
  882. void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
  883. InternalSetParentWindow(parent, IsVisible());
  884. }
  885. gfx::NativeView NativeWindowMac::GetNativeView() const {
  886. return [window_ contentView];
  887. }
  888. gfx::NativeWindow NativeWindowMac::GetNativeWindow() const {
  889. return window_;
  890. }
  891. gfx::AcceleratedWidget NativeWindowMac::GetAcceleratedWidget() const {
  892. return gfx::kNullAcceleratedWidget;
  893. }
  894. void NativeWindowMac::SetProgressBar(double progress,
  895. const NativeWindow::ProgressState state) {
  896. NSDockTile* dock_tile = [NSApp dockTile];
  897. // For the first time API invoked, we need to create a ContentView in
  898. // DockTile.
  899. if (dock_tile.contentView == nullptr) {
  900. NSImageView* image_view = [[NSImageView alloc] init];
  901. [image_view setImage:[NSApp applicationIconImage]];
  902. [dock_tile setContentView:image_view];
  903. }
  904. if ([[dock_tile.contentView subviews] count] == 0) {
  905. NSProgressIndicator* progress_indicator = [[AtomProgressBar alloc]
  906. initWithFrame:NSMakeRect(0.0f, 0.0f, dock_tile.size.width, 15.0)];
  907. [progress_indicator setStyle:NSProgressIndicatorBarStyle];
  908. [progress_indicator setIndeterminate:NO];
  909. [progress_indicator setBezeled:YES];
  910. [progress_indicator setMinValue:0];
  911. [progress_indicator setMaxValue:1];
  912. [progress_indicator setHidden:NO];
  913. [dock_tile.contentView addSubview:progress_indicator];
  914. }
  915. NSProgressIndicator* progress_indicator = static_cast<NSProgressIndicator*>(
  916. [[[dock_tile contentView] subviews] objectAtIndex:0]);
  917. if (progress < 0) {
  918. [progress_indicator setHidden:YES];
  919. } else if (progress > 1) {
  920. [progress_indicator setHidden:NO];
  921. [progress_indicator setIndeterminate:YES];
  922. [progress_indicator setDoubleValue:1];
  923. } else {
  924. [progress_indicator setHidden:NO];
  925. [progress_indicator setDoubleValue:progress];
  926. }
  927. [dock_tile display];
  928. }
  929. void NativeWindowMac::SetOverlayIcon(const gfx::Image& overlay,
  930. const std::string& description) {}
  931. void NativeWindowMac::SetVisibleOnAllWorkspaces(bool visible) {
  932. SetCollectionBehavior(visible, NSWindowCollectionBehaviorCanJoinAllSpaces);
  933. }
  934. bool NativeWindowMac::IsVisibleOnAllWorkspaces() {
  935. NSUInteger collectionBehavior = [window_ collectionBehavior];
  936. return collectionBehavior & NSWindowCollectionBehaviorCanJoinAllSpaces;
  937. }
  938. void NativeWindowMac::SetAutoHideCursor(bool auto_hide) {
  939. [window_ setDisableAutoHideCursor:!auto_hide];
  940. }
  941. void NativeWindowMac::SelectPreviousTab() {
  942. if (@available(macOS 10.12, *)) {
  943. [window_ selectPreviousTab:nil];
  944. }
  945. }
  946. void NativeWindowMac::SelectNextTab() {
  947. if (@available(macOS 10.12, *)) {
  948. [window_ selectNextTab:nil];
  949. }
  950. }
  951. void NativeWindowMac::MergeAllWindows() {
  952. if (@available(macOS 10.12, *)) {
  953. [window_ mergeAllWindows:nil];
  954. }
  955. }
  956. void NativeWindowMac::MoveTabToNewWindow() {
  957. if (@available(macOS 10.12, *)) {
  958. [window_ moveTabToNewWindow:nil];
  959. }
  960. }
  961. void NativeWindowMac::ToggleTabBar() {
  962. if (@available(macOS 10.12, *)) {
  963. [window_ toggleTabBar:nil];
  964. }
  965. }
  966. bool NativeWindowMac::AddTabbedWindow(NativeWindow* window) {
  967. if (window_ == window->GetNativeWindow()) {
  968. return false;
  969. } else {
  970. if (@available(macOS 10.12, *))
  971. [window_ addTabbedWindow:window->GetNativeWindow() ordered:NSWindowAbove];
  972. }
  973. return true;
  974. }
  975. void NativeWindowMac::SetVibrancy(const std::string& type) {
  976. if (@available(macOS 10.10, *)) {
  977. NSView* vibrant_view = [window_ vibrantView];
  978. if (type.empty()) {
  979. if (background_color_before_vibrancy_) {
  980. [window_ setBackgroundColor:background_color_before_vibrancy_];
  981. [window_ setTitlebarAppearsTransparent:transparency_before_vibrancy_];
  982. }
  983. if (vibrant_view == nil)
  984. return;
  985. [vibrant_view removeFromSuperview];
  986. [window_ setVibrantView:nil];
  987. ui::GpuSwitchingManager::SetTransparent(transparent());
  988. return;
  989. }
  990. background_color_before_vibrancy_.reset([[window_ backgroundColor] retain]);
  991. transparency_before_vibrancy_ = [window_ titlebarAppearsTransparent];
  992. ui::GpuSwitchingManager::SetTransparent(true);
  993. if (title_bar_style_ != NORMAL) {
  994. [window_ setTitlebarAppearsTransparent:YES];
  995. [window_ setBackgroundColor:[NSColor clearColor]];
  996. }
  997. NSVisualEffectView* effect_view = (NSVisualEffectView*)vibrant_view;
  998. if (effect_view == nil) {
  999. effect_view = [[[NSVisualEffectView alloc]
  1000. initWithFrame:[[window_ contentView] bounds]] autorelease];
  1001. [window_ setVibrantView:(NSView*)effect_view];
  1002. [effect_view
  1003. setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
  1004. [effect_view setBlendingMode:NSVisualEffectBlendingModeBehindWindow];
  1005. [effect_view setState:NSVisualEffectStateActive];
  1006. [[window_ contentView] addSubview:effect_view
  1007. positioned:NSWindowBelow
  1008. relativeTo:nil];
  1009. }
  1010. NSVisualEffectMaterial vibrancyType = NSVisualEffectMaterialLight;
  1011. if (type == "appearance-based") {
  1012. vibrancyType = NSVisualEffectMaterialAppearanceBased;
  1013. } else if (type == "light") {
  1014. vibrancyType = NSVisualEffectMaterialLight;
  1015. } else if (type == "dark") {
  1016. vibrancyType = NSVisualEffectMaterialDark;
  1017. } else if (type == "titlebar") {
  1018. vibrancyType = NSVisualEffectMaterialTitlebar;
  1019. }
  1020. if (@available(macOS 10.11, *)) {
  1021. // TODO(kevinsawicki): Use NSVisualEffectMaterial* constants directly once
  1022. // they are available in the minimum SDK version
  1023. if (type == "selection") {
  1024. // NSVisualEffectMaterialSelection
  1025. vibrancyType = static_cast<NSVisualEffectMaterial>(4);
  1026. } else if (type == "menu") {
  1027. // NSVisualEffectMaterialMenu
  1028. vibrancyType = static_cast<NSVisualEffectMaterial>(5);
  1029. } else if (type == "popover") {
  1030. // NSVisualEffectMaterialPopover
  1031. vibrancyType = static_cast<NSVisualEffectMaterial>(6);
  1032. } else if (type == "sidebar") {
  1033. // NSVisualEffectMaterialSidebar
  1034. vibrancyType = static_cast<NSVisualEffectMaterial>(7);
  1035. } else if (type == "medium-light") {
  1036. // NSVisualEffectMaterialMediumLight
  1037. vibrancyType = static_cast<NSVisualEffectMaterial>(8);
  1038. } else if (type == "ultra-dark") {
  1039. // NSVisualEffectMaterialUltraDark
  1040. vibrancyType = static_cast<NSVisualEffectMaterial>(9);
  1041. }
  1042. }
  1043. [effect_view setMaterial:vibrancyType];
  1044. }
  1045. }
  1046. void NativeWindowMac::SetTouchBar(
  1047. const std::vector<mate::PersistentDictionary>& items) {
  1048. if (@available(macOS 10.12.2, *)) {
  1049. touch_bar_.reset([[AtomTouchBar alloc]
  1050. initWithDelegate:window_delegate_.get()
  1051. window:this
  1052. settings:items]);
  1053. [window_ setTouchBar:nil];
  1054. }
  1055. }
  1056. void NativeWindowMac::RefreshTouchBarItem(const std::string& item_id) {
  1057. if (@available(macOS 10.12.2, *)) {
  1058. if (touch_bar_ && [window_ touchBar])
  1059. [touch_bar_ refreshTouchBarItem:[window_ touchBar] id:item_id];
  1060. }
  1061. }
  1062. void NativeWindowMac::SetEscapeTouchBarItem(
  1063. const mate::PersistentDictionary& item) {
  1064. if (@available(macOS 10.12.2, *)) {
  1065. if (touch_bar_ && [window_ touchBar])
  1066. [touch_bar_ setEscapeTouchBarItem:item forTouchBar:[window_ touchBar]];
  1067. }
  1068. }
  1069. gfx::Rect NativeWindowMac::ContentBoundsToWindowBounds(
  1070. const gfx::Rect& bounds) const {
  1071. if (has_frame()) {
  1072. gfx::Rect window_bounds(
  1073. [window_ frameRectForContentRect:bounds.ToCGRect()]);
  1074. int frame_height = window_bounds.height() - bounds.height();
  1075. window_bounds.set_y(window_bounds.y() - frame_height);
  1076. return window_bounds;
  1077. } else {
  1078. return bounds;
  1079. }
  1080. }
  1081. gfx::Rect NativeWindowMac::WindowBoundsToContentBounds(
  1082. const gfx::Rect& bounds) const {
  1083. if (has_frame()) {
  1084. gfx::Rect content_bounds(
  1085. [window_ contentRectForFrameRect:bounds.ToCGRect()]);
  1086. int frame_height = bounds.height() - content_bounds.height();
  1087. content_bounds.set_y(content_bounds.y() + frame_height);
  1088. return content_bounds;
  1089. } else {
  1090. return bounds;
  1091. }
  1092. }
  1093. bool NativeWindowMac::CanResize() const {
  1094. return resizable_;
  1095. }
  1096. views::View* NativeWindowMac::GetContentsView() {
  1097. return root_view_.get();
  1098. }
  1099. void NativeWindowMac::AddContentViewLayers() {
  1100. // Make sure the bottom corner is rounded for non-modal windows:
  1101. // http://crbug.com/396264. But do not enable it on OS X 10.9 for transparent
  1102. // window, otherwise a semi-transparent frame would show.
  1103. if (!(transparent() && base::mac::IsOS10_9()) && !is_modal()) {
  1104. // For normal window, we need to explicitly set layer for contentView to
  1105. // make setBackgroundColor work correctly.
  1106. // There is no need to do so for frameless window, and doing so would make
  1107. // titleBarStyle stop working.
  1108. if (has_frame()) {
  1109. base::scoped_nsobject<CALayer> background_layer([[CALayer alloc] init]);
  1110. [background_layer
  1111. setAutoresizingMask:kCALayerWidthSizable | kCALayerHeightSizable];
  1112. [[window_ contentView] setLayer:background_layer];
  1113. }
  1114. [[window_ contentView] setWantsLayer:YES];
  1115. }
  1116. if (!has_frame()) {
  1117. // In OSX 10.10, adding subviews to the root view for the NSView hierarchy
  1118. // produces warnings. To eliminate the warnings, we resize the contentView
  1119. // to fill the window, and add subviews to that.
  1120. // http://crbug.com/380412
  1121. if (!original_set_frame_size) {
  1122. Class cl = [[window_ contentView] class];
  1123. original_set_frame_size = class_replaceMethod(
  1124. cl, @selector(setFrameSize:), (IMP)SetFrameSize, "v@:{_NSSize=ff}");
  1125. original_view_did_move_to_superview =
  1126. class_replaceMethod(cl, @selector(viewDidMoveToSuperview),
  1127. (IMP)ViewDidMoveToSuperview, "v@:");
  1128. [[window_ contentView] viewDidMoveToWindow];
  1129. }
  1130. // The fullscreen button should always be hidden for frameless window.
  1131. [[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
  1132. if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER) {
  1133. buttons_view_.reset(
  1134. [[CustomWindowButtonView alloc] initWithFrame:NSZeroRect]);
  1135. // NSWindowStyleMaskFullSizeContentView does not work with zoom button
  1136. SetFullScreenable(false);
  1137. [[window_ contentView] addSubview:buttons_view_];
  1138. } else {
  1139. if (title_bar_style_ != NORMAL) {
  1140. if (base::mac::IsOS10_9()) {
  1141. ShowWindowButton(NSWindowZoomButton);
  1142. ShowWindowButton(NSWindowMiniaturizeButton);
  1143. ShowWindowButton(NSWindowCloseButton);
  1144. }
  1145. return;
  1146. }
  1147. // Hide the window buttons.
  1148. [[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
  1149. [[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
  1150. [[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
  1151. }
  1152. // Some third-party macOS utilities check the zoom button's enabled state to
  1153. // determine whether to show custom UI on hover, so we disable it here to
  1154. // prevent them from doing so in a frameless app window.
  1155. [[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
  1156. }
  1157. }
  1158. void NativeWindowMac::InternalSetParentWindow(NativeWindow* parent,
  1159. bool attach) {
  1160. if (is_modal())
  1161. return;
  1162. NativeWindow::SetParentWindow(parent);
  1163. // Do not remove/add if we are already properly attached.
  1164. if (attach && parent && [window_ parentWindow] == parent->GetNativeWindow())
  1165. return;
  1166. // Remove current parent window.
  1167. if ([window_ parentWindow])
  1168. [[window_ parentWindow] removeChildWindow:window_];
  1169. // Set new parent window.
  1170. // Note that this method will force the window to become visible.
  1171. if (parent && attach)
  1172. [parent->GetNativeWindow() addChildWindow:window_ ordered:NSWindowAbove];
  1173. }
  1174. void NativeWindowMac::ShowWindowButton(NSWindowButton button) {
  1175. auto view = [window_ standardWindowButton:button];
  1176. [view.superview addSubview:view positioned:NSWindowAbove relativeTo:nil];
  1177. }
  1178. void NativeWindowMac::SetForwardMouseMessages(bool forward) {
  1179. [window_ setAcceptsMouseMovedEvents:forward];
  1180. }
  1181. void NativeWindowMac::OverrideNSWindowContentView() {
  1182. // When using `views::Widget` to hold WebContents, Chromium would use
  1183. // `BridgedContentView` as content view, which does not support draggable
  1184. // regions. In order to make draggable regions work, we have to replace the
  1185. // content view with a simple NSView.
  1186. container_view_.reset([[FullSizeContentView alloc] init]);
  1187. [container_view_
  1188. setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
  1189. [container_view_ setFrame:[[[window_ contentView] superview] bounds]];
  1190. [window_ setContentView:container_view_];
  1191. AddContentViewLayers();
  1192. }
  1193. void NativeWindowMac::SetStyleMask(bool on, NSUInteger flag) {
  1194. // Changing the styleMask of a frameless windows causes it to change size so
  1195. // we explicitly disable resizing while setting it.
  1196. ScopedDisableResize disable_resize;
  1197. bool was_maximizable = IsMaximizable();
  1198. if (on)
  1199. [window_ setStyleMask:[window_ styleMask] | flag];
  1200. else
  1201. [window_ setStyleMask:[window_ styleMask] & (~flag)];
  1202. // Change style mask will make the zoom button revert to default, probably
  1203. // a bug of Cocoa or macOS.
  1204. SetMaximizable(was_maximizable);
  1205. }
  1206. void NativeWindowMac::SetCollectionBehavior(bool on, NSUInteger flag) {
  1207. bool was_maximizable = IsMaximizable();
  1208. if (on)
  1209. [window_ setCollectionBehavior:[window_ collectionBehavior] | flag];
  1210. else
  1211. [window_ setCollectionBehavior:[window_ collectionBehavior] & (~flag)];
  1212. // Change collectionBehavior will make the zoom button revert to default,
  1213. // probably a bug of Cocoa or macOS.
  1214. SetMaximizable(was_maximizable);
  1215. }
  1216. // static
  1217. NativeWindow* NativeWindow::Create(const mate::Dictionary& options,
  1218. NativeWindow* parent) {
  1219. return new NativeWindowMac(options, parent);
  1220. }
  1221. } // namespace atom