aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac3
-rw-r--r--src/nsterm.h35
-rw-r--r--src/nsterm.m493
3 files changed, 208 insertions, 323 deletions
diff --git a/configure.ac b/configure.ac
index d99e5395d35..e83ee47e256 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5647,7 +5647,8 @@ case "$opsys" in
5647 if test "$HAVE_NS" = "yes"; then 5647 if test "$HAVE_NS" = "yes"; then
5648 libs_nsgui="-framework AppKit" 5648 libs_nsgui="-framework AppKit"
5649 if test "$NS_IMPL_COCOA" = "yes"; then 5649 if test "$NS_IMPL_COCOA" = "yes"; then
5650 libs_nsgui="$libs_nsgui -framework IOKit -framework Carbon -framework IOSurface" 5650 libs_nsgui="$libs_nsgui -framework IOKit -framework Carbon \
5651 -framework IOSurface -framework QuartzCore"
5651 fi 5652 fi
5652 else 5653 else
5653 libs_nsgui= 5654 libs_nsgui=
diff --git a/src/nsterm.h b/src/nsterm.h
index 0596f3f3c10..4c61a50ecb2 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -348,16 +348,6 @@ typedef id instancetype;
348#endif 348#endif
349 349
350 350
351/* macOS 10.14 and above cannot draw directly "to the glass" and
352 therefore we draw to an offscreen buffer and swap it in when the
353 toolkit wants to draw the frame. GNUstep and macOS 10.7 and below
354 do not support this method, so we revert to drawing directly to the
355 glass. */
356#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
357#define NS_DRAW_TO_BUFFER 1
358#endif
359
360
361/* ========================================================================== 351/* ==========================================================================
362 352
363 NSColor, EmacsColor category. 353 NSColor, EmacsColor category.
@@ -423,7 +413,7 @@ typedef id instancetype;
423 ========================================================================== */ 413 ========================================================================== */
424 414
425@class EmacsToolbar; 415@class EmacsToolbar;
426@class EmacsSurface; 416@class EmacsLayer;
427 417
428#ifdef NS_IMPL_COCOA 418#ifdef NS_IMPL_COCOA
429@interface EmacsView : NSView <NSTextInput, NSWindowDelegate> 419@interface EmacsView : NSView <NSTextInput, NSWindowDelegate>
@@ -444,9 +434,6 @@ typedef id instancetype;
444 NSWindow *nonfs_window; 434 NSWindow *nonfs_window;
445 BOOL fs_is_native; 435 BOOL fs_is_native;
446 BOOL in_fullscreen_transition; 436 BOOL in_fullscreen_transition;
447#ifdef NS_DRAW_TO_BUFFER
448 EmacsSurface *surface;
449#endif
450@public 437@public
451 struct frame *emacsframe; 438 struct frame *emacsframe;
452 int scrollbarsNeedingUpdate; 439 int scrollbarsNeedingUpdate;
@@ -486,9 +473,9 @@ typedef id instancetype;
486#endif 473#endif
487- (int)fullscreenState; 474- (int)fullscreenState;
488 475
489#ifdef NS_DRAW_TO_BUFFER 476#ifdef NS_IMPL_COCOA
490- (void)focusOnDrawingBuffer; 477- (void)lockFocus;
491- (void)unfocusDrawingBuffer; 478- (void)unlockFocus;
492#endif 479#endif
493- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect; 480- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect;
494 481
@@ -715,23 +702,17 @@ typedef id instancetype;
715+ (CGFloat)scrollerWidth; 702+ (CGFloat)scrollerWidth;
716@end 703@end
717 704
718#ifdef NS_DRAW_TO_BUFFER 705#ifdef NS_IMPL_COCOA
719@interface EmacsSurface : NSObject 706@interface EmacsLayer : CALayer
720{ 707{
721 NSMutableArray *cache; 708 NSMutableArray *cache;
722 NSSize size;
723 CGColorSpaceRef colorSpace; 709 CGColorSpaceRef colorSpace;
724 IOSurfaceRef currentSurface; 710 IOSurfaceRef currentSurface;
725 IOSurfaceRef lastSurface;
726 CGContextRef context; 711 CGContextRef context;
727 CGFloat scale;
728} 712}
729- (id) initWithSize: (NSSize)s ColorSpace: (CGColorSpaceRef)cs Scale: (CGFloat)scale; 713- (id) initWithColorSpace: (CGColorSpaceRef)cs;
730- (void) dealloc; 714- (void) setColorSpace: (CGColorSpaceRef)cs;
731- (NSSize) getSize;
732- (CGContextRef) getContext; 715- (CGContextRef) getContext;
733- (void) releaseContext;
734- (IOSurfaceRef) getSurface;
735@end 716@end
736#endif 717#endif
737 718
diff --git a/src/nsterm.m b/src/nsterm.m
index f6168243a49..874af0fb379 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -72,7 +72,7 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
72#include <Carbon/Carbon.h> 72#include <Carbon/Carbon.h>
73#endif 73#endif
74 74
75#ifdef NS_DRAW_TO_BUFFER 75#ifdef NS_IMPL_COCOA
76#include <IOSurface/IOSurface.h> 76#include <IOSurface/IOSurface.h>
77#endif 77#endif
78 78
@@ -272,9 +272,6 @@ long context_menu_value = 0;
272 272
273/* display update */ 273/* display update */
274static struct frame *ns_updating_frame; 274static struct frame *ns_updating_frame;
275#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
276static NSView *focus_view = NULL;
277#endif
278static int ns_window_num = 0; 275static int ns_window_num = 0;
279static BOOL gsaved = NO; 276static BOOL gsaved = NO;
280static BOOL ns_fake_keydown = NO; 277static BOOL ns_fake_keydown = NO;
@@ -1122,26 +1119,7 @@ ns_update_begin (struct frame *f)
1122#endif 1119#endif
1123 1120
1124 ns_updating_frame = f; 1121 ns_updating_frame = f;
1125#ifdef NS_DRAW_TO_BUFFER 1122 [view lockFocus];
1126#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1127 if ([FRAME_NS_VIEW (f) wantsUpdateLayer])
1128 {
1129#endif
1130 [view focusOnDrawingBuffer];
1131#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1132 }
1133 else
1134 {
1135#endif
1136#endif /* NS_DRAW_TO_BUFFER */
1137
1138#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1139 [view lockFocus];
1140#endif
1141#if defined (NS_DRAW_TO_BUFFER) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1142 }
1143#endif
1144
1145} 1123}
1146 1124
1147 1125
@@ -1152,39 +1130,21 @@ ns_update_end (struct frame *f)
1152 external (RIF) call; for whole frame, called after gui_update_window_end 1130 external (RIF) call; for whole frame, called after gui_update_window_end
1153 -------------------------------------------------------------------------- */ 1131 -------------------------------------------------------------------------- */
1154{ 1132{
1155#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1156 EmacsView *view = FRAME_NS_VIEW (f); 1133 EmacsView *view = FRAME_NS_VIEW (f);
1157#endif
1158 1134
1159 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end"); 1135 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1160 1136
1161/* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */ 1137/* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1162 MOUSE_HL_INFO (f)->mouse_face_defer = 0; 1138 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1163 1139
1164#ifdef NS_DRAW_TO_BUFFER 1140 block_input ();
1165#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1166 if ([FRAME_NS_VIEW (f) wantsUpdateLayer])
1167 {
1168#endif
1169 [FRAME_NS_VIEW (f) unfocusDrawingBuffer];
1170#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1171 }
1172 else
1173 {
1174#endif
1175#endif /* NS_DRAW_TO_BUFFER */
1176
1177#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1178 block_input ();
1179
1180 [view unlockFocus];
1181 [[view window] flushWindow];
1182 1141
1183 unblock_input (); 1142 [view unlockFocus];
1184#endif 1143#if defined (NS_IMPL_GNUSTEP)
1185#if defined (NS_DRAW_TO_BUFFER) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400 1144 [[view window] flushWindow];
1186 }
1187#endif 1145#endif
1146
1147 unblock_input ();
1188 ns_updating_frame = NULL; 1148 ns_updating_frame = NULL;
1189} 1149}
1190 1150
@@ -1199,8 +1159,6 @@ ns_focus (struct frame *f, NSRect *r, int n)
1199 the entire window. 1159 the entire window.
1200 -------------------------------------------------------------------------- */ 1160 -------------------------------------------------------------------------- */
1201{ 1161{
1202 EmacsView *view = FRAME_NS_VIEW (f);
1203
1204 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus"); 1162 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1205 if (r != NULL) 1163 if (r != NULL)
1206 { 1164 {
@@ -1209,39 +1167,10 @@ ns_focus (struct frame *f, NSRect *r, int n)
1209 1167
1210 if (f != ns_updating_frame) 1168 if (f != ns_updating_frame)
1211 { 1169 {
1212#ifdef NS_DRAW_TO_BUFFER 1170 EmacsView *view = FRAME_NS_VIEW (f);
1213#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 1171 [view lockFocus];
1214 if ([FRAME_NS_VIEW (f) wantsUpdateLayer])
1215 {
1216#endif
1217 [view focusOnDrawingBuffer];
1218#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1219 }
1220 else
1221 {
1222#endif
1223#endif /* NS_DRAW_TO_BUFFER */
1224
1225#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1226 if (view != focus_view)
1227 {
1228 if (focus_view != NULL)
1229 {
1230 [focus_view unlockFocus];
1231 [[focus_view window] flushWindow];
1232 }
1233
1234 if (view)
1235 [view lockFocus];
1236 focus_view = view;
1237 }
1238#endif
1239#if defined (NS_DRAW_TO_BUFFER) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1240 }
1241#endif
1242 } 1172 }
1243 1173
1244
1245 /* clipping */ 1174 /* clipping */
1246 if (r) 1175 if (r)
1247 { 1176 {
@@ -1269,35 +1198,14 @@ ns_unfocus (struct frame *f)
1269 gsaved = NO; 1198 gsaved = NO;
1270 } 1199 }
1271 1200
1272#ifdef NS_DRAW_TO_BUFFER 1201 if (f != ns_updating_frame)
1273 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1274 if ([FRAME_NS_VIEW (f) wantsUpdateLayer])
1275 {
1276#endif
1277 if (! ns_updating_frame)
1278 [FRAME_NS_VIEW (f) unfocusDrawingBuffer];
1279 [FRAME_NS_VIEW (f) setNeedsDisplay:YES];
1280#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1281 }
1282 else
1283 { 1202 {
1203 EmacsView *view = FRAME_NS_VIEW (f);
1204 [view unlockFocus];
1205#if defined (NS_IMPL_GNUSTEP)
1206 [[view window] flushWindow];
1284#endif 1207#endif
1285#endif /* NS_DRAW_TO_BUFFER */
1286
1287#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1288 if (f != ns_updating_frame)
1289 {
1290 if (focus_view != NULL)
1291 {
1292 [focus_view unlockFocus];
1293 [[focus_view window] flushWindow];
1294 focus_view = NULL;
1295 }
1296 }
1297#endif
1298#if defined (NS_DRAW_TO_BUFFER) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1299 } 1208 }
1300#endif
1301} 1209}
1302 1210
1303 1211
@@ -1464,7 +1372,7 @@ ns_ring_bell (struct frame *f)
1464 } 1372 }
1465} 1373}
1466 1374
1467#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400 1375#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
1468static void 1376static void
1469hide_bell (void) 1377hide_bell (void)
1470/* -------------------------------------------------------------------------- 1378/* --------------------------------------------------------------------------
@@ -6287,10 +6195,6 @@ not_in_argv (NSString *arg)
6287 name:NSViewFrameDidChangeNotification 6195 name:NSViewFrameDidChangeNotification
6288 object:nil]; 6196 object:nil];
6289 6197
6290#ifdef NS_DRAW_TO_BUFFER
6291 [surface release];
6292#endif
6293
6294 [toolbar release]; 6198 [toolbar release];
6295 if (fs_state == FULLSCREEN_BOTH) 6199 if (fs_state == FULLSCREEN_BOTH)
6296 [nonfs_window release]; 6200 [nonfs_window release];
@@ -7303,24 +7207,6 @@ not_in_argv (NSString *arg)
7303 7207
7304 NSTRACE ("[EmacsView viewDidResize]"); 7208 NSTRACE ("[EmacsView viewDidResize]");
7305 7209
7306#ifdef NS_DRAW_TO_BUFFER
7307 /* If the buffer size doesn't match the view's backing size, destroy
7308 the buffer and let it be recreated at the correct size later. */
7309 if ([self wantsUpdateLayer] && surface)
7310 {
7311 NSRect surfaceRect = {{0, 0}, [surface getSize]};
7312 NSRect frameRect = [[self window] convertRectToBacking:frame];
7313
7314 if (!NSEqualRects (frameRect, surfaceRect))
7315 {
7316 [surface release];
7317 surface = nil;
7318
7319 [self setNeedsDisplay:YES];
7320 }
7321 }
7322#endif
7323
7324 neww = (int)NSWidth (frame); 7210 neww = (int)NSWidth (frame);
7325 newh = (int)NSHeight (frame); 7211 newh = (int)NSHeight (frame);
7326 oldw = FRAME_PIXEL_WIDTH (emacsframe); 7212 oldw = FRAME_PIXEL_WIDTH (emacsframe);
@@ -7500,16 +7386,6 @@ not_in_argv (NSString *arg)
7500 [self initWithFrame: r]; 7386 [self initWithFrame: r];
7501 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; 7387 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7502 7388
7503#ifdef NS_DRAW_TO_BUFFER
7504 /* These settings mean AppKit will retain the contents of the frame
7505 on resize. Unfortunately it also means the frame will not be
7506 automatically marked for display, but we can do that ourselves in
7507 viewDidResize. */
7508 [self setLayerContentsRedrawPolicy:
7509 NSViewLayerContentsRedrawOnSetNeedsDisplay];
7510 [self setLayerContentsPlacement:NSViewLayerContentsPlacementTopLeft];
7511#endif
7512
7513 FRAME_NS_VIEW (f) = self; 7389 FRAME_NS_VIEW (f) = self;
7514 emacsframe = f; 7390 emacsframe = f;
7515#ifdef NS_IMPL_COCOA 7391#ifdef NS_IMPL_COCOA
@@ -7549,6 +7425,17 @@ not_in_argv (NSString *arg)
7549 7425
7550 [[win contentView] addSubview: self]; 7426 [[win contentView] addSubview: self];
7551 7427
7428#ifdef NS_IMPL_COCOA
7429 /* These settings mean AppKit will retain the contents of the frame
7430 on resize. Unfortunately it also means the frame will not be
7431 automatically marked for display, but we can do that ourselves in
7432 viewDidResize. */
7433 [self setWantsLayer:YES];
7434 [self setLayerContentsRedrawPolicy:
7435 NSViewLayerContentsRedrawOnSetNeedsDisplay];
7436 [self setLayerContentsPlacement:NSViewLayerContentsPlacementTopLeft];
7437#endif
7438
7552 if (ns_drag_types) 7439 if (ns_drag_types)
7553 [self registerForDraggedTypes: ns_drag_types]; 7440 [self registerForDraggedTypes: ns_drag_types];
7554 7441
@@ -8339,44 +8226,54 @@ not_in_argv (NSString *arg)
8339} 8226}
8340 8227
8341 8228
8342#ifdef NS_DRAW_TO_BUFFER 8229#ifdef NS_IMPL_COCOA
8343- (void)focusOnDrawingBuffer 8230- (CALayer *)makeBackingLayer;
8344{ 8231{
8345 CGFloat scale = [[self window] backingScaleFactor]; 8232 EmacsLayer *l = [[EmacsLayer alloc]
8346 8233 initWithColorSpace:[[[self window] colorSpace] CGColorSpace]];
8347 NSTRACE ("[EmacsView focusOnDrawingBuffer]"); 8234 [l setDelegate:(id)self];
8235 [l setContentsScale:[[self window] backingScaleFactor]];
8348 8236
8349 if (! surface) 8237 return l;
8350 { 8238}
8351 NSRect frame = [self frame];
8352 NSSize s = NSMakeSize (NSWidth (frame) * scale, NSHeight (frame) * scale);
8353 8239
8354 surface = [[EmacsSurface alloc] initWithSize:s
8355 ColorSpace:[[[self window] colorSpace]
8356 CGColorSpace]
8357 Scale:scale];
8358 8240
8359 /* Since we're using NSViewLayerContentsRedrawOnSetNeedsDisplay 8241- (void)lockFocus
8360 the layer's scale factor is not set automatically, so do it 8242{
8361 now. */ 8243 NSTRACE ("[EmacsView lockFocus]");
8362 [[self layer] setContentsScale:scale];
8363 }
8364 8244
8365 CGContextRef context = [surface getContext]; 8245 if ([self wantsLayer])
8246 {
8247 CGContextRef context = [(EmacsLayer*)[self layer] getContext];
8366 8248
8367 [NSGraphicsContext 8249 [NSGraphicsContext
8368 setCurrentContext:[NSGraphicsContext 8250 setCurrentContext:[NSGraphicsContext
8369 graphicsContextWithCGContext:context 8251 graphicsContextWithCGContext:context
8370 flipped:YES]]; 8252 flipped:YES]];
8253 }
8254#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
8255 else
8256 [super lockFocus];
8257#endif
8371} 8258}
8372 8259
8373 8260
8374- (void)unfocusDrawingBuffer 8261- (void)unlockFocus
8375{ 8262{
8376 NSTRACE ("[EmacsView unfocusDrawingBuffer]"); 8263 NSTRACE ("[EmacsView unlockFocus]");
8377 8264
8378 [NSGraphicsContext setCurrentContext:nil]; 8265 if ([self wantsLayer])
8379 [self setNeedsDisplay:YES]; 8266 {
8267 [NSGraphicsContext setCurrentContext:nil];
8268 [self setNeedsDisplay:YES];
8269 }
8270#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
8271 else
8272 {
8273 [super unlockFocus];
8274 [super flushWindow];
8275 }
8276#endif
8380} 8277}
8381 8278
8382 8279
@@ -8385,18 +8282,19 @@ not_in_argv (NSString *arg)
8385{ 8282{
8386 NSTRACE ("EmacsView windowDidChangeBackingProperties:]"); 8283 NSTRACE ("EmacsView windowDidChangeBackingProperties:]");
8387 8284
8388 if ([self wantsUpdateLayer]) 8285 if ([self wantsLayer])
8389 { 8286 {
8390 NSRect frame = [self frame]; 8287 NSRect frame = [self frame];
8288 EmacsLayer *layer = (EmacsLayer *)[self layer];
8391 8289
8392 [surface release]; 8290 [layer setContentsScale:[[notification object] backingScaleFactor]];
8393 surface = nil; 8291 [layer setColorSpace:[[[notification object] colorSpace] CGColorSpace]];
8394 8292
8395 ns_clear_frame (emacsframe); 8293 ns_clear_frame (emacsframe);
8396 expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame)); 8294 expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame));
8397 } 8295 }
8398} 8296}
8399#endif /* NS_DRAW_TO_BUFFER */ 8297#endif /* NS_IMPL_COCOA */
8400 8298
8401 8299
8402- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect 8300- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect
@@ -8405,11 +8303,9 @@ not_in_argv (NSString *arg)
8405 NSTRACE_RECT ("Source", srcRect); 8303 NSTRACE_RECT ("Source", srcRect);
8406 NSTRACE_RECT ("Destination", dstRect); 8304 NSTRACE_RECT ("Destination", dstRect);
8407 8305
8408#ifdef NS_DRAW_TO_BUFFER 8306#ifdef NS_IMPL_COCOA
8409#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 8307 if ([self wantsLayer])
8410 if ([self wantsUpdateLayer])
8411 { 8308 {
8412#endif
8413 double scale = [[self window] backingScaleFactor]; 8309 double scale = [[self window] backingScaleFactor];
8414 CGContextRef context = [[NSGraphicsContext currentContext] CGContext]; 8310 CGContextRef context = [[NSGraphicsContext currentContext] CGContext];
8415 int bpp = CGBitmapContextGetBitsPerPixel (context) / 8; 8311 int bpp = CGBitmapContextGetBitsPerPixel (context) / 8;
@@ -8435,14 +8331,14 @@ not_in_argv (NSString *arg)
8435 (char *) srcPixels + y * rowSize, 8331 (char *) srcPixels + y * rowSize,
8436 srcRowSize); 8332 srcRowSize);
8437 8333
8438#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
8439 } 8334 }
8335#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
8440 else 8336 else
8441 { 8337 {
8442#endif 8338#endif
8443#endif /* NS_DRAW_TO_BUFFER */ 8339#endif /* NS_IMPL_COCOA */
8444 8340
8445#if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400 8341#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400
8446 hide_bell(); // Ensure the bell image isn't scrolled. 8342 hide_bell(); // Ensure the bell image isn't scrolled.
8447 8343
8448 ns_focus (emacsframe, &dstRect, 1); 8344 ns_focus (emacsframe, &dstRect, 1);
@@ -8451,77 +8347,40 @@ not_in_argv (NSString *arg)
8451 dstRect.origin.y - srcRect.origin.y)]; 8347 dstRect.origin.y - srcRect.origin.y)];
8452 ns_unfocus (emacsframe); 8348 ns_unfocus (emacsframe);
8453#endif 8349#endif
8454#if defined (NS_DRAW_TO_BUFFER) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400 8350#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400
8455 } 8351 }
8456#endif 8352#endif
8457} 8353}
8458 8354
8459 8355
8460#ifdef NS_DRAW_TO_BUFFER 8356#ifdef NS_IMPL_COCOA
8461/* If the frame has been garbaged but the toolkit wants to draw, for 8357/* If the frame has been garbaged but the toolkit wants to draw, for
8462 example when resizing the frame, we end up with a blank screen. 8358 example when resizing the frame, we end up with a blank screen.
8463 Sometimes this results in an unpleasant flicker, so try to 8359 Sometimes this results in an unpleasant flicker, so try to
8464 redisplay before drawing. */ 8360 redisplay before drawing.
8465- (void)viewWillDraw
8466{
8467 if (FRAME_GARBAGED_P (emacsframe)
8468 && !redisplaying_p
8469 && [self wantsUpdateLayer])
8470 {
8471 /* If there is IO going on when redisplay is run here Emacs
8472 crashes. I think it's because this code will always be run
8473 within the run loop and for whatever reason processing input
8474 is dangerous. This technique was stolen wholesale from
8475 nsmenu.m and seems to work. */
8476 bool owfi = waiting_for_input;
8477 waiting_for_input = 0;
8478 block_input ();
8479
8480 redisplay ();
8481
8482 unblock_input ();
8483 waiting_for_input = owfi;
8484 }
8485}
8486 8361
8487 8362 This used to be done in viewWillDraw, but with the custom layer
8488- (BOOL)wantsUpdateLayer 8363 that method is not called. */
8364- (void)layout
8489{ 8365{
8490#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 8366 [super layout];
8491 if (NSAppKitVersionNumber < 1671)
8492 return NO;
8493#endif
8494
8495 /* Running on macOS 10.14 or above. */
8496 return YES;
8497}
8498
8499 8367
8500- (void)updateLayer 8368 /* If there is IO going on when redisplay is run here Emacs
8501{ 8369 crashes. I think it's because this code will always be run
8502 NSTRACE ("[EmacsView updateLayer]"); 8370 within the run loop and for whatever reason processing input
8371 is dangerous. This technique was stolen wholesale from
8372 nsmenu.m and seems to work. */
8373 bool owfi = waiting_for_input;
8374 waiting_for_input = 0;
8375 block_input ();
8503 8376
8504 /* We run redisplay on frames that are garbaged, but marked for 8377 redisplay ();
8505 display, before updateLayer is called so if the frame is still
8506 garbaged that means the last redisplay must have refused to
8507 update the frame. */
8508 if (FRAME_GARBAGED_P (emacsframe))
8509 return;
8510 8378
8511 /* This can fail to update the screen if the same surface is 8379 unblock_input ();
8512 provided twice in a row, even if its contents have changed. 8380 waiting_for_input = owfi;
8513 There's a private method, -[CALayer setContentsChanged], that we
8514 could use to force it, but we shouldn't often get the same
8515 surface twice in a row. */
8516 [surface releaseContext];
8517 [[self layer] setContents:(id)[surface getSurface]];
8518 [surface performSelectorOnMainThread:@selector (getContext)
8519 withObject:nil
8520 waitUntilDone:NO];
8521} 8381}
8522#endif 8382#endif
8523 8383
8524
8525- (void)drawRect: (NSRect)rect 8384- (void)drawRect: (NSRect)rect
8526{ 8385{
8527 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]", 8386 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
@@ -9678,7 +9537,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9678@end /* EmacsScroller */ 9537@end /* EmacsScroller */
9679 9538
9680 9539
9681#ifdef NS_DRAW_TO_BUFFER 9540#ifdef NS_IMPL_COCOA
9682 9541
9683/* ========================================================================== 9542/* ==========================================================================
9684 9543
@@ -9686,7 +9545,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9686 9545
9687 ========================================================================== */ 9546 ========================================================================== */
9688 9547
9689@implementation EmacsSurface 9548@implementation EmacsLayer
9690 9549
9691 9550
9692/* An IOSurface is a pixel buffer that is efficiently copied to VRAM 9551/* An IOSurface is a pixel buffer that is efficiently copied to VRAM
@@ -9699,80 +9558,108 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9699 ability to draw to the screen at any time, we need to keep a cache 9558 ability to draw to the screen at any time, we need to keep a cache
9700 of multiple surfaces that we can use at will. 9559 of multiple surfaces that we can use at will.
9701 9560
9702 The EmacsSurface class maintains this cache of surfaces, and 9561 The EmacsLayer class maintains this cache of surfaces, and
9703 handles the conversion to a CGGraphicsContext that AppKit can use 9562 handles the conversion to a CGGraphicsContext that AppKit can use
9704 to draw on. 9563 to draw on.
9705 9564
9706 The cache is simple: if a free surface is found it is removed from 9565 The cache is simple: if a free surface is found it is removed from
9707 the cache and set as the "current" surface. Once Emacs is done 9566 the cache and set as the "current" surface. Once Emacs is done
9708 with drawing to the current surface, the previous surface that was 9567 with drawing to the current surface, the surface that was drawn to
9709 drawn to is added to the cache for reuse, and the current one is 9568 is added to the cache for reuse and set as the last surface. If no
9710 set as the last surface. If no free surfaces are found in the 9569 free surfaces are found in the cache then a new one is created.
9711 cache then a new one is created.
9712 9570
9713 When AppKit wants to update the screen, we provide it with the last 9571 When the layer wants to update the screen, we provide it with the
9714 surface, as that has the most recent data. 9572 last surface, as that has the most recent data. */
9715
9716 FIXME: It is possible for the cache to grow if Emacs draws faster
9717 than the surfaces can be drawn to the screen, so there should
9718 probably be some sort of pruning job that removes excess
9719 surfaces. */
9720 9573
9721#define CACHE_MAX_SIZE 2 9574#define CACHE_MAX_SIZE 2
9722 9575
9723- (id) initWithSize: (NSSize)s 9576- (id) initWithColorSpace: (CGColorSpaceRef)cs
9724 ColorSpace: (CGColorSpaceRef)cs
9725 Scale: (CGFloat)scl
9726{ 9577{
9727 NSTRACE ("[EmacsSurface initWithSize:ColorSpace:]"); 9578 NSTRACE ("[EmacsLayer initWithColorSpace:]");
9728
9729 [super init];
9730 9579
9731 cache = [[NSMutableArray arrayWithCapacity:CACHE_MAX_SIZE] retain]; 9580 self = [super init];
9732 size = s; 9581 if (self)
9733 colorSpace = cs; 9582 {
9734 scale = scl; 9583 cache = [[NSMutableArray arrayWithCapacity:CACHE_MAX_SIZE] retain];
9584 colorSpace = cs;
9585 }
9586 else
9587 {
9588 return nil;
9589 }
9735 9590
9736 return self; 9591 return self;
9737} 9592}
9738 9593
9739 9594
9740- (void) dealloc 9595- (void) setColorSpace: (CGColorSpaceRef)cs
9741{ 9596{
9742 if (context) 9597 /* We don't need to clear the cache because the new colorspace will
9743 CGContextRelease (context); 9598 be used next time we create a new context. */
9744 9599 colorSpace = cs;
9745 if (currentSurface) 9600}
9746 CFRelease (currentSurface);
9747 9601
9748 for (id object in cache)
9749 CFRelease ((IOSurfaceRef)object);
9750 9602
9603- (void) dealloc
9604{
9605 [self releaseSurfaces];
9751 [cache release]; 9606 [cache release];
9752 9607
9753 [super dealloc]; 9608 [super dealloc];
9754} 9609}
9755 9610
9756 9611
9757/* Return the size values our cached data is using. */ 9612- (void) releaseSurfaces
9758- (NSSize) getSize
9759{ 9613{
9760 return size; 9614 [self setContents:nil];
9615 [self releaseContext];
9616
9617 if (currentSurface)
9618 {
9619 CFRelease (currentSurface);
9620 currentSurface = nil;
9621 }
9622
9623 if (cache)
9624 {
9625 for (id object in cache)
9626 CFRelease ((IOSurfaceRef)object);
9627
9628 [cache removeAllObjects];
9629 }
9630}
9631
9632
9633/* Check whether the current bounds match the IOSurfaces we are using.
9634 If they do return YES, otherwise NO. */
9635- (BOOL) checkDimensions
9636{
9637 int width = NSWidth ([self bounds]) * [self contentsScale];
9638 int height = NSHeight ([self bounds]) * [self contentsScale];
9639 IOSurfaceRef s = currentSurface ? currentSurface
9640 : (IOSurfaceRef)[cache firstObject];
9641
9642 return !s || (IOSurfaceGetWidth (s) == width
9643 && IOSurfaceGetHeight (s) == height);
9761} 9644}
9762 9645
9763 9646
9764/* Return a CGContextRef that can be used for drawing to the screen. 9647/* Return a CGContextRef that can be used for drawing to the screen. */
9765 This must ALWAYS be paired with a call to releaseContext, and the
9766 calls cannot be nested. */
9767- (CGContextRef) getContext 9648- (CGContextRef) getContext
9768{ 9649{
9769 NSTRACE ("[EmacsSurface getContext]"); 9650 CGFloat scale = [self contentsScale];
9651
9652 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer getContext]");
9653 NSTRACE_MSG ("IOSurface count: %lu", [cache count] + (currentSurface ? 1 : 0));
9654
9655 if (![self checkDimensions])
9656 [self releaseSurfaces];
9770 9657
9771 if (!context) 9658 if (!context)
9772 { 9659 {
9773 IOSurfaceRef surface = NULL; 9660 IOSurfaceRef surface = NULL;
9774 9661 int width = NSWidth ([self bounds]) * scale;
9775 NSTRACE_MSG ("IOSurface count: %lu", [cache count] + (lastSurface ? 1 : 0)); 9662 int height = NSHeight ([self bounds]) * scale;
9776 9663
9777 for (id object in cache) 9664 for (id object in cache)
9778 { 9665 {
@@ -9795,11 +9682,11 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9795 else if (!surface) 9682 else if (!surface)
9796 { 9683 {
9797 int bytesPerRow = IOSurfaceAlignProperty (kIOSurfaceBytesPerRow, 9684 int bytesPerRow = IOSurfaceAlignProperty (kIOSurfaceBytesPerRow,
9798 size.width * 4); 9685 width * 4);
9799 9686
9800 surface = IOSurfaceCreate 9687 surface = IOSurfaceCreate
9801 ((CFDictionaryRef)@{(id)kIOSurfaceWidth:[NSNumber numberWithInt:size.width], 9688 ((CFDictionaryRef)@{(id)kIOSurfaceWidth:[NSNumber numberWithInt:width],
9802 (id)kIOSurfaceHeight:[NSNumber numberWithInt:size.height], 9689 (id)kIOSurfaceHeight:[NSNumber numberWithInt:height],
9803 (id)kIOSurfaceBytesPerRow:[NSNumber numberWithInt:bytesPerRow], 9690 (id)kIOSurfaceBytesPerRow:[NSNumber numberWithInt:bytesPerRow],
9804 (id)kIOSurfaceBytesPerElement:[NSNumber numberWithInt:4], 9691 (id)kIOSurfaceBytesPerElement:[NSNumber numberWithInt:4],
9805 (id)kIOSurfacePixelFormat:[NSNumber numberWithUnsignedInt:'BGRA']}); 9692 (id)kIOSurfacePixelFormat:[NSNumber numberWithUnsignedInt:'BGRA']});
@@ -9822,7 +9709,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9822 (kCGImageAlphaPremultipliedFirst 9709 (kCGImageAlphaPremultipliedFirst
9823 | kCGBitmapByteOrder32Host)); 9710 | kCGBitmapByteOrder32Host));
9824 9711
9825 CGContextTranslateCTM(context, 0, size.height); 9712 CGContextTranslateCTM(context, 0, IOSurfaceGetHeight (currentSurface));
9826 CGContextScaleCTM(context, scale, -scale); 9713 CGContextScaleCTM(context, scale, -scale);
9827 } 9714 }
9828 9715
@@ -9834,7 +9721,7 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9834 IOSurface, so it will be sent to VRAM. */ 9721 IOSurface, so it will be sent to VRAM. */
9835- (void) releaseContext 9722- (void) releaseContext
9836{ 9723{
9837 NSTRACE ("[EmacsSurface releaseContextAndGetSurface]"); 9724 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer releaseContext]");
9838 9725
9839 if (!context) 9726 if (!context)
9840 return; 9727 return;
@@ -9845,19 +9732,34 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9845 IOReturn lockStatus = IOSurfaceUnlock (currentSurface, 0, nil); 9732 IOReturn lockStatus = IOSurfaceUnlock (currentSurface, 0, nil);
9846 if (lockStatus != kIOReturnSuccess) 9733 if (lockStatus != kIOReturnSuccess)
9847 NSLog (@"Failed to unlock surface: %x", lockStatus); 9734 NSLog (@"Failed to unlock surface: %x", lockStatus);
9848
9849 /* Put currentSurface back on the end of the cache. */
9850 [cache addObject:(id)currentSurface];
9851 lastSurface = currentSurface;
9852 currentSurface = NULL;
9853} 9735}
9854 9736
9855 9737
9856/* Get the IOSurface that we want to draw to the screen. */ 9738- (void) display
9857- (IOSurfaceRef) getSurface
9858{ 9739{
9859 /* lastSurface always contains the most up-to-date and complete data. */ 9740 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer display]");
9860 return lastSurface; 9741
9742 if (context)
9743 {
9744 [self releaseContext];
9745
9746#if CACHE_MAX_SIZE == 1
9747 /* This forces the layer to see the surface as updated. */
9748 [self setContents:nil];
9749#endif
9750
9751 [self setContents:(id)currentSurface];
9752
9753 /* Put currentSurface back on the end of the cache. */
9754 [cache addObject:(id)currentSurface];
9755 currentSurface = NULL;
9756
9757 /* Schedule a run of getContext so that if Emacs is idle it will
9758 perform the buffer copy, etc. */
9759 [self performSelectorOnMainThread:@selector (getContext)
9760 withObject:nil
9761 waitUntilDone:NO];
9762 }
9861} 9763}
9862 9764
9863 9765
@@ -9867,19 +9769,20 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9867- (void) copyContentsTo: (IOSurfaceRef) destination 9769- (void) copyContentsTo: (IOSurfaceRef) destination
9868{ 9770{
9869 IOReturn lockStatus; 9771 IOReturn lockStatus;
9772 IOSurfaceRef source = (IOSurfaceRef)[self contents];
9870 void *sourceData, *destinationData; 9773 void *sourceData, *destinationData;
9871 int numBytes = IOSurfaceGetAllocSize (destination); 9774 int numBytes = IOSurfaceGetAllocSize (destination);
9872 9775
9873 NSTRACE ("[EmacsSurface copyContentsTo:]"); 9776 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer copyContentsTo:]");
9874 9777
9875 if (!lastSurface || lastSurface == destination) 9778 if (!source || source == destination)
9876 return; 9779 return;
9877 9780
9878 lockStatus = IOSurfaceLock (lastSurface, kIOSurfaceLockReadOnly, nil); 9781 lockStatus = IOSurfaceLock (source, kIOSurfaceLockReadOnly, nil);
9879 if (lockStatus != kIOReturnSuccess) 9782 if (lockStatus != kIOReturnSuccess)
9880 NSLog (@"Failed to lock source surface: %x", lockStatus); 9783 NSLog (@"Failed to lock source surface: %x", lockStatus);
9881 9784
9882 sourceData = IOSurfaceGetBaseAddress (lastSurface); 9785 sourceData = IOSurfaceGetBaseAddress (source);
9883 destinationData = IOSurfaceGetBaseAddress (destination); 9786 destinationData = IOSurfaceGetBaseAddress (destination);
9884 9787
9885 /* Since every IOSurface should have the exact same settings, a 9788 /* Since every IOSurface should have the exact same settings, a
@@ -9887,17 +9790,17 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
9887 the other. */ 9790 the other. */
9888 memcpy (destinationData, sourceData, numBytes); 9791 memcpy (destinationData, sourceData, numBytes);
9889 9792
9890 lockStatus = IOSurfaceUnlock (lastSurface, kIOSurfaceLockReadOnly, nil); 9793 lockStatus = IOSurfaceUnlock (source, kIOSurfaceLockReadOnly, nil);
9891 if (lockStatus != kIOReturnSuccess) 9794 if (lockStatus != kIOReturnSuccess)
9892 NSLog (@"Failed to unlock source surface: %x", lockStatus); 9795 NSLog (@"Failed to unlock source surface: %x", lockStatus);
9893} 9796}
9894 9797
9895#undef CACHE_MAX_SIZE 9798#undef CACHE_MAX_SIZE
9896 9799
9897@end /* EmacsSurface */ 9800@end /* EmacsLayer */
9898 9801
9899 9802
9900#endif 9803#endif /* NS_IMPL_COCOA */
9901 9804
9902 9805
9903#ifdef NS_IMPL_GNUSTEP 9806#ifdef NS_IMPL_GNUSTEP