emacs-diffs
[Top][All Lists]
Advanced

[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);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]