1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "headless/lib/browser/headless_screen_mac.h"
#import <Cocoa/Cocoa.h>
#include <optional>
#import "base/apple/scoped_objc_class_swizzler.h"
#include "base/check_deref.h"
#include "components/headless/display_util/headless_display_util.h"
#include "ui/display/screen.h"
#import "ui/gfx/mac/coordinate_conversion.h"
// Class to donate the headless screen configuration aware implementation of
// -[NSScreen frame].
@interface HeadlessScreenNSScreenDonor : NSObject
- (NSRect)frame;
@end
@implementation HeadlessScreenNSScreenDonor
- (NSRect)frame {
display::Screen& screen = CHECK_DEREF(display::Screen::GetScreen());
display::Display primary_display = screen.GetPrimaryDisplay();
const gfx::Rect bounds = primary_display.bounds();
CHECK_EQ(bounds.x(), 0);
CHECK_EQ(bounds.y(), 0);
return NSMakeRect(0, 0, bounds.width(), bounds.height());
}
@end
namespace headless {
// Holds Apple Class Swizzler instance.
class HeadlessScreenMac::ClassSwizzler {
public:
ClassSwizzler() {
swizzler_ = std::make_unique<base::apple::ScopedObjCClassSwizzler>(
[NSScreen class], [HeadlessScreenNSScreenDonor class],
@selector(frame));
}
private:
std::unique_ptr<base::apple::ScopedObjCClassSwizzler> swizzler_;
};
// static
HeadlessScreenMac* HeadlessScreenMac::Create(
const gfx::Size& window_size,
std::string_view screen_info_spec) {
return new HeadlessScreenMac(window_size, screen_info_spec);
}
HeadlessScreenMac::HeadlessScreenMac(const gfx::Size& window_size,
std::string_view screen_info_spec)
: HeadlessScreen(window_size, screen_info_spec) {
// Override [NSScreen frame] with the headless screen aware implementation.
class_swizzler_ = std::make_unique<ClassSwizzler>();
}
HeadlessScreenMac::~HeadlessScreenMac() = default;
display::Display HeadlessScreenMac::GetDisplayNearestWindow(
gfx::NativeWindow window) const {
// There are no NSWindows in headless, so this method should not be called at
// all, however content::RenderWidgetHostViewMac ctor calls it with nil
// keyWindow, so return our best guess.
return GetPrimaryDisplay();
}
display::Display HeadlessScreenMac::GetDisplayNearestView(
gfx::NativeView view) const {
// On Mac native window (i.e. NSWindow) does not exist in headless, so we have
// to rely on native view (i.e. NSView) for nearest display determination.
if (view && view.GetNativeNSView()) {
NSView* ns_view = view.GetNativeNSView();
while (NSView* parent = [ns_view superview]) {
ns_view = parent;
}
const gfx::Rect bounds = gfx::ScreenRectFromNSRect([ns_view frame]);
if (std::optional<display::Display> display =
GetDisplayFromScreenRect(display_list().displays(), bounds)) {
return display.value();
}
}
return GetPrimaryDisplay();
}
} // namespace headless
|