]> git.eshelyaron.com Git - emacs.git/commitdiff
Reinforce bitmap reconfiguration on Android
authorPo Lu <luangruo@yahoo.com>
Mon, 17 Jun 2024 09:43:24 +0000 (17:43 +0800)
committerEshel Yaron <me@eshelyaron.com>
Wed, 19 Jun 2024 08:40:34 +0000 (10:40 +0200)
* java/org/gnu/emacs/EmacsView.java (EmacsView) <unswapped>: New
field in which to record whether the back buffer has received
contents beyond those present at the last buffer swap.
<dimensionsLock>: Delete field.
(onAttachedToWindow, onLayout, handleDirtyBitmap)
(prepareForLayout): Rather, synchronize window dimensions with
the view.
(getCanvas, getBitmap): Do not reconfigure the back buffer
bitmap if such outstanding data exists.
(postSwapBuffers): New function.
(swapBuffers): If such outstanding data exists and the back
bufferis pending reconfiguration, recreate the back buffer and
report exposure.

* src/androidterm.c (handle_one_android_event): Fix indentation.

(cherry picked from commit 82f0014273193d27c71a1fcb9be778c85cfa5e65)

java/org/gnu/emacs/EmacsView.java
src/androidterm.c

index 78d1ef785da5ae95ab7f934de42d293763e88f64..2ea54217837466cb30ec5666a541e31dfe3145e5 100644 (file)
@@ -88,15 +88,15 @@ public final class EmacsView extends ViewGroup
   /* Whether or not a popup is active.  */
   private boolean popupActive;
 
+  /* Whether the back buffer has been updated since the last swap.  */
+  private boolean unswapped;
+
   /* The current context menu.  */
   private EmacsContextMenu contextMenu;
 
   /* The last measured width and height.  */
   private int measuredWidth, measuredHeight;
 
-  /* Object acting as a lock for those values.  */
-  private Object dimensionsLock;
-
   /* The serial of the last clip rectangle change.  */
   private long lastClipSerial;
 
@@ -153,9 +153,6 @@ public final class EmacsView extends ViewGroup
 
     /* Add this view as its own global layout listener.  */
     getViewTreeObserver ().addOnGlobalLayoutListener (this);
-
-    /* Create an object used as a lock.  */
-    this.dimensionsLock = new Object ();
   }
 
   private void
@@ -164,12 +161,9 @@ public final class EmacsView extends ViewGroup
     Bitmap oldBitmap;
     int measuredWidth, measuredHeight;
 
-    synchronized (dimensionsLock)
-      {
-       /* Load measuredWidth and measuredHeight.  */
-       measuredWidth = this.measuredWidth;
-       measuredHeight = this.measuredHeight;
-      }
+    /* Load measuredWidth and measuredHeight.  */
+    measuredWidth = this.measuredWidth;
+    measuredHeight = this.measuredHeight;
 
     if (measuredWidth == 0 || measuredHeight == 0)
       return;
@@ -231,8 +225,14 @@ public final class EmacsView extends ViewGroup
   public synchronized Bitmap
   getBitmap ()
   {
-    if (bitmapDirty || bitmap == null)
+    /* Never alter the bitmap if modifications have been received that
+       are still to be copied to the front buffer, as this indicates
+       that redisplay is in the process of copying matrix contents to
+       the glass, and such events as generally prompt a complete
+       regeneration of the frame's contents might not be processed.  */
+    if (!unswapped && (bitmapDirty || bitmap == null))
       handleDirtyBitmap ();
+    unswapped = true;
 
     return bitmap;
   }
@@ -242,11 +242,12 @@ public final class EmacsView extends ViewGroup
   {
     int i;
 
-    if (bitmapDirty || bitmap == null)
+    if (!unswapped && (bitmapDirty || bitmap == null))
       handleDirtyBitmap ();
 
     if (canvas == null)
       return null;
+    unswapped = true;
 
     /* Update clip rectangles if necessary.  */
     if (gc.clipRectID != lastClipSerial)
@@ -266,14 +267,11 @@ public final class EmacsView extends ViewGroup
     return canvas;
   }
 
-  public void
+  public synchronized void
   prepareForLayout (int wantedWidth, int wantedHeight)
   {
-    synchronized (dimensionsLock)
-      {
-       measuredWidth = wantedWidth;
-       measuredHeight = wantedWidth;
-      }
+    measuredWidth = wantedWidth;
+    measuredHeight = wantedWidth;
   }
 
   @Override
@@ -329,8 +327,8 @@ public final class EmacsView extends ViewGroup
   }
 
   /* Note that the monitor lock for the window must never be held from
-     within the lock for the view, because the window also locks the
-     other way around.  */
+     within that for the view, because the window acquires locks in the
+     opposite direction.  */
 
   @Override
   protected void
@@ -346,7 +344,7 @@ public final class EmacsView extends ViewGroup
     count = getChildCount ();
     needExpose = false;
 
-    synchronized (dimensionsLock)
+    synchronized (this)
       {
        /* Load measuredWidth and measuredHeight.  */
        oldMeasuredWidth = measuredWidth;
@@ -355,48 +353,48 @@ public final class EmacsView extends ViewGroup
        /* Set measuredWidth and measuredHeight.  */
        measuredWidth = right - left;
        measuredHeight = bottom - top;
-      }
 
-    /* If oldMeasuredHeight or oldMeasuredWidth are wrong, set changed
-       to true as well.  */
+       /* If oldMeasuredHeight or oldMeasuredWidth are wrong, set
+          changed to true as well.  */
 
-    if (right - left != oldMeasuredWidth
-       || bottom - top != oldMeasuredHeight)
-      changed = true;
+       if (right - left != oldMeasuredWidth
+           || bottom - top != oldMeasuredHeight)
+         changed = true;
 
-    /* Dirty the back buffer if the layout change resulted in the view
-       being resized.  */
-
-    if (changed)
-      {
-       /* Expose the window upon a change in the view's size that
-          prompts the creation of a new bitmap.  */
-       explicitlyDirtyBitmap ();
-       needExpose = true;
+       /* Dirty the back buffer if the layout change resulted in the view
+          being resized.  */
 
-       /* This might return NULL if this view is not attached.  */
-       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
+       if (changed)
          {
-           /* If a toplevel view is focused and isCurrentlyTextEditor
-              is enabled when the IME is hidden, clear
-              isCurrentlyTextEditor so it isn't shown again if the
-              user dismisses Emacs before returning.  */
-           rootWindowInsets = getRootWindowInsets ();
-
-           if (isCurrentlyTextEditor
-               && rootWindowInsets != null
-               && isAttachedToWindow
-               && !rootWindowInsets.isVisible (WindowInsets.Type.ime ())
-               /* N.B. that the keyboard is dismissed during gesture
-                  navigation under Android 30, but the system is
-                  quite temperamental regarding whether the window is
-                  focused at that point.  Ideally
-                  isCurrentlyTextEditor shouldn't be reset in that
-                  case, but detecting that situation appears to be
-                  impossible.  Sigh.  */
-               && (window == EmacsActivity.focusedWindow
-                   && hasWindowFocus ()))
-             isCurrentlyTextEditor = false;
+           /* Expose the window upon a change in the view's size that
+              prompts the creation of a new bitmap.  */
+           bitmapDirty = needExpose = true;
+
+           /* This might return NULL if this view is not attached.  */
+           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
+             {
+               /* If a toplevel view is focused and
+                  isCurrentlyTextEditor is enabled when the IME is
+                  hidden, clear isCurrentlyTextEditor so it isn't shown
+                  again if the user dismisses Emacs before
+                  returning.  */
+               rootWindowInsets = getRootWindowInsets ();
+
+               if (isCurrentlyTextEditor
+                   && rootWindowInsets != null
+                   && isAttachedToWindow
+                   && !rootWindowInsets.isVisible (WindowInsets.Type.ime ())
+                   /* N.B. that the keyboard is dismissed during
+                      gesture navigation under Android 30, but the
+                      system is quite temperamental regarding whether
+                      the window is focused at that point.  Ideally
+                      isCurrentlyTextEditor shouldn't be reset in that
+                      case, but detecting that situation appears to be
+                      impossible.  Sigh.  */
+                   && (window == EmacsActivity.focusedWindow
+                       && hasWindowFocus ()))
+                 isCurrentlyTextEditor = false;
+             }
          }
       }
 
@@ -449,6 +447,33 @@ public final class EmacsView extends ViewGroup
     damageRegion.op (left, top, right, bottom, Region.Op.UNION);
   }
 
+  /* Complete deferred reconfiguration of the front buffer after a
+     buffer swap completes, and generate Expose events for the same.  */
+
+  private void
+  postSwapBuffers ()
+  {
+    if (!unswapped)
+      return;
+
+    unswapped = false;
+
+    /* If the bitmap is dirty, reconfigure the bitmap and
+       generate an Expose event to produce its contents.  */
+
+    if ((bitmapDirty || bitmap == null)
+       /* Do not generate Expose events if handleDirtyBitmap will
+          not create a valid bitmap, or the consequent buffer swap
+          will produce another event, ad infinitum.  */
+       && isAttachedToWindow && measuredWidth != 0
+       && measuredHeight != 0)
+      {
+       handleDirtyBitmap ();
+       EmacsNative.sendExpose (this.window.handle, 0, 0,
+                               measuredWidth, measuredHeight);
+      }
+  }
+
   /* This method is called from both the UI thread and the Emacs
      thread.  */
 
@@ -467,7 +492,10 @@ public final class EmacsView extends ViewGroup
     /* Now see if there is a damage region.  */
 
     if (damageRegion.isEmpty ())
-      return;
+      {
+       postSwapBuffers ();
+       return;
+      }
 
     /* And extract and clear the damage region.  */
 
@@ -479,6 +507,7 @@ public final class EmacsView extends ViewGroup
        /* Transfer the bitmap to the surface view, then invalidate
           it.  */
        surfaceView.setBitmap (bitmap, damageRect);
+       postSwapBuffers ();
       }
   }
 
@@ -758,13 +787,9 @@ public final class EmacsView extends ViewGroup
        was called.  */
     bitmapDirty = true;
 
-    synchronized (dimensionsLock)
-      {
-       /* Now expose the view contents again.  */
-       EmacsNative.sendExpose (this.window.handle, 0, 0,
-                               measuredWidth, measuredHeight);
-      }
-
+    /* Now expose the view contents again.  */
+    EmacsNative.sendExpose (this.window.handle, 0, 0,
+                           measuredWidth, measuredHeight);
     super.onAttachedToWindow ();
   }
 
index 730c832bb5b9449e9af9bc8cbe1d21c95bff84aa..837cc50bfa14ddfa201cfe7f2b25e9016619a6f8 100644 (file)
@@ -926,11 +926,11 @@ handle_one_android_event (struct android_display_info *dpyinfo,
            XSETFRAME (inev.ie.frame_or_window, f);
          }
 
-      if (f && FRAME_OUTPUT_DATA (f)->need_cursor_updates)
-       {
-         w = XWINDOW (f->selected_window);
-         android_set_preeditarea (w, w->cursor.x, w->cursor.y);
-       }
+       if (f && FRAME_OUTPUT_DATA (f)->need_cursor_updates)
+         {
+           w = XWINDOW (f->selected_window);
+           android_set_preeditarea (w, w->cursor.x, w->cursor.y);
+         }
       }
 
       goto OTHER;