diff options
| author | Po Lu | 2023-01-15 15:45:29 +0800 |
|---|---|---|
| committer | Po Lu | 2023-01-15 15:45:29 +0800 |
| commit | da9ae10636b84b88e9eb9c827b03cdaabd1611d1 (patch) | |
| tree | ca5b14036c7771accabfd87dd72e1fc147bf9914 /src/androidmenu.c | |
| parent | a336fd98a1ed1f97d69652cade46f99868f7c7fb (diff) | |
| download | emacs-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.c | 128 |
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 | |||
| 195 | struct 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 | |||
| 206 | static void | ||
| 207 | android_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 | |||
| 191 | Lisp_Object | 222 | Lisp_Object |
| 192 | android_menu_show (struct frame *f, int x, int y, int menuflags, | 223 | android_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 | ||