Update Android port

* java/org/gnu/emacs/EmacsNative.java (EmacsNative): New
function requestSelectionUpdate.
* java/org/gnu/emacs/EmacsView.java (onCreateInputConnection):
Call it instead of losing if getting the current selection
fails.
* src/android-asset.h (AAsset_seek): Define stub.
* src/android.c (android_open): Take mode_t.
(android_open_asset, android_close_asset, android_asset_read_quit)
(android_asset_read, android_asset_lseek, android_asset_fstat):
New functions.
* src/android.h (struct android_fd_or_asset): Update prototypes.
* src/androidgui.h (enum android_ime_operation): Add new
operation to update the selection position.
* src/androidterm.c (android_handle_ime_event): Handle new
operation.
(requestSelectionUpdate): New function.
* src/fileio.c (close_file_unwind_emacs_fd): New function.
(Fcopy_file, union read_non_regular, read_non_regular)
(Finsert_file_contents): Use optimized codepath to insert
Android asset files.
* src/frame.h (enum text_conversion_operation): New operation.
* src/textconv.c (really_request_point_update)
(handle_pending_conversion_events_1, request_point_update): New
functions.
* src/textconv.h: Update prototypes.
This commit is contained in:
Po Lu 2023-03-06 15:30:29 +08:00
parent 31883b8de1
commit c0a6f14f4a
11 changed files with 392 additions and 68 deletions

View file

@ -203,6 +203,7 @@ public static native void performEditorAction (short window,
public static native ExtractedText getExtractedText (short window,
ExtractedTextRequest req,
int flags);
public static native void requestSelectionUpdate (short window);
/* Return the current value of the selection, or -1 upon

View file

@ -573,18 +573,33 @@ else if (child.getVisibility () != GONE)
/* Set a reasonable inputType. */
info.inputType = InputType.TYPE_CLASS_TEXT;
/* If this fails or ANDROID_IC_MODE_NULL was requested, then don't
initialize the input connection. */
if (mode == EmacsService.IC_MODE_NULL)
{
info.inputType = InputType.TYPE_NULL;
return null;
}
/* Obtain the current position of point and set it as the
selection. */
selection = EmacsNative.getSelection (window.handle);
Log.d (TAG, "onCreateInputConnection: current selection is: " + selection);
/* If this fails or ANDROID_IC_MODE_NULL was requested, then don't
initialize the input connection. */
if (mode == EmacsService.IC_MODE_NULL || selection == null)
if (selection != null)
Log.d (TAG, "onCreateInputConnection: current selection is: "
+ selection[0] + ", by " + selection[1]);
else
{
info.inputType = InputType.TYPE_NULL;
return null;
Log.d (TAG, "onCreateInputConnection: current selection could"
+ " not be retrieved.");
/* If the selection could not be obtained, return 0 by 0.
However, ask for the selection position to be updated as
soon as possible. */
selection = new int[] { 0, 0, };
EmacsNative.requestSelectionUpdate (window.handle);
}
if (mode == EmacsService.IC_MODE_ACTION)

View file

@ -412,3 +412,11 @@ AAsset_read (AAsset *asset, void *buffer, size_t size)
return android_asset_read_internal (asset, MIN (size, INT_MAX),
buffer);
}
static off_t
AAsset_seek (AAsset *asset, off_t offset, int whence)
{
/* Java InputStreams don't support seeking at all. */
errno = ESPIPE;
return -1;
}

View file

@ -1568,7 +1568,7 @@ android_close_on_exec (int fd)
contain all assets in the application package. */
int
android_open (const char *filename, int oflag, int mode)
android_open (const char *filename, int oflag, mode_t mode)
{
const char *name;
AAsset *asset;
@ -5971,6 +5971,154 @@ android_set_fullscreen (android_window window, bool fullscreen)
/* External asset management interface. By using functions here
to read and write from files, Emacs can avoid opening a
shared memory file descriptor for each ``asset'' file. */
/* Like android_open. However, return a structure that can
either directly hold an AAsset or a file descriptor.
Value is the structure upon success. Upon failure, value
consists of an uninitialized file descriptor, but its asset
field is set to -1, and errno is set accordingly. */
struct android_fd_or_asset
android_open_asset (const char *filename, int oflag, mode_t mode)
{
const char *name;
struct android_fd_or_asset fd;
AAsset *asset;
/* Initialize FD by setting its asset to an invalid
pointer. */
fd.asset = (void *) -1;
/* See if this is an asset. */
if (asset_manager && (name = android_get_asset_name (filename)))
{
/* Return failure for unsupported flags. */
if (oflag & O_WRONLY || oflag & O_RDWR)
{
errno = EROFS;
return fd;
}
if (oflag & O_DIRECTORY)
{
errno = ENOTSUP;
return fd;
}
/* Now try to open the asset. */
asset = AAssetManager_open (asset_manager, name,
AASSET_MODE_STREAMING);
if (!asset)
{
errno = ENOENT;
return fd;
}
/* Return the asset. */
fd.asset = asset;
return fd;
}
/* If the file is not an asset, fall back to android_open and
get a regular file descriptor. */
fd.fd = android_open (filename, oflag, mode);
if (fd.fd < 1)
return fd;
/* Set fd.asset to NULL, signifying that it is a file
descriptor. */
fd.asset = NULL;
return fd;
}
/* Like android_close. However, it takes a ``file descriptor''
opened using android_open_asset. */
int
android_close_asset (struct android_fd_or_asset asset)
{
if (!asset.asset)
return android_close (asset.fd);
AAsset_close (asset.asset);
return 0;
}
/* Like `emacs_read_quit'. However, it handles file descriptors
opened using `android_open_asset' as well. */
ssize_t
android_asset_read_quit (struct android_fd_or_asset asset,
void *buffer, size_t size)
{
if (!asset.asset)
return emacs_read_quit (asset.fd, buffer, size);
/* It doesn't seem possible to quit from inside AAsset_read,
sadly. */
return AAsset_read (asset.asset, buffer, size);
}
/* Like `read'. However, it handles file descriptors opened
using `android_open_asset' as well. */
ssize_t
android_asset_read (struct android_fd_or_asset asset,
void *buffer, size_t size)
{
if (!asset.asset)
return read (asset.fd, buffer, size);
/* It doesn't seem possible to quit from inside AAsset_read,
sadly. */
return AAsset_read (asset.asset, buffer, size);
}
/* Like `lseek', but it handles ``file descriptors'' opened with
android_open_asset. */
off_t
android_asset_lseek (struct android_fd_or_asset asset, off_t off,
int whence)
{
if (!asset.asset)
return lseek (asset.fd, off, whence);
return AAsset_seek (asset.asset, off, whence);
}
/* Like `fstat'. */
int
android_asset_fstat (struct android_fd_or_asset asset,
struct stat *statb)
{
if (!asset.asset)
return fstat (asset.fd, statb);
/* Clear statb. */
memset (statb, 0, sizeof *statb);
/* Set the mode. */
statb->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
/* Owned by root. */
statb->st_uid = 0;
statb->st_gid = 0;
/* Size of the file. */
statb->st_size = AAsset_getLength (asset.asset);
return 0;
}
#else /* ANDROID_STUBIFY */
/* X emulation functions for Android. */

View file

@ -46,7 +46,7 @@ extern int android_emacs_init (int, char **, char *);
extern int android_select (int, fd_set *, fd_set *, fd_set *,
struct timespec *);
extern int android_open (const char *, int, int);
extern int android_open (const char *, int, mode_t);
extern char *android_user_full_name (struct passwd *);
extern int android_fstat (int, struct stat *);
extern int android_fstatat (int, const char *restrict,
@ -107,6 +107,30 @@ extern void android_closedir (struct android_dir *);
/* External asset manager interface. */
struct android_fd_or_asset
{
/* The file descriptor. */
int fd;
/* The asset. If set, FD is not a real file descriptor. */
void *asset;
};
extern struct android_fd_or_asset android_open_asset (const char *,
int, mode_t);
extern int android_close_asset (struct android_fd_or_asset);
extern ssize_t android_asset_read_quit (struct android_fd_or_asset,
void *, size_t);
extern ssize_t android_asset_read (struct android_fd_or_asset,
void *, size_t);
extern off_t android_asset_lseek (struct android_fd_or_asset, off_t, int);
extern int android_asset_fstat (struct android_fd_or_asset,
struct stat *);
/* Very miscellaneous functions. */
struct android_battery_state

View file

@ -430,6 +430,7 @@ enum android_ime_operation
ANDROID_IME_SET_POINT,
ANDROID_IME_START_BATCH_EDIT,
ANDROID_IME_END_BATCH_EDIT,
ANDROID_IME_REQUEST_SELECTION_UPDATE,
};
struct android_ime_event

View file

@ -630,6 +630,10 @@ android_handle_ime_event (union android_event *event, struct frame *f)
case ANDROID_IME_END_BATCH_EDIT:
end_batch_edit (f, event->ime.counter);
break;
case ANDROID_IME_REQUEST_SELECTION_UPDATE:
request_point_update (f, event->ime.counter);
break;
}
}
@ -5169,6 +5173,28 @@ NATIVE_NAME (getSelectedText) (JNIEnv *env, jobject object,
return string;
}
JNIEXPORT void JNICALL
NATIVE_NAME (requestSelectionUpdate) (JNIEnv *env, jobject object,
jshort window)
{
JNI_STACK_ALIGNMENT_PROLOGUE;
union android_event event;
event.ime.type = ANDROID_INPUT_METHOD;
event.ime.serial = ++event_serial;
event.ime.window = window;
event.ime.operation = ANDROID_IME_REQUEST_SELECTION_UPDATE;
event.ime.start = 0;
event.ime.end = 0;
event.ime.length = 0;
event.ime.position = 0;
event.ime.text = NULL;
event.ime.counter = ++edit_counter;
android_write_event (&event);
}
#ifdef __clang__
#pragma clang diagnostic pop
#else

