diff options
| author | Alan Third | 2021-05-29 09:48:51 +0100 |
|---|---|---|
| committer | Alan Third | 2021-05-31 17:09:42 +0100 |
| commit | 784ec4b75221e254d2d434578be04466d7ef8786 (patch) | |
| tree | fd27b889b8e02a4be1a6c8fed77c6beaff86ab5e | |
| parent | 6bf76258161ca724a87fab2066c1c862ee61cf88 (diff) | |
| download | emacs-scratch/ns/surface-stuff.tar.gz emacs-scratch/ns/surface-stuff.zip | |
Simplify macOS drawing codescratch/ns/surface-stuff
Convert EmacsSurface into a CALayer subclass so we can use the
built-in relationships. Also simplify the macOS versioning code.
This will result in more warnings on older versions of macOS but makes
reading the code easier.
* configure.ac: Add QuartzCore framework.
* src/nsterm.h (NS_DRAW_TO_BUFFER): Remove define and all references.
(EmacsSurface, EmacsLayer): Rename EmacsSurface to EmacsLayer and
modify the definition to fit the new function.
* src/nsterm.m (ns_update_begin):
(ns_update_end):
(ns_focus):
(ns_unfocus): Use the new overridden lockFocus and unlockFocus and
simplify the frame management.
([EmacsView dealloc]):
([EmacsView viewDidResize:]):Don't explicitly release surfaces.
([EmacsView initFrameFromEmacs:]): Move the layer code to after the
NSWindow has been created as creating the layer now relies on some of
it's properties.
([EmacsView makeBackingLayer]): New function.
([EmacsView lockFocus]):
([EmacsView focusOnDrawingBuffer]): Rename to lockFocus.
([EmacsView unlockFocus]):
([EmacsView unfocusDrawingBuffer]): Rename to unlockFocus.
([EmacsView windowDidChangeBackingProperties]): Don't explicitly
release surfaces but reset EmacsLayer properties.
([EmacsView layout]):
([EmacsView viewWillDraw]): Rename to layout.
([EmacsView wantsUpdateLayer]): Remove function and change all callers
to [EmacsView wantsLayer].
(EmacsSurface, EmacsLayer): Rename to EmacsLayer.
([EmacsSurface getSize]):
([EmacsSurface initWithSize:ColorSpace:Scale:]): Remove methods.
([EmacsSurface initWithColorSpace:]):
([EmacsLayer checkDimensions]):
([EmacsLayer releaseSurfaces]):
([EmacsLayer display]): New functions.
* src/nsterm.m ([EmacsLayer dealloc]): Use releaseSurfaces.
([EmacsSurface getContext]): Automatically detect frame property
changes and clear the cache if required. Use built-in CALayer
properties where available.
([EmacsLayer copyContentsTo:]): Use [CALayer contents] as source.
| -rw-r--r-- | configure.ac | 3 | ||||
| -rw-r--r-- | src/nsterm.h | 35 | ||||
| -rw-r--r-- | src/nsterm.m | 493 |
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 */ |
| 274 | static struct frame *ns_updating_frame; | 274 | static struct frame *ns_updating_frame; |
| 275 | #if !defined (NS_DRAW_TO_BUFFER) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400 | ||
| 276 | static NSView *focus_view = NULL; | ||
| 277 | #endif | ||
| 278 | static int ns_window_num = 0; | 275 | static int ns_window_num = 0; |
| 279 | static BOOL gsaved = NO; | 276 | static BOOL gsaved = NO; |
| 280 | static BOOL ns_fake_keydown = NO; | 277 | static 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 |
| 1468 | static void | 1376 | static void |
| 1469 | hide_bell (void) | 1377 | hide_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 |