[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/android c0a6f14f4a5 1/2: Update Android port
From: |
Po Lu |
Subject: |
feature/android c0a6f14f4a5 1/2: Update Android port |
Date: |
Mon, 6 Mar 2023 03:06:59 -0500 (EST) |
branch: feature/android
commit c0a6f14f4a5069c28b7c90247546f1c5889a6d21
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
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.
---
java/org/gnu/emacs/EmacsNative.java | 1 +
java/org/gnu/emacs/EmacsView.java | 29 ++++--
src/android-asset.h | 8 ++
src/android.c | 150 ++++++++++++++++++++++++++++++-
src/android.h | 26 +++++-
src/androidgui.h | 1 +
src/androidterm.c | 26 ++++++
src/fileio.c | 174 ++++++++++++++++++++++++------------
src/frame.h | 1 +
src/textconv.c | 43 +++++++++
src/textconv.h | 1 +
11 files changed, 392 insertions(+), 68 deletions(-)
diff --git a/java/org/gnu/emacs/EmacsNative.java
b/java/org/gnu/emacs/EmacsNative.java
index 38370d60727..8e626b9534b 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -203,6 +203,7 @@ public final class EmacsNative
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
diff --git a/java/org/gnu/emacs/EmacsView.java
b/java/org/gnu/emacs/EmacsView.java
index f751eaaa3e4..90a2c912a5a 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -573,20 +573,35 @@ public final class EmacsView extends ViewGroup
/* Set a reasonable inputType. */
info.inputType = InputType.TYPE_CLASS_TEXT;
- /* 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 (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);
+
+ if (selection != null)
+ Log.d (TAG, "onCreateInputConnection: current selection is: "
+ + selection[0] + ", by " + selection[1]);
+ else
+ {
+ 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)
info.imeOptions |= EditorInfo.IME_ACTION_DONE;
diff --git a/src/android-asset.h b/src/android-asset.h
index 3b2f8105865..4fb309f1645 100644
--- a/src/android-asset.h
+++ b/src/android-asset.h
@@ -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;
+}
diff --git a/src/android.c b/src/android.c
index 9fc4143602c..f49249de09f 100644
--- a/src/android.c
+++ b/src/android.c
@@ -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. */
diff --git a/src/android.h b/src/android.h
index 95206b77979..ed0089ad94e 100644
--- a/src/android.h
+++ b/src/android.h
@@ -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
diff --git a/src/androidgui.h b/src/androidgui.h
index 6514c78d289..e1c80a71a59 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -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
diff --git a/src/androidterm.c b/src/androidterm.c
index a6709ac8169..0cc2b35099c 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -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
diff --git a/src/fileio.c b/src/fileio.c
index 7bc9800aaf8..ae244b8f85a 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -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)
diff --git a/src/frame.h b/src/frame.h
index ca4cca17d74..e2900d1c15b 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -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
diff --git a/src/textconv.c b/src/textconv.c
index 91d386d4c61..c1ce83b1d7d 100644
--- a/src/textconv.c
+++ b/src/textconv.c
@@ -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.
diff --git a/src/textconv.h b/src/textconv.h
index 16d13deb092..9bc9e7d9bd1 100644
--- a/src/textconv.h
+++ b/src/textconv.h
@@ -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);