diff options
| author | Po Lu | 2023-01-14 22:12:16 +0800 |
|---|---|---|
| committer | Po Lu | 2023-01-14 22:12:16 +0800 |
| commit | 2b87ab7b27163fbd7b6b64c5a44e26b0e692c00a (patch) | |
| tree | 3ab31df90bd435009d2d42b636ce3baf33bd2b28 /src/androidmenu.c | |
| parent | 28a9baccd4c8e997895d3adb3cfce4a11fa29896 (diff) | |
| download | emacs-2b87ab7b27163fbd7b6b64c5a44e26b0e692c00a.tar.gz emacs-2b87ab7b27163fbd7b6b64c5a44e26b0e692c00a.zip | |
Update Android port
* java/Makefile.in (clean): Fix distclean and bootstrap-clean rules.
* java/debug.sh (jdb_port):
(attach_existing):
(num_pids):
(line): Add new options to upload a gdbserver binary to the device.
* java/org/gnu/emacs/EmacsActivity.java (EmacsActivity): Make
focusedActivities public.
* java/org/gnu/emacs/EmacsContextMenu.java (EmacsContextMenu):
New class.
* java/org/gnu/emacs/EmacsDrawRectangle.java (perform): Fix
bounds computation.
* java/org/gnu/emacs/EmacsGC.java (markDirty): Set stroke width
explicitly.
* java/org/gnu/emacs/EmacsService.java (EmacsService)
(getLocationOnScreen, nameKeysym): New functions.
* java/org/gnu/emacs/EmacsView.java (EmacsView): Disable focus
highlight.
(onCreateContextMenu, popupMenu, cancelPopupMenu): New
functions.
* java/org/gnu/emacs/EmacsWindow.java (EmacsWindow): Implement a
kind of ``override redirect'' window for tooltips.
* src/android.c (struct android_emacs_service): New method
`name_keysym'.
(android_run_select_thread, android_init_events):
(android_select): Release select thread on semaphores instead of
signals to avoid one nasty race on SIGUSR2 delivery.
(android_init_emacs_service): Initialize new method.
(android_create_window): Handle CW_OVERRIDE_REDIRECT.
(android_move_resize_window, android_map_raised)
(android_translate_coordinates, android_get_keysym_name)
(android_build_string, android_exception_check): New functions.
* src/android.h: Update prototypes.
* src/androidfns.c (android_set_parent_frame, Fx_create_frame)
(unwind_create_tip_frame, android_create_tip_frame)
(android_hide_tip, compute_tip_xy, Fx_show_tip, Fx_hide_tip)
(syms_of_androidfns): Implement tooltips and iconification
reporting.
* src/androidgui.h (enum android_window_value_mask): Add
CWOverrideRedirect.
(struct android_set_window_attributes): Add `override_redirect'.
(ANDROID_IS_MODIFIER_KEY): Recognize Caps Lock.
* src/androidmenu.c (struct android_emacs_context_menu): New
struct.
(android_init_emacs_context_menu, android_unwind_local_frame)
(android_push_local_frame, android_menu_show, init_androidmenu):
New functions.
* src/androidterm.c (handle_one_android_event): Fix NULL pointer
dereference.
(android_fullscreen_hook): Handle fullscreen correctly.
(android_draw_box_rect): Fix top line.
(get_keysym_name): Implement function.
(android_create_terminal): Remove scroll bar stubs and add menu
hook.
* src/androidterm.h: Update prototypes.
* src/emacs.c (android_emacs_init): Initialize androidmenu.c.
* xcompile/Makefile.in: Fix clean rules.
Diffstat (limited to 'src/androidmenu.c')
| -rw-r--r-- | src/androidmenu.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/src/androidmenu.c b/src/androidmenu.c index 6f6e4ca8de9..0f0c6f4ef1f 100644 --- a/src/androidmenu.c +++ b/src/androidmenu.c | |||
| @@ -21,6 +21,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 21 | 21 | ||
| 22 | #include "lisp.h" | 22 | #include "lisp.h" |
| 23 | #include "androidterm.h" | 23 | #include "androidterm.h" |
| 24 | #include "android.h" | ||
| 25 | #include "blockinput.h" | ||
| 26 | #include "keyboard.h" | ||
| 27 | #include "menu.h" | ||
| 24 | 28 | ||
| 25 | #ifndef ANDROID_STUBIFY | 29 | #ifndef ANDROID_STUBIFY |
| 26 | 30 | ||
| @@ -35,4 +39,293 @@ popup_activated (void) | |||
| 35 | return popup_activated_flag; | 39 | return popup_activated_flag; |
| 36 | } | 40 | } |
| 37 | 41 | ||
| 42 | |||
| 43 | |||
| 44 | /* Toolkit menu implementation. */ | ||
| 45 | |||
| 46 | /* Structure describing the EmacsContextMenu class. */ | ||
| 47 | |||
| 48 | struct android_emacs_context_menu | ||
| 49 | { | ||
| 50 | jclass class; | ||
| 51 | jmethodID create_context_menu; | ||
| 52 | jmethodID add_item; | ||
| 53 | jmethodID add_submenu; | ||
| 54 | jmethodID add_pane; | ||
| 55 | jmethodID parent; | ||
| 56 | jmethodID display; | ||
| 57 | }; | ||
| 58 | |||
| 59 | /* Identifiers associated with the EmacsContextMenu class. */ | ||
| 60 | static struct android_emacs_context_menu menu_class; | ||
| 61 | |||
| 62 | static void | ||
| 63 | android_init_emacs_context_menu (void) | ||
| 64 | { | ||
| 65 | jclass old; | ||
| 66 | |||
| 67 | menu_class.class | ||
| 68 | = (*android_java_env)->FindClass (android_java_env, | ||
| 69 | "org/gnu/emacs/EmacsContextMenu"); | ||
| 70 | eassert (menu_class.class); | ||
| 71 | |||
| 72 | old = menu_class.class; | ||
| 73 | menu_class.class | ||
| 74 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 75 | (jobject) old); | ||
| 76 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 77 | |||
| 78 | if (!menu_class.class) | ||
| 79 | emacs_abort (); | ||
| 80 | |||
| 81 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 82 | menu_class.c_name \ | ||
| 83 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 84 | menu_class.class, \ | ||
| 85 | name, signature); \ | ||
| 86 | eassert (menu_class.c_name); | ||
| 87 | |||
| 88 | #define FIND_METHOD_STATIC(c_name, name, signature) \ | ||
| 89 | menu_class.c_name \ | ||
| 90 | = (*android_java_env)->GetStaticMethodID (android_java_env, \ | ||
| 91 | menu_class.class, \ | ||
| 92 | name, signature); \ | ||
| 93 | eassert (menu_class.c_name); | ||
| 94 | |||
| 95 | FIND_METHOD_STATIC (create_context_menu, "createContextMenu", | ||
| 96 | "(Ljava/lang/String;)Lorg/gnu/emacs/EmacsContextMenu;"); | ||
| 97 | |||
| 98 | FIND_METHOD (add_item, "addItem", "(ILjava/lang/String;Z)V"); | ||
| 99 | FIND_METHOD (add_submenu, "addSubmenu", "(Ljava/lang/String;" | ||
| 100 | "Ljava/lang/String;)Lorg/gnu/emacs/EmacsContextMenu;"); | ||
| 101 | FIND_METHOD (add_pane, "addPane", "(Ljava/lang/String;)V"); | ||
| 102 | FIND_METHOD (parent, "parent", "()Lorg/gnu/emacs/EmacsContextMenu;"); | ||
| 103 | FIND_METHOD (display, "display", "(Lorg/gnu/emacs/EmacsWindow;II)Z"); | ||
| 104 | |||
| 105 | #undef FIND_METHOD | ||
| 106 | #undef FIND_METHOD_STATIC | ||
| 107 | } | ||
| 108 | |||
| 109 | static void | ||
| 110 | android_unwind_local_frame (void) | ||
| 111 | { | ||
| 112 | (*android_java_env)->PopLocalFrame (android_java_env, NULL); | ||
| 113 | } | ||
| 114 | |||
| 115 | /* Push a local reference frame to the JVM stack and record it on the | ||
| 116 | specpdl. Release local references created within that frame when | ||
| 117 | the specpdl is unwound past where it is after returning. */ | ||
| 118 | |||
| 119 | static void | ||
| 120 | android_push_local_frame (void) | ||
| 121 | { | ||
| 122 | int rc; | ||
| 123 | |||
| 124 | rc = (*android_java_env)->PushLocalFrame (android_java_env, 30); | ||
| 125 | |||
| 126 | /* This means the JVM ran out of memory. */ | ||
| 127 | if (rc < 1) | ||
| 128 | android_exception_check (); | ||
| 129 | |||
| 130 | record_unwind_protect_void (android_unwind_local_frame); | ||
| 131 | } | ||
| 132 | |||
| 133 | Lisp_Object | ||
| 134 | android_menu_show (struct frame *f, int x, int y, int menuflags, | ||
| 135 | Lisp_Object title, const char **error_name) | ||
| 136 | { | ||
| 137 | jobject context_menu, current_context_menu; | ||
| 138 | jobject title_string, temp; | ||
| 139 | size_t i; | ||
| 140 | Lisp_Object pane_name, prefix; | ||
| 141 | const char *pane_string; | ||
| 142 | specpdl_ref count, count1; | ||
| 143 | Lisp_Object item_name, enable, def; | ||
| 144 | jmethodID method; | ||
| 145 | jobject store; | ||
| 146 | bool rc; | ||
| 147 | jobject window; | ||
| 148 | |||
| 149 | count = SPECPDL_INDEX (); | ||
| 150 | |||
| 151 | block_input (); | ||
| 152 | |||
| 153 | /* Push the first local frame. */ | ||
| 154 | android_push_local_frame (); | ||
| 155 | |||
| 156 | /* Push the first local frame for the context menu. */ | ||
| 157 | title_string = (!NILP (title) | ||
| 158 | ? (jobject) android_build_string (title) | ||
| 159 | : NULL); | ||
| 160 | method = menu_class.create_context_menu; | ||
| 161 | current_context_menu = context_menu | ||
| 162 | = (*android_java_env)->CallStaticObjectMethod (android_java_env, | ||
| 163 | menu_class.class, | ||
| 164 | method, | ||
| 165 | title_string); | ||
| 166 | |||
| 167 | if (title_string) | ||
| 168 | ANDROID_DELETE_LOCAL_REF (title_string); | ||
| 169 | |||
| 170 | /* Push the second local frame for temporaries. */ | ||
| 171 | count1 = SPECPDL_INDEX (); | ||
| 172 | android_push_local_frame (); | ||
| 173 | |||
| 174 | /* Iterate over the menu. */ | ||
| 175 | i = 0; | ||
| 176 | |||
| 177 | while (i < menu_items_used) | ||
| 178 | { | ||
| 179 | if (NILP (AREF (menu_items, i))) | ||
| 180 | { | ||
| 181 | /* This is the start of a new submenu. However, it can be | ||
| 182 | ignored here. */ | ||
| 183 | i += 1; | ||
| 184 | } | ||
| 185 | else if (EQ (AREF (menu_items, i), Qlambda)) | ||
| 186 | { | ||
| 187 | /* This is the end of a submenu. Go back to the previous | ||
| 188 | context menu. */ | ||
| 189 | store = current_context_menu; | ||
| 190 | current_context_menu | ||
| 191 | = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 192 | current_context_menu, | ||
| 193 | menu_class.parent); | ||
| 194 | android_exception_check (); | ||
| 195 | |||
| 196 | if (store != context_menu) | ||
| 197 | ANDROID_DELETE_LOCAL_REF (store); | ||
| 198 | i += 1; | ||
| 199 | |||
| 200 | eassert (current_context_menu); | ||
| 201 | } | ||
| 202 | else if (EQ (AREF (menu_items, i), Qquote)) | ||
| 203 | i += 1; | ||
| 204 | else if (EQ (AREF (menu_items, i), Qt)) | ||
| 205 | { | ||
| 206 | /* This is a new pane. Switch back to the topmost context | ||
| 207 | menu. */ | ||
| 208 | if (current_context_menu != context_menu) | ||
| 209 | ANDROID_DELETE_LOCAL_REF (current_context_menu); | ||
| 210 | current_context_menu = context_menu; | ||
| 211 | |||
| 212 | /* Now figure out the title of this pane. */ | ||
| 213 | pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); | ||
| 214 | prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); | ||
| 215 | pane_string = (NILP (pane_name) | ||
| 216 | ? "" : SSDATA (pane_name)); | ||
| 217 | if ((menuflags & MENU_KEYMAPS) && !NILP (prefix)) | ||
| 218 | pane_string++; | ||
| 219 | |||
| 220 | /* Add the pane. */ | ||
| 221 | temp = (*android_java_env)->NewStringUTF (android_java_env, | ||
| 222 | pane_string); | ||
| 223 | android_exception_check (); | ||
| 224 | |||
| 225 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 226 | current_context_menu, | ||
| 227 | menu_class.add_pane, | ||
| 228 | temp); | ||
| 229 | android_exception_check (); | ||
| 230 | ANDROID_DELETE_LOCAL_REF (temp); | ||
| 231 | |||
| 232 | i += MENU_ITEMS_PANE_LENGTH; | ||
| 233 | } | ||
| 234 | else | ||
| 235 | { | ||
| 236 | item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); | ||
| 237 | enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); | ||
| 238 | def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION); | ||
| 239 | |||
| 240 | /* This is an actual menu item (or submenu). Add it to the | ||
| 241 | menu. */ | ||
| 242 | |||
| 243 | if (i + MENU_ITEMS_ITEM_LENGTH < menu_items_used && | ||
| 244 | NILP (AREF (menu_items, i + MENU_ITEMS_ITEM_LENGTH))) | ||
| 245 | { | ||
| 246 | /* This is a submenu. Add it. */ | ||
| 247 | title_string = (!NILP (item_name) | ||
| 248 | ? android_build_string (item_name) | ||
| 249 | : NULL); | ||
| 250 | store = current_context_menu; | ||
| 251 | current_context_menu | ||
| 252 | = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 253 | current_context_menu, | ||
| 254 | menu_class.add_submenu, | ||
| 255 | title_string); | ||
| 256 | android_exception_check (); | ||
| 257 | |||
| 258 | if (store != context_menu) | ||
| 259 | ANDROID_DELETE_LOCAL_REF (store); | ||
| 260 | |||
| 261 | if (title_string) | ||
| 262 | ANDROID_DELETE_LOCAL_REF (title_string); | ||
| 263 | } | ||
| 264 | else if (NILP (def) && menu_separator_name_p (SSDATA (item_name))) | ||
| 265 | /* Ignore this separator item. */ | ||
| 266 | ; | ||
| 267 | else | ||
| 268 | { | ||
| 269 | /* Add this menu item with the appropriate state. */ | ||
| 270 | |||
| 271 | title_string = (!NILP (item_name) | ||
| 272 | ? android_build_string (item_name) | ||
| 273 | : NULL); | ||
| 274 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 275 | current_context_menu, | ||
| 276 | menu_class.add_item, | ||
| 277 | (jint) 1, | ||
| 278 | title_string, | ||
| 279 | (jboolean) !NILP (enable)); | ||
| 280 | android_exception_check (); | ||
| 281 | |||
| 282 | if (title_string) | ||
| 283 | ANDROID_DELETE_LOCAL_REF (title_string); | ||
| 284 | } | ||
| 285 | |||
| 286 | i += MENU_ITEMS_ITEM_LENGTH; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | /* The menu has now been built. Pop the second local frame. */ | ||
| 291 | unbind_to (count1, Qnil); | ||
| 292 | |||
| 293 | /* Now, display the context menu. */ | ||
| 294 | window = android_resolve_handle (FRAME_ANDROID_WINDOW (f), | ||
| 295 | ANDROID_HANDLE_WINDOW); | ||
| 296 | rc = (*android_java_env)->CallBooleanMethod (android_java_env, | ||
| 297 | context_menu, | ||
| 298 | window, (jint) x, | ||
| 299 | (jint) y); | ||
| 300 | android_exception_check (); | ||
| 301 | |||
| 302 | if (!rc) | ||
| 303 | /* This means displaying the menu failed. */ | ||
| 304 | goto finish; | ||
| 305 | |||
| 306 | #if 0 | ||
| 307 | record_unwind_protect_ptr (android_dismiss_menu, &context_menu); | ||
| 308 | |||
| 309 | /* Otherwise, loop waiting for the menu event to arrive. */ | ||
| 310 | android_process_events_for_menu (&id); | ||
| 311 | |||
| 312 | if (!id) | ||
| 313 | /* This means no menu item was selected. */ | ||
| 314 | goto finish; | ||
| 315 | |||
| 316 | #endif | ||
| 317 | |||
| 318 | finish: | ||
| 319 | unblock_input (); | ||
| 320 | return unbind_to (count, Qnil); | ||
| 321 | } | ||
| 322 | |||
| 323 | #endif | ||
| 324 | |||
| 325 | void | ||
| 326 | init_androidmenu (void) | ||
| 327 | { | ||
| 328 | #ifndef ANDROID_STUBIFY | ||
| 329 | android_init_emacs_context_menu (); | ||
| 38 | #endif | 330 | #endif |
| 331 | } | ||