View file

@ -113,6 +113,37 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "commands.h"
#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY
/* Type describing a file descriptor used by functions such as
`insert-file-contents'. */
typedef int emacs_fd;
/* Function used to read and open from such a file descriptor. */
#define emacs_fd_open emacs_open
#define emacs_fd_close emacs_close
#define emacs_fd_read emacs_read_quit
#define emacs_fd_lseek lseek
#define emacs_fd_fstat sys_fstat
#define emacs_fd_valid_p(fd) ((fd) >= 0)
#define emacs_fd_to_int(fds) (fds)
#else /* HAVE_ANDROID && !defined ANDROID_STUBIFY */
typedef struct android_fd_or_asset emacs_fd;
#define emacs_fd_open android_open_asset
#define emacs_fd_close android_close_asset
#define emacs_fd_read android_asset_read_quit
#define emacs_fd_lseek android_asset_lseek
#define emacs_fd_fstat android_asset_fstat
#define emacs_fd_valid_p(fd) ((fd).asset != ((void *) -1))
#define emacs_fd_to_int(fds) ((fds).asset ? -1 : (fds).fd)
#endif /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
/* True during writing of auto-save files. */
static bool auto_saving;
@ -299,6 +330,15 @@ close_file_unwind (int fd)
emacs_close (fd);
}
static void
close_file_unwind_emacs_fd (void *ptr)
{
emacs_fd *fd;
fd = ptr;
emacs_fd_close (*fd);
}
void
fclose_unwind (void *arg)
{
@ -2221,7 +2261,8 @@ permissions. */)
#else
bool already_exists = false;
mode_t new_mask;
int ifd, ofd;
emacs_fd ifd;
int ofd;
struct stat st;
#endif
@ -2265,22 +2306,24 @@ permissions. */)
report_file_error ("Copying permissions to", newname);
}
#else /* not WINDOWSNT */
ifd = emacs_open (SSDATA (encoded_file), O_RDONLY | O_NONBLOCK, 0);
ifd = emacs_fd_open (SSDATA (encoded_file), O_RDONLY | O_NONBLOCK, 0);
if (ifd < 0)
if (!emacs_fd_valid_p (ifd))
report_file_error ("Opening input file", file);
record_unwind_protect_int (close_file_unwind, ifd);
record_unwind_protect_ptr (close_file_unwind_emacs_fd, &ifd);
if (sys_fstat (ifd, &st) != 0)
if (emacs_fd_fstat (ifd, &st) != 0)
report_file_error ("Input file status", file);
if (!NILP (preserve_permissions))
{
#if HAVE_LIBSELINUX
if (is_selinux_enabled ())
if (is_selinux_enabled ()
&& emacs_fd_to_int (ifd) != -1)
{
conlength = fgetfilecon (ifd, &con);
conlength = fgetfilecon (emacs_fd_to_int (ifd),
&con);
if (conlength == -1)
report_file_error ("Doing fgetfilecon", file);
}
@ -2329,7 +2372,8 @@ permissions. */)
maybe_quit ();
if (clone_file (ofd, ifd))
if (emacs_fd_to_int (ifd) != -1
&& clone_file (ofd, emacs_fd_to_int (ifd)))
newsize = st.st_size;
else
{
@ -2337,30 +2381,38 @@ permissions. */)
ssize_t copied;
#ifndef MSDOS
for (newsize = 0; newsize < insize; newsize += copied)
newsize = 0;
if (emacs_fd_to_int (ifd) != -1)
{
/* Copy at most COPY_MAX bytes at a time; this is min
(PTRDIFF_MAX, SIZE_MAX) truncated to a value that is
surely aligned well. */
ssize_t ssize_max = TYPE_MAXIMUM (ssize_t);
ptrdiff_t copy_max = min (ssize_max, SIZE_MAX) >> 30 << 30;
off_t intail = insize - newsize;
ptrdiff_t len = min (intail, copy_max);
copied = copy_file_range (ifd, NULL, ofd, NULL, len, 0);
if (copied <= 0)
break;
maybe_quit ();
for (; newsize < insize; newsize += copied)
{
/* Copy at most COPY_MAX bytes at a time; this is min
(PTRDIFF_MAX, SIZE_MAX) truncated to a value that is
surely aligned well. */
ssize_t ssize_max = TYPE_MAXIMUM (ssize_t);
ptrdiff_t copy_max = min (ssize_max, SIZE_MAX) >> 30 << 30;
off_t intail = insize - newsize;
ptrdiff_t len = min (intail, copy_max);
copied = copy_file_range (emacs_fd_to_int (ifd), NULL,
ofd, NULL, len, 0);
if (copied <= 0)
break;
maybe_quit ();
}
}
#endif /* MSDOS */
/* Fall back on read+write if copy_file_range failed, or if the
input is empty and so could be a /proc file. read+write will
either succeed, or report an error more precisely than
copy_file_range would. */
input is empty and so could be a /proc file, or if ifd is an
invention of android.c. read+write will either succeed, or
report an error more precisely than copy_file_range
would. */
if (newsize != insize || insize == 0)
{
char buf[MAX_ALLOCA];
for (; (copied = emacs_read_quit (ifd, buf, sizeof buf));
for (; (copied = emacs_fd_read (ifd, buf, sizeof buf));
newsize += copied)
{
if (copied < 0)
@ -2408,8 +2460,10 @@ permissions. */)
}
}
switch (!NILP (preserve_permissions)
? qcopy_acl (SSDATA (encoded_file), ifd,
switch ((!NILP (preserve_permissions)
&& emacs_fd_to_int (ifd) != -1)
? qcopy_acl (SSDATA (encoded_file),
emacs_fd_to_int (ifd),
SSDATA (encoded_newname), ofd,
preserved_permissions)
: (already_exists
@ -2449,7 +2503,9 @@ permissions. */)
if (emacs_close (ofd) < 0)
report_file_error ("Write error", newname);
emacs_close (ifd);
/* Note that ifd is not closed twice because unwind_protects are
discarded at the end of this function. */
emacs_fd_close (ifd);
#ifdef MSDOS
/* In DJGPP v2.0 and later, fstat usually returns true file mode bits,
@ -3826,7 +3882,7 @@ union read_non_regular
{
struct
{
int fd;
emacs_fd fd;
ptrdiff_t inserted, trytry;
} s;
GCALIGNED_UNION_MEMBER
@ -3837,10 +3893,10 @@ static Lisp_Object
read_non_regular (Lisp_Object state)
{
union read_non_regular *data = XFIXNUMPTR (state);
int nbytes = emacs_read_quit (data->s.fd,
((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
+ data->s.inserted),
data->s.trytry);
int nbytes = emacs_fd_read (data->s.fd,
((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
+ data->s.inserted),
data->s.trytry);
return make_fixnum (nbytes);
}
@ -3989,7 +4045,7 @@ by calling `format-decode', which see. */)
{
struct stat st;
struct timespec mtime;
int fd;
emacs_fd fd;
ptrdiff_t inserted = 0;
int unprocessed;
specpdl_ref count = SPECPDL_INDEX ();
@ -4067,8 +4123,8 @@ by calling `format-decode', which see. */)
orig_filename = filename;
filename = ENCODE_FILE (filename);
fd = emacs_open (SSDATA (filename), O_RDONLY, 0);
if (fd < 0)
fd = emacs_fd_open (SSDATA (filename), O_RDONLY, 0);
if (!emacs_fd_valid_p (fd))
{
save_errno = errno;
if (NILP (visit))
@ -4086,7 +4142,7 @@ by calling `format-decode', which see. */)
}
specpdl_ref fd_index = SPECPDL_INDEX ();
record_unwind_protect_int (close_file_unwind, fd);
record_unwind_protect_ptr (close_file_unwind_emacs_fd, &fd);
/* Replacement should preserve point as it preserves markers. */
if (!NILP (replace))
@ -4096,7 +4152,7 @@ by calling `format-decode', which see. */)
XCAR (XCAR (window_markers)));
}
if (sys_fstat (fd, &st) != 0)
if (emacs_fd_fstat (fd, &st) != 0)
report_file_error ("Input file status", orig_filename);
mtime = get_stat_mtime (&st);
@ -4117,7 +4173,7 @@ by calling `format-decode', which see. */)
xsignal2 (Qfile_error,
build_string ("not a regular file"), orig_filename);
seekable = lseek (fd, 0, SEEK_CUR) < 0;
seekable = emacs_fd_lseek (fd, 0, SEEK_CUR) < 0;
if (!NILP (beg) && !seekable)
xsignal2 (Qfile_error,
build_string ("cannot use a start position in a non-seekable file/device"),
@ -4196,17 +4252,17 @@ by calling `format-decode', which see. */)
int nread;
if (st.st_size <= (1024 * 4))
nread = emacs_read_quit (fd, read_buf, 1024 * 4);
nread = emacs_fd_read (fd, read_buf, 1024 * 4);
else
{
nread = emacs_read_quit (fd, read_buf, 1024);
nread = emacs_fd_read (fd, read_buf, 1024);
if (nread == 1024)
{
int ntail;
if (lseek (fd, st.st_size - 1024 * 3, SEEK_CUR) < 0)
if (emacs_fd_lseek (fd, st.st_size - 1024 * 3, SEEK_CUR) < 0)
report_file_error ("Setting file position",
orig_filename);
ntail = emacs_read_quit (fd, read_buf + nread, 1024 * 3);
ntail = emacs_fd_read (fd, read_buf + nread, 1024 * 3);
nread = ntail < 0 ? ntail : nread + ntail;
}
}
@ -4247,7 +4303,7 @@ by calling `format-decode', which see. */)
specpdl_ptr--;
/* Rewind the file for the actual read done later. */
if (lseek (fd, 0, SEEK_SET) < 0)
if (emacs_fd_lseek (fd, 0, SEEK_SET) < 0)
report_file_error ("Setting file position", orig_filename);
}
}
@ -4306,7 +4362,7 @@ by calling `format-decode', which see. */)
if (beg_offset != 0)
{
if (lseek (fd, beg_offset, SEEK_SET) < 0)
if (emacs_fd_lseek (fd, beg_offset, SEEK_SET) < 0)
report_file_error ("Setting file position", orig_filename);
}
@ -4314,7 +4370,7 @@ by calling `format-decode', which see. */)
match the text at the beginning of the buffer. */
while (true)
{
int nread = emacs_read_quit (fd, read_buf, sizeof read_buf);
int nread = emacs_fd_read (fd, read_buf, sizeof read_buf);
if (nread < 0)
report_file_error ("Read error", orig_filename);
else if (nread == 0)
@ -4349,7 +4405,7 @@ by calling `format-decode', which see. */)
there's no need to replace anything. */
if (same_at_start - BEGV_BYTE == end_offset - beg_offset)
{
emacs_close (fd);
emacs_fd_close (fd);
clear_unwind_protect (fd_index);
/* Truncate the buffer to the size of the file. */
@ -4372,14 +4428,14 @@ by calling `format-decode', which see. */)
break;
/* How much can we scan in the next step? */
trial = min (curpos, sizeof read_buf);
if (lseek (fd, curpos - trial, SEEK_SET) < 0)
if (emacs_fd_lseek (fd, curpos - trial, SEEK_SET) < 0)
report_file_error ("Setting file position", orig_filename);
total_read = nread = 0;
while (total_read < trial)
{
nread = emacs_read_quit (fd, read_buf + total_read,
trial - total_read);
nread = emacs_fd_read (fd, read_buf + total_read,
trial - total_read);
if (nread < 0)
report_file_error ("Read error", orig_filename);
else if (nread == 0)
@ -4499,7 +4555,7 @@ by calling `format-decode', which see. */)
/* First read the whole file, performing code conversion into
CONVERSION_BUFFER. */
if (lseek (fd, beg_offset, SEEK_SET) < 0)
if (emacs_fd_lseek (fd, beg_offset, SEEK_SET) < 0)
report_file_error ("Setting file position", orig_filename);
inserted = 0; /* Bytes put into CONVERSION_BUFFER so far. */
@ -4510,8 +4566,8 @@ by calling `format-decode', which see. */)
/* Read at most READ_BUF_SIZE bytes at a time, to allow
quitting while reading a huge file. */
this = emacs_read_quit (fd, read_buf + unprocessed,
READ_BUF_SIZE - unprocessed);
this = emacs_fd_read (fd, read_buf + unprocessed,
READ_BUF_SIZE - unprocessed);
if (this <= 0)
break;
@ -4526,7 +4582,7 @@ by calling `format-decode', which see. */)
if (this < 0)
report_file_error ("Read error", orig_filename);
emacs_close (fd);
emacs_fd_close (fd);
clear_unwind_protect (fd_index);
if (unprocessed > 0)
@ -4673,7 +4729,7 @@ by calling `format-decode', which see. */)
if (beg_offset != 0 || !NILP (replace))
{
if (lseek (fd, beg_offset, SEEK_SET) < 0)
if (emacs_fd_lseek (fd, beg_offset, SEEK_SET) < 0)
report_file_error ("Setting file position", orig_filename);
}
@ -4726,10 +4782,10 @@ by calling `format-decode', which see. */)
/* Allow quitting out of the actual I/O. We don't make text
part of the buffer until all the reading is done, so a C-g
here doesn't do any harm. */
this = emacs_read_quit (fd,
((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
+ inserted),
trytry);
this = emacs_fd_read (fd,
((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
+ inserted),
trytry);
}
if (this <= 0)
@ -4756,7 +4812,7 @@ by calling `format-decode', which see. */)
else
Fset (Qdeactivate_mark, Qt);
emacs_close (fd);
emacs_fd_close (fd);
clear_unwind_protect (fd_index);
if (read_quit < 0)

View file

@ -88,6 +88,7 @@ enum text_conversion_operation
TEXTCONV_SET_COMPOSING_REGION,
TEXTCONV_SET_POINT_AND_MARK,
TEXTCONV_DELETE_SURROUNDING_TEXT,
TEXTCONV_REQUEST_POINT_UPDATE,
};
/* Structure describing a single edit being performed by the input

View file

@ -957,6 +957,26 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left,
unbind_to (count, Qnil);
}
/* Update the interface with F's new point and mark. If a batch edit
is in progress, schedule the update for when it finishes
instead. */
static void
really_request_point_update (struct frame *f)
{
/* If F's old selected window is no longer live, fail. */
if (!WINDOW_LIVE_P (f->old_selected_window))
return;
if (f->conversion.batch_edit_count > 0)
f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
else if (text_interface && text_interface->point_changed)
text_interface->point_changed (f,
XWINDOW (f->old_selected_window),
current_buffer);
}
/* Set point in F to POSITION. If MARK is not POSITION, activate the
mark and set MARK to that as well.
@ -1163,6 +1183,10 @@ handle_pending_conversion_events_1 (struct frame *f,
really_delete_surrounding_text (f, XFIXNUM (XCAR (data)),
XFIXNUM (XCDR (data)));
break;
case TEXTCONV_REQUEST_POINT_UPDATE:
really_request_point_update (f);
break;
}
/* Signal success. */
@ -1457,6 +1481,25 @@ delete_surrounding_text (struct frame *f, ptrdiff_t left,
input_pending = true;
}
/* Request an immediate call to INTERFACE->point_changed with the new
details of F's region unless a batch edit is in progress. */
void
request_point_update (struct frame *f, unsigned long counter)
{
struct text_conversion_action *action, **last;
action = xmalloc (sizeof *action);
action->operation = TEXTCONV_REQUEST_POINT_UPDATE;
action->data = Qnil;
action->next = NULL;
action->counter = counter;
for (last = &f->conversion.actions; *last; last = &(*last)->next)
;;
*last = action;
input_pending = true;
}
/* Return N characters of text around point in F's old selected
window.

View file

@ -138,6 +138,7 @@ extern void textconv_set_point_and_mark (struct frame *, ptrdiff_t,
ptrdiff_t, unsigned long);
extern void delete_surrounding_text (struct frame *, ptrdiff_t,
ptrdiff_t, unsigned long);
extern void request_point_update (struct frame *, unsigned long);
extern char *get_extracted_text (struct frame *, ptrdiff_t, ptrdiff_t *,
ptrdiff_t *, ptrdiff_t *, ptrdiff_t *);
extern bool conversion_disabled_p (void);