Fix remaining Android bugs reported over the past months

* java/org/gnu/emacs/EmacsActivity.java (attachWindow):
Guarantee that child windows promoted to toplevels receive
layout parameters that direct them to receive their parents'
dimensions.  Otherwise, the size of the window as a child is
retained on Huawei HarmonyOS 4.2 and possibly other Android
distributions.

* java/org/gnu/emacs/EmacsService.java (updateCursorAnchorInfo):
Run anchor updates on the UI thread, as
`InputMethodManager#updateCursorAnchorInfo' is liable to call
`View#requestLayout'.

* java/org/gnu/emacs/EmacsView.java (onMeasure): Always call
`measureChildren', or child frames' onLayout handlers might not
be invoked after they request a layout cycle and are duly
processed in `onLayout'.
(swapBuffers): Delete erroneous commentary.

* java/org/gnu/emacs/EmacsWindow.java (viewLayout): If
overrideRedirect, don't inadvertently clear rect.left and
rect.top by recording the window's WM window-relative position.
Fix typos.
(reparentTo): Invalidate focus after transferring frame.
(translateCoordinates): Account for override-redirect windows.
Mostly important for mouse-drag-and-drop-region.
This commit is contained in:
Po Lu 2025-02-19 20:40:12 +08:00
parent e97be722d3
commit ded77fefff
4 changed files with 71 additions and 24 deletions

View file

@ -179,6 +179,8 @@ children and RESETWHENCHILDLESS is set (implying it is a
public final void public final void
attachWindow (EmacsWindow child) attachWindow (EmacsWindow child)
{ {
FrameLayout.LayoutParams defaultParams;
if (window != null) if (window != null)
throw new IllegalStateException ("trying to attach window when one" throw new IllegalStateException ("trying to attach window when one"
+ " already exists"); + " already exists");
@ -187,8 +189,15 @@ children and RESETWHENCHILDLESS is set (implying it is a
/* Record and attach the view. */ /* Record and attach the view. */
/* Reset residual LayoutParams that might remain in effect on this
window, or some distributions of Android (e.g. Huawei HarmonyOS
4.2) will retain the size of this window as a child frame. */
defaultParams
= new FrameLayout.LayoutParams (FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
syncFullscreenWith (child);
window = child; window = child;
layout.addView (window.view); layout.addView (window.view, defaultParams);
child.setConsumer (this); child.setConsumer (this);
/* If the window isn't no-focus-on-map, focus its view. */ /* If the window isn't no-focus-on-map, focus its view. */

View file

@ -937,11 +937,11 @@ invocation of app_process (through android-emacs) can
} }
public void public void
updateCursorAnchorInfo (EmacsWindow window, float x, updateCursorAnchorInfo (final EmacsWindow window, float x,
float y, float yBaseline, float y, float yBaseline,
float yBottom) float yBottom)
{ {
CursorAnchorInfo info; final CursorAnchorInfo info;
CursorAnchorInfo.Builder builder; CursorAnchorInfo.Builder builder;
Matrix matrix; Matrix matrix;
int[] offsets; int[] offsets;
@ -963,9 +963,14 @@ invocation of app_process (through android-emacs) can
Log.d (TAG, ("updateCursorAnchorInfo: " + x + " " + y Log.d (TAG, ("updateCursorAnchorInfo: " + x + " " + y
+ " " + yBaseline + "-" + yBottom)); + " " + yBaseline + "-" + yBottom));
icBeginSynchronous (); EmacsService.SERVICE.runOnUiThread (new Runnable () {
window.view.imManager.updateCursorAnchorInfo (window.view, info); @Override
icEndSynchronous (); public void
run ()
{
window.view.imManager.updateCursorAnchorInfo (window.view, info);
}
});
} }

View file

@ -296,6 +296,9 @@ else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
&& height > MeasureSpec.getSize (heightMeasureSpec)) && height > MeasureSpec.getSize (heightMeasureSpec))
height = MeasureSpec.getSize (heightMeasureSpec); height = MeasureSpec.getSize (heightMeasureSpec);
/* This is strictly necessary to propagate layout requests to
children. */
this.measureChildren (widthMeasureSpec, heightMeasureSpec);
super.setMeasuredDimension (width, height); super.setMeasuredDimension (width, height);
} }
@ -467,9 +470,6 @@ else if (child.getVisibility () != GONE)
} }
} }
/* This method is called from both the UI thread and the Emacs
thread. */
public void public void
swapBuffers () swapBuffers ()
{ {
@ -620,8 +620,7 @@ else if (child.getVisibility () != GONE)
detachViewFromParent (index); detachViewFromParent (index);
/* The view at 0 is the surface view. */ /* The view at 0 is the surface view. */
attachViewToParent (child, 1, attachViewToParent (child, 1, child.getLayoutParams ());
child.getLayoutParams ());
} }
} }

View file

@ -50,6 +50,7 @@
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.ViewManager; import android.view.ViewManager;
import android.view.WindowManager; import android.view.WindowManager;
@ -331,23 +332,39 @@ private static class Coordinate
{ {
int rectWidth, rectHeight; int rectWidth, rectHeight;
rect.left = left; /* If this is an override-redirect window, don't ever modify
rect.top = top; rect.left and rect.top, as its WM window will always have been
rect.right = right; moved in unison with itself. */
rect.bottom = bottom;
if (overrideRedirect)
{
rect.right = rect.left + (right - left);
rect.bottom = rect.top + (bottom - top);
}
/* If parent is null, use xPosition and yPosition instead of the
geometry rectangle positions. */
else if (parent == null)
{
rect.left = xPosition;
rect.top = yPosition;
rect.right = rect.left + (right - left);
rect.bottom = rect.top + (bottom - top);
}
/* Otherwise accept the new position offered by the toolkit. FIXME:
isn't there a potential race condition here if the toolkit lays
out EmacsView after a child frame's rect is set but before it
calls onLayout to read the modifies rect? */
else
{
rect.left = left;
rect.top = top;
rect.right = right;
rect.bottom = bottom;
}
rectWidth = right - left; rectWidth = right - left;
rectHeight = bottom - top; rectHeight = bottom - top;
/* If parent is null, use xPosition and yPosition instead of the
geometry rectangle positions. */
if (parent == null)
{
left = xPosition;
top = yPosition;
}
return EmacsNative.sendConfigureNotify (this.handle, return EmacsNative.sendConfigureNotify (this.handle,
System.currentTimeMillis (), System.currentTimeMillis (),
left, top, rectWidth, left, top, rectWidth,
@ -1363,6 +1380,11 @@ else if (keyCode >= KeyEvent.KEYCODE_NUMPAD_0
EmacsWindowManager manager; EmacsWindowManager manager;
ViewManager parent; ViewManager parent;
/* Invalidate the focus; this should transfer the input focus
to the next eligible window as this window is no longer
present in parent.children. */
EmacsActivity.invalidateFocus (7);
/* First, detach this window if necessary. */ /* First, detach this window if necessary. */
manager = EmacsWindowManager.MANAGER; manager = EmacsWindowManager.MANAGER;
manager.detachWindow (EmacsWindow.this); manager.detachWindow (EmacsWindow.this);
@ -1637,6 +1659,18 @@ else if (EmacsWindow.this.isMapped)
array[0] += x; array[0] += x;
array[1] += y; array[1] += y;
/* In the case of an override redirect window, the WM window's
extents and position match the Emacs window exactly. */
if (overrideRedirect)
{
synchronized (this)
{
array[0] += rect.left;
array[1] += rect.top;
}
}
/* Return the resulting coordinates. */ /* Return the resulting coordinates. */
return array; return array;
} }