Bug 1646817 - Support DocumentChannel process switching in sidebars and popups r...
[gecko.git] / widget / cocoa / ScreenHelperCocoa.mm
blobaf4c201f14ca9bde759c6adc7789c2125ad63ea0
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ScreenHelperCocoa.h"
9 #import <Cocoa/Cocoa.h>
11 #include "mozilla/Logging.h"
12 #include "nsCocoaUtils.h"
13 #include "nsObjCExceptions.h"
15 using namespace mozilla;
17 static LazyLogModule sScreenLog("WidgetScreen");
19 @interface ScreenHelperDelegate : NSObject {
20  @private
21   mozilla::widget::ScreenHelperCocoa* mHelper;
24 - (id)initWithScreenHelper:(mozilla::widget::ScreenHelperCocoa*)aScreenHelper;
25 - (void)didChangeScreenParameters:(NSNotification*)aNotification;
26 @end
28 @implementation ScreenHelperDelegate
29 - (id)initWithScreenHelper:(mozilla::widget::ScreenHelperCocoa*)aScreenHelper {
30   if ((self = [self init])) {
31     mHelper = aScreenHelper;
33     [[NSNotificationCenter defaultCenter]
34         addObserver:self
35            selector:@selector(didChangeScreenParameters:)
36                name:NSApplicationDidChangeScreenParametersNotification
37              object:nil];
38   }
40   return self;
43 - (void)dealloc {
44   [[NSNotificationCenter defaultCenter] removeObserver:self];
45   [super dealloc];
48 - (void)didChangeScreenParameters:(NSNotification*)aNotification {
49   MOZ_LOG(sScreenLog, LogLevel::Debug,
50           ("Received NSApplicationDidChangeScreenParametersNotification"));
52   mHelper->RefreshScreens();
54 @end
56 namespace mozilla {
57 namespace widget {
59 ScreenHelperCocoa::ScreenHelperCocoa() {
60   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
62   MOZ_LOG(sScreenLog, LogLevel::Debug, ("ScreenHelperCocoa created"));
64   mDelegate = [[ScreenHelperDelegate alloc] initWithScreenHelper:this];
66   RefreshScreens();
68   NS_OBJC_END_TRY_ABORT_BLOCK;
71 ScreenHelperCocoa::~ScreenHelperCocoa() {
72   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
74   [mDelegate release];
76   NS_OBJC_END_TRY_ABORT_BLOCK;
79 static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) {
80   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
82   DesktopToLayoutDeviceScale contentsScaleFactor(nsCocoaUtils::GetBackingScaleFactor(aScreen));
83   CSSToLayoutDeviceScale defaultCssScaleFactor(contentsScaleFactor.scale);
84   NSRect frame = [aScreen frame];
85   LayoutDeviceIntRect rect =
86       nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, contentsScaleFactor.scale);
87   frame = [aScreen visibleFrame];
88   LayoutDeviceIntRect availRect =
89       nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, contentsScaleFactor.scale);
90   NSWindowDepth depth = [aScreen depth];
91   uint32_t pixelDepth = NSBitsPerPixelFromDepth(depth);
92   float dpi = 96.0f;
93   CGDirectDisplayID displayID =
94       [[[aScreen deviceDescription] objectForKey:@"NSScreenNumber"] intValue];
95   CGFloat heightMM = ::CGDisplayScreenSize(displayID).height;
96   if (heightMM > 0) {
97     dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT);
98   }
99   MOZ_LOG(sScreenLog, LogLevel::Debug,
100           ("New screen [%d %d %d %d (%d %d %d %d) %d %f %f %f]", rect.x, rect.y, rect.width,
101            rect.height, availRect.x, availRect.y, availRect.width, availRect.height, pixelDepth,
102            contentsScaleFactor.scale, defaultCssScaleFactor.scale, dpi));
104   RefPtr<Screen> screen = new Screen(rect, availRect, pixelDepth, pixelDepth, contentsScaleFactor,
105                                      defaultCssScaleFactor, dpi);
106   return screen.forget();
108   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(nullptr);
111 void ScreenHelperCocoa::RefreshScreens() {
112   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
114   MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refreshing screens"));
116   AutoTArray<RefPtr<Screen>, 4> screens;
118   for (NSScreen* screen in [NSScreen screens]) {
119     NSDictionary* desc = [screen deviceDescription];
120     if ([desc objectForKey:NSDeviceIsScreen] == nil) {
121       continue;
122     }
123     screens.AppendElement(MakeScreen(screen));
124   }
126   ScreenManager& screenManager = ScreenManager::GetSingleton();
127   screenManager.Refresh(std::move(screens));
129   NS_OBJC_END_TRY_ABORT_BLOCK;
132 NSScreen* ScreenHelperCocoa::CocoaScreenForScreen(nsIScreen* aScreen) {
133   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
135   for (NSScreen* screen in [NSScreen screens]) {
136     NSDictionary* desc = [screen deviceDescription];
137     if ([desc objectForKey:NSDeviceIsScreen] == nil) {
138       continue;
139     }
140     LayoutDeviceIntRect rect;
141     double scale;
142     aScreen->GetRect(&rect.x, &rect.y, &rect.width, &rect.height);
143     aScreen->GetContentsScaleFactor(&scale);
144     NSRect frame = [screen frame];
145     LayoutDeviceIntRect frameRect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, scale);
146     if (rect == frameRect) {
147       return screen;
148     }
149   }
150   return [NSScreen mainScreen];
152   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
155 }  // namespace widget
156 }  // namespace mozilla