aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-01-15 15:45:29 +0800
committerPo Lu2023-01-15 15:45:29 +0800
commitda9ae10636b84b88e9eb9c827b03cdaabd1611d1 (patch)
treeca5b14036c7771accabfd87dd72e1fc147bf9914 /src
parenta336fd98a1ed1f97d69652cade46f99868f7c7fb (diff)
downloademacs-da9ae10636b84b88e9eb9c827b03cdaabd1611d1.tar.gz
emacs-da9ae10636b84b88e9eb9c827b03cdaabd1611d1.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/android.c38
-rw-r--r--src/androidfns.c8
-rw-r--r--src/androidgui.h1
-rw-r--r--src/androidmenu.c128
-rw-r--r--src/androidterm.c10
-rw-r--r--src/menu.c9
6 files changed, 177 insertions, 17 deletions
diff --git a/src/android.c b/src/android.c
index ed162a903ba..3a965286460 100644
--- a/src/android.c
+++ b/src/android.c
@@ -88,6 +88,7 @@ struct android_emacs_service
88 jmethodID get_screen_height; 88 jmethodID get_screen_height;
89 jmethodID detect_mouse; 89 jmethodID detect_mouse;
90 jmethodID name_keysym; 90 jmethodID name_keysym;
91 jmethodID sync;
91}; 92};
92 93
93struct android_emacs_pixmap 94struct android_emacs_pixmap
@@ -116,15 +117,18 @@ static AAssetManager *asset_manager;
116/* Whether or not Emacs has been initialized. */ 117/* Whether or not Emacs has been initialized. */
117static int emacs_initialized; 118static int emacs_initialized;
118 119
119/* The path used to store site-lisp. */ 120/* The directory used to store site-lisp. */
120char *android_site_load_path; 121char *android_site_load_path;
121 122
122/* The path used to store native libraries. */ 123/* The directory used to store native libraries. */
123char *android_lib_dir; 124char *android_lib_dir;
124 125
125/* The path used to store game files. */ 126/* The directory used to store game files. */
126char *android_game_path; 127char *android_game_path;
127 128
129/* The directory used to store temporary files. */
130char *android_cache_dir;
131
128/* The display's pixel densities. */ 132/* The display's pixel densities. */
129double android_pixel_density_x, android_pixel_density_y; 133double android_pixel_density_x, android_pixel_density_y;
130 134
@@ -911,6 +915,7 @@ JNIEXPORT void JNICALL
911NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, 915NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
912 jobject local_asset_manager, 916 jobject local_asset_manager,
913 jobject files_dir, jobject libs_dir, 917 jobject files_dir, jobject libs_dir,
918 jobject cache_dir,
914 jfloat pixel_density_x, 919 jfloat pixel_density_x,
915 jfloat pixel_density_y, 920 jfloat pixel_density_y,
916 jobject emacs_service_object) 921 jobject emacs_service_object)
@@ -986,6 +991,20 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
986 (*env)->ReleaseStringUTFChars (env, (jstring) libs_dir, 991 (*env)->ReleaseStringUTFChars (env, (jstring) libs_dir,
987 java_string); 992 java_string);
988 993
994 java_string = (*env)->GetStringUTFChars (env, (jstring) cache_dir,
995 NULL);
996
997 if (!java_string)
998 emacs_abort ();
999
1000 android_cache_dir = strdup ((const char *) java_string);
1001
1002 if (!android_files_dir)
1003 emacs_abort ();
1004
1005 (*env)->ReleaseStringUTFChars (env, (jstring) cache_dir,
1006 java_string);
1007
989 /* Calculate the site-lisp path. */ 1008 /* Calculate the site-lisp path. */
990 1009
991 android_site_load_path = malloc (PATH_MAX + 1); 1010 android_site_load_path = malloc (PATH_MAX + 1);
@@ -1083,6 +1102,7 @@ android_init_emacs_service (void)
1083 FIND_METHOD (get_screen_height, "getScreenHeight", "(Z)I"); 1102 FIND_METHOD (get_screen_height, "getScreenHeight", "(Z)I");
1084 FIND_METHOD (detect_mouse, "detectMouse", "()Z"); 1103 FIND_METHOD (detect_mouse, "detectMouse", "()Z");
1085 FIND_METHOD (name_keysym, "nameKeysym", "(I)Ljava/lang/String;"); 1104 FIND_METHOD (name_keysym, "nameKeysym", "(I)Ljava/lang/String;");
1105 FIND_METHOD (sync, "sync", "()V");
1086#undef FIND_METHOD 1106#undef FIND_METHOD
1087} 1107}
1088 1108
@@ -1216,6 +1236,9 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv)
1216 /* Set HOME to the app data directory. */ 1236 /* Set HOME to the app data directory. */
1217 setenv ("HOME", android_files_dir, 1); 1237 setenv ("HOME", android_files_dir, 1);
1218 1238
1239 /* Set TMPDIR to the temporary files directory. */
1240 setenv ("TMPDIR", android_cache_dir, 1);
1241
1219 /* Set the cwd to that directory as well. */ 1242 /* Set the cwd to that directory as well. */
1220 if (chdir (android_files_dir)) 1243 if (chdir (android_files_dir))
1221 __android_log_print (ANDROID_LOG_WARN, __func__, 1244 __android_log_print (ANDROID_LOG_WARN, __func__,
@@ -3519,6 +3542,15 @@ android_get_keysym_name (int keysym, char *name_return, size_t size)
3519 ANDROID_DELETE_LOCAL_REF (string); 3542 ANDROID_DELETE_LOCAL_REF (string);
3520} 3543}
3521 3544
3545void
3546android_sync (void)
3547{
3548 (*android_java_env)->CallVoidMethod (android_java_env,
3549 emacs_service,
3550 service_class.sync);
3551 android_exception_check ();
3552}
3553
3522 3554
3523 3555
3524#undef faccessat 3556#undef faccessat
diff --git a/src/androidfns.c b/src/androidfns.c
index ab136bc2722..bb37c415069 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/>. */
26#include "blockinput.h" 26#include "blockinput.h"
27#include "keyboard.h" 27#include "keyboard.h"
28#include "buffer.h" 28#include "buffer.h"
29#include "androidgui.h"
29 30
30#ifndef ANDROID_STUBIFY 31#ifndef ANDROID_STUBIFY
31 32
@@ -2282,6 +2283,13 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
2282 android_map_raised (FRAME_ANDROID_WINDOW (tip_f)); 2283 android_map_raised (FRAME_ANDROID_WINDOW (tip_f));
2283 unblock_input (); 2284 unblock_input ();
2284 2285
2286 /* Synchronize with the UI thread. This is required to prevent ugly
2287 black splotches. */
2288 android_sync ();
2289
2290 /* Garbage the tip frame too. */
2291 SET_FRAME_GARBAGED (tip_f);
2292
2285 w->must_be_updated_p = true; 2293 w->must_be_updated_p = true;
2286 update_single_window (w); 2294 update_single_window (w);
2287 flush_frame (tip_f); 2295 flush_frame (tip_f);
diff --git a/src/androidgui.h b/src/androidgui.h
index 0e075fda95e..9df5b073a7c 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -504,6 +504,7 @@ extern void android_move_resize_window (android_window, int, int,
504extern void android_map_raised (android_window); 504extern void android_map_raised (android_window);
505extern void android_translate_coordinates (android_window, int, 505extern void android_translate_coordinates (android_window, int,
506 int, int *, int *); 506 int, int *, int *);
507extern void android_sync (void);
507 508
508#endif 509#endif
509 510
diff --git a/src/androidmenu.c b/src/androidmenu.c
index 7522f9c5a52..6fb4963174b 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/>. */
28 28
29#ifndef ANDROID_STUBIFY 29#ifndef ANDROID_STUBIFY
30 30
31#include <android/log.h>
32
31/* Flag indicating whether or not a popup menu has been posted and not 33/* Flag indicating whether or not a popup menu has been posted and not
32 yet popped down. */ 34 yet popped down. */
33 35
@@ -188,6 +190,35 @@ android_process_events_for_menu (int *id)
188 *id = x_display_list->menu_event_id; 190 *id = x_display_list->menu_event_id;
189} 191}
190 192
193/* Structure describing a ``subprefix'' in the menu. */
194
195struct android_menu_subprefix
196{
197 /* The subprefix above. */
198 struct android_menu_subprefix *last;
199
200 /* The subprefix itself. */
201 Lisp_Object subprefix;
202};
203
204/* Free the subprefixes starting from *DATA. */
205
206static void
207android_free_subprefixes (void *data)
208{
209 struct android_menu_subprefix **head, *subprefix;
210
211 head = data;
212
213 while (*head)
214 {
215 subprefix = *head;
216 *head = subprefix->last;
217
218 xfree (subprefix);
219 }
220}
221
191Lisp_Object 222Lisp_Object
192android_menu_show (struct frame *f, int x, int y, int menuflags, 223android_menu_show (struct frame *f, int x, int y, int menuflags,
193 Lisp_Object title, const char **error_name) 224 Lisp_Object title, const char **error_name)
@@ -198,13 +229,15 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
198 Lisp_Object pane_name, prefix; 229 Lisp_Object pane_name, prefix;
199 const char *pane_string; 230 const char *pane_string;
200 specpdl_ref count, count1; 231 specpdl_ref count, count1;
201 Lisp_Object item_name, enable, def, tem; 232 Lisp_Object item_name, enable, def, tem, entry;
202 jmethodID method; 233 jmethodID method;
203 jobject store; 234 jobject store;
204 bool rc; 235 bool rc;
205 jobject window; 236 jobject window;
206 int id, item_id; 237 int id, item_id, submenu_depth;
207 struct android_dismiss_menu_data data; 238 struct android_dismiss_menu_data data;
239 struct android_menu_subprefix *subprefix, *temp_subprefix;
240 struct android_menu_subprefix *subprefix_1;
208 241
209 count = SPECPDL_INDEX (); 242 count = SPECPDL_INDEX ();
210 243
@@ -232,7 +265,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
232 android_push_local_frame (); 265 android_push_local_frame ();
233 266
234 /* Iterate over the menu. */ 267 /* Iterate over the menu. */
235 i = 0; 268 i = 0, submenu_depth = 0;
236 269
237 while (i < menu_items_used) 270 while (i < menu_items_used)
238 { 271 {
@@ -241,6 +274,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
241 /* This is the start of a new submenu. However, it can be 274 /* This is the start of a new submenu. However, it can be
242 ignored here. */ 275 ignored here. */
243 i += 1; 276 i += 1;
277 submenu_depth += 1;
244 } 278 }
245 else if (EQ (AREF (menu_items, i), Qlambda)) 279 else if (EQ (AREF (menu_items, i), Qlambda))
246 { 280 {
@@ -256,9 +290,18 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
256 if (store != context_menu) 290 if (store != context_menu)
257 ANDROID_DELETE_LOCAL_REF (store); 291 ANDROID_DELETE_LOCAL_REF (store);
258 i += 1; 292 i += 1;
293 submenu_depth -= 1;
259 294
260 eassert (current_context_menu); 295 if (!current_context_menu || submenu_depth < 0)
296 {
297 __android_log_print (ANDROID_LOG_FATAL, __func__,
298 "unbalanced submenu pop in menu_items");
299 emacs_abort ();
300 }
261 } 301 }
302 else if (EQ (AREF (menu_items, i), Qt)
303 && submenu_depth != 0)
304 i += MENU_ITEMS_PANE_LENGTH;
262 else if (EQ (AREF (menu_items, i), Qquote)) 305 else if (EQ (AREF (menu_items, i), Qquote))
263 i += 1; 306 i += 1;
264 else if (EQ (AREF (menu_items, i), Qt)) 307 else if (EQ (AREF (menu_items, i), Qt))
@@ -300,8 +343,8 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
300 /* This is an actual menu item (or submenu). Add it to the 343 /* This is an actual menu item (or submenu). Add it to the
301 menu. */ 344 menu. */
302 345
303 if (i + MENU_ITEMS_ITEM_LENGTH < menu_items_used && 346 if (i + MENU_ITEMS_ITEM_LENGTH < menu_items_used
304 NILP (AREF (menu_items, i + MENU_ITEMS_ITEM_LENGTH))) 347 && NILP (AREF (menu_items, i + MENU_ITEMS_ITEM_LENGTH)))
305 { 348 {
306 /* This is a submenu. Add it. */ 349 /* This is a submenu. Add it. */
307 title_string = (!NILP (item_name) 350 title_string = (!NILP (item_name)
@@ -312,7 +355,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
312 = (*android_java_env)->CallObjectMethod (android_java_env, 355 = (*android_java_env)->CallObjectMethod (android_java_env,
313 current_context_menu, 356 current_context_menu,
314 menu_class.add_submenu, 357 menu_class.add_submenu,
315 title_string); 358 title_string, NULL);
316 android_exception_check (); 359 android_exception_check ();
317 360
318 if (store != context_menu) 361 if (store != context_menu)
@@ -385,13 +428,78 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
385 /* This means no menu item was selected. */ 428 /* This means no menu item was selected. */
386 goto finish; 429 goto finish;
387 430
388 /* id is an index into menu_items. Check that it remains 431 /* This means the id is invalid. */
389 valid. */
390 if (id >= ASIZE (menu_items)) 432 if (id >= ASIZE (menu_items))
391 goto finish; 433 goto finish;
392 434
393 /* Now return the menu item at that location. */ 435 /* Now return the menu item at that location. */
394 tem = AREF (menu_items, id); 436 tem = Qnil;
437 subprefix = NULL;
438 record_unwind_protect_ptr (android_free_subprefixes, &subprefix);
439
440 /* Find the selected item, and its pane, to return
441 the proper value. */
442
443 prefix = entry = Qnil;
444 i = 0;
445 while (i < menu_items_used)
446 {
447 if (NILP (AREF (menu_items, i)))
448 {
449 temp_subprefix = xmalloc (sizeof *temp_subprefix);
450 temp_subprefix->last = subprefix;
451 subprefix = temp_subprefix;
452 subprefix->subprefix = prefix;
453
454 prefix = entry;
455 i++;
456 }
457 else if (EQ (AREF (menu_items, i), Qlambda))
458 {
459 prefix = subprefix->subprefix;
460 temp_subprefix = subprefix->last;
461 xfree (subprefix);
462 subprefix = temp_subprefix;
463
464 i++;
465 }
466 else if (EQ (AREF (menu_items, i), Qt))
467 {
468 prefix
469 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
470 i += MENU_ITEMS_PANE_LENGTH;
471 }
472 /* Ignore a nil in the item list.
473 It's meaningful only for dialog boxes. */
474 else if (EQ (AREF (menu_items, i), Qquote))
475 i += 1;
476 else
477 {
478 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
479
480 if (i + MENU_ITEMS_ITEM_VALUE == id)
481 {
482 if (menuflags & MENU_KEYMAPS)
483 {
484 entry = list1 (entry);
485
486 if (!NILP (prefix))
487 entry = Fcons (prefix, entry);
488
489 for (subprefix_1 = subprefix; subprefix_1;
490 subprefix_1 = subprefix_1->last)
491 if (!NILP (subprefix_1->subprefix))
492 entry = Fcons (subprefix_1->subprefix, entry);
493 }
494
495 tem = entry;
496 }
497 i += MENU_ITEMS_ITEM_LENGTH;
498 }
499 }
500
501 Fprint (tem, Qexternal_debugging_output);
502
395 unblock_input (); 503 unblock_input ();
396 return unbind_to (count, tem); 504 return unbind_to (count, tem);
397 505
diff --git a/src/androidterm.c b/src/androidterm.c
index 4017fec60a5..6f452a52d85 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -689,6 +689,16 @@ handle_one_android_event (struct android_display_info *dpyinfo,
689 goto OTHER; 689 goto OTHER;
690 690
691 case ANDROID_MOTION_NOTIFY: 691 case ANDROID_MOTION_NOTIFY:
692
693 previous_help_echo_string = help_echo_string;
694 help_echo_string = Qnil;
695
696 if (hlinfo->mouse_face_hidden)
697 {
698 hlinfo->mouse_face_hidden = false;
699 clear_mouse_face (hlinfo);
700 }
701
692 f = any; 702 f = any;
693 703
694 if (f) 704 if (f)
diff --git a/src/menu.c b/src/menu.c
index 73d4215b94b..e1f899858d3 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -167,7 +167,7 @@ ensure_menu_items (int items)
167 } 167 }
168} 168}
169 169
170#ifdef HAVE_EXT_MENU_BAR 170#if defined HAVE_EXT_MENU_BAR || defined HAVE_ANDROID
171 171
172/* Begin a submenu. */ 172/* Begin a submenu. */
173 173
@@ -191,7 +191,7 @@ push_submenu_end (void)
191 menu_items_submenu_depth--; 191 menu_items_submenu_depth--;
192} 192}
193 193
194#endif /* HAVE_EXT_MENU_BAR */ 194#endif /* HAVE_EXT_MENU_BAR || HAVE_ANDROID */
195 195
196/* Indicate boundary between left and right. */ 196/* Indicate boundary between left and right. */
197 197
@@ -420,8 +420,9 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
420 AREF (item_properties, ITEM_PROPERTY_SELECTED), 420 AREF (item_properties, ITEM_PROPERTY_SELECTED),
421 AREF (item_properties, ITEM_PROPERTY_HELP)); 421 AREF (item_properties, ITEM_PROPERTY_HELP));
422 422
423#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) \ 423#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) \
424 || defined (HAVE_NTGUI) || defined (HAVE_HAIKU) || defined (HAVE_PGTK) 424 || defined (HAVE_NTGUI) || defined (HAVE_HAIKU) || defined (HAVE_PGTK) \
425 || defined (HAVE_ANDROID)
425 /* Display a submenu using the toolkit. */ 426 /* Display a submenu using the toolkit. */
426 if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame)) 427 if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame))
427 && ! (NILP (map) || NILP (enabled))) 428 && ! (NILP (map) || NILP (enabled)))