aboutsummaryrefslogtreecommitdiffstats
path: root/src/androidmenu.c
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/androidmenu.c
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/androidmenu.c')
-rw-r--r--src/androidmenu.c293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/androidmenu.c b/src/androidmenu.c
index 6f6e4ca8de9..0f0c6f4ef1f 100644
--- a/src/androidmenu.c
+++ b/src/androidmenu.c
@@ -21,6 +21,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
21 21
22#include "lisp.h" 22#include "lisp.h"
23#include "androidterm.h" 23#include "androidterm.h"
24#include "android.h"
25#include "blockinput.h"
26#include "keyboard.h"
27#include "menu.h"
24 28
25#ifndef ANDROID_STUBIFY 29#ifndef ANDROID_STUBIFY
26 30
@@ -35,4 +39,293 @@ popup_activated (void)
35 return popup_activated_flag; 39 return popup_activated_flag;
36} 40}
37 41
42
43
44/* Toolkit menu implementation. */
45
46/* Structure describing the EmacsContextMenu class. */
47
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}