Skip to content

Commit 82f0014

Browse files
author
Po Lu
committed
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.
1 parent 6aa5068 commit 82f0014

File tree

2 files changed

+98
-73
lines changed

2 files changed

+98
-73
lines changed

java/org/gnu/emacs/EmacsView.java

Lines changed: 93 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,15 @@ public final class EmacsView extends ViewGroup
8888
/* Whether or not a popup is active. */
8989
private boolean popupActive;
9090

91+
/* Whether the back buffer has been updated since the last swap. */
92+
private boolean unswapped;
93+
9194
/* The current context menu. */
9295
private EmacsContextMenu contextMenu;
9396

9497
/* The last measured width and height. */
9598
private int measuredWidth, measuredHeight;
9699

97-
/* Object acting as a lock for those values. */
98-
private Object dimensionsLock;
99-
100100
/* The serial of the last clip rectangle change. */
101101
private long lastClipSerial;
102102

@@ -153,9 +153,6 @@ public final class EmacsView extends ViewGroup
153153

154154
/* Add this view as its own global layout listener. */
155155
getViewTreeObserver ().addOnGlobalLayoutListener (this);
156-
157-
/* Create an object used as a lock. */
158-
this.dimensionsLock = new Object ();
159156
}
160157

161158
private void
@@ -164,12 +161,9 @@ public final class EmacsView extends ViewGroup
164161
Bitmap oldBitmap;
165162
int measuredWidth, measuredHeight;
166163

167-
synchronized (dimensionsLock)
168-
{
169-
/* Load measuredWidth and measuredHeight. */
170-
measuredWidth = this.measuredWidth;
171-
measuredHeight = this.measuredHeight;
172-
}
164+
/* Load measuredWidth and measuredHeight. */
165+
measuredWidth = this.measuredWidth;
166+
measuredHeight = this.measuredHeight;
173167

174168
if (measuredWidth == 0 || measuredHeight == 0)
175169
return;
@@ -231,8 +225,14 @@ public final class EmacsView extends ViewGroup
231225
public synchronized Bitmap
232226
getBitmap ()
233227
{
234-
if (bitmapDirty || bitmap == null)
228+
/* Never alter the bitmap if modifications have been received that
229+
are still to be copied to the front buffer, as this indicates
230+
that redisplay is in the process of copying matrix contents to
231+
the glass, and such events as generally prompt a complete
232+
regeneration of the frame's contents might not be processed. */
233+
if (!unswapped && (bitmapDirty || bitmap == null))
235234
handleDirtyBitmap ();
235+
unswapped = true;
236236

237237
return bitmap;
238238
}
@@ -242,11 +242,12 @@ public final class EmacsView extends ViewGroup
242242
{
243243
int i;
244244

245-
if (bitmapDirty || bitmap == null)
245+
if (!unswapped && (bitmapDirty || bitmap == null))
246246
handleDirtyBitmap ();
247247

248248
if (canvas == null)
249249
return null;
250+
unswapped = true;
250251

251252
/* Update clip rectangles if necessary. */
252253
if (gc.clipRectID != lastClipSerial)
@@ -266,14 +267,11 @@ public final class EmacsView extends ViewGroup
266267
return canvas;
267268
}
268269

269-
public void
270+
public synchronized void
270271
prepareForLayout (int wantedWidth, int wantedHeight)
271272
{
272-
synchronized (dimensionsLock)
273-
{
274-
measuredWidth = wantedWidth;
275-
measuredHeight = wantedWidth;
276-
}
273+
measuredWidth = wantedWidth;
274+
measuredHeight = wantedWidth;
277275
}
278276

279277
@Override
@@ -329,8 +327,8 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
329327
}
330328

331329
/* Note that the monitor lock for the window must never be held from
332-
within the lock for the view, because the window also locks the
333-
other way around. */
330+
within that for the view, because the window acquires locks in the
331+
opposite direction. */
334332

335333
@Override
336334
protected void
@@ -346,7 +344,7 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
346344
count = getChildCount ();
347345
needExpose = false;
348346

349-
synchronized (dimensionsLock)
347+
synchronized (this)
350348
{
351349
/* Load measuredWidth and measuredHeight. */
352350
oldMeasuredWidth = measuredWidth;
@@ -355,48 +353,48 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
355353
/* Set measuredWidth and measuredHeight. */
356354
measuredWidth = right - left;
357355
measuredHeight = bottom - top;
358-
}
359356

360-
/* If oldMeasuredHeight or oldMeasuredWidth are wrong, set changed
361-
to true as well. */
357+
/* If oldMeasuredHeight or oldMeasuredWidth are wrong, set
358+
changed to true as well. */
362359

363-
if (right - left != oldMeasuredWidth
364-
|| bottom - top != oldMeasuredHeight)
365-
changed = true;
360+
if (right - left != oldMeasuredWidth
361+
|| bottom - top != oldMeasuredHeight)
362+
changed = true;
366363

367-
/* Dirty the back buffer if the layout change resulted in the view
368-
being resized. */
369-
370-
if (changed)
371-
{
372-
/* Expose the window upon a change in the view's size that
373-
prompts the creation of a new bitmap. */
374-
explicitlyDirtyBitmap ();
375-
needExpose = true;
364+
/* Dirty the back buffer if the layout change resulted in the view
365+
being resized. */
376366

377-
/* This might return NULL if this view is not attached. */
378-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
367+
if (changed)
379368
{
380-
/* If a toplevel view is focused and isCurrentlyTextEditor
381-
is enabled when the IME is hidden, clear
382-
isCurrentlyTextEditor so it isn't shown again if the
383-
user dismisses Emacs before returning. */
384-
rootWindowInsets = getRootWindowInsets ();
385-
386-
if (isCurrentlyTextEditor
387-
&& rootWindowInsets != null
388-
&& isAttachedToWindow
389-
&& !rootWindowInsets.isVisible (WindowInsets.Type.ime ())
390-
/* N.B. that the keyboard is dismissed during gesture
391-
navigation under Android 30, but the system is
392-
quite temperamental regarding whether the window is
393-
focused at that point. Ideally
394-
isCurrentlyTextEditor shouldn't be reset in that
395-
case, but detecting that situation appears to be
396-
impossible. Sigh. */
397-
&& (window == EmacsActivity.focusedWindow
398-
&& hasWindowFocus ()))
399-
isCurrentlyTextEditor = false;
369+
/* Expose the window upon a change in the view's size that
370+
prompts the creation of a new bitmap. */
371+
bitmapDirty = needExpose = true;
372+
373+
/* This might return NULL if this view is not attached. */
374+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
375+
{
376+
/* If a toplevel view is focused and
377+
isCurrentlyTextEditor is enabled when the IME is
378+
hidden, clear isCurrentlyTextEditor so it isn't shown
379+
again if the user dismisses Emacs before
380+
returning. */
381+
rootWindowInsets = getRootWindowInsets ();
382+
383+
if (isCurrentlyTextEditor
384+
&& rootWindowInsets != null
385+
&& isAttachedToWindow
386+
&& !rootWindowInsets.isVisible (WindowInsets.Type.ime ())
387+
/* N.B. that the keyboard is dismissed during
388+
gesture navigation under Android 30, but the
389+
system is quite temperamental regarding whether
390+
the window is focused at that point. Ideally
391+
isCurrentlyTextEditor shouldn't be reset in that
392+
case, but detecting that situation appears to be
393+
impossible. Sigh. */
394+
&& (window == EmacsActivity.focusedWindow
395+
&& hasWindowFocus ()))
396+
isCurrentlyTextEditor = false;
397+
}
400398
}
401399
}
402400

@@ -449,6 +447,33 @@ else if (child.getVisibility () != GONE)
449447
damageRegion.op (left, top, right, bottom, Region.Op.UNION);
450448
}
451449

450+
/* Complete deferred reconfiguration of the front buffer after a
451+
buffer swap completes, and generate Expose events for the same. */
452+
453+
private void
454+
postSwapBuffers ()
455+
{
456+
if (!unswapped)
457+
return;
458+
459+
unswapped = false;
460+
461+
/* If the bitmap is dirty, reconfigure the bitmap and
462+
generate an Expose event to produce its contents. */
463+
464+
if ((bitmapDirty || bitmap == null)
465+
/* Do not generate Expose events if handleDirtyBitmap will
466+
not create a valid bitmap, or the consequent buffer swap
467+
will produce another event, ad infinitum. */
468+
&& isAttachedToWindow && measuredWidth != 0
469+
&& measuredHeight != 0)
470+
{
471+
handleDirtyBitmap ();
472+
EmacsNative.sendExpose (this.window.handle, 0, 0,
473+
measuredWidth, measuredHeight);
474+
}
475+
}
476+
452477
/* This method is called from both the UI thread and the Emacs
453478
thread. */
454479

@@ -467,7 +492,10 @@ else if (child.getVisibility () != GONE)
467492
/* Now see if there is a damage region. */
468493

469494
if (damageRegion.isEmpty ())
470-
return;
495+
{
496+
postSwapBuffers ();
497+
return;
498+
}
471499

472500
/* And extract and clear the damage region. */
473501

@@ -479,6 +507,7 @@ else if (child.getVisibility () != GONE)
479507
/* Transfer the bitmap to the surface view, then invalidate
480508
it. */
481509
surfaceView.setBitmap (bitmap, damageRect);
510+
postSwapBuffers ();
482511
}
483512
}
484513

@@ -758,13 +787,9 @@ else if (child.getVisibility () != GONE)
758787
was called. */
759788
bitmapDirty = true;
760789

761-
synchronized (dimensionsLock)
762-
{
763-
/* Now expose the view contents again. */
764-
EmacsNative.sendExpose (this.window.handle, 0, 0,
765-
measuredWidth, measuredHeight);
766-
}
767-
790+
/* Now expose the view contents again. */
791+
EmacsNative.sendExpose (this.window.handle, 0, 0,
792+
measuredWidth, measuredHeight);
768793
super.onAttachedToWindow ();
769794
}
770795

src/androidterm.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -926,11 +926,11 @@ handle_one_android_event (struct android_display_info *dpyinfo,
926926
XSETFRAME (inev.ie.frame_or_window, f);
927927
}
928928

929-
if (f && FRAME_OUTPUT_DATA (f)->need_cursor_updates)
930-
{
931-
w = XWINDOW (f->selected_window);
932-
android_set_preeditarea (w, w->cursor.x, w->cursor.y);
933-
}
929+
if (f && FRAME_OUTPUT_DATA (f)->need_cursor_updates)
930+
{
931+
w = XWINDOW (f->selected_window);
932+
android_set_preeditarea (w, w->cursor.x, w->cursor.y);
933+
}
934934
}
935935

936936
goto OTHER;

0 commit comments

Comments
 (0)