diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Fl_cocoa.mm | 183 |
1 files changed, 82 insertions, 101 deletions
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm index ad9d79fa4..2357400c6 100644 --- a/src/Fl_cocoa.mm +++ b/src/Fl_cocoa.mm @@ -524,8 +524,8 @@ void Fl_Cocoa_Screen_Driver::breakMacEventLoop() NSRange selectedRange; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 @public - CGContextRef aux_bitmap; // alternative bitmap used when drawing out of widgets' draw methods - CGImageRef cgimg; // the current graphical content of the view + CGContextRef aux_bitmap; // stores a copy of the last content of the view, also used to draw outside drawRect: + BOOL direct_draw; // YES means drawing outside drawRect: #endif } + (void)prepareEtext:(NSString*)aString; @@ -569,7 +569,8 @@ void Fl_Cocoa_Screen_Driver::breakMacEventLoop() #endif - (BOOL)did_view_resolution_change; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 -- (void)reset_layer_data; +- (void)create_aux_bitmap:(CGContextRef)gc retina:(BOOL)r; +- (void)reset_aux_bitmap; #endif @end @@ -578,7 +579,7 @@ void Fl_Cocoa_Screen_Driver::breakMacEventLoop() - (void)close { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - if (views_use_CA) [(FLView*)[self contentView] reset_layer_data]; + if (views_use_CA) [(FLView*)[self contentView] reset_aux_bitmap]; #endif [super close]; // when a fullscreen window is closed, windowDidResize may be sent after the close message was sent @@ -657,7 +658,7 @@ void Fl_Cocoa_Screen_Driver::breakMacEventLoop() int bt = parent ? 0 : get_window_frame_sizes(w); NSRect rp = NSMakeRect(round(pt.x), round(pt.y), round(s * w->w()), round(s * w->h()) + bt); if (!NSEqualRects(rp, [self frame])) { - [self setFrame:rp display:YES]; + [self setFrame:rp display:(views_use_CA ? NO : YES)]; } if (parent && ![self parentWindow]) { // useful when subwin is first shown, not when moved FLWindow *pxid = fl_xid(parent); @@ -699,7 +700,10 @@ void Fl_Cocoa_Screen_Driver::breakMacEventLoop() [xid orderWindow:NSWindowBelow relativeTo:parent_num]; [xid orderWindow:NSWindowAbove relativeTo:parent_num]; } - [view display]; // subwindow needs redrawn +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 + if (!views_use_CA || ((FLView*)view)->aux_bitmap) +#endif + [view display]; // subwindow needs redrawn } } @@ -1219,8 +1223,9 @@ static FLWindowDelegate *flwindowdelegate_instance = nil; Fl_Window *window = [nsw getFl_Window]; if (!window->parent()) starting_moved_window = window; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - if (views_use_CA && window->as_gl_window() && Fl::use_high_res_GL() && [(FLView*)[nsw contentView] did_view_resolution_change]) { - [[nsw contentView] setNeedsDisplay:YES]; // necessary with macOS ≥ 10.14.2; harmless before + FLView *view = (FLView*)[nsw contentView]; + if (views_use_CA && [view did_view_resolution_change]) { + if (window->as_gl_window() && Fl::use_high_res_GL()) [view setNeedsDisplay:YES]; // necessary with macOS ≥ 10.14.2; harmless before } #endif if (window == starting_moved_window) { @@ -1258,7 +1263,7 @@ static FLWindowDelegate *flwindowdelegate_instance = nil; update_e_xy_and_e_xy_root(nsw); #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 if (views_use_CA && !window->as_gl_window()) { - [view reset_layer_data]; + [view reset_aux_bitmap]; window->redraw(); } #endif @@ -2149,24 +2154,20 @@ static FLTextInputContext* fltextinputcontext_instance = nil; gives a graphics context whose product ultimately appears on screen. But the full content of the view must be redrawn each time drawRect: runs, in contrast to pre-10.14 where drawings were added to the previous window content. - That is why FLView maintains a CGImage (view->cgimg) equal to the last content of the FLView. - At the beginning of drawRect:, cgimg is drawn to the graphics context and released, - then drawRect: does its drawing, finally cgimg is newly set to the - view's graphical content as it is at the end of drawRect:. + That is why FLView maintains a bitmap (view->aux_bitmap) equal to the last content of the FLView. + At the beginning of drawRect:, aux_bitmap is copied to the graphics context, + then drawRect: does its drawing, finally the view's graphical content as it is at the end of + drawRect: is copied back to aux_bitmap. A problem arises to support drawing done outside Fl_Window_Driver::flush(), that is, after the app calls Fl_Window::make_current() at any time it wants. That situation is identified by the condition (views_use_CA && !through_drawRect). A graphics context usable outside drawRect: that ultimately appears on screen, - if it exists, was not identified. Thus, a bitmap graphics context (view->aux_bitmap) - is created by function prepare_bitmap_for_layer() with the size of the view - (doubled on retina). Drawing operations after the call to Fl_Window::make_current() - are directed to this bitmap. Fl_Window::make_current() also calls - [view setNeedsDisplay:YES] which instructs the system to run drawRect: - at the next event loop. Later, when drawRect: runs, it detects that drawing was - sent to aux_bitmap because that pointer is not nil. The content of aux_bitmap - is transformed to a CGImage which is assigned to view->cgimg and which is - drawn to drawRect's graphics context. + if it exists, was not identified. Drawing operations after the call to Fl_Window::make_current() + are directed to aux_bitmap. Fl_Window::make_current() sets to YES the direct_draw member + of the FLView and also calls [view setNeedsDisplay:YES] which instructs the system to + run drawRect: at the next event loop. Later, when drawRect: runs, the content of + aux_bitmap is copied to drawRect's graphics context and direct_draw is set to NO. OpenGL windows remain processed under 10.14 as before. */ @@ -2178,7 +2179,8 @@ static FLTextInputContext* fltextinputcontext_instance = nil; 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(); - NSView *view = (window->parent() && !window->as_gl_window()) ? [fl_xid(window->top_window()) contentView] : self; + NSView *view = (!views_use_CA && window->parent() && !window->as_gl_window()) ? + [fl_xid(window->top_window()) contentView] : self; if (view) { NSSize s = [view convertSizeToBacking:NSMakeSize(10, 10)]; // 10.7 d->mapped_to_retina( int(s.width + 0.5) > 10 ); @@ -2186,6 +2188,12 @@ static FLTextInputContext* fltextinputcontext_instance = nil; BOOL retval = (d->wait_for_expose_value == 0 && previous != d->mapped_to_retina()); if (retval) { d->changed_resolution(true); +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 + if (views_use_CA && !window->as_gl_window() ) { + [self reset_aux_bitmap]; + [self display]; + } +#endif } return retval; } @@ -2193,11 +2201,15 @@ static FLTextInputContext* fltextinputcontext_instance = nil; return NO; } #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 -- (void)reset_layer_data { +- (void)create_aux_bitmap:(CGContextRef)gc retina:(BOOL)r { + aux_bitmap = CGBitmapContextCreate(NULL, CGBitmapContextGetWidth(gc), CGBitmapContextGetHeight(gc), + CGBitmapContextGetBitsPerComponent(gc), CGBitmapContextGetBytesPerRow(gc), + CGBitmapContextGetColorSpace(gc), CGBitmapContextGetBitmapInfo(gc)); + if (r) CGContextScaleCTM(aux_bitmap, 2, 2); +} +- (void)reset_aux_bitmap { CGContextRelease(aux_bitmap); aux_bitmap = NULL; - CGImageRelease(cgimg); - cgimg = NULL; } #endif - (BOOL)process_keydown:(NSEvent*)theEvent @@ -2227,20 +2239,13 @@ static FLTextInputContext* fltextinputcontext_instance = nil; Fl_Window *window = [cw getFl_Window]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 CGContextRef gc = views_use_CA ? [[NSGraphicsContext currentContext] CGContext] : NULL; - if (aux_bitmap) { - CGImageRelease(cgimg); - cgimg = CGBitmapContextCreateImage(aux_bitmap); - CGContextRelease(aux_bitmap); - aux_bitmap = NULL; - if (!window->damage()) { - CGContextDrawImage(gc, NSRectToCGRect([self frame]), cgimg); - fl_unlock_function(); - return; - } - } #endif Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window); - if (!through_Fl_X_flush) { + if (!through_Fl_X_flush +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 + && !direct_draw +#endif + ) { [self did_view_resolution_change]; if (d->wait_for_expose_value) { d->wait_for_expose_value = 0; @@ -2256,20 +2261,19 @@ static FLTextInputContext* fltextinputcontext_instance = nil; window->clear_damage(FL_DAMAGE_ALL); } #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - else if (cgimg && gc && ( Fl_X::i(window)->region || !(window->damage()&FL_DAMAGE_ALL)) ) { - CGContextDrawImage(gc, NSRectToCGRect([self frame]), cgimg); + else if (gc && aux_bitmap && ( Fl_X::i(window)->region || !(window->damage()&FL_DAMAGE_ALL)) ) { + memcpy(CGBitmapContextGetData(gc), CGBitmapContextGetData(aux_bitmap), CGBitmapContextGetHeight(gc) * CGBitmapContextGetBytesPerRow(gc)); } - CGImageRelease(cgimg); - cgimg = 0; #endif through_drawRect = YES; d->Fl_Window_Driver::flush(); if (!through_Fl_X_flush) window->clear_damage(); #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - if (views_use_CA && gc) { - CGImageRelease(cgimg); - cgimg = CGBitmapContextCreateImage(gc); + if (gc) { + if (!aux_bitmap) [self create_aux_bitmap:gc retina:d->mapped_to_retina()]; + memcpy(CGBitmapContextGetData(aux_bitmap), CGBitmapContextGetData(gc), CGBitmapContextGetHeight(gc) * CGBitmapContextGetBytesPerRow(gc)); Fl_Cocoa_Window_Driver::q_release_context(); + direct_draw = NO; } #endif through_drawRect = NO; @@ -3276,19 +3280,6 @@ void Fl_Cocoa_Window_Driver::resize(int X, int Y, int W, int H) { } } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 -CGContextRef prepare_bitmap_for_layer(FLView *view) { - Fl_Window *window = [(FLWindow*)[view window] getFl_Window]; - NSRect rect = [view frame]; - if (Fl_Cocoa_Window_Driver::driver(window)->mapped_to_retina()) { - rect.size.width *= 2; rect.size.height *= 2; - } - static CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB(); - CGContextRef gc = CGBitmapContextCreate(NULL, rect.size.width, rect.size.height, 8, 4 * rect.size.width, cspace, kCGImageAlphaPremultipliedFirst); - CGContextClearRect(gc, NSRectToCGRect(rect)); - return gc; -} -#endif /* * make all drawing go into this window (called by subclass flush() impl.) @@ -3313,8 +3304,7 @@ CGContextRef prepare_bitmap_for_layer(FLView *view) { through_Fl_X_flush and through_drawRect equal NO. Before 10.14: The window graphics context is obtained. Subsequent drawing requests go to the window. After 10.14: The layered view is marked as needing display. It will be sent the drawRect: message - at the next event loop. A temporary bitmap (view->aux_bitmap) is created and subsequent drawing - operations, until drawRect: runs, are sent to it. + at the next event loop. Subsequent drawing operations, until drawRect: runs, are sent to view->aux_bitmap. CAUTION: it's not possible to call Fl::wait(), Fl::check() nor Fl::ready() while in the draw() function of a widget. Use an idle callback instead. @@ -3334,12 +3324,9 @@ void Fl_Cocoa_Window_Driver::make_current() #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 if (views_use_CA && !through_drawRect) { // detect direct calls from the app FLView *view = (FLView*)[fl_xid(pWindow) contentView]; - if (!view->aux_bitmap) { - view->aux_bitmap = prepare_bitmap_for_layer(view); - if (mapped_to_retina()) CGContextScaleCTM(view->aux_bitmap, 2, 2); - if (view->cgimg) CGContextDrawImage(view->aux_bitmap, NSRectToCGRect([view frame]), view->cgimg); - } + if (!view->aux_bitmap) [view display]; gc = view->aux_bitmap; + view->direct_draw = YES; [view setNeedsDisplay:YES]; } else #endif @@ -3349,22 +3336,12 @@ void Fl_Cocoa_Window_Driver::make_current() gc = (CGContextRef)[nsgc performSelector:gc_sel]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 if (!gc) { // to support gl_start()/gl_finish() - static CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB(); - static CGContextRef dummy_gc = NULL; - CGContextRelease(dummy_gc); - gc = dummy_gc = CGBitmapContextCreate(NULL, 10, 10, 8, 40, cspace, kCGImageAlphaPremultipliedFirst); + static CGContextRef dummy_gc = CGBitmapContextCreate(NULL, 10, 10, 8, 40, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedFirst); + gc = dummy_gc; } #endif } Fl_Graphics_Driver::default_driver().gc(gc); -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - if (views_use_CA) { - if (CGContextGetCTM(gc).d < 0) { // detect and correct double calls to make_current() - CGContextRestoreGState(gc); - CGContextRestoreGState(gc); - } - } -#endif CGContextSaveGState(gc); // native context // antialiasing must be deactivated because it applies to rectangles too // and escapes even clipping!!! @@ -3398,14 +3375,9 @@ void Fl_Cocoa_Window_Driver::q_release_context(Fl_Cocoa_Window_Driver *x) { CGContextRef gc = (CGContextRef)Fl_Graphics_Driver::default_driver().gc(); if (x && x->shown() && x->gc != gc) return; if (!gc) return; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 - if (!views_use_CA) -#endif - { - CGContextRestoreGState(gc); // match the CGContextSaveGState's of make_current - CGContextRestoreGState(gc); - CGContextFlush(gc); - } + CGContextRestoreGState(gc); // match the CGContextSaveGState's of make_current + CGContextRestoreGState(gc); + CGContextFlush(gc); Fl_Graphics_Driver::default_driver().gc(0); #if defined(FLTK_USE_CAIRO) if (Fl::cairo_autolink_context()) Fl::cairo_make_current((Fl_Window*) 0); // capture gc changes automatically to update the cairo context adequately @@ -4194,26 +4166,33 @@ static NSBitmapImageRep* GL_rect_to_nsbitmap(Fl_Window *win, int x, int y, int w return bitmap; } -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_14 +static CGImageRef rect_to_CGImage_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 FLView *view = (FLView*)[fl_xid(win) contentView]; - if (win == Fl_Window::current() && fl_graphics_driver->gc()) { // make sure to get the current content of the view - CGImageRelease(view->cgimg); - view->cgimg = CGBitmapContextCreateImage((CGContextRef)fl_graphics_driver->gc()); - } - CGImageRef cgimg = view->cgimg; - if (!cgimg) return nil; - BOOL need_subimage = x || y || w != win->w() || h != win->h(); - if (need_subimage) { + // make sure to get the most recent content of the view + CGContextRef source_bitmap = (CGContextRef)fl_graphics_driver->gc(); + if (!source_bitmap || win != Fl_Window::current()) source_bitmap = view->aux_bitmap; + if (!source_bitmap) return nil; + CGImageRef cgimg = CGBitmapContextCreateImage(source_bitmap); + if (x || y || w != win->w() || h != win->h()) { float s = Fl::screen_driver()->scale(0); if (Fl_Cocoa_Window_Driver::driver(win)->mapped_to_retina()) s *= 2; CGRect rect = CGRectMake(x * s, y * s, w * s, h * s); - cgimg = CGImageCreateWithImageInRect(cgimg, rect); + CGImageRef cgimg2 = CGImageCreateWithImageInRect(cgimg, rect); + CGImageRelease(cgimg); + cgimg = cgimg2; } - bitmap = [[NSBitmapImageRep alloc] initWithCGImage:cgimg];//10.5 - if (need_subimage) CGImageRelease(cgimg); + return cgimg; +} +#endif + +static NSBitmapImageRep* rect_to_NSBitmapImageRep_layer(Fl_Window *win, int x, int y, int w, int h) { + NSBitmapImageRep *bitmap = nil; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 + CGImageRef cgimg = rect_to_CGImage_layer(win, x, y, w, h); + if (cgimg) bitmap = [[NSBitmapImageRep alloc] initWithCGImage:cgimg];//10.5 + CGImageRelease(cgimg); #endif return bitmap; } @@ -4294,9 +4273,11 @@ CGImageRef Fl_Cocoa_Window_Driver::CGImage_from_window_rect(int x, int y, int w, CFRelease the returned CGImageRef after use */ { - Fl_Window *win = pWindow; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 + if (views_use_CA && (!capture_subwins || [[fl_xid(pWindow) childWindows] count] == 0)) return rect_to_CGImage_layer(pWindow, x, y, w, h); +#endif CGImageRef img; - NSBitmapImageRep *bitmap = rect_to_NSBitmapImageRep(win, x, y, w, h, capture_subwins); + NSBitmapImageRep *bitmap = rect_to_NSBitmapImageRep(pWindow, x, y, w, h, capture_subwins); if (fl_mac_os_version >= 100500) { img = (CGImageRef)[bitmap performSelector:@selector(CGImage)]; // requires Mac OS 10.5 CGImageRetain(img); |
