|
|
|
|
@ -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) {
|
|
|
|
|
|