diff options
| author | Po Lu | 2023-01-15 11:57:10 +0800 |
|---|---|---|
| committer | Po Lu | 2023-01-15 11:57:10 +0800 |
| commit | 6e2bc91d924fbeb0ad5728e0424eabc905c0d366 (patch) | |
| tree | f2835948a308d9d0898b9ef868893560048f6812 /java | |
| parent | c02a7b2ff48746fab891db16f58ccdc11d161745 (diff) | |
| download | emacs-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 'java')
| -rw-r--r-- | java/org/gnu/emacs/EmacsActivity.java | 15 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsContextMenu.java | 64 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsNative.java | 3 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsView.java | 2 |
4 files changed, 77 insertions, 7 deletions
diff --git a/java/org/gnu/emacs/EmacsActivity.java b/java/org/gnu/emacs/EmacsActivity.java index 4cd286d1e89..4b96a376987 100644 --- a/java/org/gnu/emacs/EmacsActivity.java +++ b/java/org/gnu/emacs/EmacsActivity.java | |||
| @@ -30,6 +30,7 @@ import android.os.Bundle; | |||
| 30 | import android.util.Log; | 30 | import android.util.Log; |
| 31 | import android.widget.FrameLayout; | 31 | import android.widget.FrameLayout; |
| 32 | import android.widget.FrameLayout.LayoutParams; | 32 | import android.widget.FrameLayout.LayoutParams; |
| 33 | import android.view.Menu; | ||
| 33 | 34 | ||
| 34 | public class EmacsActivity extends Activity | 35 | public class EmacsActivity extends Activity |
| 35 | implements EmacsWindowAttachmentManager.WindowConsumer | 36 | implements EmacsWindowAttachmentManager.WindowConsumer |
| @@ -227,4 +228,18 @@ public class EmacsActivity extends Activity | |||
| 227 | EmacsWindowAttachmentManager.MANAGER.noticeDeiconified (this); | 228 | EmacsWindowAttachmentManager.MANAGER.noticeDeiconified (this); |
| 228 | super.onResume (); | 229 | super.onResume (); |
| 229 | } | 230 | } |
| 231 | |||
| 232 | @Override | ||
| 233 | public void | ||
| 234 | onContextMenuClosed (Menu menu) | ||
| 235 | { | ||
| 236 | Log.d (TAG, "onContextMenuClosed: " + menu); | ||
| 237 | |||
| 238 | /* Send a context menu event given that no menu item has already | ||
| 239 | been selected. */ | ||
| 240 | if (!EmacsContextMenu.itemAlreadySelected) | ||
| 241 | EmacsNative.sendContextMenu ((short) 0, 0); | ||
| 242 | |||
| 243 | super.onContextMenuClosed (menu); | ||
| 244 | } | ||
| 230 | }; | 245 | }; |
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java index 8d7ae08b257..02dd1c7efa9 100644 --- a/java/org/gnu/emacs/EmacsContextMenu.java +++ b/java/org/gnu/emacs/EmacsContextMenu.java | |||
| @@ -31,6 +31,8 @@ import android.view.Menu; | |||
| 31 | import android.view.MenuItem; | 31 | import android.view.MenuItem; |
| 32 | import android.view.View; | 32 | import android.view.View; |
| 33 | 33 | ||
| 34 | import android.util.Log; | ||
| 35 | |||
| 34 | import android.widget.PopupMenu; | 36 | import android.widget.PopupMenu; |
| 35 | 37 | ||
| 36 | /* Context menu implementation. This object is built from JNI and | 38 | /* Context menu implementation. This object is built from JNI and |
| @@ -40,12 +42,31 @@ import android.widget.PopupMenu; | |||
| 40 | 42 | ||
| 41 | public class EmacsContextMenu | 43 | public class EmacsContextMenu |
| 42 | { | 44 | { |
| 43 | private class Item | 45 | private static final String TAG = "EmacsContextMenu"; |
| 46 | |||
| 47 | /* Whether or not an item was selected. */ | ||
| 48 | public static boolean itemAlreadySelected; | ||
| 49 | |||
| 50 | private class Item implements MenuItem.OnMenuItemClickListener | ||
| 44 | { | 51 | { |
| 45 | public int itemID; | 52 | public int itemID; |
| 46 | public String itemName; | 53 | public String itemName; |
| 47 | public EmacsContextMenu subMenu; | 54 | public EmacsContextMenu subMenu; |
| 48 | public boolean isEnabled; | 55 | public boolean isEnabled; |
| 56 | |||
| 57 | @Override | ||
| 58 | public boolean | ||
| 59 | onMenuItemClick (MenuItem item) | ||
| 60 | { | ||
| 61 | Log.d (TAG, "onMenuItemClick: " + itemName + " (" + itemID + ")"); | ||
| 62 | |||
| 63 | /* Send a context menu event. */ | ||
| 64 | EmacsNative.sendContextMenu ((short) 0, itemID); | ||
| 65 | |||
| 66 | /* Say that an item has already been selected. */ | ||
| 67 | itemAlreadySelected = true; | ||
| 68 | return true; | ||
| 69 | } | ||
| 49 | }; | 70 | }; |
| 50 | 71 | ||
| 51 | public List<Item> menuItems; | 72 | public List<Item> menuItems; |
| @@ -137,6 +158,7 @@ public class EmacsContextMenu | |||
| 137 | else | 158 | else |
| 138 | { | 159 | { |
| 139 | menuItem = menu.add (item.itemName); | 160 | menuItem = menu.add (item.itemName); |
| 161 | menuItem.setOnMenuItemClickListener (item); | ||
| 140 | 162 | ||
| 141 | /* If the item ID is zero, then disable the item. */ | 163 | /* If the item ID is zero, then disable the item. */ |
| 142 | if (item.itemID == 0 || !item.isEnabled) | 164 | if (item.itemID == 0 || !item.isEnabled) |
| @@ -171,6 +193,10 @@ public class EmacsContextMenu | |||
| 171 | private boolean | 193 | private boolean |
| 172 | display1 (EmacsWindow window, int xPosition, int yPosition) | 194 | display1 (EmacsWindow window, int xPosition, int yPosition) |
| 173 | { | 195 | { |
| 196 | /* Set this flag to false. It is used to decide whether or not to | ||
| 197 | send 0 in response to the context menu being closed. */ | ||
| 198 | itemAlreadySelected = false; | ||
| 199 | |||
| 174 | return window.view.popupMenu (this, xPosition, yPosition); | 200 | return window.view.popupMenu (this, xPosition, yPosition); |
| 175 | } | 201 | } |
| 176 | 202 | ||
| @@ -199,15 +225,39 @@ public class EmacsContextMenu | |||
| 199 | } | 225 | } |
| 200 | }; | 226 | }; |
| 201 | 227 | ||
| 202 | try | 228 | synchronized (runnable) |
| 203 | { | 229 | { |
| 204 | runnable.wait (); | 230 | EmacsService.SERVICE.runOnUiThread (runnable); |
| 205 | } | 231 | |
| 206 | catch (InterruptedException e) | 232 | try |
| 207 | { | 233 | { |
| 208 | EmacsNative.emacsAbort (); | 234 | runnable.wait (); |
| 235 | } | ||
| 236 | catch (InterruptedException e) | ||
| 237 | { | ||
| 238 | EmacsNative.emacsAbort (); | ||
| 239 | } | ||
| 209 | } | 240 | } |
| 210 | 241 | ||
| 211 | return rc.thing; | 242 | return rc.thing; |
| 212 | } | 243 | } |
| 244 | |||
| 245 | /* Dismiss this context menu. WINDOW is the window where the | ||
| 246 | context menu is being displayed. */ | ||
| 247 | |||
| 248 | public void | ||
| 249 | dismiss (final EmacsWindow window) | ||
| 250 | { | ||
| 251 | Runnable runnable; | ||
| 252 | |||
| 253 | EmacsService.SERVICE.runOnUiThread (new Runnable () { | ||
| 254 | @Override | ||
| 255 | public void | ||
| 256 | run () | ||
| 257 | { | ||
| 258 | window.view.cancelPopupMenu (); | ||
| 259 | itemAlreadySelected = false; | ||
| 260 | } | ||
| 261 | }); | ||
| 262 | } | ||
| 213 | }; | 263 | }; |
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java index a11e509cd7f..4a80f88edcf 100644 --- a/java/org/gnu/emacs/EmacsNative.java +++ b/java/org/gnu/emacs/EmacsNative.java | |||
| @@ -124,6 +124,9 @@ public class EmacsNative | |||
| 124 | /* Send an ANDROID_DEICONIFIED event. */ | 124 | /* Send an ANDROID_DEICONIFIED event. */ |
| 125 | public static native void sendDeiconified (short window); | 125 | public static native void sendDeiconified (short window); |
| 126 | 126 | ||
| 127 | /* Send an ANDROID_CONTEXT_MENU event. */ | ||
| 128 | public static native void sendContextMenu (short window, int menuEventID); | ||
| 129 | |||
| 127 | static | 130 | static |
| 128 | { | 131 | { |
| 129 | System.loadLibrary ("emacs"); | 132 | System.loadLibrary ("emacs"); |
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java index 1391f630be0..445d8ffa023 100644 --- a/java/org/gnu/emacs/EmacsView.java +++ b/java/org/gnu/emacs/EmacsView.java | |||
| @@ -453,6 +453,7 @@ public class EmacsView extends ViewGroup | |||
| 453 | return false; | 453 | return false; |
| 454 | 454 | ||
| 455 | contextMenu = menu; | 455 | contextMenu = menu; |
| 456 | popupActive = true; | ||
| 456 | 457 | ||
| 457 | /* On API 21 or later, use showContextMenu (float, float). */ | 458 | /* On API 21 or later, use showContextMenu (float, float). */ |
| 458 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) | 459 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) |
| @@ -469,5 +470,6 @@ public class EmacsView extends ViewGroup | |||
| 469 | + " popupActive set"); | 470 | + " popupActive set"); |
| 470 | 471 | ||
| 471 | contextMenu = null; | 472 | contextMenu = null; |
| 473 | popupActive = false; | ||
| 472 | } | 474 | } |
| 473 | }; | 475 | }; |