emacs-diffs
[Top][All Lists]
Advanced

[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,



reply via email to

[Prev in Thread] Current Thread [Next in Thread]