aboutsummaryrefslogtreecommitdiffstats
path: root/src/androidmenu.c
diff options
context:
space:
mode:
authorPo Lu2023-01-17 22:10:43 +0800
committerPo Lu2023-01-17 22:10:43 +0800
commit1b8258a1f2b6a080a4f0e819aa4a86c1ec2da89f (patch)
treed6c709e513882f5d430a98508e631cc503469fab /src/androidmenu.c
parent356249d9faf2b454879ff30f06d97beb97fb9a36 (diff)
downloademacs-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.c240
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)
168static void 168static void
169android_process_events_for_menu (int *id) 169android_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
519struct 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. */
528static struct android_emacs_dialog dialog_class;
529
530static void
531android_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
571static Lisp_Object
572android_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
699Lisp_Object
700android_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
513int 738int
@@ -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