[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/android e859a14bee7: Fix menu and popup race conditions on Andro
From: |
Po Lu |
Subject: |
feature/android e859a14bee7: Fix menu and popup race conditions on Android |
Date: |
Thu, 9 Mar 2023 03:32:23 -0500 (EST) |
branch: feature/android
commit e859a14bee7a84a3aaed45770c89ef60c68b3e08
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Fix menu and popup race conditions on Android
* java/org/gnu/emacs/EmacsActivity.java (onContextMenuClosed):
* java/org/gnu/emacs/EmacsContextMenu.java (EmacsContextMenu)
(onMenuItemClick, run):
* java/org/gnu/emacs/EmacsDialog.java (EmacsDialog, onClick)
(createDialog, onDismiss): Take menu event serial, and pass it
along in context menu events.
* java/org/gnu/emacs/EmacsNative.java (sendContextMenu): New
argument.
* src/android.c (sendContextMenu): Pass serial number in event.
* src/androidgui.h (struct android_menu_event): New field
`menu_event_serial'.
* src/androidmenu.c (FIND_METHOD_STATIC)
(android_init_emacs_context_menu): Adjust method declarations.
(android_menu_show, android_dialog_show):
* src/androidterm.c (handle_one_android_event): Expect serial in
context menu events.
* src/androidterm.h: Update prototypes.
---
java/org/gnu/emacs/EmacsActivity.java | 8 +++++++-
java/org/gnu/emacs/EmacsContextMenu.java | 14 ++++++++++----
java/org/gnu/emacs/EmacsDialog.java | 15 ++++++++++-----
java/org/gnu/emacs/EmacsNative.java | 3 ++-
src/android.c | 4 +++-
src/androidgui.h | 3 +++
src/androidmenu.c | 24 +++++++++++++++++++-----
src/androidterm.c | 7 ++++++-
src/androidterm.h | 6 ++++++
9 files changed, 66 insertions(+), 18 deletions(-)
diff --git a/java/org/gnu/emacs/EmacsActivity.java
b/java/org/gnu/emacs/EmacsActivity.java
index 692d8a14e22..735a464be8e 100644
--- a/java/org/gnu/emacs/EmacsActivity.java
+++ b/java/org/gnu/emacs/EmacsActivity.java
@@ -315,6 +315,8 @@ public class EmacsActivity extends Activity
public final void
onContextMenuClosed (Menu menu)
{
+ int serial;
+
Log.d (TAG, "onContextMenuClosed: " + menu);
/* See the comment inside onMenuItemClick. */
@@ -335,7 +337,11 @@ public class EmacsActivity extends Activity
/* Send a context menu event given that no menu item has already
been selected. */
if (!EmacsContextMenu.itemAlreadySelected)
- EmacsNative.sendContextMenu ((short) 0, 0);
+ {
+ serial = EmacsContextMenu.lastMenuEventSerial;
+ EmacsNative.sendContextMenu ((short) 0, 0,
+ serial);
+ }
super.onContextMenuClosed (menu);
}
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java
b/java/org/gnu/emacs/EmacsContextMenu.java
index 0553ff9d4a3..abc1869ac6a 100644
--- a/java/org/gnu/emacs/EmacsContextMenu.java
+++ b/java/org/gnu/emacs/EmacsContextMenu.java
@@ -49,6 +49,9 @@ public final class EmacsContextMenu
/* Whether or not a submenu was selected. */
public static boolean wasSubmenuSelected;
+ /* The serial ID of the last context menu to be displayed. */
+ public static int lastMenuEventSerial;
+
private static class Item implements MenuItem.OnMenuItemClickListener
{
public int itemID;
@@ -106,7 +109,8 @@ public final class EmacsContextMenu
}
/* Send a context menu event. */
- EmacsNative.sendContextMenu ((short) 0, itemID);
+ EmacsNative.sendContextMenu ((short) 0, itemID,
+ lastMenuEventSerial);
/* Say that an item has already been selected. */
itemAlreadySelected = true;
@@ -293,12 +297,13 @@ public final class EmacsContextMenu
false);
}
- /* Display this context menu on WINDOW, at xPosition and
- yPosition. */
+ /* Display this context menu on WINDOW, at xPosition and yPosition.
+ SERIAL is a number that will be returned in any menu event
+ generated to identify this context menu. */
public boolean
display (final EmacsWindow window, final int xPosition,
- final int yPosition)
+ final int yPosition, final int serial)
{
Runnable runnable;
final Holder<Boolean> rc;
@@ -312,6 +317,7 @@ public final class EmacsContextMenu
{
synchronized (this)
{
+ lastMenuEventSerial = serial;
rc.thing = display1 (window, xPosition, yPosition);
notify ();
}
diff --git a/java/org/gnu/emacs/EmacsDialog.java
b/java/org/gnu/emacs/EmacsDialog.java
index 80a5e5f7369..aed84de29e5 100644
--- a/java/org/gnu/emacs/EmacsDialog.java
+++ b/java/org/gnu/emacs/EmacsDialog.java
@@ -57,6 +57,9 @@ public final class EmacsDialog implements
DialogInterface.OnDismissListener
/* Dialog to dismiss after click. */
private AlertDialog dismissDialog;
+ /* The menu serial associated with this dialog box. */
+ private int menuEventSerial;
+
private class EmacsButton implements View.OnClickListener,
DialogInterface.OnClickListener
{
@@ -76,7 +79,7 @@ public final class EmacsDialog implements
DialogInterface.OnDismissListener
Log.d (TAG, "onClicked " + this);
wasButtonClicked = true;
- EmacsNative.sendContextMenu ((short) 0, id);
+ EmacsNative.sendContextMenu ((short) 0, id, menuEventSerial);
dismissDialog.dismiss ();
}
@@ -87,15 +90,16 @@ public final class EmacsDialog implements
DialogInterface.OnDismissListener
Log.d (TAG, "onClicked " + this);
wasButtonClicked = true;
- EmacsNative.sendContextMenu ((short) 0, id);
+ EmacsNative.sendContextMenu ((short) 0, id, menuEventSerial);
}
};
/* Create a popup dialog with the title TITLE and the text TEXT.
- TITLE may be NULL. */
+ TITLE may be NULL. MENUEVENTSERIAL is a number which will
+ identify this popup dialog inside events it sends. */
public static EmacsDialog
- createDialog (String title, String text)
+ createDialog (String title, String text, int menuEventSerial)
{
EmacsDialog dialog;
@@ -103,6 +107,7 @@ public final class EmacsDialog implements
DialogInterface.OnDismissListener
dialog.buttons = new ArrayList<EmacsButton> ();
dialog.title = title;
dialog.text = text;
+ dialog.menuEventSerial = menuEventSerial;
return dialog;
}
@@ -330,6 +335,6 @@ public final class EmacsDialog implements
DialogInterface.OnDismissListener
if (wasButtonClicked)
return;
- EmacsNative.sendContextMenu ((short) 0, 0);
+ EmacsNative.sendContextMenu ((short) 0, 0, menuEventSerial);
}
};
diff --git a/java/org/gnu/emacs/EmacsNative.java
b/java/org/gnu/emacs/EmacsNative.java
index 8e626b9534b..11da5db8746 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -155,7 +155,8 @@ public final class EmacsNative
public static native long sendDeiconified (short window);
/* Send an ANDROID_CONTEXT_MENU event. */
- public static native long sendContextMenu (short window, int menuEventID);
+ public static native long sendContextMenu (short window, int menuEventID,
+ int menuEventSerial);
/* Send an ANDROID_EXPOSE event. */
public static native long sendExpose (short window, int x, int y,
diff --git a/src/android.c b/src/android.c
index b14d2845544..e2ae77e30d0 100644
--- a/src/android.c
+++ b/src/android.c
@@ -2744,7 +2744,8 @@ NATIVE_NAME (sendDeiconified) (JNIEnv *env, jobject
object,
JNIEXPORT jlong JNICALL
NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object,
- jshort window, jint menu_event_id)
+ jshort window, jint menu_event_id,
+ jint menu_event_serial)
{
JNI_STACK_ALIGNMENT_PROLOGUE;
@@ -2754,6 +2755,7 @@ NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject
object,
event.menu.serial = ++event_serial;
event.menu.window = window;
event.menu.menu_event_id = menu_event_id;
+ event.menu.menu_event_serial = menu_event_serial;
android_write_event (&event);
return event_serial;
diff --git a/src/androidgui.h b/src/androidgui.h
index afcaed98cae..5858a168080 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -418,6 +418,9 @@ struct android_menu_event
/* Menu event ID. */
int menu_event_id;
+
+ /* Menu event serial; this counter identifies the context menu. */
+ int menu_event_serial;
};
enum android_ime_operation
diff --git a/src/androidmenu.c b/src/androidmenu.c
index 540b25cf602..7d9c33e28b1 100644
--- a/src/androidmenu.c
+++ b/src/androidmenu.c
@@ -35,6 +35,11 @@ along with GNU Emacs. If not, see
<https://www.gnu.org/licenses/>. */
static int popup_activated_flag;
+/* Serial number used to identify which context menu events are
+ associated with the context menu currently being displayed. */
+
+unsigned int current_menu_serial;
+
int
popup_activated (void)
{
@@ -96,7 +101,8 @@ android_init_emacs_context_menu (void)
eassert (menu_class.c_name);
FIND_METHOD_STATIC (create_context_menu, "createContextMenu",
- "(Ljava/lang/String;)Lorg/gnu/emacs/EmacsContextMenu;");
+ "(Ljava/lang/String;)"
+ "Lorg/gnu/emacs/EmacsContextMenu;");
FIND_METHOD (add_item, "addItem", "(ILjava/lang/String;ZZZ"
"Ljava/lang/String;)V");
@@ -105,7 +111,7 @@ android_init_emacs_context_menu (void)
"Lorg/gnu/emacs/EmacsContextMenu;");
FIND_METHOD (add_pane, "addPane", "(Ljava/lang/String;)V");
FIND_METHOD (parent, "parent", "()Lorg/gnu/emacs/EmacsContextMenu;");
- FIND_METHOD (display, "display", "(Lorg/gnu/emacs/EmacsWindow;II)Z");
+ FIND_METHOD (display, "display", "(Lorg/gnu/emacs/EmacsWindow;III)Z");
FIND_METHOD (dismiss, "dismiss", "(Lorg/gnu/emacs/EmacsWindow;)V");
#undef FIND_METHOD
@@ -254,8 +260,10 @@ android_menu_show (struct frame *f, int x, int y, int
menuflags,
struct android_menu_subprefix *subprefix, *temp_subprefix;
struct android_menu_subprefix *subprefix_1;
bool checkmark;
+ unsigned int serial;
count = SPECPDL_INDEX ();
+ serial = ++current_menu_serial;
block_input ();
@@ -458,7 +466,8 @@ android_menu_show (struct frame *f, int x, int y, int
menuflags,
context_menu,
menu_class.display,
window, (jint) x,
- (jint) y);
+ (jint) y,
+ (jint) serial);
android_exception_check ();
if (!rc)
@@ -606,7 +615,7 @@ android_init_emacs_dialog (void)
name, signature); \
FIND_METHOD_STATIC (create_dialog, "createDialog", "(Ljava/lang/String;"
- "Ljava/lang/String;)Lorg/gnu/emacs/EmacsDialog;");
+ "Ljava/lang/String;I)Lorg/gnu/emacs/EmacsDialog;");
FIND_METHOD (add_button, "addButton", "(Ljava/lang/String;IZ)V");
FIND_METHOD (display, "display", "()Z");
@@ -625,6 +634,10 @@ android_dialog_show (struct frame *f, Lisp_Object title,
bool rc;
int id;
jmethodID method;
+ unsigned int serial;
+
+ /* Generate a unique ID for events from this dialog box. */
+ serial = ++current_menu_serial;
if (menu_items_n_panes > 1)
{
@@ -651,7 +664,8 @@ android_dialog_show (struct frame *f, Lisp_Object title,
dialog = (*android_java_env)->CallStaticObjectMethod (android_java_env,
dialog_class.class,
method, java_header,
- java_title);
+ java_title,
+ (jint) serial);
android_exception_check ();
/* Delete now unused local references. */
diff --git a/src/androidterm.c b/src/androidterm.c
index b502b1c6de5..2e2bf86706c 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -1457,7 +1457,12 @@ handle_one_android_event (struct android_display_info
*dpyinfo,
/* Context menu handling. */
case ANDROID_CONTEXT_MENU:
- if (dpyinfo->menu_event_id == -1)
+ if (dpyinfo->menu_event_id == -1
+ /* Previously displayed popup menus might generate events
+ after dismissal, which might interfere.
+ `current_menu_serial' is always set to an identifier
+ identifying the last context menu to be displayed. */
+ && event->menu.menu_event_serial == current_menu_serial)
dpyinfo->menu_event_id = event->menu.menu_event_id;
goto OTHER;
diff --git a/src/androidterm.h b/src/androidterm.h
index 9bd11bb7853..9964eb54880 100644
--- a/src/androidterm.h
+++ b/src/androidterm.h
@@ -421,6 +421,12 @@ extern void android_finalize_font_entity (struct
font_entity *);
/* Defined in androidmenu.c. */
+#ifndef ANDROID_STUBIFY
+
+extern unsigned int current_menu_serial;
+
+#endif
+
extern Lisp_Object android_menu_show (struct frame *, int, int, int,
Lisp_Object, const char **);
extern Lisp_Object android_popup_dialog (struct frame *, Lisp_Object,
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- feature/android e859a14bee7: Fix menu and popup race conditions on Android,
Po Lu <=