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.
This commit is contained in:
parent
6aa5068ac7
commit
82f0014273
2 changed files with 97 additions and 72 deletions
|
@ -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 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
|
|||
}
|
||||
|
||||
/* 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 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
|
|||
count = getChildCount ();
|
||||
needExpose = false;
|
||||
|
||||
synchronized (dimensionsLock)
|
||||
synchronized (this)
|
||||
{
|
||||
/* Load measuredWidth and measuredHeight. */
|
||||
oldMeasuredWidth = measuredWidth;
|
||||
|
@ -355,48 +353,48 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
|
|||
/* 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;
|
||||
|
||||
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;
|
||||
/* 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 @@ else if (child.getVisibility () != GONE)
|
|||
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 @@ else if (child.getVisibility () != GONE)
|
|||
/* 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 @@ else if (child.getVisibility () != GONE)
|
|||
/* Transfer the bitmap to the surface view, then invalidate
|
||||
it. */
|
||||
surfaceView.setBitmap (bitmap, damageRect);
|
||||
postSwapBuffers ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -758,13 +787,9 @@ else if (child.getVisibility () != GONE)
|
|||
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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue