diff options
| author | Po Lu | 2023-01-17 22:10:43 +0800 |
|---|---|---|
| committer | Po Lu | 2023-01-17 22:10:43 +0800 |
| commit | 1b8258a1f2b6a080a4f0e819aa4a86c1ec2da89f (patch) | |
| tree | d6c709e513882f5d430a98508e631cc503469fab /src/androidmenu.c | |
| parent | 356249d9faf2b454879ff30f06d97beb97fb9a36 (diff) | |
| download | emacs-1b8258a1f2b6a080a4f0e819aa4a86c1ec2da89f.tar.gz emacs-1b8258a1f2b6a080a4f0e819aa4a86c1ec2da89f.zip | |
Update Android port
* doc/emacs/android.texi (Android Fonts): Document that TTC
format fonts are now supported.
* doc/emacs/emacs.texi (Top): Fix menus.
* doc/lispref/commands.texi (Touchscreen Events)
(Key Sequence Input): Document changes to touchscreen events.
* etc/DEBUG: Describe how to debug 64 bit binaries on Android.
* java/org/gnu/emacs/EmacsCopyArea.java (perform): Explicitly
recycle copy bitmap.
* java/org/gnu/emacs/EmacsDialog.java (EmacsDialog): New class.
* java/org/gnu/emacs/EmacsDrawRectangle.java (perform): Use 5
point PolyLine like X, because Android behaves like Postscript
on some devices and X elsewhere.
* java/org/gnu/emacs/EmacsFillRectangle.java (perform):
Explicitly recycle copy bitmap.
* java/org/gnu/emacs/EmacsPixmap.java (destroyHandle):
Explicitly recycle bitmap and GC if it is big.
* java/org/gnu/emacs/EmacsView.java (EmacsView): Make
`bitmapDirty' a boolean.
(handleDirtyBitmap): Reimplement in terms of that boolean.
Explicitly recycle old bitmap and GC.
(onLayout): Fix lock up.
(onDetachedFromWindow): Recycle bitmap and GC.
* java/org/gnu/emacs/EmacsWindow.java (requestViewLayout):
Update call to explicitlyDirtyBitmap.
* src/android.c (android_run_select_thread, android_select):
Really fix android_select.
(android_build_jstring): New function.
* src/android.h: Update prototypes.
* src/androidmenu.c (android_process_events_for_menu): Totally
unblock input before process_pending_signals.
(android_menu_show): Remove redundant unblock_input and
debugging code.
(struct android_emacs_dialog, android_init_emacs_dialog)
(android_dialog_show, android_popup_dialog, init_androidmenu):
Implement popup dialogs on Android.
* src/androidterm.c (android_update_tools)
(handle_one_android_event, android_frame_up_to_date): Allow
tapping tool bar items.
(android_create_terminal): Add dialog hook.
(android_wait_for_event): Adjust call to android_select.
* src/androidterm.h (struct android_touch_point): New field
`tool_bar_p'.
* src/keyboard.c (read_key_sequence, head_table)
(syms_of_keyboard): Prefix touchscreen events with posn.
* src/keyboard.h (EVENT_HEAD): Handle touchscreen events.
* src/process.c (wait_reading_process_output): Adjust call to
android_select.
* src/sfnt.c (sfnt_read_table_directory): If the first long
turns out to be ttcf, return -1.
(sfnt_read_ttc_header): New function.
(main): Test TTC support.
* src/sfnt.h (struct sfnt_ttc_header): New structure.
(enum sfnt_ttc_tag): New enum.
* src/sfntfont-android.c (struct
sfntfont_android_scanline_buffer): New structure.
(GET_SCANLINE_BUFFER): New macro. Try to avoid so much malloc
upon accessing the scanline buffer.
(sfntfont_android_put_glyphs): Do not use SAFE_ALLOCA to
allocate the scaline buffer.
(Fandroid_enumerate_fonts): Enumerate ttc fonts too.
* src/sfntfont.c (struct sfnt_font_desc): New field `offset'.
(sfnt_enum_font_1): Split out enumeration code from
sfnt_enum_font.
(sfnt_enum_font): Read TTC tables and enumerate each font
therein.
(sfntfont_open): Seek to the offset specified.
* xcompile/Makefile.in (maintainer-clean): Fix depends here.
Diffstat (limited to 'src/androidmenu.c')
| -rw-r--r-- | src/androidmenu.c | 240 |
1 files changed, 233 insertions, 7 deletions
diff --git a/src/androidmenu.c b/src/androidmenu.c index 6fb4963174b..f65b5d3ffd1 100644 --- a/src/androidmenu.c +++ b/src/androidmenu.c | |||
| @@ -168,11 +168,17 @@ android_dismiss_menu (void *pointer) | |||
| 168 | static void | 168 | static void |
| 169 | android_process_events_for_menu (int *id) | 169 | android_process_events_for_menu (int *id) |
| 170 | { | 170 | { |
| 171 | int blocked; | ||
| 172 | |||
| 171 | /* Set menu_event_id to -1; handle_one_android_event will set it to | 173 | /* Set menu_event_id to -1; handle_one_android_event will set it to |
| 172 | the event ID upon receiving a context menu event. This can cause | 174 | the event ID upon receiving a context menu event. This can cause |
| 173 | a non-local exit. */ | 175 | a non-local exit. */ |
| 174 | x_display_list->menu_event_id = -1; | 176 | x_display_list->menu_event_id = -1; |
| 175 | 177 | ||
| 178 | /* Unblock input completely. */ | ||
| 179 | blocked = interrupt_input_blocked; | ||
| 180 | totally_unblock_input (); | ||
| 181 | |||
| 176 | /* Now wait for the menu event ID to change. */ | 182 | /* Now wait for the menu event ID to change. */ |
| 177 | while (x_display_list->menu_event_id == -1) | 183 | while (x_display_list->menu_event_id == -1) |
| 178 | { | 184 | { |
| @@ -181,11 +187,11 @@ android_process_events_for_menu (int *id) | |||
| 181 | 187 | ||
| 182 | /* Process pending signals. */ | 188 | /* Process pending signals. */ |
| 183 | process_pending_signals (); | 189 | process_pending_signals (); |
| 184 | |||
| 185 | /* Maybe quit. */ | ||
| 186 | maybe_quit (); | ||
| 187 | } | 190 | } |
| 188 | 191 | ||
| 192 | /* Restore the input block. */ | ||
| 193 | interrupt_input_blocked = blocked; | ||
| 194 | |||
| 189 | /* Return the ID. */ | 195 | /* Return the ID. */ |
| 190 | *id = x_display_list->menu_event_id; | 196 | *id = x_display_list->menu_event_id; |
| 191 | } | 197 | } |
| @@ -420,9 +426,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 420 | 426 | ||
| 421 | /* Next, process events waiting for something to be selected. */ | 427 | /* Next, process events waiting for something to be selected. */ |
| 422 | popup_activated_flag = 1; | 428 | popup_activated_flag = 1; |
| 423 | unblock_input (); | ||
| 424 | android_process_events_for_menu (&id); | 429 | android_process_events_for_menu (&id); |
| 425 | block_input (); | ||
| 426 | 430 | ||
| 427 | if (!id) | 431 | if (!id) |
| 428 | /* This means no menu item was selected. */ | 432 | /* This means no menu item was selected. */ |
| @@ -498,8 +502,6 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 498 | } | 502 | } |
| 499 | } | 503 | } |
| 500 | 504 | ||
| 501 | Fprint (tem, Qexternal_debugging_output); | ||
| 502 | |||
| 503 | unblock_input (); | 505 | unblock_input (); |
| 504 | return unbind_to (count, tem); | 506 | return unbind_to (count, tem); |
| 505 | 507 | ||
| @@ -508,6 +510,229 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 508 | return unbind_to (count, Qnil); | 510 | return unbind_to (count, Qnil); |
| 509 | } | 511 | } |
| 510 | 512 | ||
| 513 | |||
| 514 | |||
| 515 | /* Toolkit dialog implementation. */ | ||
| 516 | |||
| 517 | /* Structure describing the EmacsDialog class. */ | ||
| 518 | |||
| 519 | struct android_emacs_dialog | ||
| 520 | { | ||
| 521 | jclass class; | ||
| 522 | jmethodID create_dialog; | ||
| 523 | jmethodID add_button; | ||
| 524 | jmethodID display; | ||
| 525 | }; | ||
| 526 | |||
| 527 | /* Identifiers associated with the EmacsDialog class. */ | ||
| 528 | static struct android_emacs_dialog dialog_class; | ||
| 529 | |||
| 530 | static void | ||
| 531 | android_init_emacs_dialog (void) | ||
| 532 | { | ||
| 533 | jclass old; | ||
| 534 | |||
| 535 | dialog_class.class | ||
| 536 | = (*android_java_env)->FindClass (android_java_env, | ||
| 537 | "org/gnu/emacs/EmacsDialog"); | ||
| 538 | eassert (dialog_class.class); | ||
| 539 | |||
| 540 | old = dialog_class.class; | ||
| 541 | dialog_class.class | ||
| 542 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 543 | (jobject) old); | ||
| 544 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 545 | |||
| 546 | if (!dialog_class.class) | ||
| 547 | emacs_abort (); | ||
| 548 | |||
| 549 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 550 | dialog_class.c_name \ | ||
| 551 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 552 | dialog_class.class, \ | ||
| 553 | name, signature); \ | ||
| 554 | eassert (dialog_class.c_name); | ||
| 555 | |||
| 556 | #define FIND_METHOD_STATIC(c_name, name, signature) \ | ||
| 557 | dialog_class.c_name \ | ||
| 558 | = (*android_java_env)->GetStaticMethodID (android_java_env, \ | ||
| 559 | dialog_class.class, \ | ||
| 560 | name, signature); \ | ||
| 561 | |||
| 562 | FIND_METHOD_STATIC (create_dialog, "createDialog", "(Ljava/lang/String;" | ||
| 563 | "Ljava/lang/String;)Lorg/gnu/emacs/EmacsDialog;"); | ||
| 564 | FIND_METHOD (add_button, "addButton", "(Ljava/lang/String;IZ)V"); | ||
| 565 | FIND_METHOD (display, "display", "()Z"); | ||
| 566 | |||
| 567 | #undef FIND_METHOD | ||
| 568 | #undef FIND_METHOD_STATIC | ||
| 569 | } | ||
| 570 | |||
| 571 | static Lisp_Object | ||
| 572 | android_dialog_show (struct frame *f, Lisp_Object title, | ||
| 573 | Lisp_Object header, const char **error_name) | ||
| 574 | { | ||
| 575 | specpdl_ref count; | ||
| 576 | jobject dialog, java_header, java_title, temp; | ||
| 577 | size_t i; | ||
| 578 | Lisp_Object item_name, enable, entry; | ||
| 579 | bool rc; | ||
| 580 | int id; | ||
| 581 | jmethodID method; | ||
| 582 | |||
| 583 | if (menu_items_n_panes > 1) | ||
| 584 | { | ||
| 585 | *error_name = "Multiple panes in dialog box"; | ||
| 586 | return Qnil; | ||
| 587 | } | ||
| 588 | |||
| 589 | /* Do the initial setup. */ | ||
| 590 | count = SPECPDL_INDEX (); | ||
| 591 | *error_name = NULL; | ||
| 592 | |||
| 593 | android_push_local_frame (); | ||
| 594 | |||
| 595 | /* Figure out what header to use. */ | ||
| 596 | java_header = (!NILP (header) | ||
| 597 | ? android_build_jstring ("Information") | ||
| 598 | : android_build_jstring ("Question")); | ||
| 599 | |||
| 600 | /* And the title. */ | ||
| 601 | java_title = android_build_string (title); | ||
| 602 | |||
| 603 | /* Now create the dialog. */ | ||
| 604 | method = dialog_class.create_dialog; | ||
| 605 | dialog = (*android_java_env)->CallStaticObjectMethod (android_java_env, | ||
| 606 | dialog_class.class, | ||
| 607 | method, java_header, | ||
| 608 | java_title); | ||
| 609 | android_exception_check (); | ||
| 610 | |||
| 611 | /* Delete now unused local references. */ | ||
| 612 | if (java_header) | ||
| 613 | ANDROID_DELETE_LOCAL_REF (java_header); | ||
| 614 | ANDROID_DELETE_LOCAL_REF (java_title); | ||
| 615 | |||
| 616 | /* Create the buttons. */ | ||
| 617 | i = MENU_ITEMS_PANE_LENGTH; | ||
| 618 | while (i < menu_items_used) | ||
| 619 | { | ||
| 620 | item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); | ||
| 621 | enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); | ||
| 622 | |||
| 623 | /* Verify that there is no submenu here. */ | ||
| 624 | |||
| 625 | if (NILP (item_name)) | ||
| 626 | { | ||
| 627 | *error_name = "Submenu in dialog items"; | ||
| 628 | return unbind_to (count, Qnil); | ||
| 629 | } | ||
| 630 | |||
| 631 | /* Skip past boundaries between buttons on different sides. The | ||
| 632 | Android toolkit is too silly to understand this | ||
| 633 | distinction. */ | ||
| 634 | |||
| 635 | if (EQ (item_name, Qquote)) | ||
| 636 | ++i; | ||
| 637 | else | ||
| 638 | { | ||
| 639 | /* Make sure i is within bounds. */ | ||
| 640 | if (i > TYPE_MAXIMUM (jint)) | ||
| 641 | { | ||
| 642 | *error_name = "Dialog box too big"; | ||
| 643 | return unbind_to (count, Qnil); | ||
| 644 | } | ||
| 645 | |||
| 646 | /* Add the button. */ | ||
| 647 | temp = android_build_string (item_name); | ||
| 648 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 649 | dialog, | ||
| 650 | dialog_class.add_button, | ||
| 651 | temp, (jint) i, | ||
| 652 | (jboolean) NILP (enable)); | ||
| 653 | android_exception_check (); | ||
| 654 | ANDROID_DELETE_LOCAL_REF (temp); | ||
| 655 | i += MENU_ITEMS_ITEM_LENGTH; | ||
| 656 | } | ||
| 657 | } | ||
| 658 | |||
| 659 | /* The dialog is now built. Run it. */ | ||
| 660 | rc = (*android_java_env)->CallBooleanMethod (android_java_env, | ||
| 661 | dialog, | ||
| 662 | dialog_class.display); | ||
| 663 | android_exception_check (); | ||
| 664 | |||
| 665 | if (!rc) | ||
| 666 | quit (); | ||
| 667 | |||
| 668 | /* Wait for the menu ID to arrive. */ | ||
| 669 | android_process_events_for_menu (&id); | ||
| 670 | |||
| 671 | if (!id) | ||
| 672 | quit (); | ||
| 673 | |||
| 674 | /* Find the selected item, and its pane, to return | ||
| 675 | the proper value. */ | ||
| 676 | i = 0; | ||
| 677 | while (i < menu_items_used) | ||
| 678 | { | ||
| 679 | if (EQ (AREF (menu_items, i), Qt)) | ||
| 680 | i += MENU_ITEMS_PANE_LENGTH; | ||
| 681 | else if (EQ (AREF (menu_items, i), Qquote)) | ||
| 682 | /* This is the boundary between left-side elts and right-side | ||
| 683 | elts. */ | ||
| 684 | ++i; | ||
| 685 | else | ||
| 686 | { | ||
| 687 | entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); | ||
| 688 | |||
| 689 | if (id == i) | ||
| 690 | return entry; | ||
| 691 | |||
| 692 | i += MENU_ITEMS_ITEM_LENGTH; | ||
| 693 | } | ||
| 694 | } | ||
| 695 | |||
| 696 | return Qnil; | ||
| 697 | } | ||
| 698 | |||
| 699 | Lisp_Object | ||
| 700 | android_popup_dialog (struct frame *f, Lisp_Object header, | ||
| 701 | Lisp_Object contents) | ||
| 702 | { | ||
| 703 | Lisp_Object title; | ||
| 704 | const char *error_name; | ||
| 705 | Lisp_Object selection; | ||
| 706 | specpdl_ref specpdl_count = SPECPDL_INDEX (); | ||
| 707 | |||
| 708 | check_window_system (f); | ||
| 709 | |||
| 710 | /* Decode the dialog items from what was specified. */ | ||
| 711 | title = Fcar (contents); | ||
| 712 | CHECK_STRING (title); | ||
| 713 | record_unwind_protect_void (unuse_menu_items); | ||
| 714 | |||
| 715 | if (NILP (Fcar (Fcdr (contents)))) | ||
| 716 | /* No buttons specified, add an "Ok" button so users can pop down | ||
| 717 | the dialog. */ | ||
| 718 | contents = list2 (title, Fcons (build_string ("Ok"), Qt)); | ||
| 719 | |||
| 720 | list_of_panes (list1 (contents)); | ||
| 721 | |||
| 722 | /* Display them in a dialog box. */ | ||
| 723 | block_input (); | ||
| 724 | selection = android_dialog_show (f, title, header, &error_name); | ||
| 725 | unblock_input (); | ||
| 726 | |||
| 727 | unbind_to (specpdl_count, Qnil); | ||
| 728 | discard_menu_items (); | ||
| 729 | |||
| 730 | if (error_name) | ||
| 731 | error ("%s", error_name); | ||
| 732 | |||
| 733 | return selection; | ||
| 734 | } | ||
| 735 | |||
| 511 | #else | 736 | #else |
| 512 | 737 | ||
| 513 | int | 738 | int |
| @@ -531,6 +756,7 @@ init_androidmenu (void) | |||
| 531 | { | 756 | { |
| 532 | #ifndef ANDROID_STUBIFY | 757 | #ifndef ANDROID_STUBIFY |
| 533 | android_init_emacs_context_menu (); | 758 | android_init_emacs_context_menu (); |
| 759 | android_init_emacs_dialog (); | ||
| 534 | #endif | 760 | #endif |
| 535 | } | 761 | } |
| 536 | 762 | ||