aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorPo Lu2024-06-17 17:43:24 +0800
committerPo Lu2024-06-17 17:45:48 +0800
commit82f0014273193d27c71a1fcb9be778c85cfa5e65 (patch)
tree62792993251680cebe47bf1d50775a1f4e8a8d46 /java
parent6aa5068ac71cb1b8e46c299138f99fea44319146 (diff)
downloademacs-82f0014273193d27c71a1fcb9be778c85cfa5e65.tar.gz
emacs-82f0014273193d27c71a1fcb9be778c85cfa5e65.zip
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')
-rw-r--r--java/org/gnu/emacs/EmacsView.java161
1 files changed, 93 insertions, 68 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
88 /* Whether or not a popup is active. */ 88 /* Whether or not a popup is active. */
89 private boolean popupActive; 89 private boolean popupActive;
90 90
91 /* Whether the back buffer has been updated since the last swap. */
92 private boolean unswapped;
93
91 /* The current context menu. */ 94 /* The current context menu. */
92 private EmacsContextMenu contextMenu; 95 private EmacsContextMenu contextMenu;
93 96
94 /* The last measured width and height. */ 97 /* The last measured width and height. */
95 private int measuredWidth, measuredHeight; 98 private int measuredWidth, measuredHeight;
96 99
97 /* Object acting as a lock for those values. */
98 private Object dimensionsLock;
99
100 /* The serial of the last clip rectangle change. */ 100 /* The serial of the last clip rectangle change. */
101 private long lastClipSerial; 101 private long lastClipSerial;
102 102
@@ -153,9 +153,6 @@ public final class EmacsView extends ViewGroup
153 153
154 /* Add this view as its own global layout listener. */ 154 /* Add this view as its own global layout listener. */
155 getViewTreeObserver ().addOnGlobalLayoutListener (this); 155 getViewTreeObserver ().addOnGlobalLayoutListener (this);
156
157 /* Create an object used as a lock. */
158 this.dimensionsLock = new Object ();
159 } 156 }
160 157
161 private void 158 private void
@@ -164,12 +161,9 @@ public final class EmacsView extends ViewGroup
164 Bitmap oldBitmap; 161 Bitmap oldBitmap;
165 int measuredWidth, measuredHeight; 162 int measuredWidth, measuredHeight;
166 163
167 synchronized (dimensionsLock) 164 /* Load measuredWidth and measuredHeight. */
168 { 165 measuredWidth = this.measuredWidth;
169 /* Load measuredWidth and measuredHeight. */ 166 measuredHeight = this.measuredHeight;
170 measuredWidth = this.measuredWidth;
171 measuredHeight = this.measuredHeight;
172 }
173 167
174 if (measuredWidth == 0 || measuredHeight == 0) 168 if (measuredWidth == 0 || measuredHeight == 0)
175 return; 169 return;
@@ -231,8 +225,14 @@ public final class EmacsView extends ViewGroup
231 public synchronized Bitmap 225 public synchronized Bitmap
232 getBitmap () 226 getBitmap ()
233 { 227 {
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))
235 handleDirtyBitmap (); 234 handleDirtyBitmap ();
235 unswapped = true;
236 236
237 return bitmap; 237 return bitmap;
238 } 238 }
@@ -242,11 +242,12 @@ public final class EmacsView extends ViewGroup
242 { 242 {
243 int i; 243 int i;
244 244
245 if (bitmapDirty || bitmap == null) 245 if (!unswapped && (bitmapDirty || bitmap == null))
246 handleDirtyBitmap (); 246 handleDirtyBitmap ();
247 247
248 if (canvas == null) 248 if (canvas == null)
249 return null; 249 return null;
250 unswapped = true;
250 251
251 /* Update clip rectangles if necessary. */ 252 /* Update clip rectangles if necessary. */
252 if (gc.clipRectID != lastClipSerial) 253 if (gc.clipRectID != lastClipSerial)
@@ -266,14 +267,11 @@ public final class EmacsView extends ViewGroup
266 return canvas; 267 return canvas;
267 } 268 }
268 269
269 public void 270 public synchronized void
270 prepareForLayout (int wantedWidth, int wantedHeight) 271 prepareForLayout (int wantedWidth, int wantedHeight)
271 { 272 {
272 synchronized (dimensionsLock) 273 measuredWidth = wantedWidth;
273 { 274 measuredHeight = wantedWidth;
274 measuredWidth = wantedWidth;
275 measuredHeight = wantedWidth;
276 }
277 } 275 }
278 276
279 @Override 277 @Override
@@ -329,8 +327,8 @@ public final class EmacsView extends ViewGroup
329 } 327 }
330 328
331 /* Note that the monitor lock for the window must never be held from 329 /* 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 330 within that for the view, because the window acquires locks in the
333 other way around. */ 331 opposite direction. */
334 332
335 @Override 333 @Override
336 protected void 334 protected void
@@ -346,7 +344,7 @@ public final class EmacsView extends ViewGroup
346 count = getChildCount (); 344 count = getChildCount ();
347 needExpose = false; 345 needExpose = false;
348 346
349 synchronized (dimensionsLock) 347 synchronized (this)
350 { 348 {
351 /* Load measuredWidth and measuredHeight. */ 349 /* Load measuredWidth and measuredHeight. */
352 oldMeasuredWidth = measuredWidth; 350 oldMeasuredWidth = measuredWidth;
@@ -355,48 +353,48 @@ public final class EmacsView extends ViewGroup
355 /* Set measuredWidth and measuredHeight. */ 353 /* Set measuredWidth and measuredHeight. */
356 measuredWidth = right - left; 354 measuredWidth = right - left;
357 measuredHeight = bottom - top; 355 measuredHeight = bottom - top;
358 }
359 356
360 /* If oldMeasuredHeight or oldMeasuredWidth are wrong, set changed 357 /* If oldMeasuredHeight or oldMeasuredWidth are wrong, set
361 to true as well. */ 358 changed to true as well. */
362 359
363 if (right - left != oldMeasuredWidth 360 if (right - left != oldMeasuredWidth
364 || bottom - top != oldMeasuredHeight) 361 || bottom - top != oldMeasuredHeight)
365 changed = true; 362 changed = true;
366 363
367 /* Dirty the back buffer if the layout change resulted in the view 364 /* Dirty the back buffer if the layout change resulted in the view
368 being resized. */ 365 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;
376 366
377 /* This might return NULL if this view is not attached. */ 367 if (changed)
378 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
379 { 368 {
380 /* If a toplevel view is focused and isCurrentlyTextEditor 369 /* Expose the window upon a change in the view's size that
381 is enabled when the IME is hidden, clear 370 prompts the creation of a new bitmap. */
382 isCurrentlyTextEditor so it isn't shown again if the 371 bitmapDirty = needExpose = true;
383 user dismisses Emacs before returning. */ 372
384 rootWindowInsets = getRootWindowInsets (); 373 /* This might return NULL if this view is not attached. */
385 374 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
386 if (isCurrentlyTextEditor 375 {
387 && rootWindowInsets != null 376 /* If a toplevel view is focused and
388 && isAttachedToWindow 377 isCurrentlyTextEditor is enabled when the IME is
389 && !rootWindowInsets.isVisible (WindowInsets.Type.ime ()) 378 hidden, clear isCurrentlyTextEditor so it isn't shown
390 /* N.B. that the keyboard is dismissed during gesture 379 again if the user dismisses Emacs before
391 navigation under Android 30, but the system is 380 returning. */
392 quite temperamental regarding whether the window is 381 rootWindowInsets = getRootWindowInsets ();
393 focused at that point. Ideally 382
394 isCurrentlyTextEditor shouldn't be reset in that 383 if (isCurrentlyTextEditor
395 case, but detecting that situation appears to be 384 && rootWindowInsets != null
396 impossible. Sigh. */ 385 && isAttachedToWindow
397 && (window == EmacsActivity.focusedWindow 386 && !rootWindowInsets.isVisible (WindowInsets.Type.ime ())
398 && hasWindowFocus ())) 387 /* N.B. that the keyboard is dismissed during
399 isCurrentlyTextEditor = false; 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 }
400 } 398 }
401 } 399 }
402 400
@@ -449,6 +447,33 @@ public final class EmacsView extends ViewGroup
449 damageRegion.op (left, top, right, bottom, Region.Op.UNION); 447 damageRegion.op (left, top, right, bottom, Region.Op.UNION);
450 } 448 }
451 449
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
452 /* This method is called from both the UI thread and the Emacs 477 /* This method is called from both the UI thread and the Emacs
453 thread. */ 478 thread. */
454 479
@@ -467,7 +492,10 @@ public final class EmacsView extends ViewGroup
467 /* Now see if there is a damage region. */ 492 /* Now see if there is a damage region. */
468 493
469 if (damageRegion.isEmpty ()) 494 if (damageRegion.isEmpty ())
470 return; 495 {
496 postSwapBuffers ();
497 return;
498 }
471 499
472 /* And extract and clear the damage region. */ 500 /* And extract and clear the damage region. */
473 501
@@ -479,6 +507,7 @@ public final class EmacsView extends ViewGroup
479 /* Transfer the bitmap to the surface view, then invalidate 507 /* Transfer the bitmap to the surface view, then invalidate
480 it. */ 508 it. */
481 surfaceView.setBitmap (bitmap, damageRect); 509 surfaceView.setBitmap (bitmap, damageRect);
510 postSwapBuffers ();
482 } 511 }
483 } 512 }
484 513
@@ -758,13 +787,9 @@ public final class EmacsView extends ViewGroup
758 was called. */ 787 was called. */
759 bitmapDirty = true; 788 bitmapDirty = true;
760 789
761 synchronized (dimensionsLock) 790 /* Now expose the view contents again. */
762 { 791 EmacsNative.sendExpose (this.window.handle, 0, 0,
763 /* Now expose the view contents again. */ 792 measuredWidth, measuredHeight);
764 EmacsNative.sendExpose (this.window.handle, 0, 0,
765 measuredWidth, measuredHeight);
766 }
767
768 super.onAttachedToWindow (); 793 super.onAttachedToWindow ();
769 } 794 }
770 795