cocoadisplay: Add support for high-dpi screens (#1308)

This commit is contained in:
LD 2023-10-10 16:56:04 +02:00 committed by GitHub
parent e55bb94996
commit ae3cbe4b12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 268 additions and 110 deletions

View File

@ -717,6 +717,7 @@ class build_apps(setuptools.Command):
'CFBundlePackageType': 'APPL',
'CFBundleSignature': '', #TODO
'CFBundleExecutable': self.macos_main_app,
'NSHighResolutionCapable': 'True',
}
icon = self.icon_objects.get(

View File

@ -40,12 +40,36 @@ CocoaGraphicsPipe(CGDirectDisplayID display) : _display(display) {
[thread start];
[thread autorelease];
// If the application is dpi-aware, iterate over all the screens to find the
// one with our display ID and get the backing scale factor to configure the
// detected display zoom. Otherwise the detected display zoom keeps its
// default value of 1.0
if (dpi_aware) {
NSScreen *screen;
NSEnumerator *e = [[NSScreen screens] objectEnumerator];
while (screen = (NSScreen *) [e nextObject]) {
NSNumber *num = [[screen deviceDescription] objectForKey: @"NSScreenNumber"];
if (_display == (CGDirectDisplayID) [num longValue]) {
set_detected_display_zoom([screen backingScaleFactor]);
if (cocoadisplay_cat.is_debug()) {
cocoadisplay_cat.debug()
<< "Display zoom is " << [screen backingScaleFactor] << "\n";
}
break;
}
}
}
// We used to also obtain the corresponding NSScreen here, but this causes
// the application icon to start bouncing, which may be undesirable for
// apps that will never open a window.
_display_width = CGDisplayPixelsWide(_display);
_display_height = CGDisplayPixelsHigh(_display);
// Although the name of these functions mention pixels, they actually return
// display points, we use the detected display zoom to transform the values
// into pixels.
_display_width = CGDisplayPixelsWide(_display) * _detected_display_zoom;
_display_height = CGDisplayPixelsHigh(_display) * _detected_display_zoom;
load_display_information();
if (cocoadisplay_cat.is_debug()) {
@ -64,19 +88,36 @@ load_display_information() {
// _display_information->_device_id = CGDisplaySerialNumber(_display);
// Display modes
CFDictionaryRef options = NULL;
const CFStringRef dictkeys[] = {kCGDisplayShowDuplicateLowResolutionModes};
const CFBooleanRef dictvalues[] = {kCFBooleanTrue};
options = CFDictionaryCreate(NULL,
(const void **)dictkeys,
(const void **)dictvalues,
1,
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
size_t num_modes = 0;
CFArrayRef modes = CGDisplayCopyAllDisplayModes(_display, NULL);
CFArrayRef modes = CGDisplayCopyAllDisplayModes(_display, options);
if (modes != NULL) {
num_modes = CFArrayGetCount(modes);
_display_information->_total_display_modes = num_modes;
_display_information->_display_mode_array = new DisplayMode[num_modes];
}
if (options != NULL) {
CFRelease(options);
}
for (size_t i = 0; i < num_modes; ++i) {
CGDisplayModeRef mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
_display_information->_display_mode_array[i].width = CGDisplayModeGetWidth(mode);
_display_information->_display_mode_array[i].height = CGDisplayModeGetHeight(mode);
if (dpi_aware) {
_display_information->_display_mode_array[i].width = CGDisplayModeGetPixelWidth(mode);
_display_information->_display_mode_array[i].height = CGDisplayModeGetPixelHeight(mode);
} else {
_display_information->_display_mode_array[i].width = CGDisplayModeGetWidth(mode);
_display_information->_display_mode_array[i].height = CGDisplayModeGetHeight(mode);
}
_display_information->_display_mode_array[i].refresh_rate = CGDisplayModeGetRefreshRate(mode);
_display_information->_display_mode_array[i].fullscreen_only = false;

View File

@ -63,6 +63,7 @@ public:
void handle_minimize_event(bool minimized);
void handle_maximize_event(bool maximized);
void handle_foreground_event(bool foreground);
void handle_backing_change_event();
bool handle_close_request();
void handle_close_event();
void handle_key_event(NSEvent *event);

View File

@ -132,13 +132,20 @@ move_pointer(int device, int x, int y) {
return true;
}
// Mouse position is expressed in screen points and not pixels, but in Panda3D
// we are using pixel coordinates.
// Instead of using convertPointFromBacking and have complex logic to cope with
// the change of coordinate system, we cheat and directly use the contents scale
// of the view layer to convert pixel coordinates into screen point coordinates.
CGFloat contents_scale = _view.layer.contentsScale;
if (device == 0) {
CGPoint point;
if (_properties.get_fullscreen()) {
point = CGPointMake(x, y);
point = CGPointMake(float(x) / contents_scale,
float(y) / contents_scale);
} else {
point = CGPointMake(x + _properties.get_x_origin(),
y + _properties.get_y_origin());
point = CGPointMake((float(x) + _properties.get_x_origin()) / contents_scale,
(float(y) + _properties.get_y_origin()) / contents_scale);
}
if (CGWarpMouseCursorPosition(point) == kCGErrorSuccess) {
@ -302,35 +309,89 @@ open_window() {
}
}
// Configure the origin and the size of the window.
// On macOS, screen coordinates are expressed in "points" which are independant
// of the pixel density of the screen. Panda3D however, expresses the size and
// origin of a window in pixels.
// So, when opening a window, we need to convert the origin and size from pixel
// units into point units. However, this conversion depends on the pixel density
// of the screen, the backing scale factor.
// As the origin and size of a window depends on the size of the screen of the
// parent view, their size must be converted first from points to pixels.
// If a window (or a view) is not configured to support high-dpi screen, macOS
// will upscale the window (or view) when displayed on a high-dpi screen.
// Therefore its backing scale factor will always be 1.0
// In a Panda3D application, windows are always configured as high resolution
// capable, but the view is only configured as high resolution if the dpi-aware
// configuration flag is set.
// If the app is not dpi-aware, we must upscale its size and origin from points
// into pixels as the window is always high resolution capable.
// Center the window if coordinates were set to -1 or -2 TODO: perhaps in
// future, in the case of -1, it should use the origin used in a previous
// run of Panda
// Size of the requested window
NSSize size = NSMakeSize(_properties.get_x_size(), _properties.get_y_size());
NSRect container;
CGFloat backing_scale_factor = screen.backingScaleFactor;
if (parent_nsview != NULL) {
container = [parent_nsview bounds];
// Convert parent view bounds into pixel units.
container = [parent_nsview convertRectToBacking:[parent_nsview bounds]];
// If the app is not dpi-aware, we must convert its size from points into
// pixels as the window is always high resolution capable
if (!dpi_aware) {
size = [parent_nsview convertSizeToBacking:size];
}
} else {
container = [screen frame];
container.origin = NSMakePoint(0, 0);
container = [screen convertRectToBacking:container];
if (!dpi_aware) {
// Weirdly NSScreen does not respond to convertSizeToBacking, so we have to
// create a dummy rect just for converting the window size.
NSRect rect;
rect.origin = NSMakePoint(0, 0);
rect.size = size;
rect = [screen convertRectToBacking:rect];
size = rect.size;
}
}
int x = _properties.get_x_origin();
int y = _properties.get_y_origin();
// As we are converting a single value and the view is not created yet, it's
// easier to simply use the backing scale factor and don't bother with
// coordinate system transformations.
if (x < 0) {
x = floor(container.size.width / 2 - _properties.get_x_size() / 2);
x = floor(container.size.width / 2 - size.width / 2);
} else if (!dpi_aware) {
x *= backing_scale_factor;
}
if (y < 0) {
y = floor(container.size.height / 2 - _properties.get_y_size() / 2);
y = floor(container.size.height / 2 - size.height / 2);
} else if (!dpi_aware) {
y *= backing_scale_factor;
}
if (dpi_aware) {
_properties.set_origin(x, y);
} else {
_properties.set_origin(x / backing_scale_factor, y / backing_scale_factor);
}
_properties.set_origin(x, y);
if (_parent_window_handle == (WindowHandle *)NULL) {
// Content rectangle
NSRect rect;
if (_properties.get_fullscreen()) {
rect = container;
rect = [screen convertRectFromBacking:container];
} else {
rect = NSMakeRect(x, container.size.height - _properties.get_y_size() - y,
_properties.get_x_size(), _properties.get_y_size());
rect = NSMakeRect(x, container.size.height - size.height - y,
size.width, size.height);
if (parent_nsview != NULL) {
rect = [parent_nsview convertRectFromBacking:rect];
} else {
rect = [screen convertRectFromBacking:rect];
}
}
// Configure the window decorations
@ -388,8 +449,10 @@ open_window() {
_parent_window_handle->attach_child(_window_handle);
}
// Always disable application HiDPI support, Cocoa will do the eventual upscaling for us.
[_view setWantsBestResolutionOpenGLSurface:NO];
// Configure the view to be high resolution capable using the dpi-aware
// configuration flag. If dpi-aware is false, macOS will upscale the view
// for us.
[_view setWantsBestResolutionOpenGLSurface:dpi_aware];
if (_properties.has_icon_filename()) {
NSImage *image = load_image(_properties.get_icon_filename());
if (image != nil) {
@ -596,22 +659,6 @@ set_properties_now(WindowProperties &properties) {
}
if (switched) {
if (_window != nil) {
// For some reason, setting the style mask makes it give up its
// first-responder status. And for some reason, we need to first
// restore the window to normal level before we switch fullscreen,
// otherwise we may get a black bar if we're currently on Z_top.
if (_properties.get_z_order() != WindowProperties::Z_normal) {
[_window setLevel: NSNormalWindowLevel];
}
if ([_window respondsToSelector:@selector(setStyleMask:)]) {
[_window setStyleMask:NSBorderlessWindowMask];
}
[_window makeFirstResponder:_view];
[_window setLevel:CGShieldingWindowLevel()];
[_window makeKeyAndOrderFront:nil];
}
// We've already set the size property this way; clear it.
properties.clear_size();
_properties.set_size(width, height);
@ -684,6 +731,9 @@ set_properties_now(WindowProperties &properties) {
NSMiniaturizableWindowMask | NSResizableWindowMask ];
}
[_window makeFirstResponder:_view];
// Resize event fired by makeFirstResponder has an invalid backing scale factor
// The actual size must be reset afterward
handle_resize_event();
}
}
@ -705,6 +755,9 @@ set_properties_now(WindowProperties &properties) {
NSMiniaturizableWindowMask | NSResizableWindowMask ];
}
[_window makeFirstResponder:_view];
// Resize event fired by makeFirstResponder has an invalid backing scale factor
// The actual size must be reset afterward
handle_resize_event();
}
properties.clear_undecorated();
@ -715,10 +768,13 @@ set_properties_now(WindowProperties &properties) {
int height = properties.get_y_size();
if (!_properties.get_fullscreen()) {
// We use the view, not the window, to convert the frame size, expressed
// in pixels, into points as the "dpi awareness" is managed by the view.
NSSize size = [_view convertSizeFromBacking:NSMakeSize(width, height)];
if (_window != nil) {
[_window setContentSize:NSMakeSize(width, height)];
[_window setContentSize:size];
}
[_view setFrameSize:NSMakeSize(width, height)];
[_view setFrameSize:size];
if (cocoadisplay_cat.is_debug()) {
cocoadisplay_cat.debug()
@ -768,12 +824,14 @@ set_properties_now(WindowProperties &properties) {
// Get the frame for the screen
NSRect frame;
NSRect container;
// Note again that we are using the view to convert the frame and container
// size from points into pixels.
if (_window != nil) {
NSRect window_frame = [_window frame];
frame = [_window contentRectForFrameRect:window_frame];
frame = [_view convertRectToBacking:[_window contentRectForFrameRect:window_frame]];
NSScreen *screen = [_window screen];
nassertv(screen != nil);
container = [screen frame];
container = [_view convertRectToBacking:[screen frame]];
// Prevent the centering from overlapping the Dock
if (y < 0) {
@ -783,8 +841,8 @@ set_properties_now(WindowProperties &properties) {
}
}
} else {
frame = [_view frame];
container = [[_view superview] frame];
frame = [_view convertRectToBacking:[_view frame]];
container = [[_view superview] convertRectToBacking:[[_view superview] frame]];
}
if (x < 0) {
@ -795,22 +853,22 @@ set_properties_now(WindowProperties &properties) {
}
_properties.set_origin(x, y);
if (!_properties.get_fullscreen()) {
// Remember, Mac OS X coordinates are flipped in the vertical axis.
frame.origin.x = x;
frame.origin.y = container.size.height - y - frame.size.height;
frame.origin.x = x;
// Y coordinate in backing store is not flipped, but origin is still at the bottom left
frame.origin.y = y - container.size.height;
if (cocoadisplay_cat.is_debug()) {
cocoadisplay_cat.debug()
<< "Setting window content origin to "
<< frame.origin.x << ", " << frame.origin.y << "\n";
}
if (cocoadisplay_cat.is_debug()) {
cocoadisplay_cat.debug()
<< "Setting window content origin to "
<< frame.origin.x << ", " << frame.origin.y << "\n";
}
if (_window != nil) {
[_window setFrame:[_window frameRectForContentRect:frame] display:NO];
} else {
[_view setFrame:frame];
}
if (_window != nil) {
frame = [_view convertRectFromBacking:frame];
[_window setFrame:[_window frameRectForContentRect:frame] display:NO];
} else {
frame = [_view convertRectFromBacking:frame];
[_view setFrame:frame];
}
properties.clear_origin();
}
@ -957,24 +1015,20 @@ unbind_context() {
CFMutableArrayRef CocoaGraphicsWindow::
find_display_modes(int width, int height) {
CFDictionaryRef options = NULL;
// On macOS 10.15+ (Catalina), we want to select the display mode with the
// samescaling factor as the current view to avoid cropping or scaling issues.
// This is a workaround until HiDPI display or scaling factor is properly
// handled. CGDisplayCopyAllDisplayModes() does not return upscaled display
// mode unless explicitly asked with kCGDisplayShowDuplicateLowResolutionModes
// We want to select the display mode with the same scaling factor as the
// current view to avoid cropping or scaling issues.
// CGDisplayCopyAllDisplayModes() does not return upscaled display modes
// nor the current mode, unless explicitly asked with
// kCGDisplayShowDuplicateLowResolutionModes
// (which is undocumented...).
bool macos_10_15_or_higher = false;
if (@available(macOS 10.15, *)) {
const CFStringRef dictkeys[] = {kCGDisplayShowDuplicateLowResolutionModes};
const CFBooleanRef dictvalues[] = {kCFBooleanTrue};
options = CFDictionaryCreate(NULL,
(const void **)dictkeys,
(const void **)dictvalues,
1,
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
macos_10_15_or_higher = true;
}
const CFStringRef dictkeys[] = {kCGDisplayShowDuplicateLowResolutionModes};
const CFBooleanRef dictvalues[] = {kCFBooleanTrue};
options = CFDictionaryCreate(NULL,
(const void **)dictkeys,
(const void **)dictvalues,
1,
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFMutableArrayRef valid_modes;
valid_modes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
@ -985,29 +1039,39 @@ find_display_modes(int width, int height) {
size_t num_modes = CFArrayGetCount(modes);
CGDisplayModeRef mode;
// Get the current refresh rate and pixel encoding.
CFStringRef current_pixel_encoding;
double refresh_rate;
mode = CGDisplayCopyDisplayMode(_display);
// Calculate requested display size and pixel size
CGSize display_size;
CGSize pixel_size;
if (dpi_aware) {
pixel_size = NSMakeSize(width, height);
display_size = [_view convertSizeFromBacking:pixel_size];
} else {
display_size = NSMakeSize(width, height);
// Calculate the pixel width and height of the fullscreen mode we want using
// the current display mode dimensions and pixel dimensions.
size_t pixel_width = (size_t(width) * CGDisplayModeGetPixelWidth(mode)) / CGDisplayModeGetWidth(mode);
size_t pixel_height = (size_t(height) * CGDisplayModeGetPixelHeight(mode)) / CGDisplayModeGetHeight(mode);
pixel_size = NSMakeSize(pixel_width, pixel_height);
}
// First check if the current mode is adequate.
// This test not done for macOS 10.15 and above as the mode resolution is
// not enough to identify a mode.
if (!macos_10_15_or_higher &&
CGDisplayModeGetWidth(mode) == width &&
CGDisplayModeGetHeight(mode) == height) {
if (CGDisplayModeGetWidth(mode) == display_size.width &&
CGDisplayModeGetHeight(mode) == display_size.height &&
CGDisplayModeGetPixelWidth(mode) == pixel_size.width &&
CGDisplayModeGetPixelHeight(mode) == pixel_size.height) {
CFArrayAppendValue(valid_modes, mode);
CGDisplayModeRelease(mode);
return valid_modes;
}
// Get the current refresh rate and pixel encoding.
CFStringRef current_pixel_encoding;
double refresh_rate;
current_pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
refresh_rate = CGDisplayModeGetRefreshRate(mode);
// Calculate the pixel width and height of the fullscreen mode we want using
// the currentdisplay mode dimensions and pixel dimensions.
size_t expected_pixel_width = (size_t(width) * CGDisplayModeGetPixelWidth(mode)) / CGDisplayModeGetWidth(mode);
size_t expected_pixel_height = (size_t(height) * CGDisplayModeGetPixelHeight(mode)) / CGDisplayModeGetHeight(mode);
CGDisplayModeRelease(mode);
for (size_t i = 0; i < num_modes; ++i) {
@ -1015,17 +1079,15 @@ find_display_modes(int width, int height) {
CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
// As explained above, we want to select the fullscreen display mode using
// the same scaling factor, but only for MacOS 10.15+ To do this we check
// the mode width and height but also actual pixel widh and height.
if (CGDisplayModeGetWidth(mode) == width &&
CGDisplayModeGetHeight(mode) == height &&
// We select the fullscreen display mode using he same scaling factor
// To do this we check the mode width and height but also actual pixel widh
// and height.
if (CGDisplayModeGetWidth(mode) == display_size.width &&
CGDisplayModeGetHeight(mode) == display_size.height &&
(int)(CGDisplayModeGetRefreshRate(mode) + 0.5) == (int)(refresh_rate + 0.5) &&
(!macos_10_15_or_higher ||
(CGDisplayModeGetPixelWidth(mode) == expected_pixel_width &&
CGDisplayModeGetPixelHeight(mode) == expected_pixel_height)) &&
CGDisplayModeGetPixelWidth(mode) == pixel_size.width &&
CGDisplayModeGetPixelHeight(mode) == pixel_size.height &&
CFStringCompare(pixel_encoding, current_pixel_encoding, 0) == kCFCompareEqualTo) {
if (CGDisplayModeGetRefreshRate(mode) == refresh_rate) {
// Exact match for refresh rate, prioritize this.
CFArrayInsertValueAtIndex(valid_modes, 0, mode);
@ -1103,14 +1165,25 @@ do_switch_fullscreen(CGDisplayModeRef mode) {
NSRect frame = [[[_view window] screen] frame];
if (cocoadisplay_cat.is_debug()) {
NSString *str = NSStringFromRect(frame);
NSString *str = NSStringFromSize([_view convertSizeToBacking:frame.size]);
cocoadisplay_cat.debug()
<< "Switched to fullscreen, screen rect is now " << [str UTF8String] << "\n";
<< "Switched to fullscreen, screen size is now " << [str UTF8String] << "\n";
}
if (_window != nil) {
// For some reason, setting the style mask makes it give up its
// first-responder status.
if ([_window respondsToSelector:@selector(setStyleMask:)]) {
[_window setStyleMask:NSBorderlessWindowMask];
}
[_window makeFirstResponder:_view];
[_window setLevel:CGShieldingWindowLevel()];
[_window makeKeyAndOrderFront:nil];
// Window and view frame must be updated *after* the window reconfiguration
// or the size is not set properly !
[_window setFrame:frame display:YES];
[_view setFrame:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
[_view setFrame:frame];
[_window update];
}
}
@ -1252,19 +1325,25 @@ load_cursor(const Filename &filename) {
*/
void CocoaGraphicsWindow::
handle_move_event() {
// Remember, Mac OS X uses flipped coordinates
NSRect frame;
NSRect container;
int x, y;
// Again, we are using the view to convert the frame and container size from
// points to pixels.
if (_window == nil) {
frame = [_view frame];
x = frame.origin.x;
y = [[_view superview] bounds].size.height - frame.origin.y - frame.size.height;
frame = [_view convertRectToBacking:[_view frame]];
container = [_view convertRectToBacking:[[_view superview] frame]];
} else {
frame = [_window contentRectForFrameRect:[_window frame]];
x = frame.origin.x;
y = [[_window screen] frame].size.height - frame.origin.y - frame.size.height;
frame = [_view convertRectToBacking:[_window contentRectForFrameRect:[_window frame]]];
NSScreen *screen = [_window screen];
nassertv(screen != nil);
container = [_view convertRectToBacking:[screen frame]];
}
// Y coordinate in backing store is not flipped, but origin is still at the bottom left
x = frame.origin.x;
y = container.size.height + frame.origin.y;
if (x != _properties.get_x_origin() ||
y != _properties.get_y_origin()) {
@ -1290,7 +1369,7 @@ handle_resize_event() {
[_view setFrameSize:contentRect.size];
}
NSRect frame = [_view convertRect:[_view bounds] toView:nil];
NSRect frame = [_view convertRectToBacking:[_view bounds]];
WindowProperties properties;
bool changed = false;
@ -1403,6 +1482,22 @@ handle_foreground_event(bool foreground) {
}
}
/**
* Called by the window delegate when the properties of backing store of the
* window have changed.
*/
void CocoaGraphicsWindow::
handle_backing_change_event() {
if (cocoadisplay_cat.is_debug()) {
cocoadisplay_cat.debug() << "Backing store properties have changed\n";
}
// Trigger a resize event to update the window size in case the backing scale
// factor did change.
handle_resize_event();
}
/**
* Called by the window delegate when the user requests to close the window.
* This may not always be called, which is why there is also a
@ -1693,6 +1788,13 @@ void CocoaGraphicsWindow::
handle_mouse_moved_event(bool in_window, double x, double y, bool absolute) {
double nx, ny;
// Mouse position is received in screen points and not pixels, but in Panda3D
// we want to have the coordinates expressed in pixels.
// Instead of using convertPointFrom/toBackingStore and have complex logic to
// cope with the change of coordinate system, we cheat and directly use the
// contents scale of the view layer to convert screen point into pixels and
// vice-versa.
CGFloat contents_scale = _view.layer.contentsScale;
if (absolute) {
if (cocoadisplay_cat.is_spam()) {
if (in_window != _input->get_pointer().get_in_window()) {
@ -1704,14 +1806,14 @@ handle_mouse_moved_event(bool in_window, double x, double y, bool absolute) {
}
}
nx = x;
ny = y;
nx = x * contents_scale;
ny = y * contents_scale;
} else {
// We received deltas, so add it to the current mouse position.
PointerData md = _input->get_pointer();
nx = md.get_x() + x;
ny = md.get_y() + y;
nx = md.get_x() + x * contents_scale;
ny = md.get_y() + y * contents_scale;
}
if (_properties.get_mouse_mode() == WindowProperties::M_confined
@ -1721,11 +1823,13 @@ handle_mouse_moved_event(bool in_window, double x, double y, bool absolute) {
nx = std::max(0., std::min((double) get_x_size() - 1, nx));
ny = std::max(0., std::min((double) get_y_size() - 1, ny));
// Convert back mouse position to screen space using point units
if (_properties.get_fullscreen()) {
point = CGPointMake(nx, ny);
point = CGPointMake(nx / contents_scale,
ny / contents_scale);
} else {
point = CGPointMake(nx + _properties.get_x_origin(),
ny + _properties.get_y_origin());
point = CGPointMake((nx + _properties.get_x_origin()) / contents_scale,
(ny + _properties.get_y_origin()) / contents_scale);
}
if (CGWarpMouseCursorPosition(point) == kCGErrorSuccess) {

View File

@ -29,6 +29,7 @@ class CocoaGraphicsWindow;
- (void)windowDidDeminiaturize:(NSNotification *)notification;
- (void)windowDidBecomeKey:(NSNotification *)notification;
- (void)windowDidResignKey:(NSNotification *)notification;
- (void)windowDidChangeBackingProperties:(NSNotification *)notification;
- (BOOL)windowShouldClose:(id)sender;
- (void)windowWillClose:(id)sender;

View File

@ -51,6 +51,10 @@
_graphicsWindow->handle_foreground_event(false);
}
- (void) windowDidChangeBackingProperties:(NSNotification *)notification {
_graphicsWindow->handle_backing_change_event();
}
- (BOOL) windowShouldClose:(id)sender {
if (cocoadisplay_cat.is_debug()) {
cocoadisplay_cat.debug()

View File

@ -21,6 +21,7 @@
NotifyCategoryDecl(cocoadisplay, EXPCL_PANDA_COCOADISPLAY, EXPTP_PANDA_COCOADISPLAY);
extern ConfigVariableBool cocoa_invert_wheel_x;
extern ConfigVariableBool dpi_aware;
extern EXPCL_PANDA_COCOADISPLAY void init_libcocoadisplay();

View File

@ -32,6 +32,11 @@ ConfigVariableBool cocoa_invert_wheel_x
("cocoa-invert-wheel-x", false,
PRC_DESC("Set this to true to swap the wheel_left and wheel_right mouse "
"button events, to restore to the pre-1.10.12 behavior."));
ConfigVariableBool dpi_aware
("dpi-aware", false,
PRC_DESC("The default behavior on macOS is for Panda3D to use upscaling on"
"high DPI screen. Set this to true to let the application use the"
"actual pixel density of the screen."));
/**
* Initializes the library. This must be called at least once before any of