Skip to content

Commit 2eccde3

Browse files
committed
Add support for smooth cursor for emacs 31
1 parent 3e95d57 commit 2eccde3

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed

Formula/emacs-plus@31.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class EmacsPlusAT31 < EmacsBase
2020
option "with-xwidgets", "Experimental: build with xwidgets support"
2121
option "with-no-frame-refocus", "Disables frame re-focus (ie. closing one frame does not refocus another one)"
2222
option "with-compress-install", "Build with compressed install optimization"
23+
option "with-smooth-cursor", "Build with animated smooth cursor"
2324

2425
#
2526
# Dependencies
@@ -93,6 +94,7 @@ class EmacsPlusAT31 < EmacsBase
9394
local_patch "fix-window-role", sha: "1f8423ea7e6e66c9ac6dd8e37b119972daa1264de00172a24a79a710efcb8130"
9495
local_patch "system-appearance", sha: "53283503db5ed2887e9d733baaaf80f2c810e668e782e988bda5855a0b1ebeb4"
9596
local_patch "round-undecorated-frame", sha: "26947b6724fc29fadd44889808c5cf0b4ce6278cf04f46086a21df50c8c4151d"
97+
local_patch "ksqsf-smooth-cursor", sha: "c77f045e3defe30f7a8822b4d7962c37c84afcde9198d6131bf13894af2e72ea" if build.with? "smooth-cursor"
9698

