aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-01-15 11:57:10 +0800
committerPo Lu2023-01-15 11:57:10 +0800
commit6e2bc91d924fbeb0ad5728e0424eabc905c0d366 (patch)
treef2835948a308d9d0898b9ef868893560048f6812 /src
parentc02a7b2ff48746fab891db16f58ccdc11d161745 (diff)
downloademacs-6e2bc91d924fbeb0ad5728e0424eabc905c0d366.tar.gz
emacs-6e2bc91d924fbeb0ad5728e0424eabc905c0d366.zip
Implement toolkit menus on Android
* java/org/gnu/emacs/EmacsActivity.java (onContextMenuClosed): New function. * java/org/gnu/emacs/EmacsContextMenu.java (EmacsContextMenu): New field `itemAlreadySelected'. (onMenuItemClick): New function. (inflateMenuItems): Attach onClickListener as appropriate. (display1): Clear itemAlreadySelected. (display): Fix runnable synchronization. * java/org/gnu/emacs/EmacsNative.java (sendContextMenu): New function. * java/org/gnu/emacs/EmacsView.java (popupMenu): (cancelPopupMenu): Set popupactive correctly. * src/android.c (android_run_select_thread): Fix android_select again. (android_wait_event): New function. * src/android.h: Update prototypes. * src/androidgui.h (enum android_event_type): New `ANDROID_CONTEXT_MENU' event. (struct android_menu_event, union android_event): Add new event. * src/androidmenu.c (struct android_emacs_context_menu): New structure. (android_init_emacs_context_menu): Add `dismiss' method. (struct android_dismiss_menu_data): New structure. (android_dismiss_menu, android_process_events_for_menu): New functions. (android_menu_show): Set an actual item ID. (popup_activated): Define when stubify as well. (Fmenu_or_popup_active_p): New function. (syms_of_androidmenu): New function. * src/androidterm.c (handle_one_android_event): Handle context menu events. * src/androidterm.h (struct android_display_info): New field for menu item ID. * src/emacs.c (android_emacs_init): Call syms_of_androidmenu. * src/xdisp.c (note_mouse_highlight): Return if popup_activated on Android as well.
Diffstat (limited to 'src')
-rw-r--r--src/android.c42
-rw-r--r--src/android.h1
-rw-r--r--src/androidgui.h16
-rw-r--r--src/androidmenu.c114
-rw-r--r--src/androidterm.c8
-rw-r--r--src/androidterm.h5
-rw-r--r--src/emacs.c1
-rw-r--r--src/xdisp.c3
8 files changed, 181 insertions, 9 deletions
diff --git a/src/android.c b/src/android.c
index 5e5e28c60ca..ed162a903ba 100644
--- a/src/android.c
+++ b/src/android.c
@@ -236,7 +236,7 @@ static sem_t android_pselect_sem, android_pselect_start_sem;
236static void * 236static void *
237android_run_select_thread (void *data) 237android_run_select_thread (void *data)
238{ 238{
239 sigset_t signals; 239 sigset_t signals, sigset;
240 int rc; 240 int rc;
241 241
242 sigfillset (&signals); 242 sigfillset (&signals);
@@ -259,7 +259,11 @@ android_run_select_thread (void *data)
259 259
260 /* Make sure SIGUSR1 can always wake pselect up. */ 260 /* Make sure SIGUSR1 can always wake pselect up. */
261 if (android_pselect_sigset) 261 if (android_pselect_sigset)
262 sigdelset (android_pselect_sigset, SIGUSR1); 262 {
263 sigset = *android_pselect_sigset;
264 sigdelset (&sigset, SIGUSR1);
265 android_pselect_sigset = &sigset;
266 }
263 else 267 else
264 android_pselect_sigset = &signals; 268 android_pselect_sigset = &signals;
265 269
@@ -356,6 +360,23 @@ android_pending (void)
356 return i; 360 return i;
357} 361}
358 362
363/* Wait for events to become available synchronously. Return once an
364 event arrives. */
365
366void
367android_wait_event (void)
368{
369 pthread_mutex_lock (&event_queue.mutex);
370
371 /* Wait for events to appear if there are none available to
372 read. */
373 if (!event_queue.num_events)
374 pthread_cond_wait (&event_queue.read_var,
375 &event_queue.mutex);
376
377 pthread_mutex_unlock (&event_queue.mutex);
378}
379
359void 380void
360android_next_event (union android_event *event_return) 381android_next_event (union android_event *event_return)
361{ 382{
@@ -1472,6 +1493,8 @@ NATIVE_NAME (sendIconified) (JNIEnv *env, jobject object,
1472 1493
1473 event.iconified.type = ANDROID_ICONIFIED; 1494 event.iconified.type = ANDROID_ICONIFIED;
1474 event.iconified.window = window; 1495 event.iconified.window = window;
1496
1497 android_write_event (&event);
1475} 1498}
1476 1499
1477extern JNIEXPORT void JNICALL 1500extern JNIEXPORT void JNICALL
@@ -1482,6 +1505,21 @@ NATIVE_NAME (sendDeiconified) (JNIEnv *env, jobject object,
1482 1505
1483 event.iconified.type = ANDROID_DEICONIFIED; 1506 event.iconified.type = ANDROID_DEICONIFIED;
1484 event.iconified.window = window; 1507 event.iconified.window = window;
1508
1509 android_write_event (&event);
1510}
1511
1512extern JNIEXPORT void JNICALL
1513NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object,
1514 jshort window, jint menu_event_id)
1515{
1516 union android_event event;
1517
1518 event.menu.type = ANDROID_CONTEXT_MENU;
1519 event.menu.window = window;
1520 event.menu.menu_event_id = menu_event_id;
1521
1522 android_write_event (&event);
1485} 1523}
1486 1524
1487#pragma clang diagnostic pop 1525#pragma clang diagnostic pop
diff --git a/src/android.h b/src/android.h
index 98f2494e9a3..e68e0a51fbf 100644
--- a/src/android.h
+++ b/src/android.h
@@ -89,6 +89,7 @@ extern jstring android_build_string (Lisp_Object);
89extern void android_exception_check (void); 89extern void android_exception_check (void);
90 90
91extern void android_get_keysym_name (int, char *, size_t); 91extern void android_get_keysym_name (int, char *, size_t);
92extern void android_wait_event (void);
92 93
93 94
94 95
diff --git a/src/androidgui.h b/src/androidgui.h
index 8450a1f637b..0e075fda95e 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -233,6 +233,7 @@ enum android_event_type
233 ANDROID_WHEEL, 233 ANDROID_WHEEL,
234 ANDROID_ICONIFIED, 234 ANDROID_ICONIFIED,
235 ANDROID_DEICONIFIED, 235 ANDROID_DEICONIFIED,
236 ANDROID_CONTEXT_MENU,
236 }; 237 };
237 238
238struct android_any_event 239struct android_any_event
@@ -371,6 +372,18 @@ struct android_iconify_event
371 android_window window; 372 android_window window;
372}; 373};
373 374
375struct android_menu_event
376{
377 /* Type of the event. */
378 enum android_event_type type;
379
380 /* Window associated with the event. Always None. */
381 android_window window;
382
383 /* Menu event ID. */
384 int menu_event_id;
385};
386
374union android_event 387union android_event
375{ 388{
376 enum android_event_type type; 389 enum android_event_type type;
@@ -395,6 +408,9 @@ union android_event
395 /* This has no parallel in X because Android doesn't have window 408 /* This has no parallel in X because Android doesn't have window
396 properties. */ 409 properties. */
397 struct android_iconify_event iconified; 410 struct android_iconify_event iconified;
411
412 /* This is only used to transmit selected menu items. */
413 struct android_menu_event menu;
398}; 414};
399 415
400enum 416enum
diff --git a/src/androidmenu.c b/src/androidmenu.c
index 0f0c6f4ef1f..7522f9c5a52 100644
--- a/src/androidmenu.c
+++ b/src/androidmenu.c
@@ -54,6 +54,7 @@ struct android_emacs_context_menu
54 jmethodID add_pane; 54 jmethodID add_pane;
55 jmethodID parent; 55 jmethodID parent;
56 jmethodID display; 56 jmethodID display;
57 jmethodID dismiss;
57}; 58};
58 59
59/* Identifiers associated with the EmacsContextMenu class. */ 60/* Identifiers associated with the EmacsContextMenu class. */
@@ -101,6 +102,7 @@ android_init_emacs_context_menu (void)
101 FIND_METHOD (add_pane, "addPane", "(Ljava/lang/String;)V"); 102 FIND_METHOD (add_pane, "addPane", "(Ljava/lang/String;)V");
102 FIND_METHOD (parent, "parent", "()Lorg/gnu/emacs/EmacsContextMenu;"); 103 FIND_METHOD (parent, "parent", "()Lorg/gnu/emacs/EmacsContextMenu;");
103 FIND_METHOD (display, "display", "(Lorg/gnu/emacs/EmacsWindow;II)Z"); 104 FIND_METHOD (display, "display", "(Lorg/gnu/emacs/EmacsWindow;II)Z");
105 FIND_METHOD (dismiss, "dismiss", "(Lorg/gnu/emacs/EmacsWindow;)V");
104 106
105#undef FIND_METHOD 107#undef FIND_METHOD
106#undef FIND_METHOD_STATIC 108#undef FIND_METHOD_STATIC
@@ -130,6 +132,62 @@ android_push_local_frame (void)
130 record_unwind_protect_void (android_unwind_local_frame); 132 record_unwind_protect_void (android_unwind_local_frame);
131} 133}
132 134
135/* Data for android_dismiss_menu. */
136
137struct android_dismiss_menu_data
138{
139 /* The menu object. */
140 jobject menu;
141
142 /* The window object. */
143 jobject window;
144};
145
146/* Cancel the context menu passed in POINTER. Also, clear
147 popup_activated_flag. */
148
149static void
150android_dismiss_menu (void *pointer)
151{
152 struct android_dismiss_menu_data *data;
153
154 data = pointer;
155 (*android_java_env)->CallVoidMethod (android_java_env,
156 data->menu,
157 menu_class.dismiss,
158 data->window);
159 popup_activated_flag = 0;
160}
161
162/* Recursively process events until a ANDROID_CONTEXT_MENU event
163 arrives. Then, return the item ID specified in the event in
164 *ID. */
165
166static void
167android_process_events_for_menu (int *id)
168{
169 /* Set menu_event_id to -1; handle_one_android_event will set it to
170 the event ID upon receiving a context menu event. This can cause
171 a non-local exit. */
172 x_display_list->menu_event_id = -1;
173
174 /* Now wait for the menu event ID to change. */
175 while (x_display_list->menu_event_id == -1)
176 {
177 /* Wait for events to become available. */
178 android_wait_event ();
179
180 /* Process pending signals. */
181 process_pending_signals ();
182
183 /* Maybe quit. */
184 maybe_quit ();
185 }
186
187 /* Return the ID. */
188 *id = x_display_list->menu_event_id;
189}
190
133Lisp_Object 191Lisp_Object
134android_menu_show (struct frame *f, int x, int y, int menuflags, 192android_menu_show (struct frame *f, int x, int y, int menuflags,
135 Lisp_Object title, const char **error_name) 193 Lisp_Object title, const char **error_name)
@@ -140,11 +198,13 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
140 Lisp_Object pane_name, prefix; 198 Lisp_Object pane_name, prefix;
141 const char *pane_string; 199 const char *pane_string;
142 specpdl_ref count, count1; 200 specpdl_ref count, count1;
143 Lisp_Object item_name, enable, def; 201 Lisp_Object item_name, enable, def, tem;
144 jmethodID method; 202 jmethodID method;
145 jobject store; 203 jobject store;
146 bool rc; 204 bool rc;
147 jobject window; 205 jobject window;
206 int id, item_id;
207 struct android_dismiss_menu_data data;
148 208
149 count = SPECPDL_INDEX (); 209 count = SPECPDL_INDEX ();
150 210
@@ -266,6 +326,12 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
266 ; 326 ;
267 else 327 else
268 { 328 {
329 /* Compute the item ID. This is the index of value.
330 Make sure it doesn't overflow. */
331
332 if (!INT_ADD_OK (0, i + MENU_ITEMS_ITEM_VALUE, &item_id))
333 memory_full (i + MENU_ITEMS_ITEM_VALUE * sizeof (Lisp_Object));
334
269 /* Add this menu item with the appropriate state. */ 335 /* Add this menu item with the appropriate state. */
270 336
271 title_string = (!NILP (item_name) 337 title_string = (!NILP (item_name)
@@ -274,7 +340,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
274 (*android_java_env)->CallVoidMethod (android_java_env, 340 (*android_java_env)->CallVoidMethod (android_java_env,
275 current_context_menu, 341 current_context_menu,
276 menu_class.add_item, 342 menu_class.add_item,
277 (jint) 1, 343 (jint) item_id,
278 title_string, 344 title_string,
279 (jboolean) !NILP (enable)); 345 (jboolean) !NILP (enable));
280 android_exception_check (); 346 android_exception_check ();
@@ -295,6 +361,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
295 ANDROID_HANDLE_WINDOW); 361 ANDROID_HANDLE_WINDOW);
296 rc = (*android_java_env)->CallBooleanMethod (android_java_env, 362 rc = (*android_java_env)->CallBooleanMethod (android_java_env,
297 context_menu, 363 context_menu,
364 menu_class.display,
298 window, (jint) x, 365 window, (jint) x,
299 (jint) y); 366 (jint) y);
300 android_exception_check (); 367 android_exception_check ();
@@ -303,25 +370,54 @@ android_menu_show (struct frame *f, int x, int y, int menuflags,
303 /* This means displaying the menu failed. */ 370 /* This means displaying the menu failed. */
304 goto finish; 371 goto finish;
305 372
306#if 0 373 /* Make sure the context menu is always dismissed. */
307 record_unwind_protect_ptr (android_dismiss_menu, &context_menu); 374 data.menu = context_menu;
375 data.window = window;
376 record_unwind_protect_ptr (android_dismiss_menu, &data);
308 377
309 /* Otherwise, loop waiting for the menu event to arrive. */ 378 /* Next, process events waiting for something to be selected. */
379 popup_activated_flag = 1;
380 unblock_input ();
310 android_process_events_for_menu (&id); 381 android_process_events_for_menu (&id);
382 block_input ();
311 383
312 if (!id) 384 if (!id)
313 /* This means no menu item was selected. */ 385 /* This means no menu item was selected. */
314 goto finish; 386 goto finish;
315 387
316#endif 388 /* id is an index into menu_items. Check that it remains
389 valid. */
390 if (id >= ASIZE (menu_items))
391 goto finish;
392
393 /* Now return the menu item at that location. */
394 tem = AREF (menu_items, id);
395 unblock_input ();
396 return unbind_to (count, tem);
317 397
318 finish: 398 finish:
319 unblock_input (); 399 unblock_input ();
320 return unbind_to (count, Qnil); 400 return unbind_to (count, Qnil);
321} 401}
322 402
403#else
404
405int
406popup_activated (void)
407{
408 return 0;
409}
410
323#endif 411#endif
324 412
413DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p,
414 Smenu_or_popup_active_p, 0, 0, 0,
415 doc: /* SKIP: real doc in xfns.c. */)
416 (void)
417{
418 return (popup_activated ()) ? Qt : Qnil;
419}
420
325void 421void
326init_androidmenu (void) 422init_androidmenu (void)
327{ 423{
@@ -329,3 +425,9 @@ init_androidmenu (void)
329 android_init_emacs_context_menu (); 425 android_init_emacs_context_menu ();
330#endif 426#endif
331} 427}
428
429void
430syms_of_androidmenu (void)
431{
432 defsubr (&Smenu_or_popup_active_p);
433}
diff --git a/src/androidterm.c b/src/androidterm.c
index 002d39af707..4017fec60a5 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -1125,6 +1125,14 @@ handle_one_android_event (struct android_display_info *dpyinfo,
1125 XSETFRAME (inev.ie.frame_or_window, any); 1125 XSETFRAME (inev.ie.frame_or_window, any);
1126 goto OTHER; 1126 goto OTHER;
1127 1127
1128 /* Context menu handling. */
1129 case ANDROID_CONTEXT_MENU:
1130
1131 if (dpyinfo->menu_event_id == -1)
1132 dpyinfo->menu_event_id = event->menu.menu_event_id;
1133
1134 goto OTHER;
1135
1128 default: 1136 default:
1129 goto OTHER; 1137 goto OTHER;
1130 } 1138 }
diff --git a/src/androidterm.h b/src/androidterm.h
index e83e32a5854..9aa09877196 100644
--- a/src/androidterm.h
+++ b/src/androidterm.h
@@ -132,6 +132,10 @@ struct android_display_info
132 132
133 /* The time of the last mouse movement. */ 133 /* The time of the last mouse movement. */
134 Time last_mouse_movement_time; 134 Time last_mouse_movement_time;
135
136 /* ID of the last menu event received. -1 means Emacs is waiting
137 for a context menu event. */
138 int menu_event_id;
135}; 139};
136 140
137/* Structure representing a single tool (finger or stylus) pressed 141/* Structure representing a single tool (finger or stylus) pressed
@@ -407,6 +411,7 @@ extern void android_finalize_font_entity (struct font_entity *);
407extern Lisp_Object android_menu_show (struct frame *, int, int, int, 411extern Lisp_Object android_menu_show (struct frame *, int, int, int,
408 Lisp_Object, const char **); 412 Lisp_Object, const char **);
409extern void init_androidmenu (void); 413extern void init_androidmenu (void);
414extern void syms_of_androidmenu (void);
410 415
411/* Defined in sfntfont-android.c. */ 416/* Defined in sfntfont-android.c. */
412 417
diff --git a/src/emacs.c b/src/emacs.c
index 8f5be53aad9..f4973c70610 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -2397,6 +2397,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
2397#ifdef HAVE_ANDROID 2397#ifdef HAVE_ANDROID
2398 syms_of_androidterm (); 2398 syms_of_androidterm ();
2399 syms_of_androidfns (); 2399 syms_of_androidfns ();
2400 syms_of_androidmenu ();
2400 syms_of_fontset (); 2401 syms_of_fontset ();
2401#if !defined ANDROID_STUBIFY 2402#if !defined ANDROID_STUBIFY
2402 syms_of_androidfont (); 2403 syms_of_androidfont ();
diff --git a/src/xdisp.c b/src/xdisp.c
index b9ee102af26..262a823f899 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -34959,7 +34959,8 @@ note_mouse_highlight (struct frame *f, int x, int y)
34959 struct buffer *b; 34959 struct buffer *b;
34960 34960
34961 /* When a menu is active, don't highlight because this looks odd. */ 34961 /* When a menu is active, don't highlight because this looks odd. */
34962#if defined (HAVE_X_WINDOWS) || defined (HAVE_NS) || defined (MSDOS) 34962#if defined (HAVE_X_WINDOWS) || defined (HAVE_NS) || defined (MSDOS) \
34963 || defined (HAVE_ANDROID)
34963 if (popup_activated ()) 34964 if (popup_activated ())
34964 return; 34965 return;
34965#endif 34966#endif