emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android da9ae10636 1/3: Implement submenus on Android


From: Po Lu
Subject: feature/android da9ae10636 1/3: Implement submenus on Android
Date: Mon, 16 Jan 2023 06:50:57 -0500 (EST)

branch: feature/android
commit da9ae10636b84b88e9eb9c827b03cdaabd1611d1
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Implement submenus on Android
    
    * java/org/gnu/emacs/EmacsActivity.java (onCreate): Set the
    default theme to Theme.DeviceDefault.NoActionBar if possible.
    (onContextMenuClosed): Add hack for Android bug.
    * java/org/gnu/emacs/EmacsContextMenu.java (EmacsContextMenu)
    (onMenuItemClick): Set flag upon submenu selection.
    (inflateMenuItems): Set onClickListener for submenus as well.
    (display1): Clear new flag.
    * java/org/gnu/emacs/EmacsDrawRectangle.java (perform): Fix
    rectangle bounds.
    * java/org/gnu/emacs/EmacsNative.java (EmacsNative):
    * java/org/gnu/emacs/EmacsService.java (onCreate): Pass cache
    directory.
    (sync): New function.
    * src/android.c (struct android_emacs_service): New method
    `sync'.
    (setEmacsParams, initEmacs): Handle cache directory.
    (android_init_emacs_service): Initialize new method `sync'.
    (android_sync): New function.
    * src/androidfns.c (Fx_show_tip): Call both functions.
    * src/androidgui.h: Update prototypes.
    * src/androidmenu.c (struct android_menu_subprefix)
    (android_free_subprefixes, android_menu_show): Handle submenu
    prefixes correctly.
    * src/androidterm.c (handle_one_android_event): Clear help echo
    on MotionNotify like on X.
    * src/menu.c (single_menu_item): Enable submenus on Android.
---
 java/org/gnu/emacs/EmacsActivity.java      |  12 ++-
 java/org/gnu/emacs/EmacsContextMenu.java   |  31 ++++++-
 java/org/gnu/emacs/EmacsDrawRectangle.java |   2 +-
 java/org/gnu/emacs/EmacsNative.java        |   4 +
 java/org/gnu/emacs/EmacsService.java       |  36 +++++++-
 src/android.c                              |  38 ++++++++-
 src/androidfns.c                           |   8 ++
 src/androidgui.h                           |   1 +
 src/androidmenu.c                          | 128 ++++++++++++++++++++++++++---
 src/androidterm.c                          |  10 +++
 src/menu.c                                 |   9 +-
 11 files changed, 255 insertions(+), 24 deletions(-)

diff --git a/java/org/gnu/emacs/EmacsActivity.java 
b/java/org/gnu/emacs/EmacsActivity.java
index 4b96a37698..79c0991a5d 100644
--- a/java/org/gnu/emacs/EmacsActivity.java
+++ b/java/org/gnu/emacs/EmacsActivity.java
@@ -27,6 +27,7 @@ import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Build;
 import android.util.Log;
 import android.widget.FrameLayout;
 import android.widget.FrameLayout.LayoutParams;
@@ -162,7 +163,11 @@ public class EmacsActivity extends Activity
     FrameLayout.LayoutParams params;
 
     /* Set the theme to one without a title bar.  */
-    setTheme (android.R.style.Theme_NoTitleBar);
+
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+      setTheme (android.R.style.Theme_DeviceDefault_NoActionBar);
+    else
+      setTheme (android.R.style.Theme_NoTitleBar);
 
     params = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT,
                                           LayoutParams.MATCH_PARENT);
@@ -235,6 +240,11 @@ public class EmacsActivity extends Activity
   {
     Log.d (TAG, "onContextMenuClosed: " + menu);
 
+    /* See the comment inside onMenuItemClick.  */
+    if (EmacsContextMenu.wasSubmenuSelected
+       && menu.toString ().contains ("ContextMenuBuilder"))
+      return;
+
     /* Send a context menu event given that no menu item has already
        been selected.  */
     if (!EmacsContextMenu.itemAlreadySelected)
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java 
b/java/org/gnu/emacs/EmacsContextMenu.java
index 02dd1c7efa..00e204c994 100644
--- a/java/org/gnu/emacs/EmacsContextMenu.java
+++ b/java/org/gnu/emacs/EmacsContextMenu.java
@@ -30,6 +30,7 @@ import android.os.Bundle;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.SubMenu;
 
 import android.util.Log;
 
@@ -47,6 +48,9 @@ public class EmacsContextMenu
   /* Whether or not an item was selected.  */
   public static boolean itemAlreadySelected;
 
+  /* Whether or not a submenu was selected.  */
+  public static boolean wasSubmenuSelected;
+
   private class Item implements MenuItem.OnMenuItemClickListener
   {
     public int itemID;
@@ -60,6 +64,20 @@ public class EmacsContextMenu
     {
       Log.d (TAG, "onMenuItemClick: " + itemName + " (" + itemID + ")");
 
+      if (subMenu != null)
+       {
+         /* After opening a submenu within a submenu, Android will
+            send onContextMenuClosed for a ContextMenuBuilder.  This
+            will normally confuse Emacs into thinking that the
+            context menu has been dismissed.  Wrong!
+
+            Setting this flag makes EmacsActivity to only handle
+            SubMenuBuilder being closed, which always means the menu
+            has actually been dismissed.  */
+         wasSubmenuSelected = true;
+         return false;
+       }
+
       /* Send a context menu event.  */
       EmacsNative.sendContextMenu ((short) 0, itemID);
 
@@ -144,7 +162,7 @@ public class EmacsContextMenu
   {
     Intent intent;
     MenuItem menuItem;
-    Menu submenu;
+    SubMenu submenu;
 
     for (Item item : menuItems)
       {
@@ -153,7 +171,11 @@ public class EmacsContextMenu
            /* This is a submenu.  Create the submenu and add the
               contents of the menu to it.  */
            submenu = menu.addSubMenu (item.itemName);
-           inflateMenuItems (submenu);
+           item.subMenu.inflateMenuItems (submenu);
+
+           /* This is still needed to set wasSubmenuSelected.  */
+           menuItem = submenu.getItem ();
+           menuItem.setOnMenuItemClickListener (item);
          }
        else
          {
@@ -184,7 +206,7 @@ public class EmacsContextMenu
   public EmacsContextMenu
   parent ()
   {
-    return parent;
+    return this.parent;
   }
 
   /* Like display, but does the actual work and runs in the main
@@ -197,6 +219,9 @@ public class EmacsContextMenu
        send 0 in response to the context menu being closed.  */
     itemAlreadySelected = false;
 
+    /* No submenu has been selected yet.  */
+    wasSubmenuSelected = false;
+
     return window.view.popupMenu (this, xPosition, yPosition);
   }
 
diff --git a/java/org/gnu/emacs/EmacsDrawRectangle.java 
b/java/org/gnu/emacs/EmacsDrawRectangle.java
index 84ff498847..b42e9556e8 100644
--- a/java/org/gnu/emacs/EmacsDrawRectangle.java
+++ b/java/org/gnu/emacs/EmacsDrawRectangle.java
@@ -59,7 +59,7 @@ public class EmacsDrawRectangle
       }
 
     paint = gc.gcPaint;
-    rect = new Rect (x + 1, y + 1, x + width, y + height);
+    rect = new Rect (x, y, x + width, y + height);
 
     paint.setStyle (Paint.Style.STROKE);
 
diff --git a/java/org/gnu/emacs/EmacsNative.java 
b/java/org/gnu/emacs/EmacsNative.java
index 4a80f88edc..2f3a732ea7 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -38,6 +38,9 @@ public class EmacsNative
      libDir must be the package's data storage location for native
      libraries.  It is used as PATH.
 
+     cacheDir must be the package's cache directory.  It is used as
+     the `temporary-file-directory'.
+
      pixelDensityX and pixelDensityY are the DPI values that will be
      used by Emacs.
 
@@ -45,6 +48,7 @@ public class EmacsNative
   public static native void setEmacsParams (AssetManager assetManager,
                                            String filesDir,
                                            String libDir,
+                                           String cacheDir,
                                            float pixelDensityX,
                                            float pixelDensityY,
                                            EmacsService emacsService);
diff --git a/java/org/gnu/emacs/EmacsService.java 
b/java/org/gnu/emacs/EmacsService.java
index f935b63fa0..ca38f93dc9 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -108,7 +108,7 @@ public class EmacsService extends Service
   {
     AssetManager manager;
     Context app_context;
-    String filesDir, libDir;
+    String filesDir, libDir, cacheDir;
     double pixelDensityX;
     double pixelDensityY;
 
@@ -126,12 +126,13 @@ public class EmacsService extends Service
           parameters.  */
        filesDir = app_context.getFilesDir ().getCanonicalPath ();
        libDir = getLibraryDirectory ();
+       cacheDir = app_context.getCacheDir ().getCanonicalPath ();
 
        Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir
               + " and libDir = " + libDir);
 
        EmacsNative.setEmacsParams (manager, filesDir, libDir,
-                                   (float) pixelDensityX,
+                                   cacheDir, (float) pixelDensityX,
                                    (float) pixelDensityY,
                                    this);
 
@@ -407,4 +408,35 @@ public class EmacsService extends Service
   {
     return KeyEvent.keyCodeToString (keysym);
   }
+
+  public void
+  sync ()
+  {
+    Runnable runnable;
+
+    runnable = new Runnable () {
+       public void
+       run ()
+       {
+         synchronized (this)
+           {
+             notify ();
+           }
+       }
+      };
+
+    synchronized (runnable)
+      {
+       runOnUiThread (runnable);
+
+       try
+         {
+           runnable.wait ();
+         }
+       catch (InterruptedException e)
+         {
+           EmacsNative.emacsAbort ();
+         }
+      }
+  }
 };
diff --git a/src/android.c b/src/android.c
index ed162a903b..3a96528646 100644
--- a/src/android.c
+++ b/src/android.c
@@ -88,6 +88,7 @@ struct android_emacs_service
   jmethodID get_screen_height;
   jmethodID detect_mouse;
   jmethodID name_keysym;
+  jmethodID sync;
 };
 
 struct android_emacs_pixmap
@@ -116,15 +117,18 @@ static AAssetManager *asset_manager;
 /* Whether or not Emacs has been initialized.  */
 static int emacs_initialized;
 
-/* The path used to store site-lisp.  */
+/* The directory used to store site-lisp.  */
 char *android_site_load_path;
 
-/* The path used to store native libraries.  */
+/* The directory used to store native libraries.  */
 char *android_lib_dir;
 
-/* The path used to store game files.  */
+/* The directory used to store game files.  */
 char *android_game_path;
 
+/* The directory used to store temporary files.  */
+char *android_cache_dir;
+
 /* The display's pixel densities.  */
 double android_pixel_density_x, android_pixel_density_y;
 
@@ -911,6 +915,7 @@ JNIEXPORT void JNICALL
 NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
                              jobject local_asset_manager,
                              jobject files_dir, jobject libs_dir,
+                             jobject cache_dir,
                              jfloat pixel_density_x,
                              jfloat pixel_density_y,
                              jobject emacs_service_object)
@@ -986,6 +991,20 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
   (*env)->ReleaseStringUTFChars (env, (jstring) libs_dir,
                                 java_string);
 
+  java_string = (*env)->GetStringUTFChars (env, (jstring) cache_dir,
+                                          NULL);
+
+  if (!java_string)
+    emacs_abort ();
+
+  android_cache_dir = strdup ((const char *) java_string);
+
+  if (!android_files_dir)
+    emacs_abort ();
+
+  (*env)->ReleaseStringUTFChars (env, (jstring) cache_dir,
+                                java_string);
+
   /* Calculate the site-lisp path.  */
 
   android_site_load_path = malloc (PATH_MAX + 1);
@@ -1083,6 +1102,7 @@ android_init_emacs_service (void)
   FIND_METHOD (get_screen_height, "getScreenHeight", "(Z)I");
   FIND_METHOD (detect_mouse, "detectMouse", "()Z");
   FIND_METHOD (name_keysym, "nameKeysym", "(I)Ljava/lang/String;");
+  FIND_METHOD (sync, "sync", "()V");
 #undef FIND_METHOD
 }
 
@@ -1216,6 +1236,9 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, 
jarray argv)
   /* Set HOME to the app data directory.  */
   setenv ("HOME", android_files_dir, 1);
 
+  /* Set TMPDIR to the temporary files directory.  */
+  setenv ("TMPDIR", android_cache_dir, 1);
+
   /* Set the cwd to that directory as well.  */
   if (chdir (android_files_dir))
     __android_log_print (ANDROID_LOG_WARN, __func__,
@@ -3519,6 +3542,15 @@ android_get_keysym_name (int keysym, char *name_return, 
size_t size)
   ANDROID_DELETE_LOCAL_REF (string);
 }
 
+void
+android_sync (void)
+{
+  (*android_java_env)->CallVoidMethod (android_java_env,
+                                      emacs_service,
+                                      service_class.sync);
+  android_exception_check ();
+}
+
 
 
 #undef faccessat
diff --git a/src/androidfns.c b/src/androidfns.c
index ab136bc272..bb37c41506 100644
--- a/src/androidfns.c
+++ b/src/androidfns.c
@@ -26,6 +26,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "blockinput.h"
 #include "keyboard.h"
 #include "buffer.h"
+#include "androidgui.h"
 
 #ifndef ANDROID_STUBIFY
 
@@ -2282,6 +2283,13 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
   android_map_raised (FRAME_ANDROID_WINDOW (tip_f));
   unblock_input ();
 
+  /* Synchronize with the UI thread.  This is required to prevent ugly
+     black splotches.  */
+  android_sync ();
+
+  /* Garbage the tip frame too.  */
+  SET_FRAME_GARBAGED (tip_f);
+
   w->must_be_updated_p = true;
   update_single_window (w);
   flush_frame (tip_f);
diff --git a/src/androidgui.h b/src/androidgui.h
index 0e075fda95..9df5b073a7 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -504,6 +504,7 @@ extern void android_move_resize_window (android_window, 
int, int,
 extern void android_map_raised (android_window);
 extern void android_translate_coordinates (android_window, int,
                                           int, int *, int *);
+extern void android_sync (void);
 
 #endif
 
diff --git a/src/androidmenu.c b/src/androidmenu.c
index 7522f9c5a5..6fb4963174 100644
--- a/src/androidmenu.c
+++ b/src/androidmenu.c
@@ -28,6 +28,8 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 #ifndef ANDROID_STUBIFY
 
+#include <android/log.h>
+
 /* Flag indicating whether or not a popup menu has been posted and not
    yet popped down.  */
 
@@ -188,6 +190,35 @@ android_process_events_for_menu (int *id)
   *id = x_display_list->menu_event_id;
 }
 
+/* Structure describing a ``subprefix'' in the menu.  */
+
+struct android_menu_subprefix
+{
+  /* The subprefix above.  */
+  struct android_menu_subprefix *last;
+
+  /* The subprefix itself.  */
+  Lisp_Object subprefix;
+};
+
+/* Free the subprefixes starting from *DATA.  */
+
+static void
+android_free_subprefixes (void *data)
+{
+  struct android_menu_subprefix **head, *subprefix;
+
+  head = data;
+
+  while (*head)
+    {
+      subprefix = *head;
+      *head = subprefix->last;
+
+      xfree (subprefix);
+    }
+}
+
 Lisp_Object
 android_menu_show (struct frame *f, int x, int y, int menuflags,
                   Lisp_Object title, const char **error_name)
@@ -198,13 +229,15 @@ android_menu_show (struct frame *f, int x, int y, int 
menuflags,
   Lisp_Object pane_name, prefix;
   const char *pane_string;
   specpdl_ref count, count1;
-  Lisp_Object item_name, enable, def, tem;
+  Lisp_Object item_name, enable, def, tem, entry;
   jmethodID method;
   jobject store;
   bool rc;
   jobject window;
-  int id, item_id;
+  int id, item_id, submenu_depth;
   struct android_dismiss_menu_data data;
+  struct android_menu_subprefix *subprefix, *temp_subprefix;
+  struct android_menu_subprefix *subprefix_1;
 
   count = SPECPDL_INDEX ();
 
@@ -232,7 +265,7 @@ android_menu_show (struct frame *f, int x, int y, int 
menuflags,
   android_push_local_frame ();
 
   /* Iterate over the menu.  */
-  i = 0;
+  i = 0, submenu_depth = 0;
 
   while (i < menu_items_used)
     {
@@ -241,6 +274,7 @@ android_menu_show (struct frame *f, int x, int y, int 
menuflags,
          /* This is the start of a new submenu.  However, it can be
             ignored here.  */
          i += 1;
+         submenu_depth += 1;
        }
       else if (EQ (AREF (menu_items, i), Qlambda))
        {
@@ -256,9 +290,18 @@ android_menu_show (struct frame *f, int x, int y, int 
menuflags,
          if (store != context_menu)
            ANDROID_DELETE_LOCAL_REF (store);
          i += 1;
+         submenu_depth -= 1;
 
-         eassert (current_context_menu);
+         if (!current_context_menu || submenu_depth < 0)
+           {
+             __android_log_print (ANDROID_LOG_FATAL, __func__,
+                                  "unbalanced submenu pop in menu_items");
+             emacs_abort ();
+           }
        }
+      else if (EQ (AREF (menu_items, i), Qt)
+              && submenu_depth != 0)
+       i += MENU_ITEMS_PANE_LENGTH;
       else if (EQ (AREF (menu_items, i), Qquote))
        i += 1;
       else if (EQ (AREF (menu_items, i), Qt))
@@ -300,8 +343,8 @@ android_menu_show (struct frame *f, int x, int y, int 
menuflags,
          /* This is an actual menu item (or submenu).  Add it to the
             menu.  */
 
-         if (i + MENU_ITEMS_ITEM_LENGTH < menu_items_used &&
-             NILP (AREF (menu_items, i + MENU_ITEMS_ITEM_LENGTH)))
+         if (i + MENU_ITEMS_ITEM_LENGTH < menu_items_used
+             && NILP (AREF (menu_items, i + MENU_ITEMS_ITEM_LENGTH)))
            {
              /* This is a submenu.  Add it.  */
              title_string = (!NILP (item_name)
@@ -312,7 +355,7 @@ android_menu_show (struct frame *f, int x, int y, int 
menuflags,
                = (*android_java_env)->CallObjectMethod (android_java_env,
                                                         current_context_menu,
                                                         menu_class.add_submenu,
-                                                        title_string);
+                                                        title_string, NULL);
              android_exception_check ();
 
              if (store != context_menu)
@@ -385,13 +428,78 @@ android_menu_show (struct frame *f, int x, int y, int 
menuflags,
     /* This means no menu item was selected.  */
     goto finish;
 
-  /* id is an index into menu_items.  Check that it remains
-     valid.  */
+  /* This means the id is invalid.  */
   if (id >= ASIZE (menu_items))
     goto finish;
 
   /* Now return the menu item at that location.  */
-  tem = AREF (menu_items, id);
+  tem = Qnil;
+  subprefix = NULL;
+  record_unwind_protect_ptr (android_free_subprefixes, &subprefix);
+
+  /* Find the selected item, and its pane, to return
+     the proper value.  */
+
+  prefix = entry = Qnil;
+  i = 0;
+  while (i < menu_items_used)
+    {
+      if (NILP (AREF (menu_items, i)))
+       {
+         temp_subprefix = xmalloc (sizeof *temp_subprefix);
+         temp_subprefix->last = subprefix;
+         subprefix = temp_subprefix;
+         subprefix->subprefix = prefix;
+
+         prefix = entry;
+         i++;
+       }
+      else if (EQ (AREF (menu_items, i), Qlambda))
+       {
+         prefix = subprefix->subprefix;
+         temp_subprefix = subprefix->last;
+         xfree (subprefix);
+         subprefix = temp_subprefix;
+
+         i++;
+       }
+      else if (EQ (AREF (menu_items, i), Qt))
+       {
+         prefix
+           = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
+         i += MENU_ITEMS_PANE_LENGTH;
+       }
+      /* Ignore a nil in the item list.
+        It's meaningful only for dialog boxes.  */
+      else if (EQ (AREF (menu_items, i), Qquote))
+       i += 1;
+      else
+       {
+         entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
+
+         if (i + MENU_ITEMS_ITEM_VALUE == id)
+           {
+             if (menuflags & MENU_KEYMAPS)
+               {
+                 entry = list1 (entry);
+
+                 if (!NILP (prefix))
+                   entry = Fcons (prefix, entry);
+
+                 for (subprefix_1 = subprefix; subprefix_1;
+                      subprefix_1 = subprefix_1->last)
+                   if (!NILP (subprefix_1->subprefix))
+                     entry = Fcons (subprefix_1->subprefix, entry);
+               }
+
+             tem = entry;
+           }
+         i += MENU_ITEMS_ITEM_LENGTH;
+       }
+    }
+
+  Fprint (tem, Qexternal_debugging_output);
+
   unblock_input ();
   return unbind_to (count, tem);
 
diff --git a/src/androidterm.c b/src/androidterm.c
index 4017fec60a..6f452a52d8 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -689,6 +689,16 @@ handle_one_android_event (struct android_display_info 
*dpyinfo,
       goto OTHER;
 
     case ANDROID_MOTION_NOTIFY:
+
+      previous_help_echo_string = help_echo_string;
+      help_echo_string = Qnil;
+
+      if (hlinfo->mouse_face_hidden)
+       {
+         hlinfo->mouse_face_hidden = false;
+         clear_mouse_face (hlinfo);
+       }
+
       f = any;
 
       if (f)
diff --git a/src/menu.c b/src/menu.c
index 73d4215b94..e1f899858d 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -167,7 +167,7 @@ ensure_menu_items (int items)
     }
 }
 
-#ifdef HAVE_EXT_MENU_BAR
+#if defined HAVE_EXT_MENU_BAR || defined HAVE_ANDROID
 
 /* Begin a submenu.  */
 
@@ -191,7 +191,7 @@ push_submenu_end (void)
   menu_items_submenu_depth--;
 }
 
-#endif /* HAVE_EXT_MENU_BAR */
+#endif /* HAVE_EXT_MENU_BAR || HAVE_ANDROID */
 
 /* Indicate boundary between left and right.  */
 
@@ -420,8 +420,9 @@ single_menu_item (Lisp_Object key, Lisp_Object item, 
Lisp_Object dummy, void *sk
                  AREF (item_properties, ITEM_PROPERTY_SELECTED),
                  AREF (item_properties, ITEM_PROPERTY_HELP));
 
-#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) \
-  || defined (HAVE_NTGUI) || defined (HAVE_HAIKU) || defined (HAVE_PGTK)
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS)  \
+  || defined (HAVE_NTGUI) || defined (HAVE_HAIKU) || defined (HAVE_PGTK) \
+  || defined (HAVE_ANDROID)
   /* Display a submenu using the toolkit.  */
   if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame))
       && ! (NILP (map) || NILP (enabled)))



reply via email to

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