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 {
21 mozilla::widget::ScreenHelperCocoa* mHelper;
24 - (id)initWithScreenHelper:(mozilla::widget::ScreenHelperCocoa*)aScreenHelper;
25 - (void)didChangeScreenParameters:(NSNotification*)aNotification;
28 @implementation ScreenHelperDelegate
29 - (id)initWithScreenHelper:(mozilla::widget::ScreenHelperCocoa*)aScreenHelper {
30 if ((self = [self init])) {
31 mHelper = aScreenHelper;
33 [[NSNotificationCenter defaultCenter]
35 selector:@selector(didChangeScreenParameters:)
36 name:NSApplicationDidChangeScreenParametersNotification
44 [[NSNotificationCenter defaultCenter] removeObserver:self];
48 - (void)didChangeScreenParameters:(NSNotification*)aNotification {
49 MOZ_LOG(sScreenLog, LogLevel::Debug,
50 ("Received NSApplicationDidChangeScreenParametersNotification"));
52 mHelper->RefreshScreens();
59 ScreenHelperCocoa::ScreenHelperCocoa() {
60 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
62 MOZ_LOG(sScreenLog, LogLevel::Debug, ("ScreenHelperCocoa created"));
64 mDelegate = [[ScreenHelperDelegate alloc] initWithScreenHelper:this];
68 NS_OBJC_END_TRY_ABORT_BLOCK;
71 ScreenHelperCocoa::~ScreenHelperCocoa() {
72 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
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);
93 CGDirectDisplayID displayID =
94 [[[aScreen deviceDescription] objectForKey:@"NSScreenNumber"] intValue];
95 CGFloat heightMM = ::CGDisplayScreenSize(displayID).height;
97 dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT);
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) {
123 screens.AppendElement(MakeScreen(screen));
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) {
140 LayoutDeviceIntRect rect;
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) {
150 return [NSScreen mainScreen];
152 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
155 } // namespace widget
156 } // namespace mozilla