diff options
| author | Po Lu | 2023-02-15 12:23:03 +0800 |
|---|---|---|
| committer | Po Lu | 2023-02-15 12:23:03 +0800 |
| commit | a158c1d5b964fda36f752998cef076d581dc4df4 (patch) | |
| tree | b9c7a22a7259dbd876be0e047304a338ef05e334 /src/android.c | |
| parent | 5a7855e84abd56e55b456aef4a43ae7623e76899 (diff) | |
| download | emacs-a158c1d5b964fda36f752998cef076d581dc4df4.tar.gz emacs-a158c1d5b964fda36f752998cef076d581dc4df4.zip | |
Update Android port
* configure.ac (HAVE_TEXT_CONVERSION): Define on Android.
* doc/emacs/input.texi (On-Screen Keyboards): Document ``text
conversion'' slightly.
* doc/lispref/commands.texi (Misc Events): Document new
`text-conversion' event.
* java/org/gnu/emacs/EmacsContextMenu.java (display): Use
`syncRunnable'.
* java/org/gnu/emacs/EmacsDialog.java (display): Likewise.
* java/org/gnu/emacs/EmacsEditable.java: Delete file.
* java/org/gnu/emacs/EmacsInputConnection.java
(EmacsInputConnection): Reimplement from scratch.
* java/org/gnu/emacs/EmacsNative.java (EmacsNative): Add new
functions.
* java/org/gnu/emacs/EmacsService.java (EmacsService, getEmacsView)
(getLocationOnScreen, sync, getClipboardManager, restartEmacs):
Use syncRunnable.
(syncRunnable): New function.
(updateIC, resetIC): New functions.
* java/org/gnu/emacs/EmacsView.java (EmacsView): New field
`inputConnection' and `icMode'.
(onCreateInputConnection): Update accordingly.
(setICMode, getICMode): New functions.
* lisp/bindings.el (global-map): Ignore text conversion events.
* src/alloc.c (mark_frame): Mark text conversion data.
* src/android.c (struct android_emacs_service): New fields
`update_ic' and `reset_ic'.
(event_serial): Export.
(android_query_sem): New function.
(android_init_events): Initialize new semaphore.
(android_write_event): Export.
(android_select): Check for UI thread code.
(setEmacsParams, android_init_emacs_service): Initialize new
methods.
(android_check_query, android_begin_query, android_end_query)
(android_run_in_emacs_thread):
(android_update_ic, android_reset_ic): New functions for
managing synchronous queries from one thread to another.
* src/android.h: Export new functions.
* src/androidgui.h (enum android_event_type): Add input method
events.
(enum android_ime_operation, struct android_ime_event)
(union android_event, enum android_ic_mode): New structs and
enums.
* src/androidterm.c (android_window_to_frame): Allow DPYINFO to
be NULL.
(android_decode_utf16, android_handle_ime_event)
(handle_one_android_event, android_sync_edit)
(android_copy_java_string, beginBatchEdit, endBatchEdit)
(commitCompletion, deleteSurroundingText, finishComposingText)
(getSelectedtext, getTextAfterCursor, getTextBeforeCursor)
(setComposingText, setComposingRegion, setSelection, getSelection)
(performEditorAction, getExtractedText): New functions.
(struct android_conversion_query_context):
(android_perform_conversion_query):
(android_text_to_string):
(struct android_get_selection_context):
(android_get_selection):
(struct android_get_extracted_text_context):
(android_get_extracted_text):
(struct android_extracted_text_request_class):
(struct android_extracted_text_class):
(android_update_selection):
(android_reset_conversion):
(android_set_point):
(android_compose_region_changed):
(android_notify_conversion):
(text_conversion_interface): New functions and structures.
(android_term_init): Initialize text conversion.
* src/coding.c (syms_of_coding): Define Qutf_16le on Android.
* src/frame.c (make_frame): Clear conversion data.
(delete_frame): Reset conversion state.
* src/frame.h (enum text_conversion_operation)
(struct text_conversion_action, struct text_conversion_state)
(GCALIGNED_STRUCT): Update structures.
* src/keyboard.c (read_char, readable_events, kbd_buffer_get_event)
(syms_of_keyboard): Handle text conversion events.
* src/lisp.h:
* src/process.c: Fix includes.
* src/textconv.c (enum textconv_batch_edit_flags, textconv_query)
(reset_frame_state, detect_conversion_events)
(restore_selected_window, really_commit_text)
(really_finish_composing_text, really_set_composing_text)
(really_set_composing_region, really_delete_surrounding_text)
(really_set_point, complete_edit)
(handle_pending_conversion_events_1)
(handle_pending_conversion_events, start_batch_edit)
(end_batch_edit, commit_text, finish_composing_text)
(set_composing_text, set_composing_region, textconv_set_point)
(delete_surrounding_text, get_extracted_text)
(report_selected_window_change, report_point_change)
(register_texconv_interface): New functions.
* src/textconv.h (struct textconv_interface)
(TEXTCONV_SKIP_CONVERSION_REGION): Update prototype.
* src/xdisp.c (mark_window_display_accurate_1):
* src/xfns.c (xic_string_conversion_callback):
* src/xterm.c (init_xterm): Adjust accordingly.
Diffstat (limited to 'src/android.c')
| -rw-r--r-- | src/android.c | 295 |
1 files changed, 270 insertions, 25 deletions
diff --git a/src/android.c b/src/android.c index 479eb9b10d4..8f446224dab 100644 --- a/src/android.c +++ b/src/android.c | |||
| @@ -98,6 +98,8 @@ struct android_emacs_service | |||
| 98 | jmethodID sync; | 98 | jmethodID sync; |
| 99 | jmethodID browse_url; | 99 | jmethodID browse_url; |
| 100 | jmethodID restart_emacs; | 100 | jmethodID restart_emacs; |
| 101 | jmethodID update_ic; | ||
| 102 | jmethodID reset_ic; | ||
| 101 | }; | 103 | }; |
| 102 | 104 | ||
| 103 | struct android_emacs_pixmap | 105 | struct android_emacs_pixmap |
| @@ -207,7 +209,7 @@ static struct android_emacs_window window_class; | |||
| 207 | 209 | ||
| 208 | /* The last event serial used. This is a 32 bit value, but it is | 210 | /* The last event serial used. This is a 32 bit value, but it is |
| 209 | stored in unsigned long to be consistent with X. */ | 211 | stored in unsigned long to be consistent with X. */ |
| 210 | static unsigned int event_serial; | 212 | unsigned int event_serial; |
| 211 | 213 | ||
| 212 | /* Unused pointer used to control compiler optimizations. */ | 214 | /* Unused pointer used to control compiler optimizations. */ |
| 213 | void *unused_pointer; | 215 | void *unused_pointer; |
| @@ -408,6 +410,10 @@ android_handle_sigusr1 (int sig, siginfo_t *siginfo, void *arg) | |||
| 408 | 410 | ||
| 409 | #endif | 411 | #endif |
| 410 | 412 | ||
| 413 | /* Semaphore used to indicate completion of a query. | ||
| 414 | This should ideally be defined further down. */ | ||
| 415 | static sem_t android_query_sem; | ||
| 416 | |||
| 411 | /* Set up the global event queue by initializing the mutex and two | 417 | /* Set up the global event queue by initializing the mutex and two |
| 412 | condition variables, and the linked list of events. This must be | 418 | condition variables, and the linked list of events. This must be |
| 413 | called before starting the Emacs thread. Also, initialize the | 419 | called before starting the Emacs thread. Also, initialize the |
| @@ -438,6 +444,7 @@ android_init_events (void) | |||
| 438 | 444 | ||
| 439 | sem_init (&android_pselect_sem, 0, 0); | 445 | sem_init (&android_pselect_sem, 0, 0); |
| 440 | sem_init (&android_pselect_start_sem, 0, 0); | 446 | sem_init (&android_pselect_start_sem, 0, 0); |
| 447 | sem_init (&android_query_sem, 0, 0); | ||
| 441 | 448 | ||
| 442 | event_queue.events.next = &event_queue.events; | 449 | event_queue.events.next = &event_queue.events; |
| 443 | event_queue.events.last = &event_queue.events; | 450 | event_queue.events.last = &event_queue.events; |
| @@ -538,7 +545,7 @@ android_next_event (union android_event *event_return) | |||
| 538 | pthread_mutex_unlock (&event_queue.mutex); | 545 | pthread_mutex_unlock (&event_queue.mutex); |
| 539 | } | 546 | } |
| 540 | 547 | ||
| 541 | static void | 548 | void |
| 542 | android_write_event (union android_event *event) | 549 | android_write_event (union android_event *event) |
| 543 | { | 550 | { |
| 544 | struct android_event_container *container; | 551 | struct android_event_container *container; |
| @@ -576,6 +583,10 @@ android_select (int nfds, fd_set *readfds, fd_set *writefds, | |||
| 576 | static char byte; | 583 | static char byte; |
| 577 | #endif | 584 | #endif |
| 578 | 585 | ||
| 586 | /* Check for and run anything the UI thread wants to run on the main | ||
| 587 | thread. */ | ||
| 588 | android_check_query (); | ||
| 589 | |||
| 579 | pthread_mutex_lock (&event_queue.mutex); | 590 | pthread_mutex_lock (&event_queue.mutex); |
| 580 | 591 | ||
| 581 | if (event_queue.num_events) | 592 | if (event_queue.num_events) |
| @@ -634,6 +645,10 @@ android_select (int nfds, fd_set *readfds, fd_set *writefds, | |||
| 634 | if (nfds_return < 0) | 645 | if (nfds_return < 0) |
| 635 | errno = EINTR; | 646 | errno = EINTR; |
| 636 | 647 | ||
| 648 | /* Now check for and run anything the UI thread wants to run in the | ||
| 649 | main thread. */ | ||
| 650 | android_check_query (); | ||
| 651 | |||
| 637 | return nfds_return; | 652 | return nfds_return; |
| 638 | } | 653 | } |
| 639 | 654 | ||
| @@ -1431,7 +1446,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, | |||
| 1431 | 1446 | ||
| 1432 | /* This may be called from multiple threads. setEmacsParams should | 1447 | /* This may be called from multiple threads. setEmacsParams should |
| 1433 | only ever be called once. */ | 1448 | only ever be called once. */ |
| 1434 | if (__atomic_fetch_add (&emacs_initialized, -1, __ATOMIC_RELAXED)) | 1449 | if (__atomic_fetch_add (&emacs_initialized, -1, __ATOMIC_SEQ_CST)) |
| 1435 | { | 1450 | { |
| 1436 | ANDROID_THROW (env, "java/lang/IllegalArgumentException", | 1451 | ANDROID_THROW (env, "java/lang/IllegalArgumentException", |
| 1437 | "Emacs was already initialized!"); | 1452 | "Emacs was already initialized!"); |
| @@ -1705,6 +1720,10 @@ android_init_emacs_service (void) | |||
| 1705 | FIND_METHOD (browse_url, "browseUrl", "(Ljava/lang/String;)" | 1720 | FIND_METHOD (browse_url, "browseUrl", "(Ljava/lang/String;)" |
| 1706 | "Ljava/lang/String;"); | 1721 | "Ljava/lang/String;"); |
| 1707 | FIND_METHOD (restart_emacs, "restartEmacs", "()V"); | 1722 | FIND_METHOD (restart_emacs, "restartEmacs", "()V"); |
| 1723 | FIND_METHOD (update_ic, "updateIC", | ||
| 1724 | "(Lorg/gnu/emacs/EmacsWindow;IIII)V"); | ||
| 1725 | FIND_METHOD (reset_ic, "resetIC", | ||
| 1726 | "(Lorg/gnu/emacs/EmacsWindow;I)V"); | ||
| 1708 | #undef FIND_METHOD | 1727 | #undef FIND_METHOD |
| 1709 | } | 1728 | } |
| 1710 | 1729 | ||
| @@ -1834,7 +1853,7 @@ android_init_emacs_window (void) | |||
| 1834 | #undef FIND_METHOD | 1853 | #undef FIND_METHOD |
| 1835 | } | 1854 | } |
| 1836 | 1855 | ||
| 1837 | extern JNIEXPORT void JNICALL | 1856 | JNIEXPORT void JNICALL |
| 1838 | NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv, | 1857 | NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv, |
| 1839 | jobject dump_file_object, jint api_level) | 1858 | jobject dump_file_object, jint api_level) |
| 1840 | { | 1859 | { |
| @@ -1928,19 +1947,19 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv, | |||
| 1928 | emacs_abort (); | 1947 | emacs_abort (); |
| 1929 | } | 1948 | } |
| 1930 | 1949 | ||
| 1931 | extern JNIEXPORT void JNICALL | 1950 | JNIEXPORT void JNICALL |
| 1932 | NATIVE_NAME (emacsAbort) (JNIEnv *env, jobject object) | 1951 | NATIVE_NAME (emacsAbort) (JNIEnv *env, jobject object) |
| 1933 | { | 1952 | { |
| 1934 | emacs_abort (); | 1953 | emacs_abort (); |
| 1935 | } | 1954 | } |
| 1936 | 1955 | ||
| 1937 | extern JNIEXPORT void JNICALL | 1956 | JNIEXPORT void JNICALL |
| 1938 | NATIVE_NAME (quit) (JNIEnv *env, jobject object) | 1957 | NATIVE_NAME (quit) (JNIEnv *env, jobject object) |
| 1939 | { | 1958 | { |
| 1940 | Vquit_flag = Qt; | 1959 | Vquit_flag = Qt; |
| 1941 | } | 1960 | } |
| 1942 | 1961 | ||
| 1943 | extern JNIEXPORT jlong JNICALL | 1962 | JNIEXPORT jlong JNICALL |
| 1944 | NATIVE_NAME (sendConfigureNotify) (JNIEnv *env, jobject object, | 1963 | NATIVE_NAME (sendConfigureNotify) (JNIEnv *env, jobject object, |
| 1945 | jshort window, jlong time, | 1964 | jshort window, jlong time, |
| 1946 | jint x, jint y, jint width, | 1965 | jint x, jint y, jint width, |
| @@ -1961,7 +1980,7 @@ NATIVE_NAME (sendConfigureNotify) (JNIEnv *env, jobject object, | |||
| 1961 | return event_serial; | 1980 | return event_serial; |
| 1962 | } | 1981 | } |
| 1963 | 1982 | ||
| 1964 | extern JNIEXPORT jlong JNICALL | 1983 | JNIEXPORT jlong JNICALL |
| 1965 | NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object, | 1984 | NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object, |
| 1966 | jshort window, jlong time, | 1985 | jshort window, jlong time, |
| 1967 | jint state, jint keycode, | 1986 | jint state, jint keycode, |
| @@ -1981,7 +2000,7 @@ NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object, | |||
| 1981 | return event_serial; | 2000 | return event_serial; |
| 1982 | } | 2001 | } |
| 1983 | 2002 | ||
| 1984 | extern JNIEXPORT jlong JNICALL | 2003 | JNIEXPORT jlong JNICALL |
| 1985 | NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object, | 2004 | NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object, |
| 1986 | jshort window, jlong time, | 2005 | jshort window, jlong time, |
| 1987 | jint state, jint keycode, | 2006 | jint state, jint keycode, |
| @@ -2001,7 +2020,7 @@ NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object, | |||
| 2001 | return event_serial; | 2020 | return event_serial; |
| 2002 | } | 2021 | } |
| 2003 | 2022 | ||
| 2004 | extern JNIEXPORT jlong JNICALL | 2023 | JNIEXPORT jlong JNICALL |
| 2005 | NATIVE_NAME (sendFocusIn) (JNIEnv *env, jobject object, | 2024 | NATIVE_NAME (sendFocusIn) (JNIEnv *env, jobject object, |
| 2006 | jshort window, jlong time) | 2025 | jshort window, jlong time) |
| 2007 | { | 2026 | { |
| @@ -2016,7 +2035,7 @@ NATIVE_NAME (sendFocusIn) (JNIEnv *env, jobject object, | |||
| 2016 | return event_serial; | 2035 | return event_serial; |
| 2017 | } | 2036 | } |
| 2018 | 2037 | ||
| 2019 | extern JNIEXPORT jlong JNICALL | 2038 | JNIEXPORT jlong JNICALL |
| 2020 | NATIVE_NAME (sendFocusOut) (JNIEnv *env, jobject object, | 2039 | NATIVE_NAME (sendFocusOut) (JNIEnv *env, jobject object, |
| 2021 | jshort window, jlong time) | 2040 | jshort window, jlong time) |
| 2022 | { | 2041 | { |
| @@ -2031,7 +2050,7 @@ NATIVE_NAME (sendFocusOut) (JNIEnv *env, jobject object, | |||
| 2031 | return ++event_serial; | 2050 | return ++event_serial; |
| 2032 | } | 2051 | } |
| 2033 | 2052 | ||
| 2034 | extern JNIEXPORT jlong JNICALL | 2053 | JNIEXPORT jlong JNICALL |
| 2035 | NATIVE_NAME (sendWindowAction) (JNIEnv *env, jobject object, | 2054 | NATIVE_NAME (sendWindowAction) (JNIEnv *env, jobject object, |
| 2036 | jshort window, jint action) | 2055 | jshort window, jint action) |
| 2037 | { | 2056 | { |
| @@ -2046,7 +2065,7 @@ NATIVE_NAME (sendWindowAction) (JNIEnv *env, jobject object, | |||
| 2046 | return event_serial; | 2065 | return event_serial; |
| 2047 | } | 2066 | } |
| 2048 | 2067 | ||
| 2049 | extern JNIEXPORT jlong JNICALL | 2068 | JNIEXPORT jlong JNICALL |
| 2050 | NATIVE_NAME (sendEnterNotify) (JNIEnv *env, jobject object, | 2069 | NATIVE_NAME (sendEnterNotify) (JNIEnv *env, jobject object, |
| 2051 | jshort window, jint x, jint y, | 2070 | jshort window, jint x, jint y, |
| 2052 | jlong time) | 2071 | jlong time) |
| @@ -2064,7 +2083,7 @@ NATIVE_NAME (sendEnterNotify) (JNIEnv *env, jobject object, | |||
| 2064 | return event_serial; | 2083 | return event_serial; |
| 2065 | } | 2084 | } |
| 2066 | 2085 | ||
| 2067 | extern JNIEXPORT jlong JNICALL | 2086 | JNIEXPORT jlong JNICALL |
| 2068 | NATIVE_NAME (sendLeaveNotify) (JNIEnv *env, jobject object, | 2087 | NATIVE_NAME (sendLeaveNotify) (JNIEnv *env, jobject object, |
| 2069 | jshort window, jint x, jint y, | 2088 | jshort window, jint x, jint y, |
| 2070 | jlong time) | 2089 | jlong time) |
| @@ -2082,7 +2101,7 @@ NATIVE_NAME (sendLeaveNotify) (JNIEnv *env, jobject object, | |||
| 2082 | return event_serial; | 2101 | return event_serial; |
| 2083 | } | 2102 | } |
| 2084 | 2103 | ||
| 2085 | extern JNIEXPORT jlong JNICALL | 2104 | JNIEXPORT jlong JNICALL |
| 2086 | NATIVE_NAME (sendMotionNotify) (JNIEnv *env, jobject object, | 2105 | NATIVE_NAME (sendMotionNotify) (JNIEnv *env, jobject object, |
| 2087 | jshort window, jint x, jint y, | 2106 | jshort window, jint x, jint y, |
| 2088 | jlong time) | 2107 | jlong time) |
| @@ -2100,7 +2119,7 @@ NATIVE_NAME (sendMotionNotify) (JNIEnv *env, jobject object, | |||
| 2100 | return event_serial; | 2119 | return event_serial; |
| 2101 | } | 2120 | } |
| 2102 | 2121 | ||
| 2103 | extern JNIEXPORT jlong JNICALL | 2122 | JNIEXPORT jlong JNICALL |
| 2104 | NATIVE_NAME (sendButtonPress) (JNIEnv *env, jobject object, | 2123 | NATIVE_NAME (sendButtonPress) (JNIEnv *env, jobject object, |
| 2105 | jshort window, jint x, jint y, | 2124 | jshort window, jint x, jint y, |
| 2106 | jlong time, jint state, | 2125 | jlong time, jint state, |
| @@ -2121,7 +2140,7 @@ NATIVE_NAME (sendButtonPress) (JNIEnv *env, jobject object, | |||
| 2121 | return event_serial; | 2140 | return event_serial; |
| 2122 | } | 2141 | } |
| 2123 | 2142 | ||
| 2124 | extern JNIEXPORT jlong JNICALL | 2143 | JNIEXPORT jlong JNICALL |
| 2125 | NATIVE_NAME (sendButtonRelease) (JNIEnv *env, jobject object, | 2144 | NATIVE_NAME (sendButtonRelease) (JNIEnv *env, jobject object, |
| 2126 | jshort window, jint x, jint y, | 2145 | jshort window, jint x, jint y, |
| 2127 | jlong time, jint state, | 2146 | jlong time, jint state, |
| @@ -2142,7 +2161,7 @@ NATIVE_NAME (sendButtonRelease) (JNIEnv *env, jobject object, | |||
| 2142 | return event_serial; | 2161 | return event_serial; |
| 2143 | } | 2162 | } |
| 2144 | 2163 | ||
| 2145 | extern JNIEXPORT jlong JNICALL | 2164 | JNIEXPORT jlong JNICALL |
| 2146 | NATIVE_NAME (sendTouchDown) (JNIEnv *env, jobject object, | 2165 | NATIVE_NAME (sendTouchDown) (JNIEnv *env, jobject object, |
| 2147 | jshort window, jint x, jint y, | 2166 | jshort window, jint x, jint y, |
| 2148 | jlong time, jint pointer_id) | 2167 | jlong time, jint pointer_id) |
| @@ -2161,7 +2180,7 @@ NATIVE_NAME (sendTouchDown) (JNIEnv *env, jobject object, | |||
| 2161 | return event_serial; | 2180 | return event_serial; |
| 2162 | } | 2181 | } |
| 2163 | 2182 | ||
| 2164 | extern JNIEXPORT jlong JNICALL | 2183 | JNIEXPORT jlong JNICALL |
| 2165 | NATIVE_NAME (sendTouchUp) (JNIEnv *env, jobject object, | 2184 | NATIVE_NAME (sendTouchUp) (JNIEnv *env, jobject object, |
| 2166 | jshort window, jint x, jint y, | 2185 | jshort window, jint x, jint y, |
| 2167 | jlong time, jint pointer_id) | 2186 | jlong time, jint pointer_id) |
| @@ -2180,7 +2199,7 @@ NATIVE_NAME (sendTouchUp) (JNIEnv *env, jobject object, | |||
| 2180 | return event_serial; | 2199 | return event_serial; |
| 2181 | } | 2200 | } |
| 2182 | 2201 | ||
| 2183 | extern JNIEXPORT jlong JNICALL | 2202 | JNIEXPORT jlong JNICALL |
| 2184 | NATIVE_NAME (sendTouchMove) (JNIEnv *env, jobject object, | 2203 | NATIVE_NAME (sendTouchMove) (JNIEnv *env, jobject object, |
| 2185 | jshort window, jint x, jint y, | 2204 | jshort window, jint x, jint y, |
| 2186 | jlong time, jint pointer_id) | 2205 | jlong time, jint pointer_id) |
| @@ -2199,7 +2218,7 @@ NATIVE_NAME (sendTouchMove) (JNIEnv *env, jobject object, | |||
| 2199 | return event_serial; | 2218 | return event_serial; |
| 2200 | } | 2219 | } |
| 2201 | 2220 | ||
| 2202 | extern JNIEXPORT jlong JNICALL | 2221 | JNIEXPORT jlong JNICALL |
| 2203 | NATIVE_NAME (sendWheel) (JNIEnv *env, jobject object, | 2222 | NATIVE_NAME (sendWheel) (JNIEnv *env, jobject object, |
| 2204 | jshort window, jint x, jint y, | 2223 | jshort window, jint x, jint y, |
| 2205 | jlong time, jint state, | 2224 | jlong time, jint state, |
| @@ -2221,7 +2240,7 @@ NATIVE_NAME (sendWheel) (JNIEnv *env, jobject object, | |||
| 2221 | return event_serial; | 2240 | return event_serial; |
| 2222 | } | 2241 | } |
| 2223 | 2242 | ||
| 2224 | extern JNIEXPORT jlong JNICALL | 2243 | JNIEXPORT jlong JNICALL |
| 2225 | NATIVE_NAME (sendIconified) (JNIEnv *env, jobject object, | 2244 | NATIVE_NAME (sendIconified) (JNIEnv *env, jobject object, |
| 2226 | jshort window) | 2245 | jshort window) |
| 2227 | { | 2246 | { |
| @@ -2235,7 +2254,7 @@ NATIVE_NAME (sendIconified) (JNIEnv *env, jobject object, | |||
| 2235 | return event_serial; | 2254 | return event_serial; |
| 2236 | } | 2255 | } |
| 2237 | 2256 | ||
| 2238 | extern JNIEXPORT jlong JNICALL | 2257 | JNIEXPORT jlong JNICALL |
| 2239 | NATIVE_NAME (sendDeiconified) (JNIEnv *env, jobject object, | 2258 | NATIVE_NAME (sendDeiconified) (JNIEnv *env, jobject object, |
| 2240 | jshort window) | 2259 | jshort window) |
| 2241 | { | 2260 | { |
| @@ -2249,7 +2268,7 @@ NATIVE_NAME (sendDeiconified) (JNIEnv *env, jobject object, | |||
| 2249 | return event_serial; | 2268 | return event_serial; |
| 2250 | } | 2269 | } |
| 2251 | 2270 | ||
| 2252 | extern JNIEXPORT jlong JNICALL | 2271 | JNIEXPORT jlong JNICALL |
| 2253 | NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object, | 2272 | NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object, |
| 2254 | jshort window, jint menu_event_id) | 2273 | jshort window, jint menu_event_id) |
| 2255 | { | 2274 | { |
| @@ -2264,7 +2283,7 @@ NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object, | |||
| 2264 | return event_serial; | 2283 | return event_serial; |
| 2265 | } | 2284 | } |
| 2266 | 2285 | ||
| 2267 | extern JNIEXPORT jlong JNICALL | 2286 | JNIEXPORT jlong JNICALL |
| 2268 | NATIVE_NAME (sendExpose) (JNIEnv *env, jobject object, | 2287 | NATIVE_NAME (sendExpose) (JNIEnv *env, jobject object, |
| 2269 | jshort window, jint x, jint y, | 2288 | jshort window, jint x, jint y, |
| 2270 | jint width, jint height) | 2289 | jint width, jint height) |
| @@ -2283,6 +2302,23 @@ NATIVE_NAME (sendExpose) (JNIEnv *env, jobject object, | |||
| 2283 | return event_serial; | 2302 | return event_serial; |
| 2284 | } | 2303 | } |
| 2285 | 2304 | ||
| 2305 | /* Forward declarations of deadlock prevention functions. */ | ||
| 2306 | |||
| 2307 | static void android_begin_query (void); | ||
| 2308 | static void android_end_query (void); | ||
| 2309 | |||
| 2310 | JNIEXPORT void JNICALL | ||
| 2311 | NATIVE_NAME (beginSynchronous) (JNIEnv *env, jobject object) | ||
| 2312 | { | ||
| 2313 | android_begin_query (); | ||
| 2314 | } | ||
| 2315 | |||
| 2316 | JNIEXPORT void JNICALL | ||
| 2317 | NATIVE_NAME (endSynchronous) (JNIEnv *env, jobject object) | ||
| 2318 | { | ||
| 2319 | android_end_query (); | ||
| 2320 | } | ||
| 2321 | |||
| 2286 | #ifdef __clang__ | 2322 | #ifdef __clang__ |
| 2287 | #pragma clang diagnostic pop | 2323 | #pragma clang diagnostic pop |
| 2288 | #else | 2324 | #else |
| @@ -5155,6 +5191,215 @@ android_get_current_api_level (void) | |||
| 5155 | 5191 | ||
| 5156 | 5192 | ||
| 5157 | 5193 | ||
| 5194 | /* Whether or not a query is currently being made. */ | ||
| 5195 | static bool android_servicing_query; | ||
| 5196 | |||
| 5197 | /* Function that is waiting to be run in the Emacs thread. */ | ||
| 5198 | static void (*android_query_function) (void *); | ||
| 5199 | |||
| 5200 | /* Context for that function. */ | ||
| 5201 | static void *android_query_context; | ||
| 5202 | |||
| 5203 | /* Deadlock protection. The UI thread and the Emacs thread must | ||
| 5204 | sometimes make synchronous queries to each other, which are | ||
| 5205 | normally answered inside each thread's respective event loop. | ||
| 5206 | Deadlocks can happen when both threads simultaneously make such | ||
| 5207 | synchronous queries and block waiting for each others responses. | ||
| 5208 | |||
| 5209 | The Emacs thread can be interrupted to service any queries made by | ||
| 5210 | the UI thread, but is not possible the other way around. | ||
| 5211 | |||
| 5212 | To avoid such deadlocks, an atomic counter is provided. This | ||
| 5213 | counter is incremented every time a query starts, and is set to | ||
| 5214 | zerp every time one ends. If the UI thread tries to make a query | ||
| 5215 | and sees that the counter is non-zero, it simply returns so that | ||
| 5216 | its event loop can proceed to perform and respond to the query. If | ||
| 5217 | the Emacs thread sees the same thing, then it stops to service all | ||
| 5218 | queries being made by the input method, then proceeds to make its | ||
| 5219 | query. */ | ||
| 5220 | |||
| 5221 | /* Run any function that the UI thread has asked to run, and then | ||
| 5222 | signal its completion. */ | ||
| 5223 | |||
| 5224 | void | ||
| 5225 | android_check_query (void) | ||
| 5226 | { | ||
| 5227 | void (*proc) (void *); | ||
| 5228 | void *closure; | ||
| 5229 | |||
| 5230 | if (!__atomic_load_n (&android_servicing_query, __ATOMIC_SEQ_CST)) | ||
| 5231 | return; | ||
| 5232 | |||
| 5233 | /* First, load the procedure and closure. */ | ||
| 5234 | __atomic_load (&android_query_context, &closure, __ATOMIC_SEQ_CST); | ||
| 5235 | __atomic_load (&android_query_function, &proc, __ATOMIC_SEQ_CST); | ||
| 5236 | |||
| 5237 | if (!proc) | ||
| 5238 | return; | ||
| 5239 | |||
| 5240 | proc (closure); | ||
| 5241 | |||
| 5242 | /* Finish the query. */ | ||
| 5243 | __atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST); | ||
| 5244 | __atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST); | ||
| 5245 | __atomic_clear (&android_servicing_query, __ATOMIC_SEQ_CST); | ||
| 5246 | |||
| 5247 | /* Signal completion. */ | ||
| 5248 | sem_post (&android_query_sem); | ||
| 5249 | } | ||
| 5250 | |||
| 5251 | /* Notice that the Emacs thread will start blocking waiting for a | ||
| 5252 | response from the UI thread. Process any pending queries from the | ||
| 5253 | UI thread. | ||
| 5254 | |||
| 5255 | This function may be called from Java. */ | ||
| 5256 | |||
| 5257 | static void | ||
| 5258 | android_begin_query (void) | ||
| 5259 | { | ||
| 5260 | if (__atomic_test_and_set (&android_servicing_query, | ||
| 5261 | __ATOMIC_SEQ_CST)) | ||
| 5262 | { | ||
| 5263 | /* Answer the query that is currently being made. */ | ||
| 5264 | assert (android_query_function != NULL); | ||
| 5265 | android_check_query (); | ||
| 5266 | |||
| 5267 | /* Wait for that query to complete. */ | ||
| 5268 | while (__atomic_load_n (&android_servicing_query, | ||
| 5269 | __ATOMIC_SEQ_CST)) | ||
| 5270 | ;; | ||
| 5271 | } | ||
| 5272 | } | ||
| 5273 | |||
| 5274 | /* Notice that a query has stopped. This function may be called from | ||
| 5275 | Java. */ | ||
| 5276 | |||
| 5277 | static void | ||
| 5278 | android_end_query (void) | ||
| 5279 | { | ||
| 5280 | __atomic_clear (&android_servicing_query, __ATOMIC_SEQ_CST); | ||
| 5281 | } | ||
| 5282 | |||
| 5283 | /* Synchronously ask the Emacs thread to run the specified PROC with | ||
| 5284 | the given CLOSURE. Return if this fails, or once PROC is run. | ||
| 5285 | |||
| 5286 | PROC may be run from inside maybe_quit. | ||
| 5287 | |||
| 5288 | It is not okay to run Lisp code which signals or performs non | ||
| 5289 | trivial tasks inside PROC. | ||
| 5290 | |||
| 5291 | Return 1 if the Emacs thread is currently waiting for the UI thread | ||
| 5292 | to respond and PROC could not be run, or 0 otherwise. */ | ||
| 5293 | |||
| 5294 | int | ||
| 5295 | android_run_in_emacs_thread (void (*proc) (void *), void *closure) | ||
| 5296 | { | ||
| 5297 | union android_event event; | ||
| 5298 | |||
| 5299 | event.xaction.type = ANDROID_WINDOW_ACTION; | ||
| 5300 | event.xaction.serial = ++event_serial; | ||
| 5301 | event.xaction.window = 0; | ||
| 5302 | event.xaction.action = 0; | ||
| 5303 | |||
| 5304 | /* Set android_query_function and android_query_context. */ | ||
| 5305 | __atomic_store_n (&android_query_context, closure, __ATOMIC_SEQ_CST); | ||
| 5306 | __atomic_store_n (&android_query_function, proc, __ATOMIC_SEQ_CST); | ||
| 5307 | |||
| 5308 | /* Don't allow deadlocks to happen; make sure the Emacs thread is | ||
| 5309 | not waiting for something to be done. */ | ||
| 5310 | |||
| 5311 | if (__atomic_test_and_set (&android_servicing_query, | ||
| 5312 | __ATOMIC_SEQ_CST)) | ||
| 5313 | { | ||
| 5314 | __atomic_store_n (&android_query_context, NULL, | ||
| 5315 | __ATOMIC_SEQ_CST); | ||
| 5316 | __atomic_store_n (&android_query_function, NULL, | ||
| 5317 | __ATOMIC_SEQ_CST); | ||
| 5318 | |||
| 5319 | return 1; | ||
| 5320 | } | ||
| 5321 | |||
| 5322 | /* Send a dummy event. `android_check_query' will be called inside | ||
| 5323 | wait_reading_process_output after the event arrives. | ||
| 5324 | |||
| 5325 | Otherwise, android_select will call android_check_thread the next | ||
| 5326 | time it is entered. */ | ||
| 5327 | android_write_event (&event); | ||
| 5328 | |||
| 5329 | /* Start waiting for the function to be executed. */ | ||
| 5330 | while (sem_wait (&android_query_sem) < 0) | ||
| 5331 | ;; | ||
| 5332 | |||
| 5333 | return 0; | ||
| 5334 | } | ||
| 5335 | |||
| 5336 | |||
| 5337 | |||
| 5338 | /* Input method related functions. */ | ||
| 5339 | |||
| 5340 | /* Change WINDOW's active selection to the characters between | ||
| 5341 | SELECTION_START and SELECTION_END. | ||
| 5342 | |||
| 5343 | Also, update the composing region to COMPOSING_REGION_START and | ||
| 5344 | COMPOSING_REGION_END. | ||
| 5345 | |||
| 5346 | If any value cannot fit in jint, then the behavior of the input | ||
| 5347 | method is undefined. */ | ||
| 5348 | |||
| 5349 | void | ||
| 5350 | android_update_ic (android_window window, ptrdiff_t selection_start, | ||
| 5351 | ptrdiff_t selection_end, ptrdiff_t composing_region_start, | ||
| 5352 | ptrdiff_t composing_region_end) | ||
| 5353 | { | ||
| 5354 | jobject object; | ||
| 5355 | |||
| 5356 | object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW); | ||
| 5357 | |||
| 5358 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 5359 | emacs_service, | ||
| 5360 | service_class.update_ic, | ||
| 5361 | object, | ||
| 5362 | (jint) selection_start, | ||
| 5363 | (jint) selection_end, | ||
| 5364 | (jint) composing_region_start, | ||
| 5365 | (jint) composing_region_end); | ||
| 5366 | android_exception_check (); | ||
| 5367 | } | ||
| 5368 | |||
| 5369 | /* Reinitialize any ongoing input method connection on WINDOW. | ||
| 5370 | |||
| 5371 | Any input method that is connected to WINDOW will invalidate its | ||
| 5372 | cache of the buffer contents. | ||
| 5373 | |||
| 5374 | MODE controls certain aspects of the input method's behavior: | ||
| 5375 | |||
| 5376 | - If MODE is ANDROID_IC_MODE_NULL, the input method will be | ||
| 5377 | deactivated, and an ASCII only keyboard will be displayed | ||
| 5378 | instead. | ||
| 5379 | |||
| 5380 | - If MODE is ANDROID_IC_MODE_ACTION, the input method will | ||
| 5381 | edit text normally, but send ``return'' as a key event. | ||
| 5382 | This is useful inside the mini buffer. | ||
| 5383 | |||
| 5384 | - If MODE is ANDROID_IC_MODE_TEXT, the input method is free | ||
| 5385 | to behave however it wants. */ | ||
| 5386 | |||
| 5387 | void | ||
| 5388 | android_reset_ic (android_window window, enum android_ic_mode mode) | ||
| 5389 | { | ||
| 5390 | jobject object; | ||
| 5391 | |||
| 5392 | object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW); | ||
| 5393 | |||
| 5394 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 5395 | emacs_service, | ||
| 5396 | service_class.reset_ic, | ||
| 5397 | object, (jint) mode); | ||
| 5398 | android_exception_check (); | ||
| 5399 | } | ||
| 5400 | |||
| 5401 | |||
| 5402 | |||
| 5158 | #else /* ANDROID_STUBIFY */ | 5403 | #else /* ANDROID_STUBIFY */ |
| 5159 | 5404 | ||
| 5160 | /* X emulation functions for Android. */ | 5405 | /* X emulation functions for Android. */ |