1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-31 21:01:23 -08:00

Fix more drawing bugs in NS port (bug#32932)

* src/nsterm.m (ns_row_rect): New function.
(ns_clip_to_row): Remove function.
(ns_copy_bits): Fix mistake.
(ns_shift_glyphs_for_insert): Mark the frame as dirty instead of
directly copying.
(ns_draw_fringe_bitmap): Stop using ns_clip_to_row.
(ns_draw_window_cursor): Stop using ns_clip_to_row and perform a
display when not in redisplay.
(ns_update_window_begin): Remove redundant code that never executes.
([EmacsView drawRect:]): Show the rectangle being exposed in NSTRACE.
* src/xdisp.c (expose_window_tree) [HAVE_NS]:
(expose_frame) [HAVE_NS]: Redraw even if the frame is garbaged.
This commit is contained in:
Alan Third 2018-10-29 15:37:35 +00:00
parent 9877c03293
commit 094fcf62d2
2 changed files with 93 additions and 75 deletions

View file

@ -796,6 +796,27 @@ ns_menu_bar_height (NSScreen *screen)
}
static NSRect
ns_row_rect (struct window *w, struct glyph_row *row,
enum glyph_row_area area)
/* Get the row as an NSRect. */
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
NSRect rect;
int window_x, window_y, window_width;
window_box (w, area, &window_x, &window_y, &window_width, 0);
rect.origin.x = window_x;
rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
rect.origin.y = max (rect.origin.y, window_y);
rect.size.width = window_width;
rect.size.height = row->visible_height;
return rect;
}
/* ==========================================================================
Focus (clipping) and screen update
@ -1048,29 +1069,6 @@ ns_update_begin (struct frame *f)
if (! tbar_visible != ! [toolbar isVisible])
[toolbar setVisible: tbar_visible];
}
/* 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. */
/* FIXME: I don't think we need to do this. */
if ([NSView focusView] == FRAME_NS_VIEW (f))
{
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
}
@ -1206,28 +1204,6 @@ ns_reset_clipping (struct frame *f)
}
static BOOL
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;
return ns_clip_to_rect (f, &clip_rect, 1);
}
/* ==========================================================================
Visible bell and beep.
@ -2692,7 +2668,7 @@ 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)
dest.origin.y - src.origin.y);
NSTRACE ("ns_copy_bits");
if (FRAME_NS_VIEW (f))
@ -2825,12 +2801,20 @@ 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");
ns_copy_bits (f, srcRect, dstRect);
/* 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];
}
@ -2911,6 +2895,9 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
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",
@ -2925,25 +2912,40 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
nBimgs = max_used_fringe_bitmap;
}
/* Must clip because of partially visible lines. */
if (ns_clip_to_row (w, row, ANY_AREA, YES))
{
if (!p->overlay_p)
{
int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
/* Work out the rectangle we will composite into. */
if (p->which)
imageRect = NSMakeRect (p->x, p->y, p->wd, p->h);
if (bx >= 0 && nx > 0)
{
NSRect r = NSMakeRect (bx, by, nx, ny);
NSRectClip (r);
[ns_lookup_indexed_color (face->background, f) set];
NSRectFill (r);
}
/* 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->overlay_p)
{
clearRect = NSMakeRect (p->bx, p->by, p->nx, p->ny);
clearRect = NSUnionRect (clearRect, imageRect);
}
else
{
clearRect = imageRect;
}
/* 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))
{
NSTRACE_RECT ("clearRect", clearRect);
[ns_lookup_indexed_color(face->background, f) set];
NSRectFill (clearRect);
}
if (p->which)
{
NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
EmacsImage *img = bimgs[p->which - 1];
if (!img)
@ -2964,13 +2966,6 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
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;
@ -2990,7 +2985,7 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
NSTRACE_RECT ("fromRect", fromRect);
[img drawInRect: r
[img drawInRect: imageRect
fromRect: fromRect
operation: NSCompositingOperationSourceOver
fraction: 1.0
@ -2998,7 +2993,7 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
hints: nil];
#else
{
NSPoint pt = r.origin;
NSPoint pt = imageRect.origin;
pt.y += p->h;
[img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
}
@ -3088,7 +3083,9 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
r.size.width = w->phys_cursor_width;
/* Prevent the cursor from being drawn outside the text area. */
if (ns_clip_to_row (w, glyph_row, TEXT_AREA, NO))
r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
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)
@ -3128,11 +3125,18 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
NSRectFill (s);
break;
}
ns_reset_clipping (f);
/* 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)
{
/* If this function is called outside redisplay, it probably
means we need an immediate update. */
[FRAME_NS_VIEW (f) display];
}
}
@ -8096,6 +8100,9 @@ not_in_argv (NSString *arg)
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));

View file

@ -32258,7 +32258,14 @@ expose_window_tree (struct window *w, XRectangle *r)
struct frame *f = XFRAME (w->frame);
bool mouse_face_overwritten_p = false;
while (w && !FRAME_GARBAGED_P (f))
/* NS toolkits may have aleady modified the frame in expectation of
a successful redraw, so don't bail out here if the frame is
garbaged. */
while (w
#if !defined (HAVE_NS)
&& !FRAME_GARBAGED_P (f)
#endif
)
{
mouse_face_overwritten_p
|= (WINDOWP (w->contents)
@ -32286,12 +32293,16 @@ expose_frame (struct frame *f, int x, int y, int w, int h)
TRACE ((stderr, "expose_frame "));
/* No need to redraw if frame will be redrawn soon. */
#if !defined (HAVE_NS)
/* No need to redraw if frame will be redrawn soon except under NS
where the toolkit may have already modified the frame in
expectation of us redrawing it. */
if (FRAME_GARBAGED_P (f))
{
TRACE ((stderr, " garbaged\n"));
return;
}
#endif
/* If basic faces haven't been realized yet, there is no point in
trying to redraw anything. This can happen when we get an expose