From: Alan Third <alan@idiocy.org>
To: Robert Pluim <rpluim@gmail.com>
Cc: emacs-devel@gnu.org
Subject: Re: Some NS port changes
Date: Mon, 11 Feb 2019 22:14:04 +0000 [thread overview]
Message-ID: <20190211221404.GA24399@breton.holly.idiocy.org> (raw)
In-Reply-To: <m25ztqlhf7.fsf@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 549 bytes --]
On Mon, Feb 11, 2019 at 11:59:24AM +0100, Robert Pluim wrote:
>
> I just tried this against emacs-26, and the resulting emacs is not
> functional: the display doesnʼt update, the minibuffer doesnʼt
> show. This is on Mojave (10.14.3)
Thanks for trying it. I don’t know why I expect anything to work right
any more.
Please try the attached. I don’t think the performance is terribly
good. I was caching the graphics context as recreating it appears to
be an expensive operation, but it looks like Mojave doesn’t like that.
--
Alan Third
[-- Attachment #2: offscreen-buffer.mbox --]
[-- Type: text/plain, Size: 58644 bytes --]
From d0d919061c71bd22f9e6193e68b8632e88598d18 Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Sat, 9 Feb 2019 08:57:02 +0000
Subject: [PATCH 1/4] Revert "Fix some NS drawing issues (bug#32932)"
This reverts commit 7e8eee60a9dbb0c59cf26f237b21efe7fd1043c9.
---
src/nsterm.m | 46 +++++++++++++++++++++++++---------------------
1 file changed, 25 insertions(+), 21 deletions(-)
diff --git a/src/nsterm.m b/src/nsterm.m
index bbd2c84214..0cf16642bd 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -277,6 +277,7 @@ - (NSColor *)colorUsingDefaultColorSpace
/* display update */
static int ns_window_num = 0;
+static BOOL gsaved = NO;
static BOOL ns_fake_keydown = NO;
#ifdef NS_IMPL_COCOA
static BOOL ns_menu_bar_is_hidden = NO;
@@ -1177,6 +1178,7 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
NSRectClipList (r, 2);
else
NSRectClip (*r);
+ gsaved = YES;
return YES;
}
@@ -1200,7 +1202,11 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
{
NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_reset_clipping");
- [[NSGraphicsContext currentContext] restoreGraphicsState];
+ if (gsaved)
+ {
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+ gsaved = NO;
+ }
}
@@ -2667,8 +2673,6 @@ so some key presses (TAB) are swallowed by the system. */
static void
ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
{
- NSSize delta = NSMakeSize (dest.origin.x - src.origin.x,
- dest.origin.y - src.origin.y);
NSTRACE ("ns_copy_bits");
if (FRAME_NS_VIEW (f))
@@ -2677,21 +2681,10 @@ so some key presses (TAB) are swallowed by the system. */
/* FIXME: scrollRect:by: is deprecated in macOS 10.14. There is
no obvious replacement so we may have to come up with our own. */
- [FRAME_NS_VIEW (f) scrollRect: src by: delta];
-
-#ifdef NS_IMPL_COCOA
- /* As far as I can tell from the documentation, scrollRect:by:,
- above, should copy the dirty rectangles from our source
- rectangle to our destination, however it appears it clips the
- operation to src. As a result we need to use
- translateRectsNeedingDisplayInRect:by: below, and we have to
- union src and dest so it can pick up the dirty rectangles,
- and place them, as it also clips to the rectangle.
-
- FIXME: We need a GNUstep equivalent. */
- [FRAME_NS_VIEW (f) translateRectsNeedingDisplayInRect:NSUnionRect (src, dest)
- by:delta];
-#endif
+ [FRAME_NS_VIEW (f) scrollRect: src
+ by: NSMakeSize (dest.origin.x - src.origin.x,
+ dest.origin.y - src.origin.y)];
+ [FRAME_NS_VIEW (f) setNeedsDisplay:YES];
}
}
@@ -3097,6 +3090,15 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
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_reset_clipping() here after that call. */
+ NSDisableScreenUpdates ();
+#endif
+
switch (cursor_type)
{
case DEFAULT_CURSOR:
@@ -4962,7 +4964,7 @@ static Lisp_Object ns_string_to_lispmod (const char *s)
ns_after_update_window_line,
ns_update_window_begin,
ns_update_window_end,
- 0, /* flush_display */
+ ns_flush_display, /* flush_display */
x_clear_window_mouse_face,
x_get_glyph_overhangs,
x_fix_overlapping_area,
@@ -7031,6 +7033,7 @@ - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
size_title = xmalloc (strlen (old_title) + 40);
esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
[window setTitle: [NSString stringWithUTF8String: size_title]];
+ [window display];
xfree (size_title);
}
}
@@ -8087,8 +8090,8 @@ - (void)viewWillDraw
- (void)drawRect: (NSRect)rect
{
- const NSRect *rectList;
- NSInteger numRects;
+ int x = NSMinX (rect), y = NSMinY (rect);
+ int width = NSWidth (rect), height = NSHeight (rect);
NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
NSTRACE_ARG_RECT(rect));
@@ -8096,6 +8099,7 @@ - (void)drawRect: (NSRect)rect
if (!emacsframe || !emacsframe->output_data.ns)
return;
+ ns_clear_frame_area (emacsframe, x, y, width, height);
block_input ();
/* Get only the precise dirty rectangles to avoid redrawing
--
2.20.1
From 537188acb6f90c06e62acbb46be55429efa71209 Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Sat, 9 Feb 2019 08:57:22 +0000
Subject: [PATCH 2/4] Revert "Ensure NS frame is redrawn correctly after
scroll"
This reverts commit a6ab8db3a3dc5ec107ef023c6659620584309c97.
---
src/nsterm.m | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/nsterm.m b/src/nsterm.m
index 0cf16642bd..dd8755065b 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2684,7 +2684,6 @@ so some key presses (TAB) are swallowed by the system. */
[FRAME_NS_VIEW (f) scrollRect: src
by: NSMakeSize (dest.origin.x - src.origin.x,
dest.origin.y - src.origin.y)];
- [FRAME_NS_VIEW (f) setNeedsDisplay:YES];
}
}
--
2.20.1
From db3a84ed1dd9172afacadfc9e457add944beb207 Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Sat, 9 Feb 2019 09:01:07 +0000
Subject: [PATCH 3/4] Revert "Make all NS drawing be done from drawRect"
This reverts commit 7946445962372c4255180af45cb7c857f1b0b5fa.
---
src/nsterm.m | 792 +++++++++++++++++++++++++++------------------------
1 file changed, 418 insertions(+), 374 deletions(-)
diff --git a/src/nsterm.m b/src/nsterm.m
index dd8755065b..6529a50298 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -276,7 +276,12 @@ - (NSColor *)colorUsingDefaultColorSpace
long context_menu_value = 0;
/* display update */
+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
@@ -1055,13 +1060,12 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
external (RIF) call; whole frame, called before update_window_begin
-------------------------------------------------------------------------- */
{
-#ifdef NS_IMPL_COCOA
EmacsView *view = FRAME_NS_VIEW (f);
-
NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
ns_update_auto_hide_menu_bar ();
+#ifdef NS_IMPL_COCOA
if ([view isFullscreen] && [view fsIsNative])
{
// Fix reappearing tool bar in fullscreen for Mac OS X 10.7
@@ -1071,6 +1075,36 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
[toolbar setVisible: tbar_visible];
}
#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);
+#endif
}
@@ -1151,62 +1185,118 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
external (RIF) call; for whole frame, called after update_window_end
-------------------------------------------------------------------------- */
{
+ EmacsView *view = FRAME_NS_VIEW (f);
+
NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
/* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
MOUSE_HL_INFO (f)->mouse_face_defer = 0;
-}
+ block_input ();
-static BOOL
-ns_clip_to_rect (struct frame *f, NSRect *r, int n)
+ [view unlockFocus];
+ [[view window] flushWindow];
+
+ unblock_input ();
+ ns_updating_frame = NULL;
+}
+
+static void
+ns_focus (struct frame *f, NSRect *r, int n)
/* --------------------------------------------------------------------------
- Clip the drawing area to rectangle r in frame f. If drawing is not
- currently possible mark r as dirty and return NO, otherwise return
- YES.
+ Internal: Focus on given frame. During small local updates this is used to
+ draw, however during large updates, ns_update_begin and ns_update_end are
+ called to wrap the whole thing, in which case these calls are stubbed out.
+ Except, on GNUstep, we accumulate the rectangle being drawn into, because
+ the back end won't do this automatically, and will just end up flushing
+ the entire window.
-------------------------------------------------------------------------- */
{
- NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_clip_to_rect");
- if (r)
+ NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
+ if (r != NULL)
{
NSTRACE_RECT ("r", *r);
+ }
- if ([NSView focusView] == FRAME_NS_VIEW (f))
+ if (f != ns_updating_frame)
+ {
+ NSView *view = FRAME_NS_VIEW (f);
+ if (view != focus_view)
{
- [[NSGraphicsContext currentContext] saveGraphicsState];
- if (n == 2)
- NSRectClipList (r, 2);
- else
- NSRectClip (*r);
- gsaved = YES;
+ if (focus_view != NULL)
+ {
+ [focus_view unlockFocus];
+ [[focus_view window] flushWindow];
+/*debug_lock--; */
+ }
- return YES;
- }
- else
- {
- NSView *view = FRAME_NS_VIEW (f);
- int i;
- for (i = 0 ; i < n ; i++)
- [view setNeedsDisplayInRect:r[i]];
+ if (view)
+ [view lockFocus];
+ focus_view = view;
+/*if (view) debug_lock++; */
}
}
- return NO;
+ /* clipping */
+ if (r)
+ {
+ [[NSGraphicsContext currentContext] saveGraphicsState];
+ if (n == 2)
+ NSRectClipList (r, 2);
+ else
+ NSRectClip (*r);
+ gsaved = YES;
+ }
}
static void
-ns_reset_clipping (struct frame *f)
-/* Internal: Restore the previous graphics state, unsetting any
- clipping areas. */
+ns_unfocus (struct frame *f)
+/* --------------------------------------------------------------------------
+ Internal: Remove focus on given frame
+ -------------------------------------------------------------------------- */
{
- NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_reset_clipping");
+ NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
if (gsaved)
{
[[NSGraphicsContext currentContext] restoreGraphicsState];
gsaved = NO;
}
+
+ if (f != ns_updating_frame)
+ {
+ if (focus_view != NULL)
+ {
+ [focus_view unlockFocus];
+ [[focus_view window] flushWindow];
+ focus_view = NULL;
+/*debug_lock--; */
+ }
+ }
+}
+
+
+static void
+ns_clip_to_row (struct window *w, struct glyph_row *row,
+ enum glyph_row_area area, BOOL gc)
+/* --------------------------------------------------------------------------
+ Internal (but parallels other terms): Focus drawing on given 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;
+
+ ns_focus (f, &clip_rect, 1);
}
@@ -2630,16 +2720,14 @@ so some key presses (TAB) are swallowed by the system. */
r = [view bounds];
block_input ();
- if (ns_clip_to_rect (f, &r, 1))
- {
- [ns_lookup_indexed_color (NS_FACE_BACKGROUND
- (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
- NSRectFill (r);
- ns_reset_clipping (f);
-
- /* as of 2006/11 or so this is now needed */
- ns_redraw_scroll_bars (f);
- }
+ ns_focus (f, &r, 1);
+ [ns_lookup_indexed_color (NS_FACE_BACKGROUND
+ (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
+ NSRectFill (r);
+ ns_unfocus (f);
+
+ /* as of 2006/11 or so this is now needed */
+ ns_redraw_scroll_bars (f);
unblock_input ();
}
@@ -2660,14 +2748,13 @@ so some key presses (TAB) are swallowed by the system. */
NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
r = NSIntersectionRect (r, [view frame]);
- if (ns_clip_to_rect (f, &r, 1))
- {
- [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
+ ns_focus (f, &r, 1);
+ [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
- NSRectFill (r);
+ NSRectFill (r);
- ns_reset_clipping (f);
- }
+ ns_unfocus (f);
+ return;
}
static void
@@ -2679,11 +2766,11 @@ so some key presses (TAB) are swallowed by the system. */
{
hide_bell(); // Ensure the bell image isn't scrolled.
- /* FIXME: scrollRect:by: is deprecated in macOS 10.14. There is
- no obvious replacement so we may have to come up with our own. */
+ 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);
}
}
@@ -2904,95 +2991,86 @@ so some key presses (TAB) are swallowed by the system. */
nBimgs = max_used_fringe_bitmap;
}
- /* Work out the rectangle we will composite into. */
- if (p->which)
- imageRect = NSMakeRect (p->x, p->y, p->wd, p->h);
+ /* Must clip because of partially visible lines. */
+ ns_clip_to_row (w, row, ANY_AREA, YES);
- /* Work out the rectangle we will need to clear. Because we're
- compositing rather than blitting, we need to clear the area under
- the image regardless of anything else. */
- if (p->bx >= 0 && !p->overlay_p)
+ if (!p->overlay_p)
{
- clearRect = NSMakeRect (p->bx, p->by, p->nx, p->ny);
- clearRect = NSUnionRect (clearRect, imageRect);
- }
- else
- {
- clearRect = imageRect;
- }
+ int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
- /* Handle partially visible rows. */
- clearRect = NSIntersectionRect (clearRect, rowRect);
-
- /* The visible portion of imageRect will always be contained within
- clearRect. */
- if (ns_clip_to_rect (f, &clearRect, 1))
- {
- if (! NSIsEmptyRect (clearRect))
+ if (bx >= 0 && nx > 0)
{
- NSTRACE_RECT ("clearRect", clearRect);
-
- [ns_lookup_indexed_color(face->background, f) set];
- NSRectFill (clearRect);
+ NSRect r = NSMakeRect (bx, by, nx, ny);
+ NSRectClip (r);
+ [ns_lookup_indexed_color (face->background, f) set];
+ NSRectFill (r);
}
+ }
- if (p->which)
+ if (p->which)
+ {
+ NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
+ EmacsImage *img = bimgs[p->which - 1];
+
+ if (!img)
{
- EmacsImage *img = bimgs[p->which - 1];
+ // Note: For "periodic" images, allocate one EmacsImage for
+ // the base image, and use it for all dh:s.
+ unsigned short *bits = p->bits;
+ int full_height = p->h + p->dh;
+ int i;
+ unsigned char *cbits = xmalloc (full_height);
+
+ for (i = 0; i < full_height; i++)
+ cbits[i] = bits[i];
+ img = [[EmacsImage alloc] initFromXBM: cbits width: 8
+ height: full_height
+ fg: 0 bg: 0];
+ bimgs[p->which - 1] = img;
+ xfree (cbits);
+ }
- if (!img)
- {
- // Note: For "periodic" images, allocate one EmacsImage for
- // the base image, and use it for all dh:s.
- unsigned short *bits = p->bits;
- int full_height = p->h + p->dh;
- int i;
- unsigned char *cbits = xmalloc (full_height);
-
- for (i = 0; i < full_height; i++)
- cbits[i] = bits[i];
- img = [[EmacsImage alloc] initFromXBM: cbits width: 8
- height: full_height
- fg: 0 bg: 0];
- bimgs[p->which - 1] = img;
- xfree (cbits);
- }
+ NSTRACE_RECT ("r", r);
+ NSRectClip (r);
+ /* Since we composite the bitmap instead of just blitting it, we need
+ to erase the whole background. */
+ [ns_lookup_indexed_color(face->background, f) set];
+ NSRectFill (r);
- {
- NSColor *bm_color;
- if (!p->cursor_p)
- bm_color = ns_lookup_indexed_color(face->foreground, f);
- else if (p->overlay_p)
- bm_color = ns_lookup_indexed_color(face->background, f);
- else
- bm_color = f->output_data.ns->cursor_color;
- [img setXBMColor: bm_color];
- }
+ {
+ NSColor *bm_color;
+ if (!p->cursor_p)
+ bm_color = ns_lookup_indexed_color(face->foreground, f);
+ else if (p->overlay_p)
+ bm_color = ns_lookup_indexed_color(face->background, f);
+ else
+ bm_color = f->output_data.ns->cursor_color;
+ [img setXBMColor: bm_color];
+ }
#ifdef NS_IMPL_COCOA
- // 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);
-
- [img drawInRect: imageRect
- fromRect: fromRect
- operation: NSCompositingOperationSourceOver
- fraction: 1.0
- respectFlipped: YES
- hints: nil];
+ // 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);
+
+ [img drawInRect: r
+ fromRect: fromRect
+ operation: NSCompositingOperationSourceOver
+ fraction: 1.0
+ respectFlipped: YES
+ hints: nil];
#else
- {
- NSPoint pt = imageRect.origin;
- pt.y += p->h;
- [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
- }
+ {
+ NSPoint pt = r.origin;
+ pt.y += p->h;
+ [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
+ }
#endif
- }
- ns_reset_clipping (f);
}
+ ns_unfocus (f);
}
@@ -3074,71 +3152,67 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
r.size.height = h;
r.size.width = w->phys_cursor_width;
- /* Prevent the cursor from being drawn outside the text area. */
- r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
+ /* Prevent the cursor from being drawn outside the text area. */
+ ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
- if (ns_clip_to_rect (f, &r, 1))
+
+ face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
+ if (face && NS_FACE_BACKGROUND (face)
+ == ns_index_color (FRAME_CURSOR_COLOR (f), f))
{
- face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
- if (face && NS_FACE_BACKGROUND (face)
- == ns_index_color (FRAME_CURSOR_COLOR (f), f))
- {
- [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
- hollow_color = FRAME_CURSOR_COLOR (f);
- }
- else
- [FRAME_CURSOR_COLOR (f) set];
+ [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
+ hollow_color = FRAME_CURSOR_COLOR (f);
+ }
+ 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_reset_clipping() here after that call. */
- NSDisableScreenUpdates ();
+ /* 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;
- }
-
- /* draw the character under the cursor */
- if (cursor_type != NO_CURSOR)
- draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
-
- ns_reset_clipping (f);
- }
- else if (! redisplaying_p)
+ switch (cursor_type)
{
- /* If this function is called outside redisplay, it probably
- means we need an immediate update. */
- [FRAME_NS_VIEW (f) display];
+ 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);
+
+ /* draw the character under the cursor */
+ if (cursor_type != NO_CURSOR)
+ draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+
+#ifdef NS_IMPL_COCOA
+ NSEnableScreenUpdates ();
+#endif
+
}
@@ -3156,14 +3230,12 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
- if (ns_clip_to_rect (f, &r, 1))
- {
- if (face)
- [ns_lookup_indexed_color(face->foreground, f) set];
+ ns_focus (f, &r, 1);
+ if (face)
+ [ns_lookup_indexed_color(face->foreground, f) set];
- NSRectFill(r);
- ns_reset_clipping (f);
- }
+ NSRectFill(r);
+ ns_unfocus (f);
}
@@ -3190,40 +3262,39 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
NSTRACE ("ns_draw_window_divider");
- if (ns_clip_to_rect (f, ÷r, 1))
- {
- if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
- /* A vertical divider, at least three pixels wide: Draw first and
- last pixels differently. */
- {
- [ns_lookup_indexed_color(color_first, f) set];
- NSRectFill(NSMakeRect (x0, y0, 1, y1 - y0));
- [ns_lookup_indexed_color(color, f) set];
- NSRectFill(NSMakeRect (x0 + 1, y0, x1 - x0 - 2, y1 - y0));
- [ns_lookup_indexed_color(color_last, f) set];
- NSRectFill(NSMakeRect (x1 - 1, y0, 1, y1 - y0));
- }
- else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
- /* A horizontal divider, at least three pixels high: Draw first and
- last pixels differently. */
- {
- [ns_lookup_indexed_color(color_first, f) set];
- NSRectFill(NSMakeRect (x0, y0, x1 - x0, 1));
- [ns_lookup_indexed_color(color, f) set];
- NSRectFill(NSMakeRect (x0, y0 + 1, x1 - x0, y1 - y0 - 2));
- [ns_lookup_indexed_color(color_last, f) set];
- NSRectFill(NSMakeRect (x0, y1 - 1, x1 - x0, 1));
- }
- else
- {
- /* In any other case do not draw the first and last pixels
- differently. */
- [ns_lookup_indexed_color(color, f) set];
- NSRectFill(divider);
- }
+ ns_focus (f, ÷r, 1);
- ns_reset_clipping (f);
+ if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
+ /* A vertical divider, at least three pixels wide: Draw first and
+ last pixels differently. */
+ {
+ [ns_lookup_indexed_color(color_first, f) set];
+ NSRectFill(NSMakeRect (x0, y0, 1, y1 - y0));
+ [ns_lookup_indexed_color(color, f) set];
+ NSRectFill(NSMakeRect (x0 + 1, y0, x1 - x0 - 2, y1 - y0));
+ [ns_lookup_indexed_color(color_last, f) set];
+ NSRectFill(NSMakeRect (x1 - 1, y0, 1, y1 - y0));
+ }
+ else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
+ /* A horizontal divider, at least three pixels high: Draw first and
+ last pixels differently. */
+ {
+ [ns_lookup_indexed_color(color_first, f) set];
+ NSRectFill(NSMakeRect (x0, y0, x1 - x0, 1));
+ [ns_lookup_indexed_color(color, f) set];
+ NSRectFill(NSMakeRect (x0, y0 + 1, x1 - x0, y1 - y0 - 2));
+ [ns_lookup_indexed_color(color_last, f) set];
+ NSRectFill(NSMakeRect (x0, y1 - 1, x1 - x0, 1));
+ }
+ else
+ {
+ /* In any other case do not draw the first and last pixels
+ differently. */
+ [ns_lookup_indexed_color(color, f) set];
+ NSRectFill(divider);
}
+
+ ns_unfocus (f);
}
static void
@@ -3807,84 +3878,83 @@ Function modeled after x_draw_glyph_string_box ().
n = ns_get_glyph_string_clip_rect (s, r);
*r = NSMakeRect (s->x, s->y, s->background_width, s->height);
- if (ns_clip_to_rect (s->f, r, n))
+ 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);
+ }
+ else
+ 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)
{
- if (s->hl == DRAW_MOUSE_FACE)
+ if (!s->row->full_width_p)
{
- 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);
+ int overrun, leftoverrun;
- bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
- fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
+ /* 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;
- }
-
- /* 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);
- }
+ /* 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;
- [bgCol set];
+ if (leftoverrun > 0)
+ {
+ r[i].origin.x += leftoverrun;
+ r[i].size.width -= leftoverrun;
+ }
- /* 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;
+ /* 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);
+ }
+
+ [bgCol set];
- x = r[i].origin.x;
- width = s->w->phys_cursor_width;
- r[i].size.width -= width;
- r[i].origin.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;
- NSRectFill (r[i]);
+ x = r[i].origin.x;
+ width = s->w->phys_cursor_width;
+ r[i].size.width -= width;
+ r[i].origin.x += width;
- /* 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);
- }
- else
- {
- NSRectFill (r[i]);
- }
+ 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);
+ /* 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);
+ }
+ else
+ {
+ NSRectFill (r[i]);
}
- ns_reset_clipping (s->f);
+
+ /* 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_unfocus (s->f);
s->background_filled_p = 1;
}
}
@@ -4034,11 +4104,9 @@ overwriting cursor (usually when cursor on a tab). */
if (next->first_glyph->type != STRETCH_GLYPH)
{
n = ns_get_glyph_string_clip_rect (s->next, r);
- if (ns_clip_to_rect (s->f, r, n))
- {
- ns_maybe_dumpglyphs_background (s->next, 1);
- ns_reset_clipping (s->f);
- }
+ ns_focus (s->f, r, n);
+ ns_maybe_dumpglyphs_background (s->next, 1);
+ ns_unfocus (s->f);
}
else
{
@@ -4053,12 +4121,10 @@ overwriting cursor (usually when cursor on a tab). */
|| s->first_glyph->type == COMPOSITE_GLYPH))
{
n = ns_get_glyph_string_clip_rect (s, r);
- if (ns_clip_to_rect (s->f, r, n))
- {
- ns_maybe_dumpglyphs_background (s, 1);
- ns_dumpglyphs_box_or_relief (s);
- ns_reset_clipping (s->f);
- }
+ ns_focus (s->f, r, n);
+ ns_maybe_dumpglyphs_background (s, 1);
+ ns_dumpglyphs_box_or_relief (s);
+ ns_unfocus (s->f);
box_drawn_p = 1;
}
@@ -4067,11 +4133,9 @@ overwriting cursor (usually when cursor on a tab). */
case IMAGE_GLYPH:
n = ns_get_glyph_string_clip_rect (s, r);
- if (ns_clip_to_rect (s->f, r, n))
- {
- ns_dumpglyphs_image (s, r[0]);
- ns_reset_clipping (s->f);
- }
+ ns_focus (s->f, r, n);
+ ns_dumpglyphs_image (s, r[0]);
+ ns_unfocus (s->f);
break;
case STRETCH_GLYPH:
@@ -4081,68 +4145,66 @@ overwriting cursor (usually when cursor on a tab). */
case CHAR_GLYPH:
case COMPOSITE_GLYPH:
n = ns_get_glyph_string_clip_rect (s, r);
- if (ns_clip_to_rect (s->f, r, n))
- {
- if (s->for_overlaps || (s->cmp_from > 0
- && ! s->first_glyph->u.cmp.automatic))
- s->background_filled_p = 1;
- else
- ns_maybe_dumpglyphs_background
- (s, s->first_glyph->type == COMPOSITE_GLYPH);
+ ns_focus (s->f, r, n);
- if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
- {
- unsigned long tmp = NS_FACE_BACKGROUND (s->face);
- NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
- NS_FACE_FOREGROUND (s->face) = tmp;
- }
+ if (s->for_overlaps || (s->cmp_from > 0
+ && ! s->first_glyph->u.cmp.automatic))
+ s->background_filled_p = 1;
+ else
+ ns_maybe_dumpglyphs_background
+ (s, s->first_glyph->type == COMPOSITE_GLYPH);
- {
- BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
+ if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
+ {
+ unsigned long tmp = NS_FACE_BACKGROUND (s->face);
+ NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
+ NS_FACE_FOREGROUND (s->face) = tmp;
+ }
- if (isComposite)
- ns_draw_composite_glyph_string_foreground (s);
- else
- ns_draw_glyph_string_foreground (s);
- }
+ {
+ BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
- {
- NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
- ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
- s->f)
- : FRAME_FOREGROUND_COLOR (s->f));
- [col set];
-
- /* Draw underline, overline, strike-through. */
- ns_draw_text_decoration (s, s->face, col, s->width, s->x);
- }
+ if (isComposite)
+ ns_draw_composite_glyph_string_foreground (s);
+ else
+ ns_draw_glyph_string_foreground (s);
+ }
- if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
- {
- unsigned long tmp = NS_FACE_BACKGROUND (s->face);
- NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
- NS_FACE_FOREGROUND (s->face) = tmp;
- }
+ {
+ NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
+ ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
+ s->f)
+ : FRAME_FOREGROUND_COLOR (s->f));
+ [col set];
+
+ /* Draw underline, overline, strike-through. */
+ ns_draw_text_decoration (s, s->face, col, s->width, s->x);
+ }
- ns_reset_clipping (s->f);
+ if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
+ {
+ unsigned long tmp = NS_FACE_BACKGROUND (s->face);
+ NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
+ NS_FACE_FOREGROUND (s->face) = tmp;
}
+
+ ns_unfocus (s->f);
break;
case GLYPHLESS_GLYPH:
n = ns_get_glyph_string_clip_rect (s, r);
- if (ns_clip_to_rect (s->f, r, n))
- {
- if (s->for_overlaps || (s->cmp_from > 0
- && ! s->first_glyph->u.cmp.automatic))
- s->background_filled_p = 1;
- else
- ns_maybe_dumpglyphs_background
- (s, s->first_glyph->type == COMPOSITE_GLYPH);
- /* ... */
- /* Not yet implemented. */
- /* ... */
- ns_reset_clipping (s->f);
- }
+ ns_focus (s->f, r, n);
+
+ if (s->for_overlaps || (s->cmp_from > 0
+ && ! s->first_glyph->u.cmp.automatic))
+ s->background_filled_p = 1;
+ else
+ ns_maybe_dumpglyphs_background
+ (s, s->first_glyph->type == COMPOSITE_GLYPH);
+ /* ... */
+ /* Not yet implemented. */
+ /* ... */
+ ns_unfocus (s->f);
break;
default:
@@ -4153,11 +4215,9 @@ overwriting cursor (usually when cursor on a tab). */
if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
{
n = ns_get_glyph_string_clip_rect (s, r);
- if (ns_clip_to_rect (s->f, r, n))
- {
- ns_dumpglyphs_box_or_relief (s);
- ns_reset_clipping (s->f);
- }
+ ns_focus (s->f, r, n);
+ ns_dumpglyphs_box_or_relief (s);
+ ns_unfocus (s->f);
}
s->num_clips = 0;
@@ -4963,7 +5023,7 @@ static Lisp_Object ns_string_to_lispmod (const char *s)
ns_after_update_window_line,
ns_update_window_begin,
ns_update_window_end,
- ns_flush_display, /* flush_display */
+ 0, /* flush_display */
x_clear_window_mouse_face,
x_get_glyph_overhangs,
x_fix_overlapping_area,
@@ -8101,23 +8161,7 @@ - (void)drawRect: (NSRect)rect
ns_clear_frame_area (emacsframe, x, y, width, height);
block_input ();
- /* Get only the precise dirty rectangles to avoid redrawing
- potentially large areas of the frame that haven't changed.
-
- I'm not sure this actually provides much of a performance benefit
- as it's hard to benchmark, but it certainly doesn't seem to
- hurt. */
- [self getRectsBeingDrawn:&rectList count:&numRects];
- for (int i = 0 ; i < numRects ; i++)
- {
- NSRect r = rectList[i];
-
- NSTRACE_RECT ("r", r);
-
- expose_frame (emacsframe,
- NSMinX (r), NSMinY (r),
- NSWidth (r), NSHeight (r));
- }
+ expose_frame (emacsframe, x, y, width, height);
unblock_input ();
--
2.20.1
From f7d62d0c8bae4ea31b670a32711893392298444c Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Sun, 10 Feb 2019 10:59:29 +0000
Subject: [PATCH 4/4] 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_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.
---
src/nsfns.m | 10 +-
src/nsterm.h | 9 ++
src/nsterm.m | 255 ++++++++++++++++++++++++++++++---------------------
3 files changed, 161 insertions(+), 113 deletions(-)
diff --git a/src/nsfns.m b/src/nsfns.m
index 59798d3bdd..edcdb988f7 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -286,11 +286,6 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
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;
@@ -319,7 +314,10 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
}
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 35dd9b3c3b..7ef5bba6a3 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -416,6 +416,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;
@@ -456,6 +459,12 @@ typedef id instancetype;
#endif
- (int)fullscreenState;
+#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;
diff --git a/src/nsterm.m b/src/nsterm.m
index 6529a50298..3bd61aa53f 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -279,9 +279,6 @@ - (NSColor *)colorUsingDefaultColorSpace
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
@@ -1077,33 +1074,10 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
#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
}
@@ -1192,12 +1166,17 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
/* 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;
}
@@ -1212,6 +1191,8 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
the entire window.
-------------------------------------------------------------------------- */
{
+ EmacsView *view = FRAME_NS_VIEW (f);
+
NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
if (r != NULL)
{
@@ -1219,27 +1200,34 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
}
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);
@@ -1264,6 +1252,7 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
gsaved = NO;
}
+#ifdef NS_IMPL_GNUSTEP
if (f != ns_updating_frame)
{
if (focus_view != NULL)
@@ -1271,9 +1260,9 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
[focus_view unlockFocus];
[[focus_view window] flushWindow];
focus_view = NULL;
-/*debug_lock--; */
}
}
+#endif
}
@@ -1285,16 +1274,7 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
-------------------------------------------------------------------------- */
{
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);
}
@@ -2757,22 +2737,6 @@ so some key presses (TAB) are swallowed by the system. */
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)
@@ -2825,8 +2789,12 @@ so some key presses (TAB) are swallowed by the system. */
{
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 ();
@@ -2880,20 +2848,12 @@ so some key presses (TAB) are swallowed by the system. */
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];
}
@@ -2974,9 +2934,6 @@ so some key presses (TAB) are swallowed by the system. */
struct face *face = p->face;
static EmacsImage **bimgs = NULL;
static int nBimgs = 0;
- NSRect clearRect = NSZeroRect;
- NSRect imageRect = NSZeroRect;
- NSRect rowRect = ns_row_rect (w, row, ANY_AREA);
NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
@@ -3056,6 +3013,18 @@ so some key presses (TAB) are swallowed by the system. */
NSTRACE_RECT ("fromRect", fromRect);
+ /* 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(r)];
+ [transform scaleXBy:1 yBy:-1];
+ [transform concat];
+
+ r.origin.y = 0;
+ }
+
[img drawInRect: r
fromRect: fromRect
operation: NSCompositingOperationSourceOver
@@ -3166,15 +3135,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
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:
@@ -3208,11 +3168,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
/* draw the character under the cursor */
if (cursor_type != NO_CURSOR)
draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
-
-#ifdef NS_IMPL_COCOA
- NSEnableScreenUpdates ();
-#endif
-
}
@@ -3297,6 +3252,7 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
ns_unfocus (f);
}
+
static void
ns_show_hourglass (struct frame *f)
{
@@ -3794,12 +3750,29 @@ Function modeled after x_draw_glyph_string_box ().
NSRect ir = NSMakeRect (s->slice.x,
s->img->height - s->slice.y - s->slice.height,
s->slice.width, s->slice.height);
+
+ /* 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];
+
+ /* FIXME: It should be faster to just reverse the transform than
+ save and restore the graphics state. */
+ [NSGraphicsContext saveGraphicsState];
+ [transform translateXBy:0 yBy:NSMaxY(dr)];
+ [transform scaleXBy:1 yBy:-1];
+ [transform concat];
+
+ dr.origin.y = 0;
+
[img drawInRect: dr
fromRect: ir
operation: NSCompositingOperationSourceOver
fraction: 1.0
respectFlipped: YES
hints: nil];
+
+ [NSGraphicsContext restoreGraphicsState];
#else
[img compositeToPoint: NSMakePoint (x, y + s->slice.height)
operation: NSCompositingOperationSourceOver];
@@ -7010,6 +6983,7 @@ - (void) updateFrameSize: (BOOL) delay
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:].
@@ -7349,6 +7323,8 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f
maximizing_resize = NO;
#endif
+ [self createDrawingBufferWithRect:r];
+
win = [[EmacsWindow alloc]
initWithContentRect: r
styleMask: (FRAME_UNDECORATED (f)
@@ -8139,40 +8115,105 @@ - (instancetype)toggleToolbar: (id)sender
}
-- (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;
- ns_clear_frame_area (emacsframe, x, y, width, height);
- block_input ();
+#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);
+ block_input ();
+ ns_clear_frame_area (emacsframe, x, y, width, height);
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
}
--
2.20.1
next prev parent reply other threads:[~2019-02-11 22:14 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-13 23:19 Some NS port changes Alan Third
2019-01-14 15:42 ` Eli Zaretskii
2019-01-15 16:12 ` Alan Third
2019-01-15 16:33 ` Stefan Monnier
2019-01-15 16:58 ` Alan Third
2019-01-15 20:35 ` Charles A. Roelli
2019-01-15 22:22 ` Alan Third
2019-02-10 22:14 ` Alan Third
2019-02-11 10:59 ` Robert Pluim
2019-02-11 22:14 ` Alan Third [this message]
2019-02-12 9:21 ` Robert Pluim
2019-02-14 9:08 ` Robert Pluim
2019-02-14 18:17 ` Alan Third
2019-02-15 10:51 ` Robert Pluim
-- strict thread matches above, loose matches on Subject: below --
2019-01-20 6:11 Zhang Haijun
2019-01-20 11:09 ` Alan Third
2019-01-20 11:20 ` Zhang Haijun
2019-01-20 12:26 ` Eli Zaretskii
2019-01-20 12:23 ` Eli Zaretskii
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190211221404.GA24399@breton.holly.idiocy.org \
--to=alan@idiocy.org \
--cc=emacs-devel@gnu.org \
--cc=rpluim@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).