aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-01-14 22:12:16 +0800
committerPo Lu2023-01-14 22:12:16 +0800
commit2b87ab7b27163fbd7b6b64c5a44e26b0e692c00a (patch)
tree3ab31df90bd435009d2d42b636ce3baf33bd2b28 /src
parent28a9baccd4c8e997895d3adb3cfce4a11fa29896 (diff)
downloademacs-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')
-rw-r--r--src/android.c169
-rw-r--r--src/android.h6
-rw-r--r--src/androidfns.c677
-rw-r--r--src/androidgui.h14
-rw-r--r--src/androidmenu.c293
-rw-r--r--src/androidterm.c34
-rw-r--r--src/androidterm.h6
-rw-r--r--src/emacs.c4
8 files changed, 1152 insertions, 51 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
92struct android_emacs_pixmap 93struct android_emacs_pixmap
@@ -229,14 +230,14 @@ static volatile bool android_pselect_completed;
229/* The global event queue. */ 230/* The global event queue. */
230static struct android_event_queue event_queue; 231static struct android_event_queue event_queue;
231 232
232/* Semaphore used to signal select completion. */ 233/* Semaphores used to signal select completion and start. */
233static sem_t android_pselect_sem; 234static sem_t android_pselect_sem, android_pselect_start_sem;
234 235
235static void * 236static void *
236android_run_select_thread (void *data) 237android_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
3216void
3217android_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
3224void
3225android_map_raised (android_window window)
3226{
3227 android_raise_window (window);
3228 android_map_window (window);
3229}
3230
3231void
3232android_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
3448void
3449android_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
3618jstring
3619android_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
3645void
3646android_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. */
diff --git a/src/android.h b/src/android.h
index af1e42ec370..98f2494e9a3 100644
--- a/src/android.h
+++ b/src/android.h
@@ -35,6 +35,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
35#include <android/bitmap.h> 35#include <android/bitmap.h>
36 36
37#include "androidgui.h" 37#include "androidgui.h"
38#include "lisp.h"
38#endif 39#endif
39 40
40/* This must be used in every symbol declaration to export it to the 41/* This must be used in every symbol declaration to export it to the
@@ -84,6 +85,11 @@ extern bool android_detect_mouse (void);
84extern void android_set_dont_focus_on_map (android_window, bool); 85extern void android_set_dont_focus_on_map (android_window, bool);
85extern void android_set_dont_accept_focus (android_window, bool); 86extern void android_set_dont_accept_focus (android_window, bool);
86 87
88extern jstring android_build_string (Lisp_Object);
89extern void android_exception_check (void);
90
91extern void android_get_keysym_name (int, char *, size_t);
92
87 93
88 94
89/* Directory listing emulation. */ 95/* Directory listing emulation. */
diff --git a/src/androidfns.c b/src/androidfns.c
index 459e407b901..ab136bc2722 100644
--- a/src/androidfns.c
+++ b/src/androidfns.c
@@ -25,12 +25,36 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
25#include "androidterm.h" 25#include "androidterm.h"
26#include "blockinput.h" 26#include "blockinput.h"
27#include "keyboard.h" 27#include "keyboard.h"
28#include "buffer.h"
28 29
29#ifndef ANDROID_STUBIFY 30#ifndef ANDROID_STUBIFY
30 31
31/* Some kind of reference count for the image cache. */ 32/* Some kind of reference count for the image cache. */
32static ptrdiff_t image_cache_refcount; 33static ptrdiff_t image_cache_refcount;
33 34
35/* The frame of the currently visible tooltip, or nil if none. */
36static Lisp_Object tip_frame;
37
38/* The window-system window corresponding to the frame of the
39 currently visible tooltip. */
40static android_window tip_window;
41
42/* The X and Y deltas of the last call to `x-show-tip'. */
43static Lisp_Object tip_dx, tip_dy;
44
45/* A timer that hides or deletes the currently visible tooltip when it
46 fires. */
47static Lisp_Object tip_timer;
48
49/* STRING argument of last `x-show-tip' call. */
50static Lisp_Object tip_last_string;
51
52/* Normalized FRAME argument of last `x-show-tip' call. */
53static Lisp_Object tip_last_frame;
54
55/* PARMS argument of last `x-show-tip' call. */
56static Lisp_Object tip_last_parms;
57
34#endif 58#endif
35 59
36static struct android_display_info * 60static struct android_display_info *
@@ -180,6 +204,9 @@ android_set_parent_frame (struct frame *f, Lisp_Object new_value,
180 204
181 fset_parent_frame (f, new_value); 205 fset_parent_frame (f, new_value);
182 } 206 }
207
208 /* Update the fullscreen frame parameter as well. */
209 FRAME_TERMINAL (f)->fullscreen_hook (f);
183} 210}
184 211
185void 212void
@@ -858,13 +885,13 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
858 gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0), 885 gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
859 NULL, NULL, RES_TYPE_NUMBER); 886 NULL, NULL, RES_TYPE_NUMBER);
860 887
861 /* gui_default_parameter (f, parms, Qvertical_scroll_bars, */ 888 gui_default_parameter (f, parms, Qvertical_scroll_bars,
862 /* Qleft, */ 889 Qleft,
863 /* "verticalScrollBars", "ScrollBars", */ 890 "verticalScrollBars", "ScrollBars",
864 /* RES_TYPE_SYMBOL); */ 891 RES_TYPE_SYMBOL);
865 /* gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil, */ 892 gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil,
866 /* "horizontalScrollBars", "ScrollBars", */ 893 "horizontalScrollBars", "ScrollBars",
867 /* RES_TYPE_SYMBOL); TODO */ 894 RES_TYPE_SYMBOL);
868 895
869 /* Also do the stuff which must be set before the window exists. */ 896 /* Also do the stuff which must be set before the window exists. */
870 gui_default_parameter (f, parms, Qforeground_color, build_string ("black"), 897 gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
@@ -893,7 +920,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
893 android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background, 920 android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background,
894 "scrollBarBackground", 921 "scrollBarBackground",
895 "ScrollBarBackground", false); 922 "ScrollBarBackground", false);
896#endif /* TODO */ 923#endif
897 924
898 /* Init faces before gui_default_parameter is called for the 925 /* Init faces before gui_default_parameter is called for the
899 scroll-bar-width parameter because otherwise we end up in 926 scroll-bar-width parameter because otherwise we end up in
@@ -974,12 +1001,16 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
974 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN); 1001 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
975 gui_default_parameter (f, parms, Qcursor_type, Qbox, 1002 gui_default_parameter (f, parms, Qcursor_type, Qbox,
976 "cursorType", "CursorType", RES_TYPE_SYMBOL); 1003 "cursorType", "CursorType", RES_TYPE_SYMBOL);
1004 /* Scroll bars are not supported on Android, as they are near
1005 useless. */
1006#if 0
977 gui_default_parameter (f, parms, Qscroll_bar_width, Qnil, 1007 gui_default_parameter (f, parms, Qscroll_bar_width, Qnil,
978 "scrollBarWidth", "ScrollBarWidth", 1008 "scrollBarWidth", "ScrollBarWidth",
979 RES_TYPE_NUMBER); 1009 RES_TYPE_NUMBER);
980 gui_default_parameter (f, parms, Qscroll_bar_height, Qnil, 1010 gui_default_parameter (f, parms, Qscroll_bar_height, Qnil,
981 "scrollBarHeight", "ScrollBarHeight", 1011 "scrollBarHeight", "ScrollBarHeight",
982 RES_TYPE_NUMBER); 1012 RES_TYPE_NUMBER);
1013#endif
983 gui_default_parameter (f, parms, Qalpha, Qnil, 1014 gui_default_parameter (f, parms, Qalpha, Qnil,
984 "alpha", "Alpha", RES_TYPE_NUMBER); 1015 "alpha", "Alpha", RES_TYPE_NUMBER);
985 gui_default_parameter (f, parms, Qalpha_background, Qnil, 1016 gui_default_parameter (f, parms, Qalpha_background, Qnil,
@@ -1009,8 +1040,9 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1009 1040
1010 /* Process fullscreen parameter here in the hope that normalizing a 1041 /* Process fullscreen parameter here in the hope that normalizing a
1011 fullheight/fullwidth frame will produce the size set by the last 1042 fullheight/fullwidth frame will produce the size set by the last
1012 adjust_frame_size call. */ 1043 adjust_frame_size call. Note that Android only supports the
1013 gui_default_parameter (f, parms, Qfullscreen, Qnil, 1044 `maximized' state. */
1045 gui_default_parameter (f, parms, Qfullscreen, Qmaximized,
1014 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); 1046 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
1015 1047
1016 /* When called from `x-create-frame-with-faces' visibility is 1048 /* When called from `x-create-frame-with-faces' visibility is
@@ -1661,6 +1693,391 @@ DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
1661 return result; 1693 return result;
1662} 1694}
1663 1695
1696#ifndef ANDROID_STUBIFY
1697
1698static void
1699unwind_create_tip_frame (Lisp_Object frame)
1700{
1701 Lisp_Object deleted;
1702
1703 deleted = unwind_create_frame (frame);
1704 if (EQ (deleted, Qt))
1705 {
1706 tip_window = ANDROID_NONE;
1707 tip_frame = Qnil;
1708 }
1709}
1710
1711static Lisp_Object
1712android_create_tip_frame (struct android_display_info *dpyinfo,
1713 Lisp_Object parms)
1714{
1715 struct frame *f;
1716 Lisp_Object frame;
1717 Lisp_Object name;
1718 specpdl_ref count = SPECPDL_INDEX ();
1719 bool face_change_before = face_change;
1720
1721 if (!dpyinfo->terminal->name)
1722 error ("Terminal is not live, can't create new frames on it");
1723
1724 parms = Fcopy_alist (parms);
1725
1726 /* Get the name of the frame to use for resource lookup. */
1727 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
1728 RES_TYPE_STRING);
1729 if (!STRINGP (name)
1730 && !BASE_EQ (name, Qunbound)
1731 && !NILP (name))
1732 error ("Invalid frame name--not a string or nil");
1733
1734 frame = Qnil;
1735 f = make_frame (false);
1736 f->wants_modeline = false;
1737 XSETFRAME (frame, f);
1738 record_unwind_protect (unwind_create_tip_frame, frame);
1739
1740 f->terminal = dpyinfo->terminal;
1741
1742 /* By setting the output method, we're essentially saying that
1743 the frame is live, as per FRAME_LIVE_P. If we get a signal
1744 from this point on, x_destroy_window might screw up reference
1745 counts etc. */
1746 f->output_method = output_android;
1747 f->output_data.android = xzalloc (sizeof *f->output_data.android);
1748 FRAME_FONTSET (f) = -1;
1749 f->output_data.android->white_relief.pixel = -1;
1750 f->output_data.android->black_relief.pixel = -1;
1751
1752 f->tooltip = true;
1753 fset_icon_name (f, Qnil);
1754 FRAME_DISPLAY_INFO (f) = dpyinfo;
1755 f->output_data.android->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
1756
1757 /* These colors will be set anyway later, but it's important
1758 to get the color reference counts right, so initialize them! */
1759 {
1760 Lisp_Object black;
1761
1762 /* Function android_decode_color can signal an error. Make sure
1763 to initialize color slots so that we won't try to free colors
1764 we haven't allocated. */
1765 FRAME_FOREGROUND_PIXEL (f) = -1;
1766 FRAME_BACKGROUND_PIXEL (f) = -1;
1767 f->output_data.android->cursor_pixel = -1;
1768 f->output_data.android->cursor_foreground_pixel = -1;
1769
1770 black = build_string ("black");
1771 FRAME_FOREGROUND_PIXEL (f)
1772 = android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
1773 FRAME_BACKGROUND_PIXEL (f)
1774 = android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
1775 f->output_data.android->cursor_pixel
1776 = android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
1777 f->output_data.android->cursor_foreground_pixel
1778 = android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
1779 }
1780
1781 /* Set the name; the functions to which we pass f expect the name to
1782 be set. */
1783 if (BASE_EQ (name, Qunbound) || NILP (name))
1784 f->explicit_name = false;
1785 else
1786 {
1787 fset_name (f, name);
1788 f->explicit_name = true;
1789 /* use the frame's title when getting resources for this frame. */
1790 specbind (Qx_resource_name, name);
1791 }
1792
1793 register_font_driver (&androidfont_driver, f);
1794 register_font_driver (&android_sfntfont_driver, f);
1795
1796 image_cache_refcount
1797 = FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
1798#ifdef GLYPH_DEBUG
1799 dpyinfo_refcount = dpyinfo->reference_count;
1800#endif /* GLYPH_DEBUG */
1801
1802 gui_default_parameter (f, parms, Qfont_backend, Qnil,
1803 "fontBackend", "FontBackend", RES_TYPE_STRING);
1804
1805 /* Extract the window parameters from the supplied values that are
1806 needed to determine window geometry. */
1807 android_default_font_parameter (f, parms);
1808
1809 gui_default_parameter (f, parms, Qborder_width, make_fixnum (0),
1810 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
1811
1812 /* This defaults to 1 in order to match xterm. We recognize either
1813 internalBorderWidth or internalBorder (which is what xterm calls
1814 it). */
1815 if (NILP (Fassq (Qinternal_border_width, parms)))
1816 {
1817 Lisp_Object value;
1818
1819 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
1820 "internalBorder", "internalBorder",
1821 RES_TYPE_NUMBER);
1822 if (! BASE_EQ (value, Qunbound))
1823 parms = Fcons (Fcons (Qinternal_border_width, value),
1824 parms);
1825 }
1826
1827 gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (1),
1828 "internalBorderWidth", "internalBorderWidth",
1829 RES_TYPE_NUMBER);
1830 gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0),
1831 NULL, NULL, RES_TYPE_NUMBER);
1832 gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
1833 NULL, NULL, RES_TYPE_NUMBER);
1834
1835 /* Also do the stuff which must be set before the window exists. */
1836 gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
1837 "foreground", "Foreground", RES_TYPE_STRING);
1838 gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
1839 "background", "Background", RES_TYPE_STRING);
1840 gui_default_parameter (f, parms, Qmouse_color, build_string ("black"),
1841 "pointerColor", "Foreground", RES_TYPE_STRING);
1842 gui_default_parameter (f, parms, Qcursor_color, build_string ("black"),
1843 "cursorColor", "Foreground", RES_TYPE_STRING);
1844 gui_default_parameter (f, parms, Qborder_color, build_string ("black"),
1845 "borderColor", "BorderColor", RES_TYPE_STRING);
1846 gui_default_parameter (f, parms, Qno_special_glyphs, Qnil,
1847 NULL, NULL, RES_TYPE_BOOLEAN);
1848
1849 {
1850 struct android_set_window_attributes attrs;
1851 unsigned long mask;
1852
1853 block_input ();
1854 mask = ANDROID_CW_OVERRIDE_REDIRECT;
1855
1856 attrs.override_redirect = true;
1857 tip_window
1858 = FRAME_ANDROID_WINDOW (f)
1859 = android_create_window (FRAME_DISPLAY_INFO (f)->root_window,
1860 /* x, y, width, height, value-mask,
1861 attrs. */
1862 0, 0, 1, 1, mask, &attrs);
1863 unblock_input ();
1864 }
1865
1866 /* Init faces before gui_default_parameter is called for the
1867 scroll-bar-width parameter because otherwise we end up in
1868 init_iterator with a null face cache, which should not happen. */
1869 init_frame_faces (f);
1870
1871 gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
1872 "inhibitDoubleBuffering", "InhibitDoubleBuffering",
1873 RES_TYPE_BOOLEAN);
1874
1875 gui_figure_window_size (f, parms, false, false);
1876
1877 f->output_data.android->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
1878
1879 android_make_gc (f);
1880
1881 gui_default_parameter (f, parms, Qauto_raise, Qnil,
1882 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
1883 gui_default_parameter (f, parms, Qauto_lower, Qnil,
1884 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
1885 gui_default_parameter (f, parms, Qcursor_type, Qbox,
1886 "cursorType", "CursorType", RES_TYPE_SYMBOL);
1887 gui_default_parameter (f, parms, Qalpha, Qnil,
1888 "alpha", "Alpha", RES_TYPE_NUMBER);
1889 gui_default_parameter (f, parms, Qalpha_background, Qnil,
1890 "alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
1891
1892 /* Add `tooltip' frame parameter's default value. */
1893 if (NILP (Fframe_parameter (frame, Qtooltip)))
1894 {
1895 AUTO_FRAME_ARG (arg, Qtooltip, Qt);
1896 Fmodify_frame_parameters (frame, arg);
1897 }
1898
1899 /* FIXME - can this be done in a similar way to normal frames?
1900 https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */
1901
1902 /* Set the `display-type' frame parameter before setting up faces. */
1903 {
1904 Lisp_Object disptype;
1905
1906 disptype = Qcolor;
1907
1908 if (NILP (Fframe_parameter (frame, Qdisplay_type)))
1909 {
1910 AUTO_FRAME_ARG (arg, Qdisplay_type, disptype);
1911 Fmodify_frame_parameters (frame, arg);
1912 }
1913 }
1914
1915 /* Set up faces after all frame parameters are known. This call
1916 also merges in face attributes specified for new frames. */
1917 {
1918 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
1919
1920 call2 (Qface_set_after_frame_default, frame, Qnil);
1921
1922 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
1923 {
1924 AUTO_FRAME_ARG (arg, Qbackground_color, bg);
1925 Fmodify_frame_parameters (frame, arg);
1926 }
1927 }
1928
1929 f->no_split = true;
1930
1931 /* Now that the frame will be official, it counts as a reference to
1932 its display and terminal. */
1933 f->terminal->reference_count++;
1934
1935 /* It is now ok to make the frame official even if we get an error
1936 below. And the frame needs to be on Vframe_list or making it
1937 visible won't work. */
1938 Vframe_list = Fcons (frame, Vframe_list);
1939 f->can_set_window_size = true;
1940 adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
1941 0, true, Qtip_frame);
1942
1943 /* Setting attributes of faces of the tooltip frame from resources
1944 and similar will set face_change, which leads to the clearing of
1945 all current matrices. Since this isn't necessary here, avoid it
1946 by resetting face_change to the value it had before we created
1947 the tip frame. */
1948 face_change = face_change_before;
1949
1950 /* Discard the unwind_protect. */
1951 return unbind_to (count, frame);
1952}
1953
1954static Lisp_Object
1955android_hide_tip (bool delete)
1956{
1957 if (!NILP (tip_timer))
1958 {
1959 call1 (Qcancel_timer, tip_timer);
1960 tip_timer = Qnil;
1961 }
1962
1963 if (NILP (tip_frame)
1964 || (!delete
1965 && !NILP (tip_frame)
1966 && FRAME_LIVE_P (XFRAME (tip_frame))
1967 && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
1968 return Qnil;
1969 else
1970 {
1971 Lisp_Object was_open = Qnil;
1972
1973 specpdl_ref count = SPECPDL_INDEX ();
1974 specbind (Qinhibit_redisplay, Qt);
1975 specbind (Qinhibit_quit, Qt);
1976
1977 if (!NILP (tip_frame))
1978 {
1979 struct frame *f = XFRAME (tip_frame);
1980
1981 if (FRAME_LIVE_P (f))
1982 {
1983 if (delete)
1984 {
1985 delete_frame (tip_frame, Qnil);
1986 tip_frame = Qnil;
1987 }
1988 else
1989 android_make_frame_invisible (XFRAME (tip_frame));
1990
1991 was_open = Qt;
1992 }
1993 else
1994 tip_frame = Qnil;
1995 }
1996 else
1997 tip_frame = Qnil;
1998
1999 return unbind_to (count, was_open);
2000 }
2001}
2002
2003static void
2004compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx,
2005 Lisp_Object dy, int width, int height, int *root_x,
2006 int *root_y)
2007{
2008 Lisp_Object left, top, right, bottom;
2009 int min_x, min_y, max_x, max_y = -1;
2010 android_window window;
2011 struct frame *mouse_frame;
2012
2013 /* Initialize these values in case there is no mouse frame. */
2014 *root_x = 0;
2015 *root_y = 0;
2016
2017 /* User-specified position? */
2018 left = CDR (Fassq (Qleft, parms));
2019 top = CDR (Fassq (Qtop, parms));
2020 right = CDR (Fassq (Qright, parms));
2021 bottom = CDR (Fassq (Qbottom, parms));
2022
2023 /* Move the tooltip window where the mouse pointer was last seen.
2024 Resize and show it. */
2025 if ((!FIXNUMP (left) && !FIXNUMP (right))
2026 || (!FIXNUMP (top) && !FIXNUMP (bottom)))
2027 {
2028 if (x_display_list->last_mouse_motion_frame)
2029 {
2030 *root_x = x_display_list->last_mouse_motion_x;
2031 *root_y = x_display_list->last_mouse_motion_y;
2032 mouse_frame = x_display_list->last_mouse_motion_frame;
2033 window = FRAME_ANDROID_WINDOW (mouse_frame);
2034
2035 /* Translate the coordinates to the screen. */
2036 android_translate_coordinates (window, *root_x, *root_y,
2037 root_x, root_y);
2038 }
2039 }
2040
2041 min_x = 0;
2042 min_y = 0;
2043 max_x = android_get_screen_width ();
2044 max_y = android_get_screen_height ();
2045
2046 if (FIXNUMP (top))
2047 *root_y = XFIXNUM (top);
2048 else if (FIXNUMP (bottom))
2049 *root_y = XFIXNUM (bottom) - height;
2050 else if (*root_y + XFIXNUM (dy) <= min_y)
2051 *root_y = min_y; /* Can happen for negative dy */
2052 else if (*root_y + XFIXNUM (dy) + height <= max_y)
2053 /* It fits below the pointer */
2054 *root_y += XFIXNUM (dy);
2055 else if (height + XFIXNUM (dy) + min_y <= *root_y)
2056 /* It fits above the pointer. */
2057 *root_y -= height + XFIXNUM (dy);
2058 else
2059 /* Put it on the top. */
2060 *root_y = min_y;
2061
2062 if (FIXNUMP (left))
2063 *root_x = XFIXNUM (left);
2064 else if (FIXNUMP (right))
2065 *root_x = XFIXNUM (right) - width;
2066 else if (*root_x + XFIXNUM (dx) <= min_x)
2067 *root_x = 0; /* Can happen for negative dx */
2068 else if (*root_x + XFIXNUM (dx) + width <= max_x)
2069 /* It fits to the right of the pointer. */
2070 *root_x += XFIXNUM (dx);
2071 else if (width + XFIXNUM (dx) + min_x <= *root_x)
2072 /* It fits to the left of the pointer. */
2073 *root_x -= width + XFIXNUM (dx);
2074 else
2075 /* Put it left justified on the screen -- it ought to fit that way. */
2076 *root_x = min_x;
2077}
2078
2079#endif
2080
1664DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, 2081DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
1665 doc: /* SKIP: real doc in xfns.c. */) 2082 doc: /* SKIP: real doc in xfns.c. */)
1666 (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, 2083 (Lisp_Object string, Lisp_Object frame, Lisp_Object parms,
@@ -1670,8 +2087,214 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
1670 error ("Android cross-compilation stub called!"); 2087 error ("Android cross-compilation stub called!");
1671 return Qnil; 2088 return Qnil;
1672#else 2089#else
1673 /* TODO tooltips */ 2090 struct frame *f, *tip_f;
1674 return Qnil; 2091 struct window *w;
2092 int root_x, root_y;
2093 struct buffer *old_buffer;
2094 struct text_pos pos;
2095 int width, height;
2096 int old_windows_or_buffers_changed = windows_or_buffers_changed;
2097 specpdl_ref count = SPECPDL_INDEX ();
2098 Lisp_Object window, size, tip_buf;
2099 bool displayed;
2100#ifdef ENABLE_CHECKING
2101 struct glyph_row *row, *end;
2102#endif
2103 AUTO_STRING (tip, " *tip*");
2104
2105 specbind (Qinhibit_redisplay, Qt);
2106
2107 CHECK_STRING (string);
2108 if (SCHARS (string) == 0)
2109 string = make_unibyte_string (" ", 1);
2110
2111 if (NILP (frame))
2112 frame = selected_frame;
2113 f = decode_window_system_frame (frame);
2114
2115 if (NILP (timeout))
2116 timeout = Vx_show_tooltip_timeout;
2117 CHECK_FIXNAT (timeout);
2118
2119 if (NILP (dx))
2120 dx = make_fixnum (5);
2121 else
2122 CHECK_FIXNUM (dx);
2123
2124 if (NILP (dy))
2125 dy = make_fixnum (-10);
2126 else
2127 CHECK_FIXNUM (dy);
2128
2129 tip_dx = dx;
2130 tip_dy = dy;
2131
2132 if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
2133 {
2134 if (FRAME_VISIBLE_P (XFRAME (tip_frame))
2135 && !NILP (Fequal_including_properties (tip_last_string,
2136 string))
2137 && !NILP (Fequal (tip_last_parms, parms)))
2138 {
2139 /* Only DX and DY have changed. */
2140 tip_f = XFRAME (tip_frame);
2141 if (!NILP (tip_timer))
2142 {
2143 call1 (Qcancel_timer, tip_timer);
2144 tip_timer = Qnil;
2145 }
2146
2147 block_input ();
2148 compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
2149 FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
2150 android_move_window (FRAME_ANDROID_WINDOW (tip_f),
2151 root_x, root_y);
2152 unblock_input ();
2153
2154 goto start_timer;
2155 }
2156 else
2157 android_hide_tip (true);
2158 }
2159 else
2160 android_hide_tip (true);
2161
2162 tip_last_frame = frame;
2163 tip_last_string = string;
2164 tip_last_parms = parms;
2165
2166 if (NILP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
2167 {
2168 /* Add default values to frame parameters. */
2169 if (NILP (Fassq (Qname, parms)))
2170 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
2171 if (NILP (Fassq (Qinternal_border_width, parms)))
2172 parms = Fcons (Fcons (Qinternal_border_width, make_fixnum (3)),
2173 parms);
2174 if (NILP (Fassq (Qborder_width, parms)))
2175 parms = Fcons (Fcons (Qborder_width, make_fixnum (1)), parms);
2176 if (NILP (Fassq (Qborder_color, parms)))
2177 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")),
2178 parms);
2179 if (NILP (Fassq (Qbackground_color, parms)))
2180 parms = Fcons (Fcons (Qbackground_color,
2181 build_string ("lightyellow")),
2182 parms);
2183
2184 /* Create a frame for the tooltip, and record it in the global
2185 variable tip_frame. */
2186 if (NILP (tip_frame = android_create_tip_frame (FRAME_DISPLAY_INFO (f),
2187 parms)))
2188 /* Creating the tip frame failed. */
2189 return unbind_to (count, Qnil);
2190 }
2191
2192 tip_f = XFRAME (tip_frame);
2193 window = FRAME_ROOT_WINDOW (tip_f);
2194 tip_buf = Fget_buffer_create (tip, Qnil);
2195 /* We will mark the tip window a "pseudo-window" below, and such
2196 windows cannot have display margins. */
2197 bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
2198 bset_right_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
2199 set_window_buffer (window, tip_buf, false, false);
2200 w = XWINDOW (window);
2201 w->pseudo_window_p = true;
2202 /* Try to avoid that `other-window' select us (Bug#47207). */
2203 Fset_window_parameter (window, Qno_other_window, Qt);
2204
2205 /* Set up the frame's root window. Note: The following code does not
2206 try to size the window or its frame correctly. Its only purpose is
2207 to make the subsequent text size calculations work. The right
2208 sizes should get installed when the toolkit gets back to us. */
2209 w->left_col = 0;
2210 w->top_line = 0;
2211 w->pixel_left = 0;
2212 w->pixel_top = 0;
2213
2214 if (CONSP (Vx_max_tooltip_size)
2215 && RANGED_FIXNUMP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
2216 && RANGED_FIXNUMP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
2217 {
2218 w->total_cols = XFIXNAT (XCAR (Vx_max_tooltip_size));
2219 w->total_lines = XFIXNAT (XCDR (Vx_max_tooltip_size));
2220 }
2221 else
2222 {
2223 w->total_cols = 80;
2224 w->total_lines = 40;
2225 }
2226
2227 w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
2228 w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
2229 FRAME_TOTAL_COLS (tip_f) = w->total_cols;
2230 adjust_frame_glyphs (tip_f);
2231
2232 /* Insert STRING into root window's buffer and fit the frame to the
2233 buffer. */
2234 specpdl_ref count_1 = SPECPDL_INDEX ();
2235 old_buffer = current_buffer;
2236 set_buffer_internal_1 (XBUFFER (w->contents));
2237 bset_truncate_lines (current_buffer, Qnil);
2238 specbind (Qinhibit_read_only, Qt);
2239 specbind (Qinhibit_modification_hooks, Qt);
2240 specbind (Qinhibit_point_motion_hooks, Qt);
2241 Ferase_buffer ();
2242 Finsert (1, &string);
2243 clear_glyph_matrix (w->desired_matrix);
2244 clear_glyph_matrix (w->current_matrix);
2245 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
2246 displayed = try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
2247
2248 if (!displayed && NILP (Vx_max_tooltip_size))
2249 {
2250#ifdef ENABLE_CHECKING
2251 row = w->desired_matrix->rows;
2252 end = w->desired_matrix->rows + w->desired_matrix->nrows;
2253
2254 while (row < end)
2255 {
2256 if (!row->displays_text_p
2257 || row->ends_at_zv_p)
2258 break;
2259 ++row;
2260 }
2261
2262 eassert (row < end && row->ends_at_zv_p);
2263#endif
2264 }
2265
2266 /* Calculate size of tooltip window. */
2267 size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
2268 make_fixnum (w->pixel_height), Qnil,
2269 Qnil);
2270 /* Add the frame's internal border to calculated size. */
2271 width = XFIXNUM (CAR (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
2272 height = XFIXNUM (CDR (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
2273
2274 /* Calculate position of tooltip frame. */
2275 compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
2276
2277 /* Show tooltip frame. */
2278 block_input ();
2279 android_move_resize_window (FRAME_ANDROID_WINDOW (tip_f),
2280 root_x, root_y, width,
2281 height);
2282 android_map_raised (FRAME_ANDROID_WINDOW (tip_f));
2283 unblock_input ();
2284
2285 w->must_be_updated_p = true;
2286 update_single_window (w);
2287 flush_frame (tip_f);
2288 set_buffer_internal_1 (old_buffer);
2289 unbind_to (count_1, Qnil);
2290 windows_or_buffers_changed = old_windows_or_buffers_changed;
2291
2292 start_timer:
2293 /* Let the tip disappear after timeout seconds. */
2294 tip_timer = call3 (Qrun_at_time, timeout, Qnil,
2295 Qx_hide_tip);
2296
2297 return unbind_to (count, Qnil);
1675#endif 2298#endif
1676} 2299}
1677 2300
@@ -1683,7 +2306,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
1683 error ("Android cross-compilation stub called!"); 2306 error ("Android cross-compilation stub called!");
1684 return Qnil; 2307 return Qnil;
1685#else 2308#else
1686 return Qnil; 2309 return android_hide_tip (true);
1687#endif 2310#endif
1688} 2311}
1689 2312
@@ -2112,6 +2735,17 @@ syms_of_androidfns (void)
2112 doc: /* SKIP: real doc in xfns.c. */); 2735 doc: /* SKIP: real doc in xfns.c. */);
2113 Vx_cursor_fore_pixel = Qnil; 2736 Vx_cursor_fore_pixel = Qnil;
2114 2737
2738 /* Used by Fx_show_tip. */
2739 DEFSYM (Qrun_at_time, "run-at-time");
2740 DEFSYM (Qx_hide_tip, "x-hide-tip");
2741 DEFSYM (Qcancel_timer, "cancel-timer");
2742 DEFSYM (Qassq_delete_all, "assq-delete-all");
2743 DEFSYM (Qcolor, "color");
2744
2745 DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
2746 doc: /* SKIP: real doc in xfns.c. */);
2747 Vx_max_tooltip_size = Qnil;
2748
2115 /* Functions defined. */ 2749 /* Functions defined. */
2116 defsubr (&Sx_create_frame); 2750 defsubr (&Sx_create_frame);
2117 defsubr (&Sxw_color_defined_p); 2751 defsubr (&Sxw_color_defined_p);
@@ -2139,4 +2773,21 @@ syms_of_androidfns (void)
2139 defsubr (&Sx_show_tip); 2773 defsubr (&Sx_show_tip);
2140 defsubr (&Sx_hide_tip); 2774 defsubr (&Sx_hide_tip);
2141 defsubr (&Sandroid_detect_mouse); 2775 defsubr (&Sandroid_detect_mouse);
2776
2777#ifndef ANDROID_STUBIFY
2778 tip_timer = Qnil;
2779 staticpro (&tip_timer);
2780 tip_frame = Qnil;
2781 staticpro (&tip_frame);
2782 tip_last_frame = Qnil;
2783 staticpro (&tip_last_frame);
2784 tip_last_string = Qnil;
2785 staticpro (&tip_last_string);
2786 tip_last_parms = Qnil;
2787 staticpro (&tip_last_parms);
2788 tip_dx = Qnil;
2789 staticpro (&tip_dx);
2790 tip_dy = Qnil;
2791 staticpro (&tip_dy);
2792#endif
2142} 2793}
diff --git a/src/androidgui.h b/src/androidgui.h
index 422e72408c7..8450a1f637b 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -80,13 +80,18 @@ enum android_fill_style
80 80
81enum android_window_value_mask 81enum android_window_value_mask
82 { 82 {
83 ANDROID_CW_BACK_PIXEL = (1 << 1), 83 ANDROID_CW_BACK_PIXEL = (1 << 1),
84 ANDROID_CW_OVERRIDE_REDIRECT = (1 << 2),
84 }; 85 };
85 86
86struct android_set_window_attributes 87struct android_set_window_attributes
87{ 88{
88 /* The background pixel. */ 89 /* The background pixel. */
89 unsigned long background_pixel; 90 unsigned long background_pixel;
91
92 /* Whether or not the window is override redirect. This cannot be
93 set after creation on Android. */
94 bool override_redirect;
90}; 95};
91 96
92struct android_gc_values 97struct android_gc_values
@@ -260,7 +265,7 @@ struct android_key_event
260 ((key) == 57 || (key) == 58 || (key) == 113 || (key) == 114 \ 265 ((key) == 57 || (key) == 58 || (key) == 113 || (key) == 114 \
261 || (key) == 119 || (key) == 117 || (key) == 118 || (key) == 78 \ 266 || (key) == 119 || (key) == 117 || (key) == 118 || (key) == 78 \
262 || (key) == 94 || (key) == 59 || (key) == 60 || (key) == 95 \ 267 || (key) == 94 || (key) == 59 || (key) == 60 || (key) == 95 \
263 || (key) == 63) 268 || (key) == 63 || (key) == 115)
264 269
265struct android_configure_event 270struct android_configure_event
266{ 271{
@@ -478,6 +483,11 @@ extern int android_query_tree (android_window, android_window *,
478extern void android_get_geometry (android_window, android_window *, 483extern void android_get_geometry (android_window, android_window *,
479 int *, int *, unsigned int *, 484 int *, int *, unsigned int *,
480 unsigned int *, unsigned int *); 485 unsigned int *, unsigned int *);
486extern void android_move_resize_window (android_window, int, int,
487 unsigned int, unsigned int);
488extern void android_map_raised (android_window);
489extern void android_translate_coordinates (android_window, int,
490 int, int *, int *);
481 491
482#endif 492#endif
483 493
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
48struct 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. */
60static struct android_emacs_context_menu menu_class;
61
62static void
63android_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
109static void
110android_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
119static void
120android_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
133Lisp_Object
134android_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
325void
326init_androidmenu (void)
327{
328#ifndef ANDROID_STUBIFY
329 android_init_emacs_context_menu ();
38#endif 330#endif
331}
diff --git a/src/androidterm.c b/src/androidterm.c
index a8325312498..002d39af707 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -559,6 +559,9 @@ handle_one_android_event (struct android_display_info *dpyinfo,
559 f = android_window_to_frame (dpyinfo, 559 f = android_window_to_frame (dpyinfo,
560 configureEvent.xconfigure.window); 560 configureEvent.xconfigure.window);
561 561
562 if (!f)
563 goto OTHER;
564
562 int width = configureEvent.xconfigure.width; 565 int width = configureEvent.xconfigure.width;
563 int height = configureEvent.xconfigure.height; 566 int height = configureEvent.xconfigure.height;
564 567
@@ -884,10 +887,6 @@ handle_one_android_event (struct android_display_info *dpyinfo,
884 inev.ie.arg = tab_bar_arg; 887 inev.ie.arg = tab_bar_arg;
885 } 888 }
886 } 889 }
887 else
888 {
889 /* TODO: scroll bars */
890 }
891 890
892 if (event->type == ANDROID_BUTTON_PRESS) 891 if (event->type == ANDROID_BUTTON_PRESS)
893 { 892 {
@@ -1451,7 +1450,12 @@ android_make_frame_visible_invisible (struct frame *f, bool visible)
1451static void 1450static void
1452android_fullscreen_hook (struct frame *f) 1451android_fullscreen_hook (struct frame *f)
1453{ 1452{
1454 /* TODO */ 1453 /* Explicitly setting fullscreen is not supported on Android. */
1454
1455 if (!FRAME_PARENT_FRAME (f))
1456 store_frame_param (f, Qfullscreen, Qmaximized);
1457 else
1458 store_frame_param (f, Qfullscreen, Qnil);
1455} 1459}
1456 1460
1457void 1461void
@@ -2360,7 +2364,7 @@ android_draw_box_rect (struct glyph_string *s,
2360 2364
2361 /* Top. */ 2365 /* Top. */
2362 android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc, left_x, 2366 android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc, left_x,
2363 left_x, right_x - left_x + 1, hwidth); 2367 top_y, right_x - left_x + 1, hwidth);
2364 2368
2365 /* Left. */ 2369 /* Left. */
2366 if (left_p) 2370 if (left_p)
@@ -3958,7 +3962,14 @@ frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
3958char * 3962char *
3959get_keysym_name (int keysym) 3963get_keysym_name (int keysym)
3960{ 3964{
3961 return (char *) "UNKNOWN KEYSYM"; 3965 static char buffer[64];
3966
3967#ifndef ANDROID_STUBIFY
3968 android_get_keysym_name (keysym, buffer, 64);
3969#else
3970 emacs_abort ();
3971#endif
3972 return buffer;
3962} 3973}
3963 3974
3964 3975
@@ -4009,20 +4020,13 @@ android_create_terminal (struct android_display_info *dpyinfo)
4009 terminal->set_new_font_hook = android_new_font; 4020 terminal->set_new_font_hook = android_new_font;
4010 terminal->set_bitmap_icon_hook = android_bitmap_icon; 4021 terminal->set_bitmap_icon_hook = android_bitmap_icon;
4011 terminal->implicit_set_name_hook = android_implicitly_set_name; 4022 terminal->implicit_set_name_hook = android_implicitly_set_name;
4012 /* terminal->menu_show_hook = android_menu_show; XXX */ 4023 terminal->menu_show_hook = android_menu_show;
4013 terminal->change_tab_bar_height_hook = android_change_tab_bar_height; 4024 terminal->change_tab_bar_height_hook = android_change_tab_bar_height;
4014 terminal->change_tool_bar_height_hook = android_change_tool_bar_height; 4025 terminal->change_tool_bar_height_hook = android_change_tool_bar_height;
4015 /* terminal->set_vertical_scroll_bar_hook */
4016 /* = android_set_vertical_scroll_bar; */
4017 /* terminal->set_horizontal_scroll_bar_hook */
4018 /* = android_set_horizontal_scroll_bar; */
4019 terminal->set_scroll_bar_default_width_hook 4026 terminal->set_scroll_bar_default_width_hook
4020 = android_set_scroll_bar_default_width; 4027 = android_set_scroll_bar_default_width;
4021 terminal->set_scroll_bar_default_height_hook 4028 terminal->set_scroll_bar_default_height_hook
4022 = android_set_scroll_bar_default_height; 4029 = android_set_scroll_bar_default_height;
4023 /* terminal->condemn_scroll_bars_hook = android_condemn_scroll_bars; */
4024 /* terminal->redeem_scroll_bars_hook = android_redeem_scroll_bars; */
4025 /* terminal->judge_scroll_bars_hook = android_judge_scroll_bars; */
4026 terminal->free_pixmap = android_free_pixmap_hook; 4030 terminal->free_pixmap = android_free_pixmap_hook;
4027 terminal->delete_frame_hook = android_delete_frame; 4031 terminal->delete_frame_hook = android_delete_frame;
4028 terminal->delete_terminal_hook = android_delete_terminal; 4032 terminal->delete_terminal_hook = android_delete_terminal;
diff --git a/src/androidterm.h b/src/androidterm.h
index ebde15c40a8..e83e32a5854 100644
--- a/src/androidterm.h
+++ b/src/androidterm.h
@@ -402,6 +402,12 @@ extern void syms_of_androidfont (void);
402 402
403extern void android_finalize_font_entity (struct font_entity *); 403extern void android_finalize_font_entity (struct font_entity *);
404 404
405/* Defined in androidmenu.c. */
406
407extern Lisp_Object android_menu_show (struct frame *, int, int, int,
408 Lisp_Object, const char **);
409extern void init_androidmenu (void);
410
405/* Defined in sfntfont-android.c. */ 411/* Defined in sfntfont-android.c. */
406 412
407extern const struct font_driver android_sfntfont_driver; 413extern const struct font_driver android_sfntfont_driver;
diff --git a/src/emacs.c b/src/emacs.c
index e3f6c7d66f7..8f5be53aad9 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -2499,6 +2499,10 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
2499 init_window (); 2499 init_window ();
2500 init_font (); 2500 init_font ();
2501 2501
2502#ifdef HAVE_ANDROID
2503 init_androidmenu ();
2504#endif
2505
2502#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY 2506#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
2503 init_androidfont (); 2507 init_androidfont ();
2504 init_sfntfont (); 2508 init_sfntfont ();