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/android.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/android.c')
| -rw-r--r-- | src/android.c | 169 |
1 files changed, 148 insertions, 21 deletions
diff --git a/src/android.c b/src/android.c index fba43129ee3..e4022501f9d 100644 --- a/src/android.c +++ b/src/android.c | |||
| @@ -87,6 +87,7 @@ struct android_emacs_service | |||
| 87 | jmethodID get_screen_width; | 87 | jmethodID get_screen_width; |
| 88 | jmethodID get_screen_height; | 88 | jmethodID get_screen_height; |
| 89 | jmethodID detect_mouse; | 89 | jmethodID detect_mouse; |
| 90 | jmethodID name_keysym; | ||
| 90 | }; | 91 | }; |
| 91 | 92 | ||
| 92 | struct android_emacs_pixmap | 93 | struct android_emacs_pixmap |
| @@ -229,14 +230,14 @@ static volatile bool android_pselect_completed; | |||
| 229 | /* The global event queue. */ | 230 | /* The global event queue. */ |
| 230 | static struct android_event_queue event_queue; | 231 | static struct android_event_queue event_queue; |
| 231 | 232 | ||
| 232 | /* Semaphore used to signal select completion. */ | 233 | /* Semaphores used to signal select completion and start. */ |
| 233 | static sem_t android_pselect_sem; | 234 | static sem_t android_pselect_sem, android_pselect_start_sem; |
| 234 | 235 | ||
| 235 | static void * | 236 | static void * |
| 236 | android_run_select_thread (void *data) | 237 | android_run_select_thread (void *data) |
| 237 | { | 238 | { |
| 238 | sigset_t signals; | 239 | sigset_t signals; |
| 239 | int sig, rc; | 240 | int rc; |
| 240 | 241 | ||
| 241 | sigfillset (&signals); | 242 | sigfillset (&signals); |
| 242 | 243 | ||
| @@ -245,23 +246,10 @@ android_run_select_thread (void *data) | |||
| 245 | "pthread_sigmask: %s", | 246 | "pthread_sigmask: %s", |
| 246 | strerror (errno)); | 247 | strerror (errno)); |
| 247 | 248 | ||
| 248 | sigemptyset (&signals); | ||
| 249 | sigaddset (&signals, SIGUSR1); | ||
| 250 | |||
| 251 | if (pthread_sigmask (SIG_UNBLOCK, &signals, NULL)) | ||
| 252 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 253 | "pthread_sigmask: %s", | ||
| 254 | strerror (errno)); | ||
| 255 | |||
| 256 | sigemptyset (&signals); | ||
| 257 | sigaddset (&signals, SIGUSR2); | ||
| 258 | |||
| 259 | while (true) | 249 | while (true) |
| 260 | { | 250 | { |
| 261 | /* Keep waiting for SIGUSR2, ignoring EINTR in the meantime. */ | 251 | /* Wait for the thread to be released. */ |
| 262 | 252 | sem_wait (&android_pselect_start_sem); | |
| 263 | while (sigwait (&signals, &sig)) | ||
| 264 | /* Spin. */; | ||
| 265 | 253 | ||
| 266 | /* Get the select lock and call pselect. */ | 254 | /* Get the select lock and call pselect. */ |
| 267 | pthread_mutex_lock (&event_queue.select_mutex); | 255 | pthread_mutex_lock (&event_queue.select_mutex); |
| @@ -322,6 +310,7 @@ android_init_events (void) | |||
| 322 | strerror (errno)); | 310 | strerror (errno)); |
| 323 | 311 | ||
| 324 | sem_init (&android_pselect_sem, 0, 0); | 312 | sem_init (&android_pselect_sem, 0, 0); |
| 313 | sem_init (&android_pselect_start_sem, 0, 0); | ||
| 325 | 314 | ||
| 326 | event_queue.events.next = &event_queue.events; | 315 | event_queue.events.next = &event_queue.events; |
| 327 | event_queue.events.last = &event_queue.events; | 316 | event_queue.events.last = &event_queue.events; |
| @@ -444,7 +433,9 @@ android_select (int nfds, fd_set *readfds, fd_set *writefds, | |||
| 444 | android_pselect_sigset = sigset; | 433 | android_pselect_sigset = sigset; |
| 445 | pthread_mutex_unlock (&event_queue.select_mutex); | 434 | pthread_mutex_unlock (&event_queue.select_mutex); |
| 446 | 435 | ||
| 447 | pthread_kill (event_queue.select_thread, SIGUSR2); | 436 | /* Release the select thread. */ |
| 437 | sem_post (&android_pselect_start_sem); | ||
| 438 | |||
| 448 | pthread_cond_wait (&event_queue.read_var, &event_queue.mutex); | 439 | pthread_cond_wait (&event_queue.read_var, &event_queue.mutex); |
| 449 | 440 | ||
| 450 | /* Interrupt the select thread now, in case it's still in | 441 | /* Interrupt the select thread now, in case it's still in |
| @@ -1058,6 +1049,7 @@ android_init_emacs_service (void) | |||
| 1058 | FIND_METHOD (get_screen_width, "getScreenWidth", "(Z)I"); | 1049 | FIND_METHOD (get_screen_width, "getScreenWidth", "(Z)I"); |
| 1059 | FIND_METHOD (get_screen_height, "getScreenHeight", "(Z)I"); | 1050 | FIND_METHOD (get_screen_height, "getScreenHeight", "(Z)I"); |
| 1060 | FIND_METHOD (detect_mouse, "detectMouse", "()Z"); | 1051 | FIND_METHOD (detect_mouse, "detectMouse", "()Z"); |
| 1052 | FIND_METHOD (name_keysym, "nameKeysym", "(I)Ljava/lang/String;"); | ||
| 1061 | #undef FIND_METHOD | 1053 | #undef FIND_METHOD |
| 1062 | } | 1054 | } |
| 1063 | 1055 | ||
| @@ -1678,6 +1670,7 @@ android_create_window (android_window parent, int x, int y, | |||
| 1678 | jobject object, parent_object, old; | 1670 | jobject object, parent_object, old; |
| 1679 | android_window window; | 1671 | android_window window; |
| 1680 | android_handle prev_max_handle; | 1672 | android_handle prev_max_handle; |
| 1673 | bool override_redirect; | ||
| 1681 | 1674 | ||
| 1682 | parent_object = android_resolve_handle (parent, ANDROID_HANDLE_WINDOW); | 1675 | parent_object = android_resolve_handle (parent, ANDROID_HANDLE_WINDOW); |
| 1683 | 1676 | ||
| @@ -1695,7 +1688,8 @@ android_create_window (android_window parent, int x, int y, | |||
| 1695 | 1688 | ||
| 1696 | constructor | 1689 | constructor |
| 1697 | = (*android_java_env)->GetMethodID (android_java_env, class, "<init>", | 1690 | = (*android_java_env)->GetMethodID (android_java_env, class, "<init>", |
| 1698 | "(SLorg/gnu/emacs/EmacsWindow;IIII)V"); | 1691 | "(SLorg/gnu/emacs/EmacsWindow;" |
| 1692 | "IIIIZ)V"); | ||
| 1699 | assert (constructor != NULL); | 1693 | assert (constructor != NULL); |
| 1700 | 1694 | ||
| 1701 | old = class; | 1695 | old = class; |
| @@ -1707,10 +1701,17 @@ android_create_window (android_window parent, int x, int y, | |||
| 1707 | memory_full (0); | 1701 | memory_full (0); |
| 1708 | } | 1702 | } |
| 1709 | 1703 | ||
| 1704 | /* N.B. that ANDROID_CW_OVERRIDE_REDIRECT can only be set at window | ||
| 1705 | creation time. */ | ||
| 1706 | override_redirect = ((value_mask | ||
| 1707 | & ANDROID_CW_OVERRIDE_REDIRECT) | ||
| 1708 | && attrs->override_redirect); | ||
| 1709 | |||
| 1710 | object = (*android_java_env)->NewObject (android_java_env, class, | 1710 | object = (*android_java_env)->NewObject (android_java_env, class, |
| 1711 | constructor, (jshort) window, | 1711 | constructor, (jshort) window, |
| 1712 | parent_object, (jint) x, (jint) y, | 1712 | parent_object, (jint) x, (jint) y, |
| 1713 | (jint) width, (jint) height); | 1713 | (jint) width, (jint) height, |
| 1714 | (jboolean) override_redirect); | ||
| 1714 | if (!object) | 1715 | if (!object) |
| 1715 | { | 1716 | { |
| 1716 | (*android_java_env)->ExceptionClear (android_java_env); | 1717 | (*android_java_env)->ExceptionClear (android_java_env); |
| @@ -3212,6 +3213,66 @@ android_get_geometry (android_window handle, | |||
| 3212 | ANDROID_DELETE_LOCAL_REF (window_geometry); | 3213 | ANDROID_DELETE_LOCAL_REF (window_geometry); |
| 3213 | } | 3214 | } |
| 3214 | 3215 | ||
| 3216 | void | ||
| 3217 | android_move_resize_window (android_window window, int x, int y, | ||
| 3218 | unsigned int width, unsigned int height) | ||
| 3219 | { | ||
| 3220 | android_move_window (window, x, y); | ||
| 3221 | android_resize_window (window, width, height); | ||
| 3222 | } | ||
| 3223 | |||
| 3224 | void | ||
| 3225 | android_map_raised (android_window window) | ||
| 3226 | { | ||
| 3227 | android_raise_window (window); | ||
| 3228 | android_map_window (window); | ||
| 3229 | } | ||
| 3230 | |||
| 3231 | void | ||
| 3232 | android_translate_coordinates (android_window src, int x, | ||
| 3233 | int y, int *root_x, int *root_y) | ||
| 3234 | { | ||
| 3235 | jobject window; | ||
| 3236 | jarray coordinates; | ||
| 3237 | jmethodID method; | ||
| 3238 | jint *ints; | ||
| 3239 | |||
| 3240 | window = android_resolve_handle (src, ANDROID_HANDLE_WINDOW); | ||
| 3241 | method = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 3242 | "translateCoordinates", | ||
| 3243 | "(II)[I"); | ||
| 3244 | coordinates | ||
| 3245 | = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 3246 | window, method, | ||
| 3247 | (jint) x, (jint) y); | ||
| 3248 | |||
| 3249 | if (!coordinates) | ||
| 3250 | { | ||
| 3251 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 3252 | memory_full (0); | ||
| 3253 | } | ||
| 3254 | |||
| 3255 | /* The array must contain two elements: X, Y translated to the root | ||
| 3256 | window. */ | ||
| 3257 | eassert ((*android_java_env)->GetArrayLength (android_java_env, | ||
| 3258 | coordinates) | ||
| 3259 | == 2); | ||
| 3260 | |||
| 3261 | /* Obtain the coordinates from the array. */ | ||
| 3262 | ints = (*android_java_env)->GetIntArrayElements (android_java_env, | ||
| 3263 | coordinates, NULL); | ||
| 3264 | *root_x = ints[0]; | ||
| 3265 | *root_y = ints[1]; | ||
| 3266 | |||
| 3267 | /* Release the coordinates. */ | ||
| 3268 | (*android_java_env)->ReleaseIntArrayElements (android_java_env, | ||
| 3269 | coordinates, ints, | ||
| 3270 | JNI_ABORT); | ||
| 3271 | |||
| 3272 | /* And free the local reference. */ | ||
| 3273 | ANDROID_DELETE_LOCAL_REF (coordinates); | ||
| 3274 | } | ||
| 3275 | |||
| 3215 | 3276 | ||
| 3216 | 3277 | ||
| 3217 | /* Low level drawing primitives. */ | 3278 | /* Low level drawing primitives. */ |
| @@ -3384,6 +3445,30 @@ android_set_dont_accept_focus (android_window handle, | |||
| 3384 | (jboolean) no_accept_focus); | 3445 | (jboolean) no_accept_focus); |
| 3385 | } | 3446 | } |
| 3386 | 3447 | ||
| 3448 | void | ||
| 3449 | android_get_keysym_name (int keysym, char *name_return, size_t size) | ||
| 3450 | { | ||
| 3451 | jobject string; | ||
| 3452 | const char *buffer; | ||
| 3453 | |||
| 3454 | string = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 3455 | emacs_service, | ||
| 3456 | service_class.name_keysym, | ||
| 3457 | (jint) keysym); | ||
| 3458 | android_exception_check (); | ||
| 3459 | |||
| 3460 | buffer = (*android_java_env)->GetStringUTFChars (android_java_env, | ||
| 3461 | (jstring) string, | ||
| 3462 | NULL); | ||
| 3463 | android_exception_check (); | ||
| 3464 | strncpy (name_return, buffer, size - 1); | ||
| 3465 | |||
| 3466 | (*android_java_env)->ReleaseStringUTFChars (android_java_env, | ||
| 3467 | (jstring) string, | ||
| 3468 | buffer); | ||
| 3469 | ANDROID_DELETE_LOCAL_REF (string); | ||
| 3470 | } | ||
| 3471 | |||
| 3387 | 3472 | ||
| 3388 | 3473 | ||
| 3389 | #undef faccessat | 3474 | #undef faccessat |
| @@ -3525,6 +3610,48 @@ emacs_abort (void) | |||
| 3525 | abort (); | 3610 | abort (); |
| 3526 | } | 3611 | } |
| 3527 | 3612 | ||
| 3613 | |||
| 3614 | |||
| 3615 | /* Given a Lisp string TEXT, return a local reference to an equivalent | ||
| 3616 | Java string. */ | ||
| 3617 | |||
| 3618 | jstring | ||
| 3619 | android_build_string (Lisp_Object text) | ||
| 3620 | { | ||
| 3621 | Lisp_Object encoded; | ||
| 3622 | jstring string; | ||
| 3623 | |||
| 3624 | encoded = ENCODE_UTF_8 (text); | ||
| 3625 | |||
| 3626 | /* Note that Java expects this string to be in ``modified UTF | ||
| 3627 | encoding'', which is actually UTF-8, except with NUL encoded as a | ||
| 3628 | two-byte sequence. The only consequence of passing an actual | ||
| 3629 | UTF-8 string is that NUL bytes cannot be represented, which is | ||
| 3630 | not really of consequence. */ | ||
| 3631 | string = (*android_java_env)->NewStringUTF (android_java_env, | ||
| 3632 | SSDATA (encoded)); | ||
| 3633 | if (!string) | ||
| 3634 | { | ||
| 3635 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 3636 | memory_full (0); | ||
| 3637 | } | ||
| 3638 | |||
| 3639 | return string; | ||
| 3640 | } | ||
| 3641 | |||
| 3642 | /* Check for JNI exceptions and call memory_full in that | ||
| 3643 | situation. */ | ||
| 3644 | |||
| 3645 | void | ||
| 3646 | android_exception_check (void) | ||
| 3647 | { | ||
| 3648 | if ((*android_java_env)->ExceptionCheck (android_java_env)) | ||
| 3649 | { | ||
| 3650 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 3651 | memory_full (0); | ||
| 3652 | } | ||
| 3653 | } | ||
| 3654 | |||
| 3528 | #else /* ANDROID_STUBIFY */ | 3655 | #else /* ANDROID_STUBIFY */ |
| 3529 | 3656 | ||
| 3530 | /* X emulation functions for Android. */ | 3657 | /* X emulation functions for Android. */ |