diff options
| author | Po Lu | 2023-01-15 11:57:10 +0800 |
|---|---|---|
| committer | Po Lu | 2023-01-15 11:57:10 +0800 |
| commit | 6e2bc91d924fbeb0ad5728e0424eabc905c0d366 (patch) | |
| tree | f2835948a308d9d0898b9ef868893560048f6812 /src/androidmenu.c | |
| parent | c02a7b2ff48746fab891db16f58ccdc11d161745 (diff) | |
| download | emacs-6e2bc91d924fbeb0ad5728e0424eabc905c0d366.tar.gz emacs-6e2bc91d924fbeb0ad5728e0424eabc905c0d366.zip | |
Implement toolkit menus on Android
* java/org/gnu/emacs/EmacsActivity.java (onContextMenuClosed):
New function.
* java/org/gnu/emacs/EmacsContextMenu.java (EmacsContextMenu):
New field `itemAlreadySelected'.
(onMenuItemClick): New function.
(inflateMenuItems): Attach onClickListener as appropriate.
(display1): Clear itemAlreadySelected.
(display): Fix runnable synchronization.
* java/org/gnu/emacs/EmacsNative.java (sendContextMenu): New
function.
* java/org/gnu/emacs/EmacsView.java (popupMenu):
(cancelPopupMenu): Set popupactive correctly.
* src/android.c (android_run_select_thread): Fix android_select
again.
(android_wait_event): New function.
* src/android.h: Update prototypes.
* src/androidgui.h (enum android_event_type): New
`ANDROID_CONTEXT_MENU' event.
(struct android_menu_event, union android_event): Add new event.
* src/androidmenu.c (struct android_emacs_context_menu): New
structure.
(android_init_emacs_context_menu): Add `dismiss' method.
(struct android_dismiss_menu_data): New structure.
(android_dismiss_menu, android_process_events_for_menu): New
functions.
(android_menu_show): Set an actual item ID.
(popup_activated): Define when stubify as well.
(Fmenu_or_popup_active_p): New function.
(syms_of_androidmenu): New function.
* src/androidterm.c (handle_one_android_event): Handle context
menu events.
* src/androidterm.h (struct android_display_info): New field for
menu item ID.
* src/emacs.c (android_emacs_init): Call syms_of_androidmenu.
* src/xdisp.c (note_mouse_highlight): Return if popup_activated
on Android as well.
Diffstat (limited to 'src/androidmenu.c')
| -rw-r--r-- | src/androidmenu.c | 114 |
1 files changed, 108 insertions, 6 deletions
diff --git a/src/androidmenu.c b/src/androidmenu.c index 0f0c6f4ef1f..7522f9c5a52 100644 --- a/src/androidmenu.c +++ b/src/androidmenu.c | |||
| @@ -54,6 +54,7 @@ struct android_emacs_context_menu | |||
| 54 | jmethodID add_pane; | 54 | jmethodID add_pane; |
| 55 | jmethodID parent; | 55 | jmethodID parent; |
| 56 | jmethodID display; | 56 | jmethodID display; |
| 57 | jmethodID dismiss; | ||
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| 59 | /* Identifiers associated with the EmacsContextMenu class. */ | 60 | /* Identifiers associated with the EmacsContextMenu class. */ |
| @@ -101,6 +102,7 @@ android_init_emacs_context_menu (void) | |||
| 101 | FIND_METHOD (add_pane, "addPane", "(Ljava/lang/String;)V"); | 102 | FIND_METHOD (add_pane, "addPane", "(Ljava/lang/String;)V"); |
| 102 | FIND_METHOD (parent, "parent", "()Lorg/gnu/emacs/EmacsContextMenu;"); | 103 | FIND_METHOD (parent, "parent", "()Lorg/gnu/emacs/EmacsContextMenu;"); |
| 103 | FIND_METHOD (display, "display", "(Lorg/gnu/emacs/EmacsWindow;II)Z"); | 104 | FIND_METHOD (display, "display", "(Lorg/gnu/emacs/EmacsWindow;II)Z"); |
| 105 | FIND_METHOD (dismiss, "dismiss", "(Lorg/gnu/emacs/EmacsWindow;)V"); | ||
| 104 | 106 | ||
| 105 | #undef FIND_METHOD | 107 | #undef FIND_METHOD |
| 106 | #undef FIND_METHOD_STATIC | 108 | #undef FIND_METHOD_STATIC |
| @@ -130,6 +132,62 @@ android_push_local_frame (void) | |||
| 130 | record_unwind_protect_void (android_unwind_local_frame); | 132 | record_unwind_protect_void (android_unwind_local_frame); |
| 131 | } | 133 | } |
| 132 | 134 | ||
| 135 | /* Data for android_dismiss_menu. */ | ||
| 136 | |||
| 137 | struct android_dismiss_menu_data | ||
| 138 | { | ||
| 139 | /* The menu object. */ | ||
| 140 | jobject menu; | ||
| 141 | |||
| 142 | /* The window object. */ | ||
| 143 | jobject window; | ||
| 144 | }; | ||
| 145 | |||
| 146 | /* Cancel the context menu passed in POINTER. Also, clear | ||
| 147 | popup_activated_flag. */ | ||
| 148 | |||
| 149 | static void | ||
| 150 | android_dismiss_menu (void *pointer) | ||
| 151 | { | ||
| 152 | struct android_dismiss_menu_data *data; | ||
| 153 | |||
| 154 | data = pointer; | ||
| 155 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 156 | data->menu, | ||
| 157 | menu_class.dismiss, | ||
| 158 | data->window); | ||
| 159 | popup_activated_flag = 0; | ||
| 160 | } | ||
| 161 | |||
| 162 | /* Recursively process events until a ANDROID_CONTEXT_MENU event | ||
| 163 | arrives. Then, return the item ID specified in the event in | ||
| 164 | *ID. */ | ||
| 165 | |||
| 166 | static void | ||
| 167 | android_process_events_for_menu (int *id) | ||
| 168 | { | ||
| 169 | /* Set menu_event_id to -1; handle_one_android_event will set it to | ||
| 170 | the event ID upon receiving a context menu event. This can cause | ||
| 171 | a non-local exit. */ | ||
| 172 | x_display_list->menu_event_id = -1; | ||
| 173 | |||
| 174 | /* Now wait for the menu event ID to change. */ | ||
| 175 | while (x_display_list->menu_event_id == -1) | ||
| 176 | { | ||
| 177 | /* Wait for events to become available. */ | ||
| 178 | android_wait_event (); | ||
| 179 | |||
| 180 | /* Process pending signals. */ | ||
| 181 | process_pending_signals (); | ||
| 182 | |||
| 183 | /* Maybe quit. */ | ||
| 184 | maybe_quit (); | ||
| 185 | } | ||
| 186 | |||
| 187 | /* Return the ID. */ | ||
| 188 | *id = x_display_list->menu_event_id; | ||
| 189 | } | ||
| 190 | |||
| 133 | Lisp_Object | 191 | Lisp_Object |
| 134 | android_menu_show (struct frame *f, int x, int y, int menuflags, | 192 | android_menu_show (struct frame *f, int x, int y, int menuflags, |
| 135 | Lisp_Object title, const char **error_name) | 193 | Lisp_Object title, const char **error_name) |
| @@ -140,11 +198,13 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 140 | Lisp_Object pane_name, prefix; | 198 | Lisp_Object pane_name, prefix; |
| 141 | const char *pane_string; | 199 | const char *pane_string; |
| 142 | specpdl_ref count, count1; | 200 | specpdl_ref count, count1; |
| 143 | Lisp_Object item_name, enable, def; | 201 | Lisp_Object item_name, enable, def, tem; |
| 144 | jmethodID method; | 202 | jmethodID method; |
| 145 | jobject store; | 203 | jobject store; |
| 146 | bool rc; | 204 | bool rc; |
| 147 | jobject window; | 205 | jobject window; |
| 206 | int id, item_id; | ||
| 207 | struct android_dismiss_menu_data data; | ||
| 148 | 208 | ||
| 149 | count = SPECPDL_INDEX (); | 209 | count = SPECPDL_INDEX (); |
| 150 | 210 | ||
| @@ -266,6 +326,12 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 266 | ; | 326 | ; |
| 267 | else | 327 | else |
| 268 | { | 328 | { |
| 329 | /* Compute the item ID. This is the index of value. | ||
| 330 | Make sure it doesn't overflow. */ | ||
| 331 | |||
| 332 | if (!INT_ADD_OK (0, i + MENU_ITEMS_ITEM_VALUE, &item_id)) | ||
| 333 | memory_full (i + MENU_ITEMS_ITEM_VALUE * sizeof (Lisp_Object)); | ||
| 334 | |||
| 269 | /* Add this menu item with the appropriate state. */ | 335 | /* Add this menu item with the appropriate state. */ |
| 270 | 336 | ||
| 271 | title_string = (!NILP (item_name) | 337 | title_string = (!NILP (item_name) |
| @@ -274,7 +340,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 274 | (*android_java_env)->CallVoidMethod (android_java_env, | 340 | (*android_java_env)->CallVoidMethod (android_java_env, |
| 275 | current_context_menu, | 341 | current_context_menu, |
| 276 | menu_class.add_item, | 342 | menu_class.add_item, |
| 277 | (jint) 1, | 343 | (jint) item_id, |
| 278 | title_string, | 344 | title_string, |
| 279 | (jboolean) !NILP (enable)); | 345 | (jboolean) !NILP (enable)); |
| 280 | android_exception_check (); | 346 | android_exception_check (); |
| @@ -295,6 +361,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 295 | ANDROID_HANDLE_WINDOW); | 361 | ANDROID_HANDLE_WINDOW); |
| 296 | rc = (*android_java_env)->CallBooleanMethod (android_java_env, | 362 | rc = (*android_java_env)->CallBooleanMethod (android_java_env, |
| 297 | context_menu, | 363 | context_menu, |
| 364 | menu_class.display, | ||
| 298 | window, (jint) x, | 365 | window, (jint) x, |
| 299 | (jint) y); | 366 | (jint) y); |
| 300 | android_exception_check (); | 367 | android_exception_check (); |
| @@ -303,25 +370,54 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 303 | /* This means displaying the menu failed. */ | 370 | /* This means displaying the menu failed. */ |
| 304 | goto finish; | 371 | goto finish; |
| 305 | 372 | ||
| 306 | #if 0 | 373 | /* Make sure the context menu is always dismissed. */ |
| 307 | record_unwind_protect_ptr (android_dismiss_menu, &context_menu); | 374 | data.menu = context_menu; |
| 375 | data.window = window; | ||
| 376 | record_unwind_protect_ptr (android_dismiss_menu, &data); | ||
| 308 | 377 | ||
| 309 | /* Otherwise, loop waiting for the menu event to arrive. */ | 378 | /* Next, process events waiting for something to be selected. */ |
| 379 | popup_activated_flag = 1; | ||
| 380 | unblock_input (); | ||
| 310 | android_process_events_for_menu (&id); | 381 | android_process_events_for_menu (&id); |
| 382 | block_input (); | ||
| 311 | 383 | ||
| 312 | if (!id) | 384 | if (!id) |
| 313 | /* This means no menu item was selected. */ | 385 | /* This means no menu item was selected. */ |
| 314 | goto finish; | 386 | goto finish; |
| 315 | 387 | ||
| 316 | #endif | 388 | /* id is an index into menu_items. Check that it remains |
| 389 | valid. */ | ||
| 390 | if (id >= ASIZE (menu_items)) | ||
| 391 | goto finish; | ||
| 392 | |||
| 393 | /* Now return the menu item at that location. */ | ||
| 394 | tem = AREF (menu_items, id); | ||
| 395 | unblock_input (); | ||
| 396 | return unbind_to (count, tem); | ||
| 317 | 397 | ||
| 318 | finish: | 398 | finish: |
| 319 | unblock_input (); | 399 | unblock_input (); |
| 320 | return unbind_to (count, Qnil); | 400 | return unbind_to (count, Qnil); |
| 321 | } | 401 | } |
| 322 | 402 | ||
| 403 | #else | ||
| 404 | |||
| 405 | int | ||
| 406 | popup_activated (void) | ||
| 407 | { | ||
| 408 | return 0; | ||
| 409 | } | ||
| 410 | |||
| 323 | #endif | 411 | #endif |
| 324 | 412 | ||
| 413 | DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, | ||
| 414 | Smenu_or_popup_active_p, 0, 0, 0, | ||
| 415 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 416 | (void) | ||
| 417 | { | ||
| 418 | return (popup_activated ()) ? Qt : Qnil; | ||
| 419 | } | ||
| 420 | |||
| 325 | void | 421 | void |
| 326 | init_androidmenu (void) | 422 | init_androidmenu (void) |
| 327 | { | 423 | { |
| @@ -329,3 +425,9 @@ init_androidmenu (void) | |||
| 329 | android_init_emacs_context_menu (); | 425 | android_init_emacs_context_menu (); |
| 330 | #endif | 426 | #endif |
| 331 | } | 427 | } |
| 428 | |||
| 429 | void | ||
| 430 | syms_of_androidmenu (void) | ||
| 431 | { | ||
| 432 | defsubr (&Smenu_or_popup_active_p); | ||
| 433 | } | ||