From: Po Lu Date: Mon, 17 Jun 2024 09:43:24 +0000 (+0800) Subject: Reinforce bitmap reconfiguration on Android X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=afaeb15948770ad938fadf27e353fb6d4a339dd5;p=emacs.git Reinforce bitmap reconfiguration on Android * java/org/gnu/emacs/EmacsView.java (EmacsView) : New field in which to record whether the back buffer has received contents beyond those present at the last buffer swap. : 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) --- 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. */ - - 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 (); } diff --git a/src/androidterm.c b/src/androidterm.c index 730c832bb5b..837cc50bfa1 100644 --- a/src/androidterm.c +++ b/src/androidterm.c @@ -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;