summaryrefslogtreecommitdiff
path: root/src/nsterm.m
diff options
context:
space:
mode:
Diffstat (limited to 'src/nsterm.m')
-rw-r--r--src/nsterm.m968
1 files changed, 542 insertions, 426 deletions
diff --git a/src/nsterm.m b/src/nsterm.m
index ed2d82ceaef..c0535825eee 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -287,7 +287,10 @@ struct ns_display_info *x_display_list; /* Chain of existing displays */
long context_menu_value = 0;
/* display update */
+static struct frame *ns_updating_frame;
+static NSView *focus_view = NULL;
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;
@@ -1097,13 +1100,12 @@ ns_update_begin (struct frame *f)
external (RIF) call; whole frame, called before gui_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
@@ -1113,6 +1115,13 @@ ns_update_begin (struct frame *f)
[toolbar setVisible: tbar_visible];
}
#endif
+
+ ns_updating_frame = f;
+#ifdef NS_IMPL_COCOA
+ [view focusOnDrawingBuffer];
+#else
+ [view lockFocus];
+#endif
}
@@ -1123,57 +1132,123 @@ ns_update_end (struct frame *f)
external (RIF) call; for whole frame, called after gui_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;
-}
+#ifdef NS_IMPL_COCOA
+ [NSGraphicsContext setCurrentContext:nil];
+#else
+ block_input ();
-static BOOL
-ns_clip_to_rect (struct frame *f, NSRect *r, int n)
+ [view unlockFocus];
+ [[view window] flushWindow];
+
+ unblock_input ();
+#endif
+ 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)
+ EmacsView *view = FRAME_NS_VIEW (f);
+
+ 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)
+#ifdef NS_IMPL_COCOA
+ [view focusOnDrawingBuffer];
+#else
+ {
+ if (view != focus_view)
{
- [[NSGraphicsContext currentContext] saveGraphicsState];
- if (n == 2)
- NSRectClipList (r, 2);
- else
- NSRectClip (*r);
+ if (focus_view != NULL)
+ {
+ [focus_view unlockFocus];
+ [[focus_view window] flushWindow];
+ }
- return YES;
+ if (view)
+ [view lockFocus];
+ focus_view = view;
}
+ }
+#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);
else
+ NSRectClip (*r);
+ gsaved = YES;
+ }
+}
+
+
+static void
+ns_unfocus (struct frame *f)
+/* --------------------------------------------------------------------------
+ Internal: Remove focus on given frame
+ -------------------------------------------------------------------------- */
+{
+ NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
+
+ if (gsaved)
+ {
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+ gsaved = NO;
+ }
+
+#ifdef NS_IMPL_GNUSTEP
+ if (f != ns_updating_frame)
+ {
+ if (focus_view != NULL)
{
- NSView *view = FRAME_NS_VIEW (f);
- int i;
- for (i = 0 ; i < n ; i++)
- [view setNeedsDisplayInRect:r[i]];
+ [focus_view unlockFocus];
+ [[focus_view window] flushWindow];
+ focus_view = NULL;
}
}
-
- return NO;
+#endif
}
static void
-ns_reset_clipping (struct frame *f)
-/* Internal: Restore the previous graphics state, unsetting any
- clipping areas. */
+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
+ -------------------------------------------------------------------------- */
{
- NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_reset_clipping");
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ NSRect clip_rect = ns_row_rect (w, row, area);
- [[NSGraphicsContext currentContext] restoreGraphicsState];
+ ns_focus (f, &clip_rect, 1);
}
@@ -2026,17 +2101,13 @@ ns_set_appearance (struct frame *f, Lisp_Object new_value, Lisp_Object old_value
return;
if (EQ (new_value, Qdark))
- {
- window.appearance = [NSAppearance
- appearanceNamed: NSAppearanceNameVibrantDark];
- FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark;
- }
+ FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark;
+ else if (EQ (new_value, Qlight))
+ FRAME_NS_APPEARANCE (f) = ns_appearance_aqua;
else
- {
- window.appearance = [NSAppearance
- appearanceNamed: NSAppearanceNameAqua];
- FRAME_NS_APPEARANCE (f) = ns_appearance_aqua;
- }
+ FRAME_NS_APPEARANCE (f) = ns_appearance_system_default;
+
+ [window setAppearance];
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
}
@@ -2302,8 +2373,10 @@ ns_color_index_to_rgba(int idx, struct frame *f)
EmacsCGFloat r, g, b, a;
[col getRed: &r green: &g blue: &b alpha: &a];
- return ARGB_TO_ULONG((int)(a*255),
- (int)(r*255), (int)(g*255), (int)(b*255));
+ return ARGB_TO_ULONG((unsigned long) (a * 255),
+ (unsigned long) (r * 255),
+ (unsigned long) (g * 255),
+ (unsigned long) (b * 255));
}
void
@@ -2323,8 +2396,10 @@ ns_query_color(void *col, Emacs_Color *color_def, bool setPixel)
if (setPixel == YES)
color_def->pixel
- = ARGB_TO_ULONG((int)(a*255),
- (int)(r*255), (int)(g*255), (int)(b*255));
+ = ARGB_TO_ULONG((unsigned long) (a * 255),
+ (unsigned long) (r * 255),
+ (unsigned long) (g * 255),
+ (unsigned long) (b * 255));
}
bool
@@ -2770,16 +2845,16 @@ ns_clear_frame (struct frame *f)
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 */
+ /* FIXME: I don't see any reason for this and removing it makes no
+ difference here. Do we need it for GNUstep? */
+ //ns_redraw_scroll_bars (f);
unblock_input ();
}
@@ -2800,46 +2875,15 @@ ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
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
-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))
- {
- 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. */
- [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
- }
-}
static void
ns_scroll_run (struct window *w, struct run *run)
@@ -2892,8 +2936,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 ();
@@ -2947,20 +2995,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];
}
@@ -3080,66 +3120,64 @@ 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)
- {
- // 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
- reverseBytes: NO];
- 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
+ reverseBytes: NO];
+ bimgs[p->which - 1] = img;
+ xfree (cbits);
+ }
- {
- 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];
+ }
- // 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);
+ [img drawInRect: imageRect
+ fromRect: fromRect
+ operation: NSCompositingOperationSourceOver
+ fraction: 1.0
+ respectFlipped: YES
+ hints: nil];
}
+ ns_unfocus (f);
}
@@ -3224,60 +3262,52 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
/* Prevent the cursor from being drawn outside the text area. */
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)
+ == 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];
-
- 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_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
+ hollow_color = FRAME_CURSOR_COLOR (f);
+ }
+ else
+ [FRAME_CURSOR_COLOR (f) set];
- /* 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);
+ ns_focus (f, &r, 1);
- 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. 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);
}
@@ -3295,14 +3325,12 @@ ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
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);
}
@@ -3329,42 +3357,42 @@ ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
NSTRACE ("ns_draw_window_divider");
- if (ns_clip_to_rect (f, &divider, 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, &divider, 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
ns_show_hourglass (struct frame *f)
{
@@ -3888,15 +3916,22 @@ 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];
+
+ /* ImageMagick images don't have transforms. */
+ if (img->transform)
+ [doTransform appendTransform:img->transform];
+
+ [doTransform concat];
[img drawInRect:ir fromRect:ir
operation:NSCompositingOperationSourceOver
@@ -3969,6 +4004,7 @@ static void
ns_dumpglyphs_stretch (struct glyph_string *s)
{
NSRect r[2];
+ NSRect glyphRect;
int n, i;
struct face *face;
NSColor *fgCol, *bgCol;
@@ -3976,82 +4012,57 @@ 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 (ns_clip_to_rect (s->f, r, n))
+ if (s->hl == DRAW_MOUSE_FACE)
{
- /* 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);
+ 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);
- 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);
- bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
- fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
+ glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height);
- 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;
- }
- }
+ [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;
+ /* 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;
- x = r[i].origin.x;
- width = s->w->phys_cursor_width;
- r[i].size.width -= width;
- r[i].origin.x += width;
+ NSRectFill (glyphRect);
- NSRectFill (r[i]);
+ /* 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 (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);
- }
- 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, NSWidth (glyphRect),
+ NSMinX (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, r[i].size.width,
- r[i].origin.x);
- }
- ns_reset_clipping (s->f);
- }
+ ns_unfocus (s->f);
s->background_filled_p = 1;
}
}
@@ -4201,11 +4212,9 @@ ns_draw_glyph_string (struct glyph_string *s)
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
{
@@ -4220,12 +4229,10 @@ ns_draw_glyph_string (struct glyph_string *s)
|| 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;
}
@@ -4234,11 +4241,9 @@ ns_draw_glyph_string (struct glyph_string *s)
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:
@@ -4248,68 +4253,66 @@ ns_draw_glyph_string (struct glyph_string *s)
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:
@@ -4320,11 +4323,9 @@ ns_draw_glyph_string (struct glyph_string *s)
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;
@@ -6583,13 +6584,18 @@ not_in_argv (NSString *arg)
{
NSRect rect;
NSPoint pt;
- struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
+ struct window *win;
NSTRACE ("[EmacsView firstRectForCharacterRange:]");
if (NS_KEYLOG)
NSLog (@"firstRectForCharRange request");
+ if (WINDOWP (echo_area_window) && ! NILP (call0 (intern ("ns-in-echo-area"))))
+ win = XWINDOW (echo_area_window);
+ else
+ win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
+
rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
@@ -6696,8 +6702,6 @@ not_in_argv (NSString *arg)
NSTRACE ("[EmacsView mouseDown:]");
- [self deleteWorkingText];
-
if (!emacs_event)
return;
@@ -7087,6 +7091,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 createDrawingBuffer];
[view setFrame: wr];
// To do: consider using [NSNotificationCenter postNotificationName:].
@@ -7169,6 +7174,7 @@ not_in_argv (NSString *arg)
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);
}
}
@@ -7322,7 +7328,6 @@ not_in_argv (NSString *arg)
if (emacs_event && is_focus_frame)
{
- [self deleteWorkingText];
emacs_event->kind = FOCUS_OUT_EVENT;
EV_TRAILER ((id)nil);
}
@@ -7425,6 +7430,8 @@ not_in_argv (NSString *arg)
maximizing_resize = NO;
#endif
+ [self createDrawingBuffer];
+
win = [[EmacsWindow alloc]
initWithContentRect: r
styleMask: (FRAME_UNDECORATED (f)
@@ -7466,16 +7473,8 @@ not_in_argv (NSString *arg)
if (! FRAME_UNDECORATED (f))
[self createToolbar: f];
-#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
-#ifndef NSAppKitVersionNumber10_10
-#define NSAppKitVersionNumber10_10 1343
-#endif
- if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_10
- && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua)
- win.appearance = [NSAppearance
- appearanceNamed: NSAppearanceNameVibrantDark];
-#endif
+ [win setAppearance];
#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
@@ -8216,55 +8215,146 @@ not_in_argv (NSString *arg)
}
-- (void)viewWillDraw
+#ifdef NS_IMPL_COCOA
+- (void)createDrawingBuffer
+ /* Create and store a new CGGraphicsContext for Emacs to draw into.
+
+ We can't do this in GNUstep as there's no equivalent, 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];
+ NSTRACE ("EmacsView createDrawingBuffer]");
+
+ NSGraphicsContext *screen;
+ CGColorSpaceRef colorSpace = [[[self window] colorSpace] CGColorSpace];
+ CGFloat scale = [[self window] backingScaleFactor];
+ NSRect frame = [self frame];
+
+ if (drawingBuffer != nil)
+ CGContextRelease (drawingBuffer);
+
+ drawingBuffer = CGBitmapContextCreate (nil, NSWidth (frame) * scale, NSHeight (frame) * scale,
+ 8, 0, colorSpace,
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
+
+ /* This fixes the scale to match the backing scale factor, and flips the image. */
+ CGContextTranslateCTM(drawingBuffer, 0, NSHeight (frame) * scale);
+ CGContextScaleCTM(drawingBuffer, scale, -scale);
}
-- (void)drawRect: (NSRect)rect
+
+- (void)focusOnDrawingBuffer
{
- const NSRect *rectList;
- NSInteger numRects;
+ NSTRACE ("EmacsView focusOnDrawingBuffer]");
- NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
- NSTRACE_ARG_RECT(rect));
+ NSGraphicsContext *buf =
+ [NSGraphicsContext
+ graphicsContextWithCGContext:drawingBuffer flipped:YES];
- if (!emacsframe || !emacsframe->output_data.ns)
- return;
+ [NSGraphicsContext setCurrentContext:buf];
+}
- block_input ();
- /* Get only the precise dirty rectangles to avoid redrawing
- potentially large areas of the frame that haven't changed.
+- (void)windowDidChangeBackingProperties:(NSNotification *)notification
+ /* Update the drawing buffer when the backing scale factor changes. */
+{
+ NSTRACE ("EmacsView windowDidChangeBackingProperties:]");
+
+ CGFloat old = [[[notification userInfo]
+ objectForKey:@"NSBackingPropertyOldScaleFactorKey"]
+ doubleValue];
+ CGFloat new = [[self window] backingScaleFactor];
- 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++)
+ if (old != new)
{
- NSRect r = rectList[i];
+ NSRect frame = [self frame];
+ [self createDrawingBuffer];
+ ns_clear_frame (emacsframe);
+ expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame));
+ }
+}
+#endif /* NS_IMPL_COCOA */
- NSTRACE_RECT ("r", r);
- expose_frame (emacsframe,
- NSMinX (r), NSMinY (r),
- NSWidth (r), NSHeight (r));
- }
+- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect
+{
+ NSTRACE ("[EmacsView copyRect:To:]");
+ NSTRACE_RECT ("Source", srcRect);
+ NSTRACE_RECT ("Destination", dstRect);
- unblock_input ();
+#ifdef NS_IMPL_COCOA
+ CGImageRef copy;
+ NSRect frame = [self frame];
+ NSAffineTransform *setOrigin = [NSAffineTransform transform];
+
+ [[NSGraphicsContext currentContext] saveGraphicsState];
+
+ /* Set the clipping before messing with the buffer's
+ orientation. */
+ NSRectClip (dstRect);
+
+ /* Unflip the buffer as the copied image will be unflipped, and
+ offset the top left so when we draw back into the buffer the
+ correct part of the image is drawn. */
+ CGContextScaleCTM(drawingBuffer, 1, -1);
+ CGContextTranslateCTM(drawingBuffer,
+ NSMinX (dstRect) - NSMinX (srcRect),
+ -NSHeight (frame) - (NSMinY (dstRect) - NSMinY (srcRect)));
+
+ /* Take a copy of the buffer and then draw it back to the buffer,
+ limited by the clipping rectangle. */
+ copy = CGBitmapContextCreateImage (drawingBuffer);
+ CGContextDrawImage (drawingBuffer, frame, copy);
+
+ CGImageRelease (copy);
+
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+ [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
+}
- /*
- 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;
- */
+#ifdef NS_IMPL_COCOA
+- (BOOL)wantsUpdateLayer
+{
+ return YES;
+}
+
+
+- (void)updateLayer
+{
+ NSTRACE ("[EmacsView updateLayer]");
+
+ CGImageRef contentsImage = CGBitmapContextCreateImage(drawingBuffer);
+ [[self layer] setContents:(id)contentsImage];
+ CGImageRelease(contentsImage);
+}
+#endif
+
+
+- (void)drawRect: (NSRect)rect
+{
+ NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
+ NSTRACE_ARG_RECT(rect));
+
+ if (!emacsframe || !emacsframe->output_data.ns)
+ return;
+
+ 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 ();
}
@@ -8725,6 +8815,32 @@ not_in_argv (NSString *arg)
#endif
}
+- (void)setAppearance
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
+ struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
+ NSAppearance *appearance = nil;
+
+ NSTRACE ("[EmacsWindow setAppearance]");
+
+#ifndef NSAppKitVersionNumber10_10
+#define NSAppKitVersionNumber10_10 1343
+#endif
+
+ if (NSAppKitVersionNumber < NSAppKitVersionNumber10_10)
+ return;
+
+ if (FRAME_NS_APPEARANCE (f) == ns_appearance_vibrant_dark)
+ appearance =
+ [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark];
+ else if (FRAME_NS_APPEARANCE (f) == ns_appearance_aqua)
+ appearance =
+ [NSAppearance appearanceNamed:NSAppearanceNameAqua];
+
+ [self setAppearance:appearance];
+#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
+}
+
- (void)setFrame:(NSRect)windowFrame
display:(BOOL)displayViews
{