summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Third <address@hidden>2019-02-10 10:59:29 +0000
committerAlan Third <alan@idiocy.org>2019-12-30 11:22:17 +0000
commit53f3d1f9f41e291f50977bbcff1d43416972208e (patch)
tree302db920b0cc9f5bab9b18e55e6daffab9cb13e3
parentf01286675ad7ff520138ca2a42a9bf3a45740b54 (diff)
downloademacs-scratch/ns/draw-to-bitmap.tar.gz
Draw to offscreen buffer on macOSscratch/ns/draw-to-bitmap
* 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 3e835a71d03..4ae73de6754 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)
error ("Unknown color");
}
- /* Clear the frame; in some instances the NS-internal GC appears not
- to update, or it does update and cannot clear old text
- properly. */
- if (FRAME_VISIBLE_P (f))
- ns_clear_frame (f);
-
[col retain];
[f->output_data.ns->background_color release];
f->output_data.ns->background_color = col;
@@ -324,7 +318,10 @@ ns_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
}
if (FRAME_VISIBLE_P (f))
- SET_FRAME_GARBAGED (f);
+ {
+ SET_FRAME_GARBAGED (f);
+ ns_clear_frame (f);
+ }
}
unblock_input ();
}
diff --git a/src/nsterm.h b/src/nsterm.h
index 3803009afa6..e9394e184fd 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -417,6 +417,9 @@ typedef id instancetype;
int maximized_width, maximized_height;
NSWindow *nonfs_window;
BOOL fs_is_native;
+#ifdef NS_IMPL_COCOA
+ NSBitmapImageRep *drawingBuffer;
+#endif
@public
struct frame *emacsframe;
int rows, cols;
@@ -457,7 +460,13 @@ typedef id instancetype;
#endif
- (int)fullscreenState;
-/* Non-notification versions of NSView methods. Used for direct calls. */
+#ifdef NS_IMPL_COCOA
+- (void)focusOnDrawingBuffer;
+#endif
+- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect;
+- (void)createDrawingBufferWithRect:(NSRect)rect;
+
+/* Non-notification versions of NSView methods. Used for direct calls. */
- (void)windowWillEnterFullScreen;
- (void)windowDidEnterFullScreen;
- (void)windowWillExitFullScreen;
diff --git a/src/nsterm.m b/src/nsterm.m
index 2d76a260d8d..e643707394b 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -290,9 +290,6 @@ long context_menu_value = 0;
static struct frame *ns_updating_frame;
static NSView *focus_view = NULL;
static int ns_window_num = 0;
-#ifdef NS_IMPL_GNUSTEP
-static NSRect uRect; // TODO: This is dead, remove it?
-#endif
static BOOL gsaved = NO;
static BOOL ns_fake_keydown = NO;
#ifdef NS_IMPL_COCOA
@@ -1120,33 +1117,10 @@ ns_update_begin (struct frame *f)
#endif
ns_updating_frame = f;
- [view lockFocus];
-
- /* drawRect may have been called for say the minibuffer, and then clip path
- is for the minibuffer. But the display engine may draw more because
- we have set the frame as garbaged. So reset clip path to the whole
- view. */
#ifdef NS_IMPL_COCOA
- {
- NSBezierPath *bp;
- NSRect r = [view frame];
- NSRect cr = [[view window] frame];
- /* If a large frame size is set, r may be larger than the window frame
- before constrained. In that case don't change the clip path, as we
- will clear in to the tool bar and title bar. */
- if (r.size.height
- + FRAME_NS_TITLEBAR_HEIGHT (f)
- + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
- {
- bp = [[NSBezierPath bezierPathWithRect: r] retain];
- [bp setClip];
- [bp release];
- }
- }
-#endif
-
-#ifdef NS_IMPL_GNUSTEP
- uRect = NSMakeRect (0, 0, 0, 0);
+ [view focusOnDrawingBuffer];
+#else
+ [view lockFocus];
#endif
}
@@ -1165,12 +1139,17 @@ ns_update_end (struct frame *f)
/* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
MOUSE_HL_INFO (f)->mouse_face_defer = 0;
+#ifdef NS_IMPL_COCOA
+ [NSGraphicsContext setCurrentContext:nil];
+ [view display];
+#else
block_input ();
[view unlockFocus];
[[view window] flushWindow];
unblock_input ();
+#endif
ns_updating_frame = NULL;
}
@@ -1185,6 +1164,8 @@ ns_focus (struct frame *f, NSRect *r, int n)
the entire window.
-------------------------------------------------------------------------- */
{
+ EmacsView *view = FRAME_NS_VIEW (f);
+
NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
if (r != NULL)
{
@@ -1192,27 +1173,34 @@ ns_focus (struct frame *f, NSRect *r, int n)
}
if (f != ns_updating_frame)
+#ifdef NS_IMPL_COCOA
+ [view focusOnDrawingBuffer];
+#else
{
- NSView *view = FRAME_NS_VIEW (f);
if (view != focus_view)
{
if (focus_view != NULL)
{
[focus_view unlockFocus];
[[focus_view window] flushWindow];
-/*debug_lock--; */
}
if (view)
[view lockFocus];
focus_view = view;
-/*if (view) debug_lock++; */
}
}
+#endif
/* clipping */
if (r)
{
+#ifdef NS_IMPL_COCOA
+ int i;
+ for (i = 0 ; i < n ; i++)
+ [view setNeedsDisplayInRect:r[i]];
+#endif
+
[[NSGraphicsContext currentContext] saveGraphicsState];
if (n == 2)
NSRectClipList (r, 2);
@@ -1237,6 +1225,7 @@ ns_unfocus (struct frame *f)
gsaved = NO;
}
+#ifdef NS_IMPL_GNUSTEP
if (f != ns_updating_frame)
{
if (focus_view != NULL)
@@ -1244,9 +1233,9 @@ ns_unfocus (struct frame *f)
[focus_view unlockFocus];
[[focus_view window] flushWindow];
focus_view = NULL;
-/*debug_lock--; */
}
}
+#endif
}
@@ -1258,16 +1247,7 @@ ns_clip_to_row (struct window *w, struct glyph_row *row,
-------------------------------------------------------------------------- */
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
- NSRect clip_rect;
- int window_x, window_y, window_width;
-
- window_box (w, area, &window_x, &window_y, &window_width, 0);
-
- clip_rect.origin.x = window_x;
- clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
- clip_rect.origin.y = max (clip_rect.origin.y, window_y);
- clip_rect.size.width = window_width;
- clip_rect.size.height = row->visible_height;
+ NSRect clip_rect = ns_row_rect (w, row, area);
ns_focus (f, &clip_rect, 1);
}
@@ -2911,22 +2891,6 @@ ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
return;
}
-static void
-ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
-{
- NSTRACE ("ns_copy_bits");
-
- if (FRAME_NS_VIEW (f))
- {
- hide_bell(); // Ensure the bell image isn't scrolled.
-
- ns_focus (f, &dest, 1);
- [FRAME_NS_VIEW (f) scrollRect: src
- by: NSMakeSize (dest.origin.x - src.origin.x,
- dest.origin.y - src.origin.y)];
- ns_unfocus (f);
- }
-}
static void
ns_scroll_run (struct window *w, struct run *run)
@@ -2979,8 +2943,12 @@ ns_scroll_run (struct window *w, struct run *run)
{
NSRect srcRect = NSMakeRect (x, from_y, width, height);
NSRect dstRect = NSMakeRect (x, to_y, width, height);
+ EmacsView *view = FRAME_NS_VIEW (f);
- ns_copy_bits (f, srcRect , dstRect);
+ [view copyRect:srcRect to:dstRect];
+#ifdef NS_IMPL_COCOA
+ [view setNeedsDisplayInRect:srcRect];
+#endif
}
unblock_input ();
@@ -3034,20 +3002,12 @@ ns_shift_glyphs_for_insert (struct frame *f,
External (RIF): copy an area horizontally, don't worry about clearing src
-------------------------------------------------------------------------- */
{
- //NSRect srcRect = NSMakeRect (x, y, width, height);
+ NSRect srcRect = NSMakeRect (x, y, width, height);
NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
NSTRACE ("ns_shift_glyphs_for_insert");
- /* This doesn't work now as we copy the "bits" before we've had a
- chance to actually draw any changes to the screen. This means in
- certain circumstances we end up with copies of the cursor all
- over the place. Just mark the area dirty so it is redrawn later.
-
- FIXME: Work out how to do this properly. */
- // ns_copy_bits (f, srcRect, dstRect);
-
- [FRAME_NS_VIEW (f) setNeedsDisplayInRect:dstRect];
+ [FRAME_NS_VIEW (f) copyRect:srcRect to:dstRect];
}
@@ -3167,20 +3127,18 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
/* The visible portion of imageRect will always be contained within
clearRect. */
- if (ns_clip_to_rect (f, &clearRect, 1))
+ ns_focus (f, &clearRect, 1);
+ if (! NSIsEmptyRect (clearRect))
{
- if (! NSIsEmptyRect (clearRect))
- {
- NSTRACE_RECT ("clearRect", clearRect);
+ NSTRACE_RECT ("clearRect", clearRect);
- [ns_lookup_indexed_color(face->background, f) set];
- NSRectFill (clearRect);
- }
+ [ns_lookup_indexed_color(face->background, f) set];
+ NSRectFill (clearRect);
}
- if (p->which)
- {
- EmacsImage *img = bimgs[p->which - 1];
+ if (p->which)
+ {
+ EmacsImage *img = bimgs[p->which - 1];
if (!img)
{
@@ -3213,20 +3171,30 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
[img setXBMColor: bm_color];
}
- // Note: For periodic images, the full image height is "h + hd".
- // By using the height h, a suitable part of the image is used.
- NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
+ // Note: For periodic images, the full image height is "h + hd".
+ // By using the height h, a suitable part of the image is used.
+ NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
- NSTRACE_RECT ("fromRect", fromRect);
+ NSTRACE_RECT ("fromRect", fromRect);
- [img drawInRect: imageRect
- fromRect: fromRect
- operation: NSCompositingOperationSourceOver
- fraction: 1.0
- respectFlipped: YES
- hints: nil];
- }
- ns_reset_clipping (f);
+ /* Because we're drawing into an offscreen buffer which isn't
+ flipped, the images come out upside down. To work around it
+ we need to do some fancy transforms. */
+ {
+ NSAffineTransform *transform = [NSAffineTransform transform];
+ [transform translateXBy:0 yBy:NSMaxY(imageRect)];
+ [transform scaleXBy:1 yBy:-1];
+ [transform concat];
+
+ imageRect.origin.y = 0;
+ }
+
+ [img drawInRect: imageRect
+ fromRect: fromRect
+ operation: NSCompositingOperationSourceOver
+ fraction: 1.0
+ respectFlipped: YES
+ hints: nil];
}
ns_unfocus (f);
}
@@ -3323,54 +3291,42 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
else
[FRAME_CURSOR_COLOR (f) set];
-#ifdef NS_IMPL_COCOA
- /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
- atomic. Cleaner ways of doing this should be investigated.
- One way would be to set a global variable DRAWING_CURSOR
- when making the call to draw_phys..(), don't focus in that
- case, then move the ns_unfocus() here after that call. */
- NSDisableScreenUpdates ();
-#endif
-
- switch (cursor_type)
- {
- case DEFAULT_CURSOR:
- case NO_CURSOR:
- break;
- case FILLED_BOX_CURSOR:
- NSRectFill (r);
- break;
- case HOLLOW_BOX_CURSOR:
- NSRectFill (r);
- [hollow_color set];
- NSRectFill (NSInsetRect (r, 1, 1));
- [FRAME_CURSOR_COLOR (f) set];
- break;
- case HBAR_CURSOR:
- NSRectFill (r);
- break;
- case BAR_CURSOR:
- s = r;
- /* If the character under cursor is R2L, draw the bar cursor
- on the right of its glyph, rather than on the left. */
- cursor_glyph = get_phys_cursor_glyph (w);
- if ((cursor_glyph->resolved_level & 1) != 0)
- s.origin.x += cursor_glyph->pixel_width - s.size.width;
-
- NSRectFill (s);
- break;
- }
- ns_unfocus (f);
+ ns_focus (f, &r, 1);
- /* Draw the character under the cursor. Other terms only draw
- the character on top of box cursors, so do the same here. */
- if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR)
- draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+ switch (cursor_type)
+ {
+ case DEFAULT_CURSOR:
+ case NO_CURSOR:
+ break;
+ case FILLED_BOX_CURSOR:
+ NSRectFill (r);
+ break;
+ case HOLLOW_BOX_CURSOR:
+ NSRectFill (r);
+ [hollow_color set];
+ NSRectFill (NSInsetRect (r, 1, 1));
+ [FRAME_CURSOR_COLOR (f) set];
+ break;
+ case HBAR_CURSOR:
+ NSRectFill (r);
+ break;
+ case BAR_CURSOR:
+ s = r;
+ /* If the character under cursor is R2L, draw the bar cursor
+ on the right of its glyph, rather than on the left. */
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if ((cursor_glyph->resolved_level & 1) != 0)
+ s.origin.x += cursor_glyph->pixel_width - s.size.width;
-#ifdef NS_IMPL_COCOA
- NSEnableScreenUpdates ();
-#endif
+ NSRectFill (s);
+ break;
+ }
+ ns_unfocus (f);
+ /* Draw the character under the cursor. Other terms only draw
+ the character on top of box cursors, so do the same here. */
+ if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR)
+ draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
}
@@ -3455,6 +3411,7 @@ ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
ns_unfocus (f);
}
+
static void
ns_show_hourglass (struct frame *f)
{
@@ -3978,15 +3935,27 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
[[NSGraphicsContext currentContext] saveGraphicsState];
- /* Because of the transforms it's far too difficult to work out
- what portion of the original, untransformed, image will be
- drawn, so the clipping area will ensure we draw only the
- correct bit. */
+ /* Because of the transforms it's difficult to work out what
+ portion of the original, untransformed, image will be drawn,
+ so the clipping area will ensure we draw only the correct
+ bit. */
NSRectClip (dr);
[setOrigin translateXBy:x - s->slice.x yBy:y - s->slice.y];
[setOrigin concat];
- [img->transform concat];
+
+ NSAffineTransform *doTransform = [NSAffineTransform transform];
+
+ /* We have to flip the image around the X axis as the offscreen
+ bitmap we're drawing to is flipped. */
+ [doTransform scaleXBy:1 yBy:-1];
+ [doTransform translateXBy:0 yBy:-[img size].height];
+
+ /* ImageMagick images don't have transforms. */
+ if (img->transform)
+ [doTransform appendTransform:img->transform];
+
+ [doTransform concat];
[img drawInRect:ir fromRect:ir
operation:NSCompositingOperationSourceOver
@@ -4059,6 +4028,7 @@ static void
ns_dumpglyphs_stretch (struct glyph_string *s)
{
NSRect r[2];
+ NSRect glyphRect;
int n, i;
struct face *face;
NSColor *fgCol, *bgCol;
@@ -4066,106 +4036,56 @@ ns_dumpglyphs_stretch (struct glyph_string *s)
if (!s->background_filled_p)
{
n = ns_get_glyph_string_clip_rect (s, r);
-
ns_focus (s->f, r, n);
if (s->hl == DRAW_MOUSE_FACE)
- {
- face = FACE_FROM_ID_OR_NULL (s->f,
- MOUSE_HL_INFO (s->f)->mouse_face_face_id);
- if (!face)
- face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
- }
+ {
+ face = FACE_FROM_ID_OR_NULL (s->f,
+ MOUSE_HL_INFO (s->f)->mouse_face_face_id);
+ if (!face)
+ face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+ }
else
- face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+ face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
- for (i = 0; i < n; ++i)
- {
- /* FIXME: Why are we reusing the clipping rectangles? The
- other terms don't appear to do anything like this. */
- *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
-
- if (s->hl == DRAW_MOUSE_FACE)
- {
- int overrun, leftoverrun;
-
- /* truncate to avoid overwriting fringe and/or scrollbar */
- overrun = max (0, (s->x + s->background_width)
- - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
- - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
- r[i].size.width -= overrun;
-
- for (i = 0; i < n; ++i)
- {
- if (!s->row->full_width_p)
- {
- int overrun, leftoverrun;
-
- /* truncate to avoid overwriting fringe and/or scrollbar */
- overrun = max (0, (s->x + s->background_width)
- - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
- - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
- r[i].size.width -= overrun;
-
- /* truncate to avoid overwriting to left of the window box */
- leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
- + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
-
- if (leftoverrun > 0)
- {
- r[i].origin.x += leftoverrun;
- r[i].size.width -= leftoverrun;
- }
- }
-
- if (leftoverrun > 0)
- {
- r[i].origin.x += leftoverrun;
- r[i].size.width -= leftoverrun;
- }
-
- /* XXX: Try to work between problem where a stretch glyph on
- a partially-visible bottom row will clear part of the
- modeline, and another where list-buffers headers and similar
- rows erroneously have visible_height set to 0. Not sure
- where this is coming from as other terms seem not to show. */
- r[i].size.height = min (s->height, s->row->visible_height);
- }
+ glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height);
- [bgCol set];
+ [bgCol set];
- /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
- overwriting cursor (usually when cursor on a tab) */
- if (s->hl == DRAW_CURSOR)
- {
- CGFloat x, width;
+ /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
+ overwriting cursor (usually when cursor on a tab) */
+ if (s->hl == DRAW_CURSOR)
+ {
+ CGFloat x, width;
- x = r[i].origin.x;
- width = s->w->phys_cursor_width;
- r[i].size.width -= width;
- r[i].origin.x += width;
+ /* FIXME: This looks like it will only work for left to
+ right languages. */
+ x = NSMinX (glyphRect);
+ width = s->w->phys_cursor_width;
+ glyphRect.size.width -= width;
+ glyphRect.origin.x += width;
- NSRectFill (r[i]);
+ NSRectFill (glyphRect);
- /* Draw overlining, etc. on the cursor. */
- if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
- ns_draw_text_decoration (s, face, bgCol, width, x);
- else
- ns_draw_text_decoration (s, face, fgCol, width, x);
- }
+ /* Draw overlining, etc. on the cursor. */
+ if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
+ ns_draw_text_decoration (s, face, bgCol, width, x);
else
- {
- NSRectFill (r[i]);
- }
-
- /* Draw overlining, etc. on the stretch glyph (or the part
- of the stretch glyph after the cursor). */
- ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
- r[i].origin.x);
+ ns_draw_text_decoration (s, face, fgCol, width, x);
}
+ else
+ {
+ NSRectFill (glyphRect);
+ }
+
+ /* Draw overlining, etc. on the stretch glyph (or the part
+ of the stretch glyph after the cursor). */
+ ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect),
+ NSMinX (glyphRect));
+
ns_unfocus (s->f);
s->background_filled_p = 1;
}
@@ -7192,6 +7112,7 @@ not_in_argv (NSString *arg)
from non-native fullscreen, in other circumstances it appears
to be a noop. (bug#28872) */
wr = NSMakeRect (0, 0, neww, newh);
+ [self createDrawingBufferWithRect:wr];
[view setFrame: wr];
// To do: consider using [NSNotificationCenter postNotificationName:].
@@ -7531,6 +7452,8 @@ not_in_argv (NSString *arg)
maximizing_resize = NO;
#endif
+ [self createDrawingBufferWithRect:r];
+
win = [[EmacsWindow alloc]
initWithContentRect: r
styleMask: (FRAME_UNDECORATED (f)
@@ -8322,38 +8245,105 @@ not_in_argv (NSString *arg)
}
-- (void)viewWillDraw
+- (void)createDrawingBufferWithRect:(NSRect)rect
+ /* Create and store a new NSBitmapImageRep for Emacs to draw
+ into.
+
+ Drawing to an offscreen bitmap doesn't work in GNUstep as there's
+ a bug in graphicsContextWithBitmapImageRep
+ (https://savannah.gnu.org/bugs/?38405). So under GNUstep we
+ retain the old method of drawing direct to the EmacsView. */
{
- /* If the frame has been garbaged there's no point in redrawing
- anything. */
- if (FRAME_GARBAGED_P (emacsframe))
- [self setNeedsDisplay:NO];
+#ifdef NS_IMPL_COCOA
+ if (drawingBuffer != nil)
+ [drawingBuffer release];
+
+ drawingBuffer = [[self bitmapImageRepForCachingDisplayInRect:rect] retain];
+#endif
}
-- (void)drawRect: (NSRect)rect
+
+#ifdef NS_IMPL_COCOA
+- (void)focusOnDrawingBuffer
{
- int x = NSMinX (rect), y = NSMinY (rect);
- int width = NSWidth (rect), height = NSHeight (rect);
+ /* Creating the graphics context each time is very slow, but it
+ doesn't seem possible to cache and reuse it. */
+ [NSGraphicsContext
+ setCurrentContext:
+ [NSGraphicsContext graphicsContextWithBitmapImageRep:drawingBuffer]];
+}
+
+
+- (void)windowDidChangeBackingProperties:(NSNotification *)notification
+ /* Update the drawing buffer when the backing scale factor changes. */
+{
+ CGFloat old = [[[notification userInfo]
+ objectForKey:@"NSBackingPropertyOldScaleFactorKey"]
+ doubleValue];
+ CGFloat new = [[self window] backingScaleFactor];
+
+ if (old != new)
+ {
+ NSRect frame = [self frame];
+ [self createDrawingBufferWithRect:frame];
+ ns_clear_frame (emacsframe);
+ expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame));
+ }
+}
+#endif
+
+- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect
+{
+ NSTRACE ("[EmacsView copyRect:To:]");
+ NSTRACE_RECT ("Source", srcRect);
+ NSTRACE_RECT ("Destination", dstRect);
+
+#ifdef NS_IMPL_COCOA
+ [drawingBuffer drawInRect:dstRect
+ fromRect:srcRect
+ operation:NSCompositingOperationCopy
+ fraction:1.0
+ respectFlipped:NO
+ hints:nil];
+
+ [self setNeedsDisplayInRect:dstRect];
+#else
+ hide_bell(); // Ensure the bell image isn't scrolled.
+
+ ns_focus (emacsframe, &dstRect, 1);
+ [self scrollRect: srcRect
+ by: NSMakeSize (dstRect.origin.x - srcRect.origin.x,
+ dstRect.origin.y - srcRect.origin.y)];
+ ns_unfocus (emacsframe);
+#endif
+}
+
+
+- (void)drawRect: (NSRect)rect
+{
NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
NSTRACE_ARG_RECT(rect));
if (!emacsframe || !emacsframe->output_data.ns)
return;
+#ifdef NS_IMPL_COCOA
+ [drawingBuffer drawInRect:rect
+ fromRect:rect
+ operation:NSCompositingOperationSourceOver
+ fraction:1
+ respectFlipped:NO
+ hints:nil];
+#else
+ int x = NSMinX (rect), y = NSMinY (rect);
+ int width = NSWidth (rect), height = NSHeight (rect);
+
ns_clear_frame_area (emacsframe, x, y, width, height);
block_input ();
expose_frame (emacsframe, x, y, width, height);
unblock_input ();
-
- /*
- drawRect: may be called (at least in Mac OS X 10.5) for invisible
- views as well for some reason. Thus, do not infer visibility
- here.
-
- emacsframe->async_visible = 1;
- emacsframe->async_iconified = 0;
- */
+#endif
}