Commit 1c94bf39 authored by Ken Thomases's avatar Ken Thomases Committed by Alexandre Julliard

winemac: Add support for a high-resolution ("Retina") rendering mode.

When this Retina mode is enabled and the primary display is in the user's default configuration, Wine gets told that screen and window sizes and mouse coordinates are twice what Cocoa reports them as in its virtual coordinate system ("points"). The Windows apps then renders at that high resolution and the Mac driver blits it to screen. If the screen is actually a Retina display in a high-DPI mode, then this extra detail will be preserved. Otherwise, the rendering will be downsampled and blurry. This is intended to be combined with increasing the Windows DPI, as via winecfg. If that is doubled to 192, then, in theory, graphical elements will remain the same visual size on screen but be rendered with finer detail. Unfortunately, many Windows programs don't correctly handle non-standard DPI so the results are not always perfect. The registry setting to enable Retina mode is: [HKEY_CURRENT_USER\Software\Wine\Mac Driver] "RetinaMode"="y" Note that this setting is not looked for in the AppDefaults\<exe name> key because it doesn't make sense for only some processes in a Wine session to see the high-resolution sizes and coordinates. Signed-off-by: 's avatarKen Thomases <ken@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 91733274
......@@ -1590,6 +1590,7 @@ static NSString* WineLocalizedString(unsigned int stringID)
{
if (clippingCursor)
[self clipCursorLocation:&point];
point = cgpoint_win_from_mac(point);
event = macdrv_create_event(MOUSE_MOVED_ABSOLUTE, targetWindow);
event->mouse_moved.x = floor(point.x);
......@@ -1600,18 +1601,20 @@ static NSString* WineLocalizedString(unsigned int stringID)
}
else
{
double scale = retina_on ? 2 : 1;
/* Add event delta to accumulated delta error */
/* deltaY is already flipped */
mouseMoveDeltaX += [anEvent deltaX];
mouseMoveDeltaY += [anEvent deltaY];
event = macdrv_create_event(MOUSE_MOVED, targetWindow);
event->mouse_moved.x = mouseMoveDeltaX;
event->mouse_moved.y = mouseMoveDeltaY;
event->mouse_moved.x = mouseMoveDeltaX * scale;
event->mouse_moved.y = mouseMoveDeltaY * scale;
/* Keep the remainder after integer truncation. */
mouseMoveDeltaX -= event->mouse_moved.x;
mouseMoveDeltaY -= event->mouse_moved.y;
mouseMoveDeltaX -= event->mouse_moved.x / scale;
mouseMoveDeltaY -= event->mouse_moved.y / scale;
}
if (event->type == MOUSE_MOVED_ABSOLUTE || event->mouse_moved.x || event->mouse_moved.y)
......@@ -1730,6 +1733,8 @@ static NSString* WineLocalizedString(unsigned int stringID)
{
macdrv_event* event;
pt = cgpoint_win_from_mac(pt);
event = macdrv_create_event(MOUSE_BUTTON, window);
event->mouse_button.button = [theEvent buttonNumber];
event->mouse_button.pressed = pressed;
......@@ -1811,6 +1816,8 @@ static NSString* WineLocalizedString(unsigned int stringID)
double x, y;
BOOL continuous = FALSE;
pt = cgpoint_win_from_mac(pt);
event = macdrv_create_event(MOUSE_SCROLL, window);
event->mouse_scroll.x = floor(pt.x);
event->mouse_scroll.y = floor(pt.y);
......@@ -2146,6 +2153,26 @@ static NSString* WineLocalizedString(unsigned int stringID)
}
}
- (void) setRetinaMode:(int)mode
{
retina_on = mode;
if (clippingCursor)
{
double scale = mode ? 0.5 : 2.0;
cursorClipRect.origin.x *= scale;
cursorClipRect.origin.y *= scale;
cursorClipRect.size.width *= scale;
cursorClipRect.size.height *= scale;
}
for (WineWindow* window in [NSApp windows])
{
if ([window isKindOfClass:[WineWindow class]])
[window setRetinaMode:mode];
}
}
/*
* ---------- NSApplicationDelegate methods ----------
......@@ -2496,7 +2523,7 @@ int macdrv_get_cursor_position(CGPoint *pos)
OnMainThread(^{
NSPoint location = [NSEvent mouseLocation];
location = [[WineApplicationController sharedController] flippedMouseLocation:location];
*pos = NSPointToCGPoint(location);
*pos = cgpoint_win_from_mac(NSPointToCGPoint(location));
});
return TRUE;
......@@ -2513,7 +2540,7 @@ int macdrv_set_cursor_position(CGPoint pos)
__block int ret;
OnMainThread(^{
ret = [[WineApplicationController sharedController] setCursorPosition:pos];
ret = [[WineApplicationController sharedController] setCursorPosition:cgpoint_mac_from_win(pos)];
});
return ret;
......@@ -2526,13 +2553,17 @@ int macdrv_set_cursor_position(CGPoint pos)
* to or larger than the whole desktop region, the cursor is unclipped.
* Returns zero on failure, non-zero on success.
*/
int macdrv_clip_cursor(CGRect rect)
int macdrv_clip_cursor(CGRect r)
{
__block int ret;
OnMainThread(^{
WineApplicationController* controller = [WineApplicationController sharedController];
BOOL clipping = FALSE;
CGRect rect = r;
if (!CGRectIsInfinite(rect))
rect = cgrect_mac_from_win(rect);
if (!CGRectIsInfinite(rect))
{
......@@ -2676,3 +2707,10 @@ int macdrv_select_input_source(TISInputSourceRef input_source)
return ret;
}
void macdrv_set_cocoa_retina_mode(int new_mode)
{
OnMainThread(^{
[[WineApplicationController sharedController] setRetinaMode:new_mode];
});
}
......@@ -78,6 +78,8 @@ int macdrv_get_displays(struct macdrv_display** displays, int* count)
convert_display_rect(&disps[i].frame, frame, primary_frame);
convert_display_rect(&disps[i].work_frame, visible_frame,
primary_frame);
disps[i].frame = cgrect_win_from_mac(disps[i].frame);
disps[i].work_frame = cgrect_win_from_mac(disps[i].work_frame);
}
*displays = disps;
......
......@@ -323,6 +323,8 @@ static const OSType WineHotKeySignature = 'Wine';
{
MacDrvEvent* event;
pos = cgpoint_win_from_mac(pos);
[eventsLock lock];
for (event in events)
......
......@@ -26,6 +26,8 @@
NSView* latentView;
BOOL needsUpdate;
BOOL shouldClearToBlack;
GLint backing_size[2];
}
@property BOOL needsUpdate;
......
......@@ -27,6 +27,10 @@
@interface WineOpenGLContext ()
@property (retain, nonatomic) NSView* latentView;
+ (NSView*) dummyView;
- (void) wine_updateBackingSize:(const CGSize*)size;
@end
......@@ -40,6 +44,81 @@
[super dealloc];
}
+ (NSView*) dummyView
{
static NSWindow* dummyWindow;
static dispatch_once_t once;
dispatch_once(&once, ^{
OnMainThread(^{
dummyWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
});
});
return dummyWindow.contentView;
}
// Normally, we take care that disconnecting a context from a view doesn't
// destroy that view's GL surface (see -clearDrawableLeavingSurfaceOnScreen).
// However, if we're using a surface backing size and that size changes, we
// need to destroy and recreate the surface or we get weird behavior.
- (void) resetSurfaceIfBackingSizeChanged
{
if (!retina_enabled)
return;
int view_backing[2];
if (macdrv_get_view_backing_size((macdrv_view)self.view, view_backing) &&
(view_backing[0] != backing_size[0] || view_backing[1] != backing_size[1]))
{
view_backing[0] = backing_size[0];
view_backing[1] = backing_size[1];
macdrv_set_view_backing_size((macdrv_view)self.view, view_backing);
NSView* save = self.view;
[super clearDrawable];
[super setView:save];
shouldClearToBlack = TRUE;
}
}
- (void) wine_updateBackingSize:(const CGSize*)size
{
GLint enabled;
if (!retina_enabled)
return;
if (size)
{
if (CGLIsEnabled(self.CGLContextObj, kCGLCESurfaceBackingSize, &enabled) != kCGLNoError)
enabled = 0;
if (!enabled || backing_size[0] != size->width || backing_size[1] != size->height)
{
backing_size[0] = size->width;
backing_size[1] = size->height;
CGLSetParameter(self.CGLContextObj, kCGLCPSurfaceBackingSize, backing_size);
}
if (!enabled)
CGLEnable(self.CGLContextObj, kCGLCESurfaceBackingSize);
[self resetSurfaceIfBackingSizeChanged];
}
else
{
backing_size[0] = 0;
backing_size[1] = 0;
if (CGLIsEnabled(self.CGLContextObj, kCGLCESurfaceBackingSize, &enabled) == kCGLNoError && enabled)
CGLDisable(self.CGLContextObj, kCGLCESurfaceBackingSize);
}
}
- (void) setView:(NSView*)newView
{
NSView* oldView = [self view];
......@@ -53,6 +132,8 @@
NSView* oldView = [self view];
[super clearDrawable];
[oldView release];
[self wine_updateBackingSize:NULL];
}
/* On at least some versions of Mac OS X, -[NSOpenGLContext clearDrawable] has the
......@@ -64,19 +145,7 @@
original implementation proceed. */
- (void) clearDrawableLeavingSurfaceOnScreen
{
static NSWindow* dummyWindow;
static dispatch_once_t once;
dispatch_once(&once, ^{
OnMainThread(^{
dummyWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
});
});
[self setView:[dummyWindow contentView]];
[self setView:[[self class] dummyView]];
[self clearDrawable];
}
......@@ -189,7 +258,7 @@ void macdrv_dispose_opengl_context(macdrv_opengl_context c)
/***********************************************************************
* macdrv_make_context_current
*/
void macdrv_make_context_current(macdrv_opengl_context c, macdrv_view v)
void macdrv_make_context_current(macdrv_opengl_context c, macdrv_view v, CGRect r)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineOpenGLContext *context = (WineOpenGLContext*)c;
......@@ -198,7 +267,10 @@ void macdrv_make_context_current(macdrv_opengl_context c, macdrv_view v)
if (context && view)
{
if (view == [context view] || view == [context latentView])
{
[context wine_updateBackingSize:&r.size];
macdrv_update_opengl_context(c);
}
else
{
[context removeFromViews:NO];
......@@ -207,13 +279,18 @@ void macdrv_make_context_current(macdrv_opengl_context c, macdrv_view v)
if (context.needsUpdate)
{
context.needsUpdate = FALSE;
if (context.view)
[context setView:[[context class] dummyView]];
[context wine_updateBackingSize:&r.size];
[context setView:view];
[context setLatentView:nil];
[context resetSurfaceIfBackingSizeChanged];
}
else
{
if ([context view])
[context clearDrawableLeavingSurfaceOnScreen];
[context wine_updateBackingSize:&r.size];
[context setLatentView:view];
}
}
......@@ -257,10 +334,14 @@ void macdrv_update_opengl_context(macdrv_opengl_context c)
[context setView:context.latentView];
context.latentView = nil;
[context resetSurfaceIfBackingSizeChanged];
[context clearToBlackIfNeeded];
}
else
{
[context update];
[context resetSurfaceIfBackingSizeChanged];
}
}
[pool release];
......
......@@ -46,6 +46,9 @@
CGDirectDisplayID _lastDisplayID;
NSTimeInterval _lastDisplayTime;
NSRect wineFrame;
NSRect roundedWineFrame;
NSBezierPath* shape;
NSData* shapeData;
BOOL shapeChangedSinceLastDraw;
......@@ -88,6 +91,7 @@
@property (readonly, nonatomic) BOOL floating;
@property (readonly, getter=isFullscreen, nonatomic) BOOL fullscreen;
@property (readonly, getter=isFakingClose, nonatomic) BOOL fakingClose;
@property (readonly, nonatomic) NSRect wine_fractionalFrame;
- (NSInteger) minimumLevelForActive:(BOOL)active;
- (void) updateFullscreen;
......@@ -99,4 +103,6 @@
- (void) updateForCursorClipping;
- (void) setRetinaMode:(int)mode;
@end
......@@ -488,7 +488,7 @@ static int get_default_bpp(void)
#if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
static CFDictionaryRef create_mode_dict(CGDisplayModeRef display_mode)
static CFDictionaryRef create_mode_dict(CGDisplayModeRef display_mode, BOOL is_original)
{
CFDictionaryRef ret;
SInt32 io_flags = CGDisplayModeGetIOFlags(display_mode);
......@@ -498,6 +498,12 @@ static CFDictionaryRef create_mode_dict(CGDisplayModeRef display_mode)
CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(display_mode);
CFNumberRef cf_io_flags, cf_width, cf_height, cf_refresh;
if (retina_enabled && is_original)
{
width *= 2;
height *= 2;
}
io_flags &= kDisplayModeValidFlag | kDisplayModeSafeFlag | kDisplayModeInterlacedFlag |
kDisplayModeStretchedFlag | kDisplayModeTelevisionFlag;
cf_io_flags = CFNumberCreate(NULL, kCFNumberSInt32Type, &io_flags);
......@@ -581,7 +587,7 @@ static CFArrayRef copy_display_modes(CGDirectDisplayID display)
BOOL better = TRUE;
CGDisplayModeRef new_mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i);
BOOL new_is_original = display_mode_matches_descriptor(new_mode, desc);
CFDictionaryRef key = create_mode_dict(new_mode);
CFDictionaryRef key = create_mode_dict(new_mode, new_is_original);
/* If a given mode is the user's default, then always list it in preference to any similar
modes that may exist. */
......@@ -667,6 +673,23 @@ static CFArrayRef copy_display_modes(CGDirectDisplayID display)
}
void check_retina_status(void)
{
if (retina_enabled)
{
struct display_mode_descriptor* desc = create_original_display_mode_descriptor(kCGDirectMainDisplay);
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(kCGDirectMainDisplay);
BOOL new_value = display_mode_matches_descriptor(mode, desc);
CGDisplayModeRelease(mode);
free_display_mode_descriptor(desc);
if (new_value != retina_on)
macdrv_set_cocoa_retina_mode(new_value);
}
}
/***********************************************************************
* ChangeDisplaySettingsEx (MACDRV.@)
*
......@@ -681,9 +704,11 @@ LONG CDECL macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode,
struct macdrv_display *displays;
int num_displays;
CFArrayRef display_modes;
struct display_mode_descriptor* desc;
CFIndex count, i, safe, best;
CGDisplayModeRef best_display_mode;
uint32_t best_io_flags;
BOOL best_is_original;
TRACE("%s %p %p 0x%08x %p\n", debugstr_w(devname), devmode, hwnd, flags, lpvoid);
......@@ -748,17 +773,26 @@ LONG CDECL macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode,
TRACE(" %sinterlaced", devmode->dmDisplayFlags & DM_INTERLACED ? "" : "non-");
TRACE("\n");
desc = create_original_display_mode_descriptor(displays[0].displayID);
safe = -1;
best_display_mode = NULL;
count = CFArrayGetCount(display_modes);
for (i = 0; i < count; i++)
{
CGDisplayModeRef display_mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(display_modes, i);
BOOL is_original = display_mode_matches_descriptor(display_mode, desc);
uint32_t io_flags = CGDisplayModeGetIOFlags(display_mode);
int mode_bpp = display_mode_bits_per_pixel(display_mode);
size_t width = CGDisplayModeGetWidth(display_mode);
size_t height = CGDisplayModeGetHeight(display_mode);
if (is_original && retina_enabled)
{
width *= 2;
height *= 2;
}
if (!(io_flags & kDisplayModeValidFlag) || !(io_flags & kDisplayModeSafeFlag))
continue;
......@@ -817,6 +851,7 @@ better:
best_display_mode = display_mode;
best = safe;
best_io_flags = io_flags;
best_is_original = is_original;
}
if (best_display_mode)
......@@ -837,6 +872,12 @@ better:
size_t width = CGDisplayModeGetWidth(best_display_mode);
size_t height = CGDisplayModeGetHeight(best_display_mode);
if (best_is_original && retina_enabled)
{
width *= 2;
height *= 2;
}
SendMessageW(GetDesktopWindow(), WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp,
MAKELPARAM(width, height));
ret = DISP_CHANGE_SUCCESSFUL;
......@@ -854,6 +895,7 @@ better:
bpp, devmode->dmDisplayFrequency);
}
free_display_mode_descriptor(desc);
CFRelease(display_modes);
macdrv_free_displays(displays);
......@@ -1082,6 +1124,16 @@ BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode,
devmode->dmPelsWidth = CGDisplayModeGetWidth(display_mode);
devmode->dmPelsHeight = CGDisplayModeGetHeight(display_mode);
if (retina_enabled)
{
struct display_mode_descriptor* desc = create_original_display_mode_descriptor(displays[0].displayID);
if (display_mode_matches_descriptor(display_mode, desc))
{
devmode->dmPelsWidth *= 2;
devmode->dmPelsHeight *= 2;
}
free_display_mode_descriptor(desc);
}
devmode->dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
devmode->dmDisplayFlags = 0;
......@@ -1329,8 +1381,18 @@ void macdrv_displays_changed(const macdrv_event *event)
size_t width = CGDisplayModeGetWidth(mode);
size_t height = CGDisplayModeGetHeight(mode);
int mode_bpp = display_mode_bits_per_pixel(mode);
struct display_mode_descriptor* desc = create_original_display_mode_descriptor(mainDisplay);
BOOL is_original = display_mode_matches_descriptor(mode, desc);
free_display_mode_descriptor(desc);
CGDisplayModeRelease(mode);
if (is_original && retina_enabled)
{
width *= 2;
height *= 2;
}
SendMessageW(hwnd, WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp,
MAKELPARAM(width, height));
}
......
......@@ -51,6 +51,8 @@ static int desktop_vert_res; /* height in pixels of virtual desktop */
static int bits_per_pixel; /* pixel depth of screen */
static int device_data_valid; /* do the above variables have up-to-date values? */
int retina_on = FALSE;
static CRITICAL_SECTION device_data_section;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
......@@ -94,6 +96,29 @@ static DWORD get_dpi(void)
/***********************************************************************
* compute_desktop_rect
*/
static void compute_desktop_rect(void)
{
CGDirectDisplayID displayIDs[32];
uint32_t count, i;
desktop_rect = CGRectNull;
if (CGGetActiveDisplayList(sizeof(displayIDs)/sizeof(displayIDs[0]),
displayIDs, &count) != kCGErrorSuccess ||
!count)
{
displayIDs[0] = CGMainDisplayID();
count = 1;
}
for (i = 0; i < count; i++)
desktop_rect = CGRectUnion(desktop_rect, CGDisplayBounds(displayIDs[i]));
desktop_rect = cgrect_win_from_mac(desktop_rect);
}
/***********************************************************************
* macdrv_get_desktop_rect
*
* Returns the rectangle encompassing all the screens.
......@@ -101,27 +126,16 @@ static DWORD get_dpi(void)
CGRect macdrv_get_desktop_rect(void)
{
CGRect ret;
CGDirectDisplayID displayIDs[32];
uint32_t count, i;
EnterCriticalSection(&device_data_section);
if (!device_data_valid)
{
desktop_rect = CGRectNull;
if (CGGetActiveDisplayList(sizeof(displayIDs)/sizeof(displayIDs[0]),
displayIDs, &count) != kCGErrorSuccess ||
!count)
{
displayIDs[0] = CGMainDisplayID();
count = 1;
}
for (i = 0; i < count; i++)
desktop_rect = CGRectUnion(desktop_rect, CGDisplayBounds(displayIDs[i]));
check_retina_status();
compute_desktop_rect();
}
ret = desktop_rect;
LeaveCriticalSection(&device_data_section);
TRACE("%s\n", wine_dbgstr_cgrect(ret));
......@@ -141,12 +155,23 @@ static void device_init(void)
CGSize size_mm = CGDisplayScreenSize(mainDisplay);
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(mainDisplay);
check_retina_status();
/* Initialize device caps */
log_pixels_x = log_pixels_y = get_dpi();
if (!log_pixels_x)
{
size_t width = CGDisplayPixelsWide(mainDisplay);
size_t height = CGDisplayPixelsHigh(mainDisplay);
if (retina_on)
{
/* Although CGDisplayPixelsWide/High() claim to report in pixels, they
actually report in points. */
width *= 2;
height *= 2;
}
log_pixels_x = MulDiv(width, 254, size_mm.width * 10);
log_pixels_y = MulDiv(height, 254, size_mm.height * 10);
}
......@@ -181,7 +206,13 @@ static void device_init(void)
vert_res = CGDisplayPixelsHigh(mainDisplay);
}
macdrv_get_desktop_rect();
if (retina_on)
{
horz_res *= 2;
vert_res *= 2;
}
compute_desktop_rect();
desktop_horz_res = desktop_rect.size.width;
desktop_vert_res = desktop_rect.size.height;
......
......@@ -219,6 +219,7 @@ extern CFArrayRef create_app_icon_images(void) DECLSPEC_HIDDEN;
extern void macdrv_status_item_mouse_button(const macdrv_event *event) DECLSPEC_HIDDEN;
extern void macdrv_status_item_mouse_move(const macdrv_event *event) DECLSPEC_HIDDEN;
extern void check_retina_status(void) DECLSPEC_HIDDEN;
/**************************************************************************
* Mac IME driver
......
......@@ -160,6 +160,78 @@ extern int cursor_clipping_locks_windows DECLSPEC_HIDDEN;
extern int use_precise_scrolling DECLSPEC_HIDDEN;
extern int gl_surface_mode DECLSPEC_HIDDEN;
extern CFDictionaryRef localized_strings DECLSPEC_HIDDEN;
extern int retina_enabled DECLSPEC_HIDDEN; /* Whether Retina mode is enabled via registry setting. */
extern int retina_on DECLSPEC_HIDDEN; /* Whether Retina mode is currently active (enabled and display is in default mode). */
static inline CGRect cgrect_mac_from_win(CGRect rect)
{
if (retina_on)
{
rect.origin.x /= 2;
rect.origin.y /= 2;
rect.size.width /= 2;
rect.size.height /= 2;
}
return rect;
}
static inline CGRect cgrect_win_from_mac(CGRect rect)
{
if (retina_on)
{
rect.origin.x *= 2;
rect.origin.y *= 2;
rect.size.width *= 2;
rect.size.height *= 2;
}
return rect;
}
static inline CGSize cgsize_mac_from_win(CGSize size)
{
if (retina_on)
{
size.width /= 2;
size.height /= 2;
}
return size;
}
static inline CGSize cgsize_win_from_mac(CGSize size)
{
if (retina_on)
{
size.width *= 2;
size.height *= 2;
}
return size;
}
static inline CGPoint cgpoint_mac_from_win(CGPoint point)
{
if (retina_on)
{
point.x /= 2;
point.y /= 2;
}
return point;
}
static inline CGPoint cgpoint_win_from_mac(CGPoint point)
{
if (retina_on)
{
point.x *= 2;
point.y *= 2;
}
return point;
}
extern int macdrv_start_cocoa_app(unsigned long long tickcount) DECLSPEC_HIDDEN;
extern void macdrv_window_rejected_focus(const struct macdrv_event *event) DECLSPEC_HIDDEN;
......@@ -168,6 +240,7 @@ extern void macdrv_set_application_icon(CFArrayRef images) DECLSPEC_HIDDEN;
extern void macdrv_quit_reply(int reply) DECLSPEC_HIDDEN;
extern int macdrv_using_input_method(void) DECLSPEC_HIDDEN;
extern void macdrv_set_mouse_capture_window(macdrv_window window) DECLSPEC_HIDDEN;
extern void macdrv_set_cocoa_retina_mode(int new_mode) DECLSPEC_HIDDEN;
/* cursor */
......@@ -443,6 +516,8 @@ extern void macdrv_dispose_view(macdrv_view v) DECLSPEC_HIDDEN;
extern void macdrv_set_view_window_and_frame(macdrv_view v, macdrv_window w, CGRect rect) DECLSPEC_HIDDEN;
extern void macdrv_add_view_opengl_context(macdrv_view v, macdrv_opengl_context c) DECLSPEC_HIDDEN;
extern void macdrv_remove_view_opengl_context(macdrv_view v, macdrv_opengl_context c) DECLSPEC_HIDDEN;
extern int macdrv_get_view_backing_size(macdrv_view v, int backing_size[2]) DECLSPEC_HIDDEN;
extern void macdrv_set_view_backing_size(macdrv_view v, const int backing_size[2]) DECLSPEC_HIDDEN;
extern uint32_t macdrv_window_background_color(void) DECLSPEC_HIDDEN;
extern void macdrv_send_text_input_event(int pressed, unsigned int flags, int repeat, int keyc,
void* data, int* done) DECLSPEC_HIDDEN;
......@@ -470,7 +545,7 @@ extern int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data, macdrv_w
/* opengl */
extern macdrv_opengl_context macdrv_create_opengl_context(void* cglctx) DECLSPEC_HIDDEN;
extern void macdrv_dispose_opengl_context(macdrv_opengl_context c) DECLSPEC_HIDDEN;
extern void macdrv_make_context_current(macdrv_opengl_context c, macdrv_view v) DECLSPEC_HIDDEN;
extern void macdrv_make_context_current(macdrv_opengl_context c, macdrv_view v, CGRect r) DECLSPEC_HIDDEN;
extern void macdrv_update_opengl_context(macdrv_opengl_context c) DECLSPEC_HIDDEN;
extern void macdrv_flush_opengl_context(macdrv_opengl_context c) DECLSPEC_HIDDEN;
......
......@@ -58,6 +58,7 @@ int allow_immovable_windows = TRUE;
int cursor_clipping_locks_windows = TRUE;
int use_precise_scrolling = TRUE;
int gl_surface_mode = GL_SURFACE_IN_FRONT_OPAQUE;
int retina_enabled = FALSE;
HMODULE macdrv_module = 0;
CFDictionaryRef localized_strings;
......@@ -196,6 +197,11 @@ static void setup_options(void)
gl_surface_mode = GL_SURFACE_IN_FRONT_OPAQUE;
}
/* Don't use appkey. The DPI and monitor sizes should be consistent for all
processes in the prefix. */
if (!get_config_key(hkey, NULL, "RetinaMode", buffer, sizeof(buffer)))
retina_enabled = IS_OPTION_TRUE(buffer[0]);
if (appkey) RegCloseKey(appkey);
if (hkey) RegCloseKey(hkey);
}
......
......@@ -65,12 +65,15 @@ struct wgl_context
CGLContextObj cglcontext;
HWND draw_hwnd;
macdrv_view draw_view;
RECT draw_rect;
struct wgl_pbuffer *draw_pbuffer;
macdrv_view read_view;
RECT read_rect;
struct wgl_pbuffer *read_pbuffer;
BOOL has_been_current;
BOOL sharing;
LONG update_swap_interval;
LONG view_moved;
DWORD last_flush_time;
UINT major;
};
......@@ -1691,6 +1694,23 @@ done:
/**********************************************************************
* mark_contexts_for_moved_view
*/
static void mark_contexts_for_moved_view(macdrv_view view)
{
struct wgl_context *context;
EnterCriticalSection(&context_section);
LIST_FOR_EACH_ENTRY(context, &context_list, struct wgl_context, entry)
{
if (context->draw_view == view)
InterlockedExchange(&context->view_moved, TRUE);
}
LeaveCriticalSection(&context_section);
}
/**********************************************************************
* set_gl_view_parent
*/
void set_gl_view_parent(HWND hwnd, HWND parent)
......@@ -1716,6 +1736,7 @@ void set_gl_view_parent(HWND hwnd, HWND parent)
}
macdrv_set_view_window_and_frame(data->gl_view, cocoa_window, cgrect_from_rect(data->gl_rect));
mark_contexts_for_moved_view(data->gl_view);
}
release_win_data(data);
......@@ -1723,28 +1744,59 @@ void set_gl_view_parent(HWND hwnd, HWND parent)
/**********************************************************************
* sync_context_rect
*/
static BOOL sync_context_rect(struct wgl_context *context)
{
BOOL ret = FALSE;
if (InterlockedCompareExchange(&context->view_moved, FALSE, TRUE))
{
struct macdrv_win_data *data = get_win_data(context->draw_hwnd);
if (data && data->gl_view && data->gl_view == context->draw_view &&
memcmp(&context->draw_rect, &data->gl_rect, sizeof(context->draw_rect)))
{
context->draw_rect = data->gl_rect;
ret = TRUE;
}
release_win_data(data);
}
return ret;
}
/**********************************************************************
* make_context_current
*/
static void make_context_current(struct wgl_context *context, BOOL read)
{
macdrv_view view;
RECT view_rect;
struct wgl_pbuffer *pbuffer;
if (read)
{
view = context->read_view;
view_rect = context->read_rect;
pbuffer = context->read_pbuffer;
}
else
{
sync_context_rect(context);
view = context->draw_view;
view_rect = context->draw_rect;
pbuffer = context->draw_pbuffer;
}
if (view || !pbuffer)
macdrv_make_context_current(context->context, view);
macdrv_make_context_current(context->context, view, cgrect_from_rect(view_rect));
else
{
GLint enabled;
if (CGLIsEnabled(context->cglcontext, kCGLCESurfaceBackingSize, &enabled) == kCGLNoError && enabled)
CGLDisable(context->cglcontext, kCGLCESurfaceBackingSize);
CGLSetPBuffer(context->cglcontext, pbuffer->pbuffer, pbuffer->face,
pbuffer->level, 0);
CGLSetCurrentContext(context->cglcontext);
......@@ -1753,6 +1805,16 @@ static void make_context_current(struct wgl_context *context, BOOL read)
/**********************************************************************
* sync_context
*/
static void sync_context(struct wgl_context *context)
{
if (sync_context_rect(context))
make_context_current(context, FALSE);
}
/**********************************************************************
* set_swap_interval
*/
static BOOL set_swap_interval(struct wgl_context *context, long interval)
......@@ -2275,6 +2337,7 @@ static void macdrv_glFinish(void)
struct wgl_context *context = NtCurrentTeb()->glContext;
sync_swap_interval(context);
sync_context(context);
pglFinish();
}
......@@ -2287,6 +2350,7 @@ static void macdrv_glFlush(void)
struct wgl_context *context = NtCurrentTeb()->glContext;
sync_swap_interval(context);
sync_context(context);
if (skip_single_buffer_flushes)
{
......@@ -2367,6 +2431,7 @@ static void macdrv_glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
{
struct wgl_context *context = NtCurrentTeb()->glContext;
sync_context(context);
macdrv_update_opengl_context(context->context);
pglViewport(x, y, width, height);
}
......@@ -3552,7 +3617,7 @@ static BOOL macdrv_wglMakeContextCurrentARB(HDC draw_hdc, HDC read_hdc, struct w
if (!context)
{
macdrv_make_context_current(NULL, NULL);
macdrv_make_context_current(NULL, NULL, CGRectNull);
NtCurrentTeb()->glContext = NULL;
return TRUE;
}
......@@ -3585,6 +3650,7 @@ static BOOL macdrv_wglMakeContextCurrentARB(HDC draw_hdc, HDC read_hdc, struct w
context->draw_hwnd = hwnd;
context->draw_view = data->gl_view;
context->draw_rect = data->gl_rect;
context->draw_pbuffer = NULL;
release_win_data(data);
}
......@@ -3631,7 +3697,10 @@ static BOOL macdrv_wglMakeContextCurrentARB(HDC draw_hdc, HDC read_hdc, struct w
if ((data = get_win_data(hwnd)))
{
if (data->gl_view != context->draw_view)
{
context->read_view = data->gl_view;
context->read_rect = data->gl_rect;
}
release_win_data(data);
}
}
......@@ -3643,8 +3712,9 @@ static BOOL macdrv_wglMakeContextCurrentARB(HDC draw_hdc, HDC read_hdc, struct w
}
}
TRACE("making context current with draw_view %p draw_pbuffer %p read_view %p read_pbuffer %p format %u\n",
context->draw_view, context->draw_pbuffer, context->read_view, context->read_pbuffer, context->format);
TRACE("making context current with draw_view %p %s draw_pbuffer %p read_view %p %s read_pbuffer %p format %u\n",
context->draw_view, wine_dbgstr_rect(&context->draw_rect), context->draw_pbuffer,
context->read_view, wine_dbgstr_rect(&context->read_rect), context->read_pbuffer, context->format);
make_context_current(context, FALSE);
context->has_been_current = TRUE;
......@@ -4361,6 +4431,7 @@ void sync_gl_view(struct macdrv_win_data *data)
TRACE("Setting GL view %p frame to %s\n", data->gl_view, wine_dbgstr_rect(&rect));
macdrv_set_view_window_and_frame(data->gl_view, NULL, cgrect_from_rect(rect));
data->gl_rect = rect;
mark_contexts_for_moved_view(data->gl_view);
}
}
......@@ -4607,7 +4678,10 @@ static BOOL macdrv_wglSwapBuffers(HDC hdc)
(context ? context->cglcontext : NULL));
if (context)
{
sync_swap_interval(context);
sync_context(context);
}
if ((hwnd = WindowFromDC(hdc)))
{
......
......@@ -403,7 +403,7 @@ CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_dat
cgimage = CGImageCreate(CGRectGetWidth(visrect), CGRectGetHeight(visrect),
8, 32, bytes_per_row, colorspace,
alphaInfo | kCGBitmapByteOrder32Little,
provider, NULL, FALSE, kCGRenderingIntentDefault);
provider, NULL, retina_on, kCGRenderingIntentDefault);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorspace);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment