diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Fl_cocoa.mm | 388 |
1 files changed, 288 insertions, 100 deletions
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm index 68eaf7168..7a64ff64d 100644 --- a/src/Fl_cocoa.mm +++ b/src/Fl_cocoa.mm @@ -102,6 +102,7 @@ static int main_screen_height; // height of menubar-containing screen used to co static BOOL through_drawRect = NO; // through_Fl_X_flush = YES means Fl_Cocoa_Window_Driver::flush() was called static BOOL through_Fl_X_flush = NO; +static BOOL views_use_CA = NO; // YES means views are layer-backed, as on macOS 10.14 when linked with SDK 10.14 static int im_enabled = -1; // OS version-dependent pasteboard type names #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 @@ -529,6 +530,75 @@ void Fl_Cocoa_Screen_Driver::breakMacEventLoop() #endif @end +@interface FLView : NSView <NSTextInput +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +, NSTextInputClient +#endif +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 +,NSDraggingSource +#endif +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 +, CALayerDelegate +#endif +> { + BOOL in_key_event; // YES means keypress is being processed by handleEvent + BOOL need_handle; // YES means Fl::handle(FL_KEYBOARD,) is needed after handleEvent processing + NSInteger identifier; + NSRange selectedRange; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 +@public + CGContextRef layer_gc; +#endif +} ++ (void)prepareEtext:(NSString*)aString; ++ (void)concatEtext:(NSString*)aString; +- (BOOL)process_keydown:(NSEvent*)theEvent; +- (id)initWithFrame:(NSRect)frameRect; +- (void)drawRect:(NSRect)rect; +- (BOOL)acceptsFirstResponder; +- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent; +- (void)resetCursorRects; +- (BOOL)performKeyEquivalent:(NSEvent*)theEvent; +- (void)mouseUp:(NSEvent *)theEvent; +- (void)rightMouseUp:(NSEvent *)theEvent; +- (void)otherMouseUp:(NSEvent *)theEvent; +- (void)mouseDown:(NSEvent *)theEvent; +- (void)rightMouseDown:(NSEvent *)theEvent; +- (void)otherMouseDown:(NSEvent *)theEvent; +- (void)mouseMoved:(NSEvent *)theEvent; +- (void)mouseDragged:(NSEvent *)theEvent; +- (void)rightMouseDragged:(NSEvent *)theEvent; +- (void)otherMouseDragged:(NSEvent *)theEvent; +- (void)scrollWheel:(NSEvent *)theEvent; +- (void)magnifyWithEvent:(NSEvent *)theEvent; +- (void)keyDown:(NSEvent *)theEvent; +- (void)keyUp:(NSEvent *)theEvent; +- (void)flagsChanged:(NSEvent *)theEvent; +- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender; +- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender; +- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender; +- (void)draggingExited:(id < NSDraggingInfo >)sender; +- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal; +#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 +- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange; +- (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection replacementRange:(NSRange)replacementRange; +- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange; +- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange; +- (NSInteger)windowLevel; +#endif +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 +- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context; +#endif +- (BOOL)did_view_resolution_change; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 +- (BOOL)wantsLayer; +- (BOOL)wantsUpdateLayer; +- (void)updateLayer; +- (void)viewFrameDidChange; +#endif +@end + + @implementation FLWindow - (void)close { @@ -737,9 +807,9 @@ double Fl_Cocoa_Screen_Driver::wait(double time_to_wait) // the idle function may turn off idle, we can then wait: if (Fl::idle) time_to_wait = 0.0; } - NSDisableScreenUpdates(); // 10.3 Makes updates to all windows appear as a single event + if (fl_mac_os_version < 101100) NSDisableScreenUpdates(); // 10.3 Makes updates to all windows appear as a single event Fl::flush(); - NSEnableScreenUpdates(); // 10.3 + if (fl_mac_os_version < 101100) NSEnableScreenUpdates(); // 10.3 if (Fl::idle && !in_idle) // 'idle' may have been set within flush() time_to_wait = 0.0; int retval = do_queued_events(time_to_wait); @@ -1078,6 +1148,9 @@ static FLTextView *fltextview_instance = nil; - (void)windowDidMiniaturize:(NSNotification *)notif; - (BOOL)windowShouldClose:(id)fl; - (void)anyWindowWillClose:(NSNotification *)notif; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 +- (void)viewFrameDidChangeNotification:(NSNotification *)notif; +#endif - (void)doNothing:(id)unused; @end @@ -1181,6 +1254,18 @@ static FLWindowDelegate *flwindowdelegate_instance = nil; // FLTK sets position of parent and children. setSubwindowFrame is no longer necessary. if (fl_mac_os_version < 101000) [nsw recursivelySendToSubwindows:@selector(setSubwindowFrame)]; [nsw checkSubwindowFrame]; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + if (views_use_CA && [(FLView*)[nsw contentView] did_view_resolution_change]) { + if (window->as_gl_window()) { // move layered GL window to different resolution + NSView *view = [nsw contentView]; + [view display]; [view display]; // 2 necessary for toplevel GL windows + } else [(FLView*)[nsw contentView] viewFrameDidChange]; + if (window->parent()) { + [nsw setSubwindowFrame]; + [[nsw contentView] display]; + } + } +#endif fl_unlock_function(); } - (void)windowDidResize:(NSNotification *)notif @@ -1209,6 +1294,12 @@ static FLWindowDelegate *flwindowdelegate_instance = nil; [nsw recursivelySendToSubwindows:@selector(setSubwindowFrame)]; [nsw recursivelySendToSubwindows:@selector(checkSubwindowFrame)]; if (window->as_gl_window() && Fl_X::i(window)) d->in_windowDidResize(false); +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + if (views_use_CA && window->as_gl_window() && !window->parent()) { // resize toplevel layered GL window + id pre = [[[nsw contentView] layer] presentationLayer]; + if (pre) [[nsw contentView] layer].contents = pre; + } +#endif fl_unlock_function(); } - (void)windowDidResignKey:(NSNotification *)notif @@ -1323,6 +1414,13 @@ static FLWindowDelegate *flwindowdelegate_instance = nil; } fl_unlock_function(); } +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 +-(void)viewFrameDidChangeNotification:(NSNotification *)notif +{ + NSView *view = (NSView*)[notif object]; + if ([view layer] && [view isMemberOfClass:[FLView class]]) [(FLView*)view viewFrameDidChange]; +} +#endif - (void)doNothing:(id)unused { return; @@ -1666,6 +1764,12 @@ void Fl_Cocoa_Screen_Driver::open_display_platform() { selector:@selector(anyWindowWillClose:) name:NSWindowWillCloseNotification object:nil]; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + [[NSNotificationCenter defaultCenter] addObserver:[FLWindowDelegate singleInstance] + selector:@selector(viewFrameDidChangeNotification:) + name:NSViewFrameDidChangeNotification + object:nil]; +#endif if (![NSThread isMultiThreaded]) { // With old OS X versions, it is necessary to create one thread for secondary pthreads to be // allowed to use cocoa, especially to create an NSAutoreleasePool. @@ -2067,61 +2171,144 @@ static FLTextInputContext* fltextinputcontext_instance = nil; } @end -@interface FLView : NSView <NSTextInput -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 -, NSTextInputClient -#endif -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 -,NSDraggingSource -#endif -> { - BOOL in_key_event; // YES means keypress is being processed by handleEvent - BOOL need_handle; // YES means Fl::handle(FL_KEYBOARD,) is needed after handleEvent processing - NSInteger identifier; - NSRange selectedRange; +/* Implementation note for the support of layer-backed views. + MacOS 10.14 Mojave changes the way all drawing to displays is performed: + all NSView objects become layer-backed, that is, the drawing is done by + Core Animation to a CALayer object whose content is then displayed by the NSView. + The global variable views_use_CA is set to YES when such change applies, + that is, for apps running under 10.14 and linked to SDK 10.14. + When views_use_CA is NO, views are not supposed to be layer-backed. + + Each layer-backed non-OpenGL window has a single FLView object which itself has an associated CALayer. + FLView sets wantsUpdateLayer to YES. Consequently, FLView objects are drawn + by the updateLayer message. An FLView has also a member variable + CGContextRef layer_gc, a bitmap context the size of the view (double on Retina). + All Quartz drawings go to this bitmap. updateLayer finishes by using an image copy + of the bitmap as the layer's contents. That step fills the window. + FLView implements viewFrameDidChange which deletes the bitmap and zeros layer_gc. + This ensures the bitmap is recreated when the window is resized. + viewFrameDidChange is also called when the window flips between low/high resolution displays. + + Each layer-backed OpenGL window has an associated FLViewGL object, derived from FLView. + FLViewGL sets wantsUpdateLayer to NO. Consequently, FLViewGL objects are drawn + by the drawLayer:inContext: message which calls drawRect: which draws the GL scene. + */ + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 +static CGContextRef prepare_bitmap_for_layer(int w, int h ) { + CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB(); + CGContextRef gc = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, cspace, kCGImageAlphaPremultipliedFirst); + CGColorSpaceRelease(cspace); + CGContextClearRect(gc, CGRectMake(0,0,w,h)); + return gc; } -+ (void)prepareEtext:(NSString*)aString; -+ (void)concatEtext:(NSString*)aString; -- (BOOL)process_keydown:(NSEvent*)theEvent; -- (id)initWithFrame:(NSRect)frameRect; -- (void)drawRect:(NSRect)rect; -- (BOOL)acceptsFirstResponder; -- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent; -- (void)resetCursorRects; -- (BOOL)performKeyEquivalent:(NSEvent*)theEvent; -- (void)mouseUp:(NSEvent *)theEvent; -- (void)rightMouseUp:(NSEvent *)theEvent; -- (void)otherMouseUp:(NSEvent *)theEvent; -- (void)mouseDown:(NSEvent *)theEvent; -- (void)rightMouseDown:(NSEvent *)theEvent; -- (void)otherMouseDown:(NSEvent *)theEvent; -- (void)mouseMoved:(NSEvent *)theEvent; -- (void)mouseDragged:(NSEvent *)theEvent; -- (void)rightMouseDragged:(NSEvent *)theEvent; -- (void)otherMouseDragged:(NSEvent *)theEvent; -- (void)scrollWheel:(NSEvent *)theEvent; -- (void)magnifyWithEvent:(NSEvent *)theEvent; -- (void)keyDown:(NSEvent *)theEvent; -- (void)keyUp:(NSEvent *)theEvent; -- (void)flagsChanged:(NSEvent *)theEvent; -- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender; -- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender; -- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender; -- (void)draggingExited:(id < NSDraggingInfo >)sender; -- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal; -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 -- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange; -- (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection replacementRange:(NSRange)replacementRange; -- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange; -- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange; -- (NSInteger)windowLevel; -#endif -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 -- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context; -#endif + +@interface FLViewGL : FLView // only for layered GL windows +- (BOOL)wantsUpdateLayer; +- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx; +- (void)viewFrameDidChange; @end +@implementation FLViewGL +- (BOOL)wantsUpdateLayer { + return NO; +} +- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx { + [self drawRect:[self frame]];//essai + Fl_Window *window = [(FLWindow*)[self window] getFl_Window]; + if (window->parent()) window->redraw(); // useful during resize of GL subwindow + if (Fl_Cocoa_Window_Driver::driver(window)->wait_for_expose_value) { + // 1st drawing of GL window + NSRect r = [[self window] frame]; + r.size.width -= 1; + [[self window] setFrame:r display:NO]; // very dirty but works. Should find something better. + r.size.width += 1; + [[self window] setFrame:r display:YES]; + } + Fl_Cocoa_Window_Driver::driver(window)->wait_for_expose_value = 0; +} +- (void)viewFrameDidChange +{ + [[self layer] display]; // for layered GL windows +} +@end +#endif //>= MAC_OS_X_VERSION_10_8 + @implementation FLView +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 +- (BOOL)wantsLayer { + return views_use_CA; +} +- (BOOL)wantsUpdateLayer { + return views_use_CA; +} +- (void)updateLayer { + // called if views are layered (but not for GL) : all drawing to window goes through this + Fl_Window *window = [(FLWindow*)[self window] getFl_Window]; + Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window); + float scale = Fl::screen_driver()->scale(0); + NSRect rect = [self frame]; + if (!window->parent() && window->border() && fabs(rect.size.height - window->h() * scale) > 5. ) { // this happens with tabbed windows + window->resize([[self window] frame].origin.x/scale, + (main_screen_height - ([[self window] frame].origin.y + rect.size.height))/scale, + rect.size.width/scale, rect.size.height/scale); + } + if (!layer_gc) { // runs when window is created, resized, changed screen resolution + NSRect r = [self frame]; + [self layer].bounds = NSRectToCGRect(r); + d->wait_for_expose_value = 0; + [self did_view_resolution_change]; + if (d->mapped_to_retina()) { + r.size.width *= 2; r.size.height *= 2; + [self layer].contentsScale = 2.; + } else [self layer].contentsScale = 1.; + layer_gc = prepare_bitmap_for_layer(r.size.width, r.size.height); + Fl_X *i = Fl_X::i(window); + if ( i->region ) { + Fl_Graphics_Driver::default_driver().XDestroyRegion(i->region); + i->region = 0; + } + window->clear_damage(FL_DAMAGE_ALL); + } + if (window->damage()) { + through_drawRect = YES; + d->Fl_Window_Driver::flush(); + Fl_Cocoa_Window_Driver::q_release_context(); + through_drawRect = NO; + window->clear_damage(); + CGImageRef cgimg = CGBitmapContextCreateImage(layer_gc); // requires 10.4 + [self layer].contents = (id)cgimg; + CGImageRelease(cgimg); + } +} + +-(void)viewFrameDidChange +{ + CGContextRelease(layer_gc); + layer_gc = NULL; +} +-(void)dealloc { + CGContextRelease(layer_gc); + [super dealloc]; +} +#endif //>= MAC_OS_X_VERSION_10_8 + +- (BOOL)did_view_resolution_change { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 + if (fl_mac_os_version >= 100700) { // determine whether window is mapped to a retina display + Fl_Window *window = [(FLWindow*)[self window] getFl_Window]; + Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window); + bool previous = d->mapped_to_retina(); + NSSize s = [self convertSizeToBacking:NSMakeSize(10, 10)]; // 10.7 + d->mapped_to_retina( int(s.width + 0.5) > 10 ); + BOOL retval = (d->wait_for_expose_value == 0 && previous != d->mapped_to_retina()); + if (retval) d->changed_resolution(true); + return retval; + } +#endif + return NO; +} + - (BOOL)process_keydown:(NSEvent*)theEvent { id o = fl_mac_os_version >= 100600 ? [self performSelector:@selector(inputContext)] : [FLTextInputContext singleInstance]; @@ -2139,7 +2326,7 @@ static FLTextInputContext* fltextinputcontext_instance = nil; } /* - * Gets called when a window is created or resized, or moved between retina and non-retina displays + * Gets called when a non-layered window is created or resized, or moved between retina and non-retina displays * (with Mac OS ≥ 10.11 also when deminiaturized) */ - (void)drawRect:(NSRect)rect @@ -2155,17 +2342,8 @@ static FLTextInputContext* fltextinputcontext_instance = nil; } through_drawRect = YES; Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window); - if (fl_mac_os_version >= 100700) { // determine whether window is mapped to a retina display - bool previous = d->mapped_to_retina(); - // rewrite next call that requires 10.7 and therefore triggers a compiler warning on old SDKs - //NSSize s = [[cw contentView] convertSizeToBacking:NSMakeSize(10, 10)]; - typedef NSSize (*convertSizeIMP)(id, SEL, NSSize); - static convertSizeIMP addr = (convertSizeIMP)[NSView instanceMethodForSelector:@selector(convertSizeToBacking:)]; - NSSize s = addr([cw contentView], @selector(convertSizeToBacking:), NSMakeSize(10, 10)); - d->mapped_to_retina( int(s.width + 0.5) > 10 ); - if (d->wait_for_expose_value == 0 && previous != d->mapped_to_retina()) d->changed_resolution(true); - } - d->wait_for_expose_value = 0; + [self did_view_resolution_change]; + if (!views_use_CA) d->wait_for_expose_value = 0; Fl_X *i = Fl_X::i(window); if ( i->region ) { Fl_Graphics_Driver::default_driver().XDestroyRegion(i->region); @@ -2770,11 +2948,13 @@ void Fl_Cocoa_Gl_Window_Driver::GLcontext_makecurrent(NSOpenGLContext* ctxt) /* * Initialize the given port for redraw and call the window's flush() to actually draw the content - */ + */ void Fl_Cocoa_Window_Driver::flush() { if (pWindow->as_gl_window()) { Fl_Window_Driver::flush(); + } else if (views_use_CA) { + [[fl_xid(pWindow) contentView] updateLayer]; } else { make_current_counts = 1; NSView *view = (through_drawRect ? nil : [fl_xid(pWindow) contentView]); @@ -2944,7 +3124,12 @@ Fl_X* Fl_Cocoa_Window_Driver::makeWindow() x->next = NULL; Fl_X::first = x; } - FLView *myview = [[FLView alloc] initWithFrame:crect]; + FLView *myview = +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + views_use_CA && w->as_gl_window() ? [FLViewGL alloc] : +#endif + [FLView alloc]; + myview = [myview initWithFrame:crect]; [cw setContentView:myview]; [myview release]; [cw setLevel:winlevel]; @@ -3214,10 +3399,14 @@ void Fl_Cocoa_Window_Driver::resize(int X,int Y,int W,int H) { */ void Fl_Cocoa_Window_Driver::make_current() { - if (make_current_counts > 1) return; + if (make_current_counts > 1 && !views_use_CA) return; if (make_current_counts) make_current_counts++; + if (views_use_CA && !through_drawRect) { + pWindow->damage(FL_DAMAGE_CHILD); // force display of previous draws to this window + } q_release_context(); Fl_X *i = Fl_X::i(pWindow); + //NSLog(@"region-count=%d damage=%u",i->region?i->region->count:0, pWindow->damage()); fl_window = i->xid; ((Fl_Quartz_Graphics_Driver&)Fl_Graphics_Driver::default_driver()).high_resolution( mapped_to_retina() ); @@ -3225,20 +3414,18 @@ void Fl_Cocoa_Window_Driver::make_current() destroy_double_buffer(); changed_resolution(false); } - /*NSGraphicsContext *nsgc; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 - if (fl_mac_os_version >= 100400) - nsgc = [fl_window graphicsContext]; // 10.4 - else -#endif*/ - NSGraphicsContext *nsgc = through_Fl_X_flush ? [NSGraphicsContext currentContext] : [NSGraphicsContext graphicsContextWithWindow:fl_window]; - if (!nsgc) { // this occurs on 10.14 when through_Fl_X_flush==0 - [[fl_window contentView] lockFocus]; - nsgc = [NSGraphicsContext currentContext]; - } - gc = (CGContextRef)[nsgc graphicsPort]; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + if (views_use_CA) { + gc = ((FLView*)[fl_window contentView])->layer_gc; + } else +#endif + { + NSGraphicsContext *nsgc = through_Fl_X_flush ? [NSGraphicsContext currentContext] : [NSGraphicsContext graphicsContextWithWindow:fl_window]; + gc = (CGContextRef)[nsgc graphicsPort]; + } Fl_Graphics_Driver::default_driver().gc(gc); CGContextSaveGState(gc); // native context + if (views_use_CA && mapped_to_retina()) CGContextScaleCTM(gc, 2,2); // antialiasing must be deactivated because it applies to rectangles too // and escapes even clipping!!! // it gets activated when needed (e.g., draw text) @@ -4058,22 +4245,20 @@ static NSBitmapImageRep* GL_rect_to_nsbitmap(Fl_Window *win, int x, int y, int w return bitmap; } -static NSBitmapImageRep* rect_to_NSBitmapImageRep_noredraw(Fl_Window *win, int x, int y, int w, int h) -{ -// under macOS 10.14 and when linked with 10.14 SDK, initWithFocusedViewRect: does not work -// this other procedure does capture screen data, but does not capture window parts outside the screen +static NSBitmapImageRep* rect_to_NSBitmapImageRep_layer(Fl_Window *win, int x, int y, int w, int h) +{ // capture window data for layer-based views because initWithFocusedViewRect: does not work for them NSBitmapImageRep *bitmap = nil; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - NSRect wrect = [fl_xid(win) frame]; // window on screen from bottom - int bx, by, bt; - get_window_frame_sizes(bx, by, bt, win); - wrect.size.height -= bt; // exclude titlebar - wrect.origin.y = main_screen_height - (wrect.origin.y + wrect.size.height); // window on screen from top - CGRect cgbounds = NSRectToCGRect(wrect);//10.5 - float s = Fl_Graphics_Driver::default_driver().scale(); - cgbounds.origin.x += x*s +0.5; cgbounds.origin.y += y*s +0.5; - cgbounds.size.width = w*s; cgbounds.size.height = h*s; - CGImageRef cgimg = CGWindowListCreateImage(cgbounds, kCGWindowListOptionIncludingWindow, [fl_xid(win) windowNumber], kCGWindowImageBoundsIgnoreFraming); //10.5 +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + CGContextRef gc = ((FLView*)[fl_xid(win) contentView])->layer_gc; + CGImageRef cgimg = CGBitmapContextCreateImage(gc); // requires 10.4 + float s = Fl::screen_driver()->scale(0); + int resolution = Fl_Cocoa_Window_Driver::driver(win->top_window())->mapped_to_retina() ? 2 : 1; + if (x || y || w != win->w() || h != win->h()) { + CGRect rect = CGRectMake(x * s * resolution, y * s * resolution, w * s * resolution, h * s * resolution); + CGImageRef cgimg2 = CGImageCreateWithImageInRect(cgimg, rect); + CGImageRelease(cgimg); + cgimg = cgimg2; + } bitmap = [[NSBitmapImageRep alloc] initWithCGImage:cgimg];//10.5 CGImageRelease(cgimg); #endif @@ -4091,10 +4276,8 @@ static NSBitmapImageRep* rect_to_NSBitmapImageRep(Fl_Window *win, int x, int y, float s = Fl_Graphics_Driver::default_driver().scale(); if (win->as_gl_window() && y >= 0) { bitmap = GL_rect_to_nsbitmap(win, x, y, w, h); -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - } else if (fl_mac_os_version >= 101400 && [[fl_xid(win) contentView] layer /*10.5*/]) { - bitmap = rect_to_NSBitmapImageRep_noredraw(win, x, y, w, h); -#endif + } else if (views_use_CA) { + bitmap = rect_to_NSBitmapImageRep_layer(win, x, y, w, h); } else { NSView *winview = nil; if ( through_Fl_X_flush && Fl_Window::current() == win ) { @@ -4288,7 +4471,12 @@ int Fl_Darwin_System_Driver::calc_mac_os_version() { sscanf(s, "%d.%d.%d", &M, &m, &b); } [localPool release]; - return fl_mac_os_version = M*10000 + m*100 + b; + fl_mac_os_version = M*10000 + m*100 + b; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 + if (fl_mac_os_version >= 101400) views_use_CA = YES; +#endif + //if (fl_mac_os_version >= 101300) views_use_CA = YES; // to get as with mojave + return fl_mac_os_version; } // |