9799
#
98100
# Install
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
From ebfa4855d7a323ebc3424936d6a3df812f74967a Mon Sep 17 00:00:00 2001
2+
From: Mingkai Dong <mk@dong.mk>
3+
Date: Sat, 5 Apr 2025 00:27:15 +0800
4+
Subject: [PATCH] Add smooth cursor animation
5+
6+
This adds and extends the patch from ksqsf.
7+
https://github.com/ksqsf/emacsmoe/pull/7
8+
---
9+
lisp/term/ns-win.el | 7 ++++++
10+
src/nsterm.h | 1 +
11+
src/nsterm.m | 59 +++++++++++++++++++++++++++++++++++++++++++++
12+
3 files changed, 67 insertions(+)
13+
14+
diff --git a/lisp/term/ns-win.el b/lisp/term/ns-win.el
15+
index 46639f2422b..8c606c441af 100644
16+
--- a/lisp/term/ns-win.el
17+
+++ b/lisp/term/ns-win.el
18+
@@ -65,6 +65,13 @@ x-command-line-resources
19+
;; nsterm.m.
20+
(defvar ns-input-file)
21+
22+
+(defcustom ns-cursor-animation-duration 0.1
23+
+ "Duration in seconds for cursor animation on macOS.
24+
+This controls how long the cursor animation takes when changing position or style.
25+
+A value of 0 disables animation."
26+
+ :type 'number
27+
+ :group 'ns)
28+
+
29+
(defun ns-handle-nxopen (_switch &optional temp)
30+
(setq unread-command-events (append unread-command-events
31+
(if temp '(ns-open-temp-file)
32+
diff --git a/src/nsterm.h b/src/nsterm.h
33+
index 2abf402f8bc..33338370537 100644
34+
--- a/src/nsterm.h
35+
+++ b/src/nsterm.h
36+
@@ -485,6 +485,7 @@ #define NSTRACE_UNSILENCE()
37+
struct frame *emacsframe;
38+
int scrollbarsNeedingUpdate;
39+
NSRect ns_userRect;
40+
+ CALayer *cursor_layer;
41+
}
42+
43+
/* AppKit-side interface. */
44+
diff --git a/src/nsterm.m b/src/nsterm.m
45+
index 5514a693c86..95238209356 100644
46+
--- a/src/nsterm.m
47+
+++ b/src/nsterm.m
48+
@@ -44,6 +44,7 @@ Updated by Christian Limpach (chris@nice.ch)
49+
50+
#include "lisp.h"
51+
#include "blockinput.h"
52+
+#include "dispextern.h"
53+
#include "sysselect.h"
54+
#include "nsterm.h"
55+
#include "systime.h"
56+
@@ -71,6 +72,7 @@ Updated by Christian Limpach (chris@nice.ch)
57+
#include "macfont.h"
58+
#include <Carbon/Carbon.h>
59+
#include <IOSurface/IOSurface.h>
60+
+#include <QuartzCore/QuartzCore.h>
61+
#endif
62+
63+
static EmacsMenu *dockMenu;
64+
@@ -3016,6 +3018,12 @@ Hide the window (X11 semantics)
65+
ns_unfocus (f);
66+
}
67+
68+
+static double
69+
+ns_get_cursor_animation_duration (void)
70+
+{
71+
+ Lisp_Object duration = Fsymbol_value (intern_c_string ("ns-cursor-animation-duration"));
72+
+ return NUMBERP (duration) ? XFLOATINT (duration) : 0.1;
73+
+}
74+
75+
static void
76+
ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
77+
@@ -3101,6 +3109,45 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
78+
/* Prevent the cursor from being drawn outside the text area. */
79+
r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
80+
81+
+ /* We use the CA layer as a temporary animation layer. */
82+
+ EmacsView *view = FRAME_NS_VIEW (f);
83+
+ CALayer *cursor_layer = view->cursor_layer;
84+
+
85+
+ if (active_p && cursor_layer) {
86+
+ NSRect r2 = r;
87+
+ r2.origin.y = [view bounds].size.height - r2.size.height - r2.origin.y;
88+
+ cursor_glyph = get_phys_cursor_glyph (w);
89+
+ if ((cursor_glyph->resolved_level & 1) != 0)
90+
+ r2.origin.x += cursor_glyph->pixel_width - r2.size.width;
91+
+
92+
+ switch (cursor_type)
93+
+ {
94+
+ case DEFAULT_CURSOR:
95+
+ case NO_CURSOR:
96+
+ /* Make the layer invisible. */
97+
+ cursor_layer.opacity = 0.0;
98+
+ cursor_layer.backgroundColor = nil;
99+
+ cursor_layer.frame = r2;
100+
+ break;
101+
+ case FILLED_BOX_CURSOR:
102+
+ case HOLLOW_BOX_CURSOR:
103+
+ case HBAR_CURSOR:
104+
+ case BAR_CURSOR:
105+
+ [CATransaction begin];
106+
+ [CATransaction setAnimationDuration:ns_get_cursor_animation_duration ()];
107+
+ [CATransaction setCompletionBlock:^{
108+
+ cursor_layer.backgroundColor = nil; /* hide after animation */
109+
+ cursor_layer.opacity = 0.0;
110+
+ }];
111+
+ cursor_layer.backgroundColor = FRAME_CURSOR_COLOR (f).CGColor;
112+
+ cursor_layer.opacity = 1.0;
113+
+ cursor_layer.frame = r2;
114+
+ [CATransaction commit];
115+
+ break;
116+
+ }
117+
+ }
118+
+ /* Below is the original Emacs drawing code for the cursor. */
119+
+
120+
ns_focus (f, NULL, 0);
121+
122+
NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
123+
@@ -9381,6 +9428,18 @@ - (instancetype) initWithEmacsFrame: (struct frame *) f
124+
[[self contentView] addSubview:view];
125+
[self makeFirstResponder:view];
126+
127+
+ /* Overlay a canvas view on top of EmacsView. */
128+
+ NSView *canvasView = [[NSView alloc] initWithFrame:view.bounds];
129+
+ canvasView.wantsLayer = YES;
130+
+ canvasView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
131+
+ [view addSubview:canvasView positioned:NSWindowAbove relativeTo:nil];
132+
+
133+
+ /* Create a cursor layer on the canvas. */
134+
+ view->cursor_layer = [CALayer layer];
135+
+ [canvasView.layer addSublayer: view->cursor_layer];
136+
+ view->cursor_layer.frame = CGRectMake(0, 0, 0, 0);
137+
+
138+
+
139+
#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
140+
#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
141+
if ([self respondsToSelector: @selector(useOptimizedDrawing:)])
142+
--
143+
2.49.0
144+

0 commit comments

Comments
 (0)