summaryrefslogtreecommitdiff
path: root/java/org/gnu/emacs/EmacsView.java
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2024-06-17 17:43:24 +0800
committerPo Lu <luangruo@yahoo.com>2024-06-17 17:45:48 +0800
commit82f0014273193d27c71a1fcb9be778c85cfa5e65 (patch)
tree62792993251680cebe47bf1d50775a1f4e8a8d46 /java/org/gnu/emacs/EmacsView.java
parent6aa5068ac71cb1b8e46c299138f99fea44319146 (diff)
Reinforce bitmap reconfiguration on Android
* 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.
Diffstat (limited to 'java/org/gnu/emacs/EmacsView.java')
-rw-r--r--java/org/gnu/emacs/EmacsView.java159
1 files changed, 92 insertions, 67 deletions
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java
index 78d1ef785da..2ea54217837 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -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. */
+ /* 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;
-
- /* 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 ();
+ /* 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;
+ 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 ();
}