From: Po Lu Date: Mon, 6 Mar 2023 07:30:29 +0000 (+0800) Subject: Update Android port X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=c0a6f14f4a5069c28b7c90247546f1c5889a6d21;p=emacs.git 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. --- 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 . */ #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);