aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Third2019-02-10 10:59:29 +0000
committerAlan Third2020-01-24 16:05:42 +0000
commitf674c905dc98a4617c40c4bc115462b4ad2ebfc2 (patch)
tree7c75bab5bdc5f04f73f8f254eb0a76a54ca2e0b1
parent3ad7813296760cecfd3fd35a5fb47930d61a573d (diff)
downloademacs-f674c905dc98a4617c40c4bc115462b4ad2ebfc2.tar.gz
emacs-f674c905dc98a4617c40c4bc115462b4ad2ebfc2.zip
Draw to offscreen buffer on macOS
* src/nsfns.m (x_set_background_color): Clear the frame after changing the background color, not before. * src/nsterm.h (drawingBuffer): New variable. ([EmacsView focusOnDrawingBuffer]): ([EmacsView copyRect:to:]): ([EmacsView createDrawingBufferWithRect:]): New methods. * src/nsterm.m (ns_update_begin): (ns_update_end): (ns_focus): (ns_unfocus): Handle drawing to offscreen buffer. (ns_clip_to_row): Use ns_row_rect. (ns_copy_bits): Remove unused function. (ns_scroll_run): (ns_shift_glyphs_for_insert): Use new scrolling method. (ns_draw_fringe_bitmap): (ns_dumpglyphs_image): When drawing to the offscreen buffer, flip images so they appear the right way up. (ns_dumpglyphs_stretch): Remove unnecessary code. (ns_draw_window_cursor): Don't disable screen updates. ([EmacsView updateFrameSize:]): Update the size of the offscreen buffer. ([EmacsView initFrameFromEmacs:]): Create offscreen buffer. ([EmacsView windowDidChangeBackingProperties:]): ([EmacsView createDrawingBufferWithRect:]): ([EmacsView focusOnDrawingBuffer]): ([EmacsView copyRect]): New methods. ([EmacsView viewWillDraw]): Remove method as it no longer does anything useful. ([EmacsView drawRect:]): Handle drawing from offscreen buffer.
-rw-r--r--src/nsfns.m11
-rw-r--r--src/nsterm.h11
-rw-r--r--src/nsterm.m478
3 files changed, 248 insertions, 252 deletions
diff --git a/src/nsfns.m b/src/nsfns.m
index 3be4e390e0d..cbde93b3f10 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -287,12 +287,6 @@ ns_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
287 error ("Unknown color"); 287 error ("Unknown color");
288 } 288 }
289 289
290 /* Clear the frame; in some instances the NS-internal GC appears not
291 to update, or it does update and cannot clear old text
292 properly. */
293 if (FRAME_VISIBLE_P (f))
294 ns_clear_frame (f);
295
296 [col retain]; 290 [col retain];
297 [f->output_data.ns->background_color release]; 291 [f->output_data.ns->background_color release];
298 f->output_data.ns->background_color = col; 292 f->output_data.ns->background_color = col;
@@ -324,7 +318,10 @@ ns_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
324 } 318 }
325 319
326 if (FRAME_VISIBLE_P (f)) 320 if (FRAME_VISIBLE_P (f))
327 SET_FRAME_GARBAGED (f); 321 {
322 SET_FRAME_GARBAGED (f);
323 ns_clear_frame (f);
324 }
328 } 325 }
329 unblock_input (); 326 unblock_input ();
330} 327}
diff --git a/src/nsterm.h b/src/nsterm.h
index 7d12ecc243c..980ca534cfa 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -417,6 +417,9 @@ typedef id instancetype;
417 int maximized_width, maximized_height; 417 int maximized_width, maximized_height;
418 NSWindow *nonfs_window; 418 NSWindow *nonfs_window;
419 BOOL fs_is_native; 419 BOOL fs_is_native;
420#ifdef NS_IMPL_COCOA
421 NSBitmapImageRep *drawingBuffer;
422#endif
420@public 423@public
421 struct frame *emacsframe; 424 struct frame *emacsframe;
422 int rows, cols; 425 int rows, cols;
@@ -457,7 +460,13 @@ typedef id instancetype;
457#endif 460#endif
458- (int)fullscreenState; 461- (int)fullscreenState;
459 462
460/* Non-notification versions of NSView methods. Used for direct calls. */ 463#ifdef NS_IMPL_COCOA
464- (void)focusOnDrawingBuffer;
465#endif
466- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect;
467- (void)createDrawingBufferWithRect:(NSRect)rect;
468
469/* Non-notification versions of NSView methods. Used for direct calls. */
461- (void)windowWillEnterFullScreen; 470- (void)windowWillEnterFullScreen;
462- (void)windowDidEnterFullScreen; 471- (void)windowDidEnterFullScreen;
463- (void)windowWillExitFullScreen; 472- (void)windowWillExitFullScreen;
diff --git a/src/nsterm.m b/src/nsterm.m
index 222af19aa20..9d427b9b38d 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -290,9 +290,6 @@ long context_menu_value = 0;
290static struct frame *ns_updating_frame; 290static struct frame *ns_updating_frame;
291static NSView *focus_view = NULL; 291static NSView *focus_view = NULL;
292static int ns_window_num = 0; 292static int ns_window_num = 0;
293#ifdef NS_IMPL_GNUSTEP
294static NSRect uRect; // TODO: This is dead, remove it?
295#endif
296static BOOL gsaved = NO; 293static BOOL gsaved = NO;
297static BOOL ns_fake_keydown = NO; 294static BOOL ns_fake_keydown = NO;
298#ifdef NS_IMPL_COCOA 295#ifdef NS_IMPL_COCOA
@@ -1120,33 +1117,10 @@ ns_update_begin (struct frame *f)
1120#endif 1117#endif
1121 1118
1122 ns_updating_frame = f; 1119 ns_updating_frame = f;
1123 [view lockFocus];
1124
1125 /* drawRect may have been called for say the minibuffer, and then clip path
1126 is for the minibuffer. But the display engine may draw more because
1127 we have set the frame as garbaged. So reset clip path to the whole
1128 view. */
1129#ifdef NS_IMPL_COCOA 1120#ifdef NS_IMPL_COCOA
1130 { 1121 [view focusOnDrawingBuffer];
1131 NSBezierPath *bp; 1122#else
1132 NSRect r = [view frame]; 1123 [view lockFocus];
1133 NSRect cr = [[view window] frame];
1134 /* If a large frame size is set, r may be larger than the window frame
1135 before constrained. In that case don't change the clip path, as we
1136 will clear in to the tool bar and title bar. */
1137 if (r.size.height
1138 + FRAME_NS_TITLEBAR_HEIGHT (f)
1139 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1140 {
1141 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1142 [bp setClip];
1143 [bp release];
1144 }
1145 }
1146#endif
1147
1148#ifdef NS_IMPL_GNUSTEP
1149 uRect = NSMakeRect (0, 0, 0, 0);
1150#endif 1124#endif
1151} 1125}
1152 1126
@@ -1165,12 +1139,17 @@ ns_update_end (struct frame *f)
1165/* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */ 1139/* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1166 MOUSE_HL_INFO (f)->mouse_face_defer = 0; 1140 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1167 1141
1142#ifdef NS_IMPL_COCOA
1143 [NSGraphicsContext setCurrentContext:nil];
1144 [view display];
1145#else
1168 block_input (); 1146 block_input ();
1169 1147
1170 [view unlockFocus]; 1148 [view unlockFocus];
1171 [[view window] flushWindow]; 1149 [[view window] flushWindow];
1172 1150
1173 unblock_input (); 1151 unblock_input ();
1152#endif
1174 ns_updating_frame = NULL; 1153 ns_updating_frame = NULL;
1175} 1154}
1176 1155
@@ -1185,6 +1164,8 @@ ns_focus (struct frame *f, NSRect *r, int n)
1185 the entire window. 1164 the entire window.
1186 -------------------------------------------------------------------------- */ 1165 -------------------------------------------------------------------------- */
1187{ 1166{
1167 EmacsView *view = FRAME_NS_VIEW (f);
1168
1188 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus"); 1169 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1189 if (r != NULL) 1170 if (r != NULL)
1190 { 1171 {
@@ -1192,27 +1173,34 @@ ns_focus (struct frame *f, NSRect *r, int n)
1192 } 1173 }
1193 1174
1194 if (f != ns_updating_frame) 1175 if (f != ns_updating_frame)
1176#ifdef NS_IMPL_COCOA
1177 [view focusOnDrawingBuffer];
1178#else
1195 { 1179 {
1196 NSView *view = FRAME_NS_VIEW (f);
1197 if (view != focus_view) 1180 if (view != focus_view)
1198 { 1181 {
1199 if (focus_view != NULL) 1182 if (focus_view != NULL)
1200 { 1183 {
1201 [focus_view unlockFocus]; 1184 [focus_view unlockFocus];
1202 [[focus_view window] flushWindow]; 1185 [[focus_view window] flushWindow];
1203/*debug_lock--; */
1204 } 1186 }
1205 1187
1206 if (view) 1188 if (view)
1207 [view lockFocus]; 1189 [view lockFocus];
1208 focus_view = view; 1190 focus_view = view;
1209/*if (view) debug_lock++; */
1210 } 1191 }
1211 } 1192 }
1193#endif
1212 1194
1213 /* clipping */ 1195 /* clipping */
1214 if (r) 1196 if (r)
1215 { 1197 {
1198#ifdef NS_IMPL_COCOA
1199 int i;
1200 for (i = 0 ; i < n ; i++)
1201 [view setNeedsDisplayInRect:r[i]];
1202#endif
1203
1216 [[NSGraphicsContext currentContext] saveGraphicsState]; 1204 [[NSGraphicsContext currentContext] saveGraphicsState];
1217 if (n == 2) 1205 if (n == 2)
1218 NSRectClipList (r, 2); 1206 NSRectClipList (r, 2);
@@ -1237,6 +1225,7 @@ ns_unfocus (struct frame *f)
1237 gsaved = NO; 1225 gsaved = NO;
1238 } 1226 }
1239 1227
1228#ifdef NS_IMPL_GNUSTEP
1240 if (f != ns_updating_frame) 1229 if (f != ns_updating_frame)
1241 { 1230 {
1242 if (focus_view != NULL) 1231 if (focus_view != NULL)
@@ -1244,9 +1233,9 @@ ns_unfocus (struct frame *f)
1244 [focus_view unlockFocus]; 1233 [focus_view unlockFocus];
1245 [[focus_view window] flushWindow]; 1234 [[focus_view window] flushWindow];
1246 focus_view = NULL; 1235 focus_view = NULL;
1247/*debug_lock--; */
1248 } 1236 }
1249 } 1237 }
1238#endif
1250} 1239}
1251 1240
1252 1241
@@ -1258,16 +1247,7 @@ ns_clip_to_row (struct window *w, struct glyph_row *row,
1258 -------------------------------------------------------------------------- */ 1247 -------------------------------------------------------------------------- */
1259{ 1248{
1260 struct frame *f = XFRAME (WINDOW_FRAME (w)); 1249 struct frame *f = XFRAME (WINDOW_FRAME (w));
1261 NSRect clip_rect; 1250 NSRect clip_rect = ns_row_rect (w, row, area);
1262 int window_x, window_y, window_width;
1263
1264 window_box (w, area, &window_x, &window_y, &window_width, 0);
1265
1266 clip_rect.origin.x = window_x;
1267 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1268 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1269 clip_rect.size.width = window_width;
1270 clip_rect.size.height = row->visible_height;
1271 1251
1272 ns_focus (f, &clip_rect, 1); 1252 ns_focus (f, &clip_rect, 1);
1273} 1253}
@@ -2903,22 +2883,6 @@ ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2903 return; 2883 return;
2904} 2884}
2905 2885
2906static void
2907ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2908{
2909 NSTRACE ("ns_copy_bits");
2910
2911 if (FRAME_NS_VIEW (f))
2912 {
2913 hide_bell(); // Ensure the bell image isn't scrolled.
2914
2915 ns_focus (f, &dest, 1);
2916 [FRAME_NS_VIEW (f) scrollRect: src
2917 by: NSMakeSize (dest.origin.x - src.origin.x,
2918 dest.origin.y - src.origin.y)];
2919 ns_unfocus (f);
2920 }
2921}
2922 2886
2923static void 2887static void
2924ns_scroll_run (struct window *w, struct run *run) 2888ns_scroll_run (struct window *w, struct run *run)
@@ -2971,8 +2935,12 @@ ns_scroll_run (struct window *w, struct run *run)
2971 { 2935 {
2972 NSRect srcRect = NSMakeRect (x, from_y, width, height); 2936 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2973 NSRect dstRect = NSMakeRect (x, to_y, width, height); 2937 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2938 EmacsView *view = FRAME_NS_VIEW (f);
2974 2939
2975 ns_copy_bits (f, srcRect , dstRect); 2940 [view copyRect:srcRect to:dstRect];
2941#ifdef NS_IMPL_COCOA
2942 [view setNeedsDisplayInRect:srcRect];
2943#endif
2976 } 2944 }
2977 2945
2978 unblock_input (); 2946 unblock_input ();
@@ -3026,20 +2994,12 @@ ns_shift_glyphs_for_insert (struct frame *f,
3026 External (RIF): copy an area horizontally, don't worry about clearing src 2994 External (RIF): copy an area horizontally, don't worry about clearing src
3027 -------------------------------------------------------------------------- */ 2995 -------------------------------------------------------------------------- */
3028{ 2996{
3029 //NSRect srcRect = NSMakeRect (x, y, width, height); 2997 NSRect srcRect = NSMakeRect (x, y, width, height);
3030 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height); 2998 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
3031 2999
3032 NSTRACE ("ns_shift_glyphs_for_insert"); 3000 NSTRACE ("ns_shift_glyphs_for_insert");
3033 3001
3034 /* This doesn't work now as we copy the "bits" before we've had a 3002 [FRAME_NS_VIEW (f) copyRect:srcRect to:dstRect];
3035 chance to actually draw any changes to the screen. This means in
3036 certain circumstances we end up with copies of the cursor all
3037 over the place. Just mark the area dirty so it is redrawn later.
3038
3039 FIXME: Work out how to do this properly. */
3040 // ns_copy_bits (f, srcRect, dstRect);
3041
3042 [FRAME_NS_VIEW (f) setNeedsDisplayInRect:dstRect];
3043} 3003}
3044 3004
3045 3005
@@ -3159,20 +3119,18 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3159 3119
3160 /* The visible portion of imageRect will always be contained within 3120 /* The visible portion of imageRect will always be contained within
3161 clearRect. */ 3121 clearRect. */
3162 if (ns_clip_to_rect (f, &clearRect, 1)) 3122 ns_focus (f, &clearRect, 1);
3123 if (! NSIsEmptyRect (clearRect))
3163 { 3124 {
3164 if (! NSIsEmptyRect (clearRect)) 3125 NSTRACE_RECT ("clearRect", clearRect);
3165 {
3166 NSTRACE_RECT ("clearRect", clearRect);
3167 3126
3168 [ns_lookup_indexed_color(face->background, f) set]; 3127 [ns_lookup_indexed_color(face->background, f) set];
3169 NSRectFill (clearRect); 3128 NSRectFill (clearRect);
3170 }
3171 } 3129 }
3172 3130
3173 if (p->which) 3131 if (p->which)
3174 { 3132 {
3175 EmacsImage *img = bimgs[p->which - 1]; 3133 EmacsImage *img = bimgs[p->which - 1];
3176 3134
3177 if (!img) 3135 if (!img)
3178 { 3136 {
@@ -3205,20 +3163,30 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3205 [img setXBMColor: bm_color]; 3163 [img setXBMColor: bm_color];
3206 } 3164 }
3207 3165
3208 // Note: For periodic images, the full image height is "h + hd". 3166 // Note: For periodic images, the full image height is "h + hd".
3209 // By using the height h, a suitable part of the image is used. 3167 // By using the height h, a suitable part of the image is used.
3210 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h); 3168 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
3211 3169
3212 NSTRACE_RECT ("fromRect", fromRect); 3170 NSTRACE_RECT ("fromRect", fromRect);
3213 3171
3214 [img drawInRect: imageRect 3172 /* Because we're drawing into an offscreen buffer which isn't
3215 fromRect: fromRect 3173 flipped, the images come out upside down. To work around it
3216 operation: NSCompositingOperationSourceOver 3174 we need to do some fancy transforms. */
3217 fraction: 1.0 3175 {
3218 respectFlipped: YES 3176 NSAffineTransform *transform = [NSAffineTransform transform];
3219 hints: nil]; 3177 [transform translateXBy:0 yBy:NSMaxY(imageRect)];
3220 } 3178 [transform scaleXBy:1 yBy:-1];
3221 ns_reset_clipping (f); 3179 [transform concat];
3180
3181 imageRect.origin.y = 0;
3182 }
3183
3184 [img drawInRect: imageRect
3185 fromRect: fromRect
3186 operation: NSCompositingOperationSourceOver
3187 fraction: 1.0
3188 respectFlipped: YES
3189 hints: nil];
3222 } 3190 }
3223 ns_unfocus (f); 3191 ns_unfocus (f);
3224} 3192}
@@ -3315,54 +3283,42 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3315 else 3283 else
3316 [FRAME_CURSOR_COLOR (f) set]; 3284 [FRAME_CURSOR_COLOR (f) set];
3317 3285
3318#ifdef NS_IMPL_COCOA 3286 ns_focus (f, &r, 1);
3319 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3320 atomic. Cleaner ways of doing this should be investigated.
3321 One way would be to set a global variable DRAWING_CURSOR
3322 when making the call to draw_phys..(), don't focus in that
3323 case, then move the ns_unfocus() here after that call. */
3324 NSDisableScreenUpdates ();
3325#endif
3326
3327 switch (cursor_type)
3328 {
3329 case DEFAULT_CURSOR:
3330 case NO_CURSOR:
3331 break;
3332 case FILLED_BOX_CURSOR:
3333 NSRectFill (r);
3334 break;
3335 case HOLLOW_BOX_CURSOR:
3336 NSRectFill (r);
3337 [hollow_color set];
3338 NSRectFill (NSInsetRect (r, 1, 1));
3339 [FRAME_CURSOR_COLOR (f) set];
3340 break;
3341 case HBAR_CURSOR:
3342 NSRectFill (r);
3343 break;
3344 case BAR_CURSOR:
3345 s = r;
3346 /* If the character under cursor is R2L, draw the bar cursor
3347 on the right of its glyph, rather than on the left. */
3348 cursor_glyph = get_phys_cursor_glyph (w);
3349 if ((cursor_glyph->resolved_level & 1) != 0)
3350 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3351
3352 NSRectFill (s);
3353 break;
3354 }
3355 ns_unfocus (f);
3356 3287
3357 /* Draw the character under the cursor. Other terms only draw 3288 switch (cursor_type)
3358 the character on top of box cursors, so do the same here. */ 3289 {
3359 if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR) 3290 case DEFAULT_CURSOR:
3360 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); 3291 case NO_CURSOR:
3292 break;
3293 case FILLED_BOX_CURSOR:
3294 NSRectFill (r);
3295 break;
3296 case HOLLOW_BOX_CURSOR:
3297 NSRectFill (r);
3298 [hollow_color set];
3299 NSRectFill (NSInsetRect (r, 1, 1));
3300 [FRAME_CURSOR_COLOR (f) set];
3301 break;
3302 case HBAR_CURSOR:
3303 NSRectFill (r);
3304 break;
3305 case BAR_CURSOR:
3306 s = r;
3307 /* If the character under cursor is R2L, draw the bar cursor
3308 on the right of its glyph, rather than on the left. */
3309 cursor_glyph = get_phys_cursor_glyph (w);
3310 if ((cursor_glyph->resolved_level & 1) != 0)
3311 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3361 3312
3362#ifdef NS_IMPL_COCOA 3313 NSRectFill (s);
3363 NSEnableScreenUpdates (); 3314 break;
3364#endif 3315 }
3316 ns_unfocus (f);
3365 3317
3318 /* Draw the character under the cursor. Other terms only draw
3319 the character on top of box cursors, so do the same here. */
3320 if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR)
3321 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3366} 3322}
3367 3323
3368 3324
@@ -3447,6 +3403,7 @@ ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3447 ns_unfocus (f); 3403 ns_unfocus (f);
3448} 3404}
3449 3405
3406
3450static void 3407static void
3451ns_show_hourglass (struct frame *f) 3408ns_show_hourglass (struct frame *f)
3452{ 3409{
@@ -3970,15 +3927,27 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3970 3927
3971 [[NSGraphicsContext currentContext] saveGraphicsState]; 3928 [[NSGraphicsContext currentContext] saveGraphicsState];
3972 3929
3973 /* Because of the transforms it's far too difficult to work out 3930 /* Because of the transforms it's difficult to work out what
3974 what portion of the original, untransformed, image will be 3931 portion of the original, untransformed, image will be drawn,
3975 drawn, so the clipping area will ensure we draw only the 3932 so the clipping area will ensure we draw only the correct
3976 correct bit. */ 3933 bit. */
3977 NSRectClip (dr); 3934 NSRectClip (dr);
3978 3935
3979 [setOrigin translateXBy:x - s->slice.x yBy:y - s->slice.y]; 3936 [setOrigin translateXBy:x - s->slice.x yBy:y - s->slice.y];
3980 [setOrigin concat]; 3937 [setOrigin concat];
3981 [img->transform concat]; 3938
3939 NSAffineTransform *doTransform = [NSAffineTransform transform];
3940
3941 /* We have to flip the image around the X axis as the offscreen
3942 bitmap we're drawing to is flipped. */
3943 [doTransform scaleXBy:1 yBy:-1];
3944 [doTransform translateXBy:0 yBy:-[img size].height];
3945
3946 /* ImageMagick images don't have transforms. */
3947 if (img->transform)
3948 [doTransform appendTransform:img->transform];
3949
3950 [doTransform concat];
3982 3951
3983 [img drawInRect:ir fromRect:ir 3952 [img drawInRect:ir fromRect:ir
3984 operation:NSCompositingOperationSourceOver 3953 operation:NSCompositingOperationSourceOver
@@ -4051,6 +4020,7 @@ static void
4051ns_dumpglyphs_stretch (struct glyph_string *s) 4020ns_dumpglyphs_stretch (struct glyph_string *s)
4052{ 4021{
4053 NSRect r[2]; 4022 NSRect r[2];
4023 NSRect glyphRect;
4054 int n, i; 4024 int n, i;
4055 struct face *face; 4025 struct face *face;
4056 NSColor *fgCol, *bgCol; 4026 NSColor *fgCol, *bgCol;
@@ -4058,106 +4028,56 @@ ns_dumpglyphs_stretch (struct glyph_string *s)
4058 if (!s->background_filled_p) 4028 if (!s->background_filled_p)
4059 { 4029 {
4060 n = ns_get_glyph_string_clip_rect (s, r); 4030 n = ns_get_glyph_string_clip_rect (s, r);
4061
4062 ns_focus (s->f, r, n); 4031 ns_focus (s->f, r, n);
4063 4032
4064 if (s->hl == DRAW_MOUSE_FACE) 4033 if (s->hl == DRAW_MOUSE_FACE)
4065 { 4034 {
4066 face = FACE_FROM_ID_OR_NULL (s->f, 4035 face = FACE_FROM_ID_OR_NULL (s->f,
4067 MOUSE_HL_INFO (s->f)->mouse_face_face_id); 4036 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
4068 if (!face) 4037 if (!face)
4069 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); 4038 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
4070 } 4039 }
4071 else 4040 else
4072 face = FACE_FROM_ID (s->f, s->first_glyph->face_id); 4041 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
4073 4042
4074 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); 4043 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
4075 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); 4044 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
4076 4045
4077 for (i = 0; i < n; ++i) 4046 glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height);
4078 {
4079 /* FIXME: Why are we reusing the clipping rectangles? The
4080 other terms don't appear to do anything like this. */
4081 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
4082
4083 if (s->hl == DRAW_MOUSE_FACE)
4084 {
4085 int overrun, leftoverrun;
4086
4087 /* truncate to avoid overwriting fringe and/or scrollbar */
4088 overrun = max (0, (s->x + s->background_width)
4089 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
4090 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
4091 r[i].size.width -= overrun;
4092
4093 for (i = 0; i < n; ++i)
4094 {
4095 if (!s->row->full_width_p)
4096 {
4097 int overrun, leftoverrun;
4098
4099 /* truncate to avoid overwriting fringe and/or scrollbar */
4100 overrun = max (0, (s->x + s->background_width)
4101 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
4102 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
4103 r[i].size.width -= overrun;
4104
4105 /* truncate to avoid overwriting to left of the window box */
4106 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
4107 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
4108
4109 if (leftoverrun > 0)
4110 {
4111 r[i].origin.x += leftoverrun;
4112 r[i].size.width -= leftoverrun;
4113 }
4114 }
4115
4116 if (leftoverrun > 0)
4117 {
4118 r[i].origin.x += leftoverrun;
4119 r[i].size.width -= leftoverrun;
4120 }
4121
4122 /* XXX: Try to work between problem where a stretch glyph on
4123 a partially-visible bottom row will clear part of the
4124 modeline, and another where list-buffers headers and similar
4125 rows erroneously have visible_height set to 0. Not sure
4126 where this is coming from as other terms seem not to show. */
4127 r[i].size.height = min (s->height, s->row->visible_height);
4128 }
4129 4047
4130 [bgCol set]; 4048 [bgCol set];
4131 4049
4132 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid 4050 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
4133 overwriting cursor (usually when cursor on a tab) */ 4051 overwriting cursor (usually when cursor on a tab) */
4134 if (s->hl == DRAW_CURSOR) 4052 if (s->hl == DRAW_CURSOR)
4135 { 4053 {
4136 CGFloat x, width; 4054 CGFloat x, width;
4137 4055
4138 x = r[i].origin.x; 4056 /* FIXME: This looks like it will only work for left to
4139 width = s->w->phys_cursor_width; 4057 right languages. */
4140 r[i].size.width -= width; 4058 x = NSMinX (glyphRect);
4141 r[i].origin.x += width; 4059 width = s->w->phys_cursor_width;
4060 glyphRect.size.width -= width;
4061 glyphRect.origin.x += width;
4142 4062
4143 NSRectFill (r[i]); 4063 NSRectFill (glyphRect);
4144 4064
4145 /* Draw overlining, etc. on the cursor. */ 4065 /* Draw overlining, etc. on the cursor. */
4146 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) 4066 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4147 ns_draw_text_decoration (s, face, bgCol, width, x); 4067 ns_draw_text_decoration (s, face, bgCol, width, x);
4148 else
4149 ns_draw_text_decoration (s, face, fgCol, width, x);
4150 }
4151 else 4068 else
4152 { 4069 ns_draw_text_decoration (s, face, fgCol, width, x);
4153 NSRectFill (r[i]);
4154 }
4155
4156 /* Draw overlining, etc. on the stretch glyph (or the part
4157 of the stretch glyph after the cursor). */
4158 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
4159 r[i].origin.x);
4160 } 4070 }
4071 else
4072 {
4073 NSRectFill (glyphRect);
4074 }
4075
4076 /* Draw overlining, etc. on the stretch glyph (or the part
4077 of the stretch glyph after the cursor). */
4078 ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect),
4079 NSMinX (glyphRect));
4080
4161 ns_unfocus (s->f); 4081 ns_unfocus (s->f);
4162 s->background_filled_p = 1; 4082 s->background_filled_p = 1;
4163 } 4083 }
@@ -7184,6 +7104,7 @@ not_in_argv (NSString *arg)
7184 from non-native fullscreen, in other circumstances it appears 7104 from non-native fullscreen, in other circumstances it appears
7185 to be a noop. (bug#28872) */ 7105 to be a noop. (bug#28872) */
7186 wr = NSMakeRect (0, 0, neww, newh); 7106 wr = NSMakeRect (0, 0, neww, newh);
7107 [self createDrawingBufferWithRect:wr];
7187 [view setFrame: wr]; 7108 [view setFrame: wr];
7188 7109
7189 // To do: consider using [NSNotificationCenter postNotificationName:]. 7110 // To do: consider using [NSNotificationCenter postNotificationName:].
@@ -7523,6 +7444,8 @@ not_in_argv (NSString *arg)
7523 maximizing_resize = NO; 7444 maximizing_resize = NO;
7524#endif 7445#endif
7525 7446
7447 [self createDrawingBufferWithRect:r];
7448
7526 win = [[EmacsWindow alloc] 7449 win = [[EmacsWindow alloc]
7527 initWithContentRect: r 7450 initWithContentRect: r
7528 styleMask: (FRAME_UNDECORATED (f) 7451 styleMask: (FRAME_UNDECORATED (f)
@@ -8306,38 +8229,105 @@ not_in_argv (NSString *arg)
8306} 8229}
8307 8230
8308 8231
8309- (void)viewWillDraw 8232- (void)createDrawingBufferWithRect:(NSRect)rect
8233 /* Create and store a new NSBitmapImageRep for Emacs to draw
8234 into.
8235
8236 Drawing to an offscreen bitmap doesn't work in GNUstep as there's
8237 a bug in graphicsContextWithBitmapImageRep
8238 (https://savannah.gnu.org/bugs/?38405). So under GNUstep we
8239 retain the old method of drawing direct to the EmacsView. */
8310{ 8240{
8311 /* If the frame has been garbaged there's no point in redrawing 8241#ifdef NS_IMPL_COCOA
8312 anything. */ 8242 if (drawingBuffer != nil)
8313 if (FRAME_GARBAGED_P (emacsframe)) 8243 [drawingBuffer release];
8314 [self setNeedsDisplay:NO]; 8244
8245 drawingBuffer = [[self bitmapImageRepForCachingDisplayInRect:rect] retain];
8246#endif
8315} 8247}
8316 8248
8317- (void)drawRect: (NSRect)rect 8249
8250#ifdef NS_IMPL_COCOA
8251- (void)focusOnDrawingBuffer
8318{ 8252{
8319 int x = NSMinX (rect), y = NSMinY (rect); 8253 /* Creating the graphics context each time is very slow, but it
8320 int width = NSWidth (rect), height = NSHeight (rect); 8254 doesn't seem possible to cache and reuse it. */
8255 [NSGraphicsContext
8256 setCurrentContext:
8257 [NSGraphicsContext graphicsContextWithBitmapImageRep:drawingBuffer]];
8258}
8259
8260
8261- (void)windowDidChangeBackingProperties:(NSNotification *)notification
8262 /* Update the drawing buffer when the backing scale factor changes. */
8263{
8264 CGFloat old = [[[notification userInfo]
8265 objectForKey:@"NSBackingPropertyOldScaleFactorKey"]
8266 doubleValue];
8267 CGFloat new = [[self window] backingScaleFactor];
8268
8269 if (old != new)
8270 {
8271 NSRect frame = [self frame];
8272 [self createDrawingBufferWithRect:frame];
8273 ns_clear_frame (emacsframe);
8274 expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame));
8275 }
8276}
8277#endif
8278
8321 8279
8280- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect
8281{
8282 NSTRACE ("[EmacsView copyRect:To:]");
8283 NSTRACE_RECT ("Source", srcRect);
8284 NSTRACE_RECT ("Destination", dstRect);
8285
8286#ifdef NS_IMPL_COCOA
8287 [drawingBuffer drawInRect:dstRect
8288 fromRect:srcRect
8289 operation:NSCompositingOperationCopy
8290 fraction:1.0
8291 respectFlipped:NO
8292 hints:nil];
8293
8294 [self setNeedsDisplayInRect:dstRect];
8295#else
8296 hide_bell(); // Ensure the bell image isn't scrolled.
8297
8298 ns_focus (emacsframe, &dstRect, 1);
8299 [self scrollRect: srcRect
8300 by: NSMakeSize (dstRect.origin.x - srcRect.origin.x,
8301 dstRect.origin.y - srcRect.origin.y)];
8302 ns_unfocus (emacsframe);
8303#endif
8304}
8305
8306
8307- (void)drawRect: (NSRect)rect
8308{
8322 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]", 8309 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
8323 NSTRACE_ARG_RECT(rect)); 8310 NSTRACE_ARG_RECT(rect));
8324 8311
8325 if (!emacsframe || !emacsframe->output_data.ns) 8312 if (!emacsframe || !emacsframe->output_data.ns)
8326 return; 8313 return;
8327 8314
8315#ifdef NS_IMPL_COCOA
8316 [drawingBuffer drawInRect:rect
8317 fromRect:rect
8318 operation:NSCompositingOperationSourceOver
8319 fraction:1
8320 respectFlipped:NO
8321 hints:nil];
8322#else
8323 int x = NSMinX (rect), y = NSMinY (rect);
8324 int width = NSWidth (rect), height = NSHeight (rect);
8325
8328 ns_clear_frame_area (emacsframe, x, y, width, height); 8326 ns_clear_frame_area (emacsframe, x, y, width, height);
8329 block_input (); 8327 block_input ();
8330 expose_frame (emacsframe, x, y, width, height); 8328 expose_frame (emacsframe, x, y, width, height);
8331 unblock_input (); 8329 unblock_input ();
8332 8330#endif
8333 /*
8334 drawRect: may be called (at least in Mac OS X 10.5) for invisible
8335 views as well for some reason. Thus, do not infer visibility
8336 here.
8337
8338 emacsframe->async_visible = 1;
8339 emacsframe->async_iconified = 0;
8340 */
8341} 8331}
8342 8332
8343 8333