aboutsummaryrefslogtreecommitdiffstats
path: root/src/androidmenu.c
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/androidmenu.c
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/androidmenu.c')
-rw-r--r--src/androidmenu.c128
1 files changed, 118 insertions, 10 deletions
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