diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.in | 52 | ||||
| -rw-r--r-- | src/alloc.c | 12 | ||||
| -rw-r--r-- | src/android-emacs.c | 30 | ||||
| -rw-r--r-- | src/android.c | 2335 | ||||
| -rw-r--r-- | src/android.h | 70 | ||||
| -rw-r--r-- | src/androidfns.c | 1779 | ||||
| -rw-r--r-- | src/androidfont.c | 955 | ||||
| -rw-r--r-- | src/androidgui.h | 315 | ||||
| -rw-r--r-- | src/androidterm.c | 3161 | ||||
| -rw-r--r-- | src/androidterm.h | 366 | ||||
| -rw-r--r-- | src/dired.c | 5 | ||||
| -rw-r--r-- | src/dispextern.h | 31 | ||||
| -rw-r--r-- | src/dispnew.c | 48 | ||||
| -rw-r--r-- | src/editfns.c | 8 | ||||
| -rw-r--r-- | src/emacs.c | 37 | ||||
| -rw-r--r-- | src/epaths.in | 22 | ||||
| -rw-r--r-- | src/fileio.c | 25 | ||||
| -rw-r--r-- | src/filelock.c | 6 | ||||
| -rw-r--r-- | src/fns.c | 4 | ||||
| -rw-r--r-- | src/font.c | 16 | ||||
| -rw-r--r-- | src/font.h | 3 | ||||
| -rw-r--r-- | src/frame.c | 30 | ||||
| -rw-r--r-- | src/frame.h | 35 | ||||
| -rw-r--r-- | src/image.c | 88 | ||||
| -rw-r--r-- | src/lisp.h | 12 | ||||
| -rw-r--r-- | src/lread.c | 6 | ||||
| -rw-r--r-- | src/pdumper.c | 2 | ||||
| -rw-r--r-- | src/process.c | 17 | ||||
| -rw-r--r-- | src/scroll.c | 7 | ||||
| -rw-r--r-- | src/sysdep.c | 98 | ||||
| -rw-r--r-- | src/term.c | 135 | ||||
| -rw-r--r-- | src/termhooks.h | 22 | ||||
| -rw-r--r-- | src/terminal.c | 2 | ||||
| -rw-r--r-- | src/verbose.mk.in | 8 | ||||
| -rw-r--r-- | src/xdisp.c | 26 | ||||
| -rw-r--r-- | src/xfaces.c | 59 |
36 files changed, 9725 insertions, 102 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index da11e130b2a..b0ba9825a65 100644 --- a/src/Makefile.in +++ b/src/Makefile.in | |||
| @@ -33,6 +33,16 @@ top_builddir = @top_builddir@ | |||
| 33 | # MinGW CPPFLAGS may use this. | 33 | # MinGW CPPFLAGS may use this. |
| 34 | abs_top_srcdir=@abs_top_srcdir@ | 34 | abs_top_srcdir=@abs_top_srcdir@ |
| 35 | VPATH = $(srcdir) | 35 | VPATH = $(srcdir) |
| 36 | |||
| 37 | # This is not empty if this is a Makefile that will be copied to | ||
| 38 | # xcompile/src. | ||
| 39 | XCONFIGURE = @XCONFIGURE@ | ||
| 40 | |||
| 41 | ifneq ($(XCONFIGURE),) | ||
| 42 | vpath %.c := $(srcdir) | ||
| 43 | vpath %.h := $(srcdir) | ||
| 44 | endif | ||
| 45 | |||
| 36 | CC = @CC@ | 46 | CC = @CC@ |
| 37 | CXX = @CXX@ | 47 | CXX = @CXX@ |
| 38 | CFLAGS = @CFLAGS@ | 48 | CFLAGS = @CFLAGS@ |
| @@ -48,6 +58,7 @@ LIBOBJS = @LIBOBJS@ | |||
| 48 | 58 | ||
| 49 | lispsource = $(top_srcdir)/lisp | 59 | lispsource = $(top_srcdir)/lisp |
| 50 | lib = ../lib | 60 | lib = ../lib |
| 61 | hostlib = $(top_builddir)/lib | ||
| 51 | libsrc = ../lib-src | 62 | libsrc = ../lib-src |
| 52 | etc = ../etc | 63 | etc = ../etc |
| 53 | oldXMenudir = ../oldXMenu | 64 | oldXMenudir = ../oldXMenu |
| @@ -326,7 +337,7 @@ W32_RES_LINK=@W32_RES_LINK@ | |||
| 326 | ## if HAVE_HARFBUZZ, hbfont.o is added regardless of the rest | 337 | ## if HAVE_HARFBUZZ, hbfont.o is added regardless of the rest |
| 327 | FONT_OBJ=@FONT_OBJ@ | 338 | FONT_OBJ=@FONT_OBJ@ |
| 328 | 339 | ||
| 329 | ## Empty for MinGW, cm.o for the rest. | 340 | ## Empty for MinGW and Android, cm.o for the rest. |
| 330 | CM_OBJ=@CM_OBJ@ | 341 | CM_OBJ=@CM_OBJ@ |
| 331 | 342 | ||
| 332 | LIBGPM = @LIBGPM@ | 343 | LIBGPM = @LIBGPM@ |
| @@ -370,6 +381,10 @@ HAIKU_CXX_OBJ = @HAIKU_CXX_OBJ@ | |||
| 370 | HAIKU_LIBS = @HAIKU_LIBS@ | 381 | HAIKU_LIBS = @HAIKU_LIBS@ |
| 371 | HAIKU_CFLAGS = @HAIKU_CFLAGS@ | 382 | HAIKU_CFLAGS = @HAIKU_CFLAGS@ |
| 372 | 383 | ||
| 384 | ANDROID_OBJ = @ANDROID_OBJ@ | ||
| 385 | ANDROID_LIBS = @ANDROID_LIBS@ | ||
| 386 | ANDROID_CFLAGS = @ANDROID_CFLAGS@ | ||
| 387 | |||
| 373 | DUMPING=@DUMPING@ | 388 | DUMPING=@DUMPING@ |
| 374 | CHECK_STRUCTS = @CHECK_STRUCTS@ | 389 | CHECK_STRUCTS = @CHECK_STRUCTS@ |
| 375 | HAVE_PDUMPER = @HAVE_PDUMPER@ | 390 | HAVE_PDUMPER = @HAVE_PDUMPER@ |
| @@ -411,7 +426,8 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \ | |||
| 411 | $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ | 426 | $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ |
| 412 | $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) $(XSYNC_CFLAGS) $(TREE_SITTER_CFLAGS) \ | 427 | $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) $(XSYNC_CFLAGS) $(TREE_SITTER_CFLAGS) \ |
| 413 | $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \ | 428 | $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \ |
| 414 | $(WERROR_CFLAGS) $(HAIKU_CFLAGS) $(XCOMPOSITE_CFLAGS) $(XSHAPE_CFLAGS) | 429 | $(WERROR_CFLAGS) $(HAIKU_CFLAGS) $(XCOMPOSITE_CFLAGS) $(XSHAPE_CFLAGS) \ |
| 430 | $(ANDROID_CFLAGS) | ||
| 415 | ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) | 431 | ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) |
| 416 | ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \ | 432 | ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \ |
| 417 | $(filter-out $(NON_OBJC_CFLAGS),$(WARN_CFLAGS)) $(CFLAGS) \ | 433 | $(filter-out $(NON_OBJC_CFLAGS),$(WARN_CFLAGS)) $(CFLAGS) \ |
| @@ -449,7 +465,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ | |||
| 449 | $(if $(HYBRID_MALLOC),sheap.o) \ | 465 | $(if $(HYBRID_MALLOC),sheap.o) \ |
| 450 | $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ | 466 | $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ |
| 451 | $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) \ | 467 | $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) \ |
| 452 | $(HAIKU_OBJ) $(PGTK_OBJ) | 468 | $(HAIKU_OBJ) $(PGTK_OBJ) $(ANDROID_OBJ) |
| 453 | doc_obj = $(base_obj) $(NS_OBJC_OBJ) | 469 | doc_obj = $(base_obj) $(NS_OBJC_OBJ) |
| 454 | obj = $(doc_obj) $(HAIKU_CXX_OBJ) | 470 | obj = $(doc_obj) $(HAIKU_CXX_OBJ) |
| 455 | 471 | ||
| @@ -466,7 +482,8 @@ SOME_MACHINE_OBJECTS = dosfns.o msdos.o \ | |||
| 466 | w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ | 482 | w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ |
| 467 | w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \ | 483 | w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \ |
| 468 | xsettings.o xgselect.o termcap.o hbfont.o \ | 484 | xsettings.o xgselect.o termcap.o hbfont.o \ |
| 469 | haikuterm.o haikufns.o haikumenu.o haikufont.o | 485 | haikuterm.o haikufns.o haikumenu.o haikufont.o androidterm.o androidfns.o \ |
| 486 | androidfont.o | ||
| 470 | 487 | ||
| 471 | ## gmalloc.o if !SYSTEM_MALLOC && !DOUG_LEA_MALLOC, else empty. | 488 | ## gmalloc.o if !SYSTEM_MALLOC && !DOUG_LEA_MALLOC, else empty. |
| 472 | GMALLOC_OBJ=@GMALLOC_OBJ@ | 489 | GMALLOC_OBJ=@GMALLOC_OBJ@ |
| @@ -569,7 +586,8 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(PGTK_LIBS) $(LIBX_BASE) $(LIBIMAGE | |||
| 569 | $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \ | 586 | $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \ |
| 570 | $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ | 587 | $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ |
| 571 | $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(XINPUT_LIBS) $(HAIKU_LIBS) \ | 588 | $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(XINPUT_LIBS) $(HAIKU_LIBS) \ |
| 572 | $(TREE_SITTER_LIBS) $(SQLITE3_LIBS) $(XCOMPOSITE_LIBS) $(XSHAPE_LIBS) | 589 | $(TREE_SITTER_LIBS) $(SQLITE3_LIBS) $(XCOMPOSITE_LIBS) $(XSHAPE_LIBS) \ |
| 590 | $(ANDROID_LIBS) | ||
| 573 | 591 | ||
| 574 | ## FORCE it so that admin/unidata can decide whether this file is | 592 | ## FORCE it so that admin/unidata can decide whether this file is |
| 575 | ## up-to-date. Although since charprop depends on bootstrap-emacs, | 593 | ## up-to-date. Although since charprop depends on bootstrap-emacs, |
| @@ -658,7 +676,7 @@ $(etc)/DOC: $(libsrc)/make-docfile$(EXEEXT) $(doc_obj) | |||
| 658 | $(SOME_MACHINE_OBJECTS) $(doc_obj) > $(etc)/DOC | 676 | $(SOME_MACHINE_OBJECTS) $(doc_obj) > $(etc)/DOC |
| 659 | 677 | ||
| 660 | $(libsrc)/make-docfile$(EXEEXT) $(libsrc)/make-fingerprint$(EXEEXT): \ | 678 | $(libsrc)/make-docfile$(EXEEXT) $(libsrc)/make-fingerprint$(EXEEXT): \ |
| 661 | $(lib)/libgnu.a | 679 | $(hostlib)/libgnu.a |
| 662 | $(MAKE) -C $(dir $@) $(notdir $@) | 680 | $(MAKE) -C $(dir $@) $(notdir $@) |
| 663 | 681 | ||
| 664 | buildobj.h: Makefile | 682 | buildobj.h: Makefile |
| @@ -719,6 +737,27 @@ ifeq ($(DUMPING),unexec) | |||
| 719 | endif | 737 | endif |
| 720 | endif | 738 | endif |
| 721 | 739 | ||
| 740 | ifeq ($(XCONFIGURE),android) | ||
| 741 | ## The Android package internally links to and communicates with a | ||
| 742 | ## shared library named `libemacs.so' at startup. This is built | ||
| 743 | ## almost the same way temacs is. But it is position independent. It | ||
| 744 | ## is not dumped here. Instead, it dumps itself the first time it | ||
| 745 | ## starts on the user's device. | ||
| 746 | |||
| 747 | libemacs.so: $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \ | ||
| 748 | $(MAKE_PDUMPER_FINGERPRINT) | ||
| 749 | $(AM_V_CCLD)$(CC) -o $@ $(ALL_CFLAGS) $(TEMACS_LDFLAGS) \ | ||
| 750 | $(LDFLAGS) -shared $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(LIBES) | ||
| 751 | $(AM_V_at)$(MAKE_PDUMPER_FINGERPRINT) $@ | ||
| 752 | |||
| 753 | # There is also a binary named `android-emacs' which simply calls | ||
| 754 | # emacs.so. | ||
| 755 | |||
| 756 | android-emacs: libemacs.so android-emacs.o | ||
| 757 | $(AM_V_CCLD)$(CC) -o $@ $(ALL_CFLAGS) $(LDFLAGS) \ | ||
| 758 | -L. "-l:libemacs.so" android-emacs.o | ||
| 759 | endif | ||
| 760 | |||
| 722 | ## The following oldxmenu-related rules are only (possibly) used if | 761 | ## The following oldxmenu-related rules are only (possibly) used if |
| 723 | ## HAVE_X11 && !USE_GTK, but there is no harm in always defining them. | 762 | ## HAVE_X11 && !USE_GTK, but there is no harm in always defining them. |
| 724 | $(lwlibdir)/liblw.a: $(config_h) globals.h lisp.h FORCE | 763 | $(lwlibdir)/liblw.a: $(config_h) globals.h lisp.h FORCE |
| @@ -747,6 +786,7 @@ ns-app: emacs$(EXEEXT) $(pdmp) | |||
| 747 | .PHONY: versionclean | 786 | .PHONY: versionclean |
| 748 | 787 | ||
| 749 | mostlyclean: | 788 | mostlyclean: |
| 789 | rm -f aemacs emacs.so | ||
| 750 | rm -f temacs$(EXEEXT) core ./*.core \#* ./*.o | 790 | rm -f temacs$(EXEEXT) core ./*.core \#* ./*.o |
| 751 | rm -f dmpstruct.h | 791 | rm -f dmpstruct.h |
| 752 | rm -f emacs.pdmp | 792 | rm -f emacs.pdmp |
diff --git a/src/alloc.c b/src/alloc.c index e7edc0595b3..b8d326f4407 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -3342,6 +3342,14 @@ cleanup_vector (struct Lisp_Vector *vector) | |||
| 3342 | drv->close_font (font); | 3342 | drv->close_font (font); |
| 3343 | } | 3343 | } |
| 3344 | } | 3344 | } |
| 3345 | |||
| 3346 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 3347 | /* The Android font driver needs the ability to associate extra | ||
| 3348 | information with font entities. */ | ||
| 3349 | if ((vector->header.size & PSEUDOVECTOR_SIZE_MASK) | ||
| 3350 | == FONT_ENTITY_MAX) | ||
| 3351 | android_finalize_font_entity (PSEUDOVEC_STRUCT (vector, font_entity)); | ||
| 3352 | #endif | ||
| 3345 | } | 3353 | } |
| 3346 | else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_THREAD)) | 3354 | else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_THREAD)) |
| 3347 | finalize_one_thread (PSEUDOVEC_STRUCT (vector, thread_state)); | 3355 | finalize_one_thread (PSEUDOVEC_STRUCT (vector, thread_state)); |
| @@ -6467,6 +6475,10 @@ garbage_collect (void) | |||
| 6467 | mark_xselect (); | 6475 | mark_xselect (); |
| 6468 | #endif | 6476 | #endif |
| 6469 | 6477 | ||
| 6478 | #ifdef HAVE_ANDROID | ||
| 6479 | mark_androidterm (); | ||
| 6480 | #endif | ||
| 6481 | |||
| 6470 | #ifdef HAVE_NS | 6482 | #ifdef HAVE_NS |
| 6471 | mark_nsterm (); | 6483 | mark_nsterm (); |
| 6472 | #endif | 6484 | #endif |
diff --git a/src/android-emacs.c b/src/android-emacs.c new file mode 100644 index 00000000000..d4fa14e39fb --- /dev/null +++ b/src/android-emacs.c | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* Android initialization for GNU Emacs. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | #include "android.h" | ||
| 22 | |||
| 23 | /* android-emacs is a wrapper around libemacs. It simply calls | ||
| 24 | android_emacs_init with the argv and argc given to it. */ | ||
| 25 | |||
| 26 | int | ||
| 27 | main (int argc, char **argv) | ||
| 28 | { | ||
| 29 | return android_emacs_init (argc, argv); | ||
| 30 | } | ||
diff --git a/src/android.c b/src/android.c new file mode 100644 index 00000000000..dd841cf383a --- /dev/null +++ b/src/android.c | |||
| @@ -0,0 +1,2335 @@ | |||
| 1 | /* Android initialization for GNU Emacs. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | #include <fcntl.h> | ||
| 22 | #include <unistd.h> | ||
| 23 | #include <pthread.h> | ||
| 24 | #include <limits.h> | ||
| 25 | #include <signal.h> | ||
| 26 | #include <semaphore.h> | ||
| 27 | |||
| 28 | #include <sys/stat.h> | ||
| 29 | #include <sys/mman.h> | ||
| 30 | |||
| 31 | #include <assert.h> | ||
| 32 | |||
| 33 | #include "android.h" | ||
| 34 | #include "androidgui.h" | ||
| 35 | |||
| 36 | #include "lisp.h" | ||
| 37 | #include "blockinput.h" | ||
| 38 | #include "coding.h" | ||
| 39 | #include "epaths.h" | ||
| 40 | |||
| 41 | /* Whether or not Emacs is running inside the application process and | ||
| 42 | Android windowing should be enabled. */ | ||
| 43 | bool android_init_gui; | ||
| 44 | |||
| 45 | #ifndef ANDROID_STUBIFY | ||
| 46 | |||
| 47 | #include <android/asset_manager.h> | ||
| 48 | #include <android/asset_manager_jni.h> | ||
| 49 | #include <android/log.h> | ||
| 50 | |||
| 51 | #include <linux/ashmem.h> | ||
| 52 | |||
| 53 | #define ANDROID_THROW(env, class, msg) \ | ||
| 54 | ((*(env))->ThrowNew ((env), (*(env))->FindClass ((env), class), msg)) | ||
| 55 | |||
| 56 | #define ANDROID_MAX_ASSET_FD 65535 | ||
| 57 | |||
| 58 | struct android_fd_table_entry | ||
| 59 | { | ||
| 60 | /* Various flags associated with this table. */ | ||
| 61 | short flags; | ||
| 62 | |||
| 63 | /* The stat buffer associated with this entry. */ | ||
| 64 | struct stat statb; | ||
| 65 | }; | ||
| 66 | |||
| 67 | enum android_fd_table_entry_flags | ||
| 68 | { | ||
| 69 | ANDROID_FD_TABLE_ENTRY_IS_VALID = 1, | ||
| 70 | }; | ||
| 71 | |||
| 72 | struct android_emacs_service | ||
| 73 | { | ||
| 74 | jclass class; | ||
| 75 | jmethodID fill_rectangle; | ||
| 76 | jmethodID fill_polygon; | ||
| 77 | jmethodID draw_rectangle; | ||
| 78 | jmethodID draw_line; | ||
| 79 | jmethodID draw_point; | ||
| 80 | jmethodID copy_area; | ||
| 81 | jmethodID clear_window; | ||
| 82 | jmethodID clear_area; | ||
| 83 | }; | ||
| 84 | |||
| 85 | struct android_emacs_pixmap | ||
| 86 | { | ||
| 87 | jclass class; | ||
| 88 | jmethodID constructor; | ||
| 89 | }; | ||
| 90 | |||
| 91 | struct android_graphics_point | ||
| 92 | { | ||
| 93 | jclass class; | ||
| 94 | jmethodID constructor; | ||
| 95 | }; | ||
| 96 | |||
| 97 | /* The asset manager being used. */ | ||
| 98 | static AAssetManager *asset_manager; | ||
| 99 | |||
| 100 | /* Whether or not Emacs has been initialized. */ | ||
| 101 | static int emacs_initialized; | ||
| 102 | |||
| 103 | /* The path used to store site-lisp. */ | ||
| 104 | char *android_site_load_path; | ||
| 105 | |||
| 106 | /* The path used to store native libraries. */ | ||
| 107 | char *android_lib_dir; | ||
| 108 | |||
| 109 | /* The Android application data directory. */ | ||
| 110 | static char *android_files_dir; | ||
| 111 | |||
| 112 | /* Array of structures used to hold asset information corresponding to | ||
| 113 | a file descriptor. This assumes Emacs does not do funny things | ||
| 114 | with dup. It currently does not. */ | ||
| 115 | static struct android_fd_table_entry android_table[ANDROID_MAX_ASSET_FD]; | ||
| 116 | |||
| 117 | /* The Java environment being used for the main thread. */ | ||
| 118 | JNIEnv *android_java_env; | ||
| 119 | |||
| 120 | /* The EmacsGC class. */ | ||
| 121 | static jclass emacs_gc_class; | ||
| 122 | |||
| 123 | /* Various fields. */ | ||
| 124 | static jfieldID emacs_gc_foreground, emacs_gc_background; | ||
| 125 | static jfieldID emacs_gc_function, emacs_gc_clip_rects; | ||
| 126 | static jfieldID emacs_gc_clip_x_origin, emacs_gc_clip_y_origin; | ||
| 127 | static jfieldID emacs_gc_stipple, emacs_gc_clip_mask; | ||
| 128 | static jfieldID emacs_gc_fill_style, emacs_gc_ts_origin_x; | ||
| 129 | static jfieldID emacs_gc_ts_origin_y; | ||
| 130 | |||
| 131 | /* The constructor and one function. */ | ||
| 132 | static jmethodID emacs_gc_constructor, emacs_gc_mark_dirty; | ||
| 133 | |||
| 134 | /* The Rect class. */ | ||
| 135 | static jclass android_rect_class; | ||
| 136 | |||
| 137 | /* Its constructor. */ | ||
| 138 | static jmethodID android_rect_constructor; | ||
| 139 | |||
| 140 | /* The EmacsService object. */ | ||
| 141 | static jobject emacs_service; | ||
| 142 | |||
| 143 | /* Various methods associated with the EmacsService. */ | ||
| 144 | static struct android_emacs_service service_class; | ||
| 145 | |||
| 146 | /* Various methods associated with the EmacsPixmap class. */ | ||
| 147 | static struct android_emacs_pixmap pixmap_class; | ||
| 148 | |||
| 149 | /* Various methods associated with the Point class. */ | ||
| 150 | static struct android_graphics_point point_class; | ||
| 151 | |||
| 152 | |||
| 153 | |||
| 154 | /* Event handling functions. Events are stored on a (circular) queue | ||
| 155 | that is read synchronously. The Android port replaces pselect with | ||
| 156 | a function android_select, which runs pselect in a separate thread, | ||
| 157 | but more importantly also waits for events to be available on the | ||
| 158 | android event queue. */ | ||
| 159 | |||
| 160 | struct android_event_container | ||
| 161 | { | ||
| 162 | /* The next and last events in this queue. */ | ||
| 163 | struct android_event_container *volatile next, *last; | ||
| 164 | |||
| 165 | /* The event itself. */ | ||
| 166 | union android_event event; | ||
| 167 | }; | ||
| 168 | |||
| 169 | struct android_event_queue | ||
| 170 | { | ||
| 171 | /* Mutex protecting the event queue. */ | ||
| 172 | pthread_mutex_t mutex; | ||
| 173 | |||
| 174 | /* Mutex protecting the select data. */ | ||
| 175 | pthread_mutex_t select_mutex; | ||
| 176 | |||
| 177 | /* The thread used to run select. */ | ||
| 178 | pthread_t select_thread; | ||
| 179 | |||
| 180 | /* Condition variable for the writing side. */ | ||
| 181 | pthread_cond_t write_var; | ||
| 182 | |||
| 183 | /* Condition variables for the reading side. */ | ||
| 184 | pthread_cond_t read_var; | ||
| 185 | |||
| 186 | /* The number of events in the queue. If this is greater than 1024, | ||
| 187 | writing will block. */ | ||
| 188 | volatile int num_events; | ||
| 189 | |||
| 190 | /* Circular queue of events. */ | ||
| 191 | struct android_event_container events; | ||
| 192 | }; | ||
| 193 | |||
| 194 | /* Arguments to pselect used by the select thread. */ | ||
| 195 | static volatile int android_pselect_nfds; | ||
| 196 | static fd_set *volatile android_pselect_readfds; | ||
| 197 | static fd_set *volatile android_pselect_writefds; | ||
| 198 | static fd_set *volatile android_pselect_exceptfds; | ||
| 199 | static struct timespec *volatile android_pselect_timeout; | ||
| 200 | static const sigset_t *volatile android_pselect_sigset; | ||
| 201 | |||
| 202 | /* Value of pselect. */ | ||
| 203 | static int android_pselect_rc; | ||
| 204 | |||
| 205 | /* Whether or not pselect finished. */ | ||
| 206 | static volatile bool android_pselect_completed; | ||
| 207 | |||
| 208 | /* The global event queue. */ | ||
| 209 | static struct android_event_queue event_queue; | ||
| 210 | |||
| 211 | /* Semaphore used to signal select completion. */ | ||
| 212 | static sem_t android_pselect_sem; | ||
| 213 | |||
| 214 | static void * | ||
| 215 | android_run_select_thread (void *data) | ||
| 216 | { | ||
| 217 | sigset_t signals; | ||
| 218 | int sig, rc; | ||
| 219 | |||
| 220 | sigfillset (&signals); | ||
| 221 | |||
| 222 | if (pthread_sigmask (SIG_BLOCK, &signals, NULL)) | ||
| 223 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 224 | "pthread_sigmask: %s", | ||
| 225 | strerror (errno)); | ||
| 226 | |||
| 227 | sigemptyset (&signals); | ||
| 228 | sigaddset (&signals, SIGUSR1); | ||
| 229 | |||
| 230 | if (pthread_sigmask (SIG_UNBLOCK, &signals, NULL)) | ||
| 231 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 232 | "pthread_sigmask: %s", | ||
| 233 | strerror (errno)); | ||
| 234 | |||
| 235 | sigemptyset (&signals); | ||
| 236 | sigaddset (&signals, SIGUSR2); | ||
| 237 | |||
| 238 | while (true) | ||
| 239 | { | ||
| 240 | /* Keep waiting for SIGUSR2, ignoring EINTR in the meantime. */ | ||
| 241 | |||
| 242 | while (sigwait (&signals, &sig)) | ||
| 243 | /* Spin. */; | ||
| 244 | |||
| 245 | /* Get the select lock and call pselect. */ | ||
| 246 | pthread_mutex_lock (&event_queue.select_mutex); | ||
| 247 | rc = pselect (android_pselect_nfds, | ||
| 248 | android_pselect_readfds, | ||
| 249 | android_pselect_writefds, | ||
| 250 | android_pselect_exceptfds, | ||
| 251 | android_pselect_timeout, | ||
| 252 | android_pselect_sigset); | ||
| 253 | android_pselect_rc = rc; | ||
| 254 | pthread_mutex_unlock (&event_queue.select_mutex); | ||
| 255 | |||
| 256 | /* Signal the Emacs thread that pselect is done. If read_var | ||
| 257 | was signaled by android_write_event, event_queue.mutex could | ||
| 258 | still be locked, so this must come before. */ | ||
| 259 | sem_post (&android_pselect_sem); | ||
| 260 | |||
| 261 | pthread_mutex_lock (&event_queue.mutex); | ||
| 262 | android_pselect_completed = true; | ||
| 263 | pthread_cond_signal (&event_queue.read_var); | ||
| 264 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | static void | ||
| 269 | android_handle_sigusr1 (int sig, siginfo_t *siginfo, void *arg) | ||
| 270 | { | ||
| 271 | /* Nothing to do here, this signal handler is only installed to make | ||
| 272 | sure the disposition of SIGUSR1 is enough. */ | ||
| 273 | } | ||
| 274 | |||
| 275 | /* Set up the global event queue by initializing the mutex and two | ||
| 276 | condition variables, and the linked list of events. This must be | ||
| 277 | called before starting the Emacs thread. Also, initialize the | ||
| 278 | thread used to run pselect. | ||
| 279 | |||
| 280 | These functions must also use the C library malloc and free, | ||
| 281 | because xmalloc is not thread safe. */ | ||
| 282 | |||
| 283 | static void | ||
| 284 | android_init_events (void) | ||
| 285 | { | ||
| 286 | struct sigaction sa; | ||
| 287 | |||
| 288 | if (pthread_mutex_init (&event_queue.mutex, NULL)) | ||
| 289 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 290 | "pthread_mutex_init: %s", | ||
| 291 | strerror (errno)); | ||
| 292 | |||
| 293 | if (pthread_mutex_init (&event_queue.select_mutex, NULL)) | ||
| 294 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 295 | "pthread_mutex_init: %s", | ||
| 296 | strerror (errno)); | ||
| 297 | |||
| 298 | if (pthread_cond_init (&event_queue.write_var, NULL)) | ||
| 299 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 300 | "pthread_cond_init: %s", | ||
| 301 | strerror (errno)); | ||
| 302 | |||
| 303 | if (pthread_cond_init (&event_queue.read_var, NULL)) | ||
| 304 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 305 | "pthread_cond_init: %s", | ||
| 306 | strerror (errno)); | ||
| 307 | |||
| 308 | sem_init (&android_pselect_sem, 0, 0); | ||
| 309 | |||
| 310 | event_queue.events.next = &event_queue.events; | ||
| 311 | event_queue.events.last = &event_queue.events; | ||
| 312 | |||
| 313 | /* Before starting the select thread, make sure the disposition for | ||
| 314 | SIGUSR1 is correct. */ | ||
| 315 | sigfillset (&sa.sa_mask); | ||
| 316 | sa.sa_sigaction = android_handle_sigusr1; | ||
| 317 | sa.sa_flags = SA_SIGINFO; | ||
| 318 | |||
| 319 | if (sigaction (SIGUSR1, &sa, NULL)) | ||
| 320 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 321 | "sigaction: %s", | ||
| 322 | strerror (errno)); | ||
| 323 | |||
| 324 | /* Start the select thread. */ | ||
| 325 | if (pthread_create (&event_queue.select_thread, NULL, | ||
| 326 | android_run_select_thread, NULL)) | ||
| 327 | __android_log_print (ANDROID_LOG_FATAL, __func__, | ||
| 328 | "pthread_create: %s", | ||
| 329 | strerror (errno)); | ||
| 330 | } | ||
| 331 | |||
| 332 | int | ||
| 333 | android_pending (void) | ||
| 334 | { | ||
| 335 | int i; | ||
| 336 | |||
| 337 | pthread_mutex_lock (&event_queue.mutex); | ||
| 338 | i = event_queue.num_events; | ||
| 339 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 340 | |||
| 341 | return i; | ||
| 342 | } | ||
| 343 | |||
| 344 | void | ||
| 345 | android_next_event (union android_event *event_return) | ||
| 346 | { | ||
| 347 | struct android_event_container *container; | ||
| 348 | |||
| 349 | pthread_mutex_lock (&event_queue.mutex); | ||
| 350 | |||
| 351 | /* Wait for events to appear if there are none available to | ||
| 352 | read. */ | ||
| 353 | if (!event_queue.num_events) | ||
| 354 | pthread_cond_wait (&event_queue.read_var, | ||
| 355 | &event_queue.mutex); | ||
| 356 | |||
| 357 | /* Obtain the event from the end of the queue. */ | ||
| 358 | container = event_queue.events.last; | ||
| 359 | eassert (container != &event_queue.events); | ||
| 360 | |||
| 361 | /* Remove the event from the queue and copy it to the caller | ||
| 362 | supplied buffer. */ | ||
| 363 | container->last->next = container->next; | ||
| 364 | container->next->last = container->last; | ||
| 365 | *event_return = container->event; | ||
| 366 | event_queue.num_events--; | ||
| 367 | |||
| 368 | /* Free the container. */ | ||
| 369 | free (container); | ||
| 370 | |||
| 371 | /* Signal that events can now be written. */ | ||
| 372 | pthread_cond_signal (&event_queue.write_var); | ||
| 373 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 374 | } | ||
| 375 | |||
| 376 | static void | ||
| 377 | android_write_event (union android_event *event) | ||
| 378 | { | ||
| 379 | struct android_event_container *container; | ||
| 380 | |||
| 381 | container = malloc (sizeof *container); | ||
| 382 | |||
| 383 | if (!container) | ||
| 384 | return; | ||
| 385 | |||
| 386 | pthread_mutex_lock (&event_queue.mutex); | ||
| 387 | |||
| 388 | /* The event queue is full, wait for events to be read. */ | ||
| 389 | if (event_queue.num_events >= 1024) | ||
| 390 | pthread_cond_wait (&event_queue.write_var, | ||
| 391 | &event_queue.mutex); | ||
| 392 | |||
| 393 | container->next = event_queue.events.next; | ||
| 394 | container->last = &event_queue.events; | ||
| 395 | container->next->last = container; | ||
| 396 | container->last->next = container; | ||
| 397 | container->event = *event; | ||
| 398 | event_queue.num_events++; | ||
| 399 | pthread_cond_signal (&event_queue.read_var); | ||
| 400 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 401 | } | ||
| 402 | |||
| 403 | int | ||
| 404 | android_select (int nfds, fd_set *readfds, fd_set *writefds, | ||
| 405 | fd_set *exceptfds, struct timespec *timeout, | ||
| 406 | const sigset_t *sigset) | ||
| 407 | { | ||
| 408 | int nfds_return; | ||
| 409 | |||
| 410 | pthread_mutex_lock (&event_queue.mutex); | ||
| 411 | |||
| 412 | if (event_queue.num_events) | ||
| 413 | { | ||
| 414 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 415 | return 1; | ||
| 416 | } | ||
| 417 | |||
| 418 | nfds_return = 0; | ||
| 419 | android_pselect_completed = false; | ||
| 420 | |||
| 421 | pthread_mutex_lock (&event_queue.select_mutex); | ||
| 422 | android_pselect_nfds = nfds; | ||
| 423 | android_pselect_readfds = readfds; | ||
| 424 | android_pselect_writefds = writefds; | ||
| 425 | android_pselect_exceptfds = exceptfds; | ||
| 426 | android_pselect_timeout = timeout; | ||
| 427 | android_pselect_sigset = sigset; | ||
| 428 | pthread_mutex_unlock (&event_queue.select_mutex); | ||
| 429 | |||
| 430 | pthread_kill (event_queue.select_thread, SIGUSR2); | ||
| 431 | pthread_cond_wait (&event_queue.read_var, &event_queue.mutex); | ||
| 432 | |||
| 433 | /* Interrupt the select thread now, in case it's still in | ||
| 434 | pselect. */ | ||
| 435 | pthread_kill (event_queue.select_thread, SIGUSR1); | ||
| 436 | |||
| 437 | /* Wait for pselect to return in any case. */ | ||
| 438 | sem_wait (&android_pselect_sem); | ||
| 439 | |||
| 440 | /* If there are now events in the queue, return 1. */ | ||
| 441 | if (event_queue.num_events) | ||
| 442 | nfds_return = 1; | ||
| 443 | |||
| 444 | /* Add the return value of pselect. */ | ||
| 445 | if (android_pselect_rc >= 0) | ||
| 446 | nfds_return += android_pselect_rc; | ||
| 447 | |||
| 448 | if (!nfds_return && android_pselect_rc < 0) | ||
| 449 | nfds_return = android_pselect_rc; | ||
| 450 | |||
| 451 | /* Unlock the event queue mutex. */ | ||
| 452 | pthread_mutex_unlock (&event_queue.mutex); | ||
| 453 | |||
| 454 | return nfds_return; | ||
| 455 | } | ||
| 456 | |||
| 457 | |||
| 458 | |||
| 459 | static void * | ||
| 460 | android_run_debug_thread (void *data) | ||
| 461 | { | ||
| 462 | FILE *file; | ||
| 463 | int fd; | ||
| 464 | char *line; | ||
| 465 | size_t n; | ||
| 466 | |||
| 467 | fd = (int) data; | ||
| 468 | file = fdopen (fd, "r"); | ||
| 469 | |||
| 470 | if (!file) | ||
| 471 | return NULL; | ||
| 472 | |||
| 473 | line = NULL; | ||
| 474 | |||
| 475 | while (true) | ||
| 476 | { | ||
| 477 | if (getline (&line, &n, file) < 0) | ||
| 478 | { | ||
| 479 | free (line); | ||
| 480 | break; | ||
| 481 | } | ||
| 482 | |||
| 483 | __android_log_print (ANDROID_LOG_INFO, __func__, "%s", line); | ||
| 484 | } | ||
| 485 | |||
| 486 | fclose (file); | ||
| 487 | return NULL; | ||
| 488 | } | ||
| 489 | |||
| 490 | |||
| 491 | |||
| 492 | /* Intercept USER_FULL_NAME and return something that makes sense if | ||
| 493 | pw->pw_gecos is NULL. */ | ||
| 494 | |||
| 495 | char * | ||
| 496 | android_user_full_name (struct passwd *pw) | ||
| 497 | { | ||
| 498 | if (!pw->pw_gecos) | ||
| 499 | return (char *) "Android user"; | ||
| 500 | |||
| 501 | return pw->pw_gecos; | ||
| 502 | } | ||
| 503 | |||
| 504 | /* Given a real file name, return the part that describes its asset | ||
| 505 | path, or NULL if it is not an asset. */ | ||
| 506 | |||
| 507 | static const char * | ||
| 508 | android_get_asset_name (const char *filename) | ||
| 509 | { | ||
| 510 | if (!strcmp (filename, "/assets") || !strcmp (filename, "/assets/")) | ||
| 511 | return "/"; | ||
| 512 | |||
| 513 | if (!strncmp (filename, "/assets/", sizeof "/assets/" - 1)) | ||
| 514 | return filename + (sizeof "/assets/" - 1); | ||
| 515 | |||
| 516 | return NULL; | ||
| 517 | } | ||
| 518 | |||
| 519 | /* Like fstat. However, look up the asset corresponding to the file | ||
| 520 | descriptor. If it exists, return the right information. */ | ||
| 521 | |||
| 522 | int | ||
| 523 | android_fstat (int fd, struct stat *statb) | ||
| 524 | { | ||
| 525 | if (fd < ANDROID_MAX_ASSET_FD | ||
| 526 | && (android_table[fd].flags | ||
| 527 | & ANDROID_FD_TABLE_ENTRY_IS_VALID)) | ||
| 528 | { | ||
| 529 | memcpy (statb, &android_table[fd].statb, | ||
| 530 | sizeof *statb); | ||
| 531 | return 0; | ||
| 532 | } | ||
| 533 | |||
| 534 | return fstat (fd, statb); | ||
| 535 | } | ||
| 536 | |||
| 537 | /* Like fstatat. However, if dirfd is AT_FDCWD and PATHNAME is an | ||
| 538 | asset, find the information for the corresponding asset. */ | ||
| 539 | |||
| 540 | int | ||
| 541 | android_fstatat (int dirfd, const char *restrict pathname, | ||
| 542 | struct stat *restrict statbuf, int flags) | ||
| 543 | { | ||
| 544 | AAsset *asset_desc; | ||
| 545 | const char *asset; | ||
| 546 | |||
| 547 | if (dirfd == AT_FDCWD | ||
| 548 | && asset_manager | ||
| 549 | && (asset = android_get_asset_name (pathname))) | ||
| 550 | { | ||
| 551 | /* AASSET_MODE_STREAMING is fastest here. */ | ||
| 552 | asset_desc = AAssetManager_open (asset_manager, asset, | ||
| 553 | AASSET_MODE_STREAMING); | ||
| 554 | |||
| 555 | if (!asset_desc) | ||
| 556 | return ENOENT; | ||
| 557 | |||
| 558 | memset (statbuf, 0, sizeof *statbuf); | ||
| 559 | |||
| 560 | /* Fill in the stat buffer. */ | ||
| 561 | statbuf->st_mode = S_IFREG; | ||
| 562 | statbuf->st_size = AAsset_getLength (asset_desc); | ||
| 563 | |||
| 564 | /* Close the asset. */ | ||
| 565 | AAsset_close (asset_desc); | ||
| 566 | return 0; | ||
| 567 | } | ||
| 568 | |||
| 569 | return fstatat (dirfd, pathname, statbuf, flags); | ||
| 570 | } | ||
| 571 | |||
| 572 | /* Return if NAME is a file that is actually an asset and is | ||
| 573 | accessible, as long as !(amode & W_OK). */ | ||
| 574 | |||
| 575 | bool | ||
| 576 | android_file_access_p (const char *name, int amode) | ||
| 577 | { | ||
| 578 | AAsset *asset; | ||
| 579 | AAssetDir *directory; | ||
| 580 | |||
| 581 | if (!asset_manager) | ||
| 582 | return false; | ||
| 583 | |||
| 584 | if (!(amode & W_OK) && (name = android_get_asset_name (name))) | ||
| 585 | { | ||
| 586 | /* Check if the asset exists by opening it. Suboptimal! */ | ||
| 587 | asset = AAssetManager_open (asset_manager, name, | ||
| 588 | AASSET_MODE_UNKNOWN); | ||
| 589 | |||
| 590 | if (!asset) | ||
| 591 | { | ||
| 592 | /* See if it's a directory also. */ | ||
| 593 | directory = AAssetManager_openDir (asset_manager, name); | ||
| 594 | |||
| 595 | if (directory) | ||
| 596 | { | ||
| 597 | AAssetDir_close (directory); | ||
| 598 | return true; | ||
| 599 | } | ||
| 600 | |||
| 601 | return false; | ||
| 602 | } | ||
| 603 | |||
| 604 | AAsset_close (asset); | ||
| 605 | return true; | ||
| 606 | } | ||
| 607 | |||
| 608 | return false; | ||
| 609 | } | ||
| 610 | |||
| 611 | /* Get a file descriptor backed by a temporary in-memory file for the | ||
| 612 | given asset. */ | ||
| 613 | |||
| 614 | static int | ||
| 615 | android_hack_asset_fd (AAsset *asset) | ||
| 616 | { | ||
| 617 | int fd, rc; | ||
| 618 | unsigned char *mem; | ||
| 619 | size_t size; | ||
| 620 | |||
| 621 | fd = open ("/dev/ashmem", O_RDWR); | ||
| 622 | |||
| 623 | if (fd < 0) | ||
| 624 | return -1; | ||
| 625 | |||
| 626 | /* Assets must be small enough to fit in size_t, if off_t is | ||
| 627 | larger. */ | ||
| 628 | size = AAsset_getLength (asset); | ||
| 629 | |||
| 630 | /* An empty name means the memory area will exist until the file | ||
| 631 | descriptor is closed, because no other process can attach. */ | ||
| 632 | rc = ioctl (fd, ASHMEM_SET_NAME, ""); | ||
| 633 | |||
| 634 | if (rc < 0) | ||
| 635 | { | ||
| 636 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 637 | "ioctl ASHMEM_SET_NAME: %s", | ||
| 638 | strerror (errno)); | ||
| 639 | close (fd); | ||
| 640 | return -1; | ||
| 641 | } | ||
| 642 | |||
| 643 | rc = ioctl (fd, ASHMEM_SET_SIZE, size); | ||
| 644 | |||
| 645 | if (rc < 0) | ||
| 646 | { | ||
| 647 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 648 | "ioctl ASHMEM_SET_SIZE: %s", | ||
| 649 | strerror (errno)); | ||
| 650 | close (fd); | ||
| 651 | return -1; | ||
| 652 | } | ||
| 653 | |||
| 654 | if (!size) | ||
| 655 | return fd; | ||
| 656 | |||
| 657 | /* Now map the resource. */ | ||
| 658 | mem = mmap (NULL, size, PROT_WRITE, MAP_SHARED, fd, 0); | ||
| 659 | if (mem == MAP_FAILED) | ||
| 660 | { | ||
| 661 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 662 | "mmap: %s", strerror (errno)); | ||
| 663 | close (fd); | ||
| 664 | return -1; | ||
| 665 | } | ||
| 666 | |||
| 667 | if (AAsset_read (asset, mem, size) != size) | ||
| 668 | { | ||
| 669 | /* Too little was read. Close the file descriptor and report an | ||
| 670 | error. */ | ||
| 671 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 672 | "AAsset_read: %s", strerror (errno)); | ||
| 673 | close (fd); | ||
| 674 | return -1; | ||
| 675 | } | ||
| 676 | |||
| 677 | /* Return anyway even if munmap fails. */ | ||
| 678 | munmap (mem, size); | ||
| 679 | return fd; | ||
| 680 | } | ||
| 681 | |||
| 682 | /* `open' and such are modified even though they exist on Android, | ||
| 683 | because Emacs treats "/assets/" as a special directory that must | ||
| 684 | contain all assets in the application package. */ | ||
| 685 | |||
| 686 | int | ||
| 687 | android_open (const char *filename, int oflag, int mode) | ||
| 688 | { | ||
| 689 | const char *name; | ||
| 690 | AAsset *asset; | ||
| 691 | int fd; | ||
| 692 | off_t out_start, out_length; | ||
| 693 | bool fd_hacked; | ||
| 694 | |||
| 695 | /* This flag means whether or not fd should not be duplicated. */ | ||
| 696 | fd_hacked = false; | ||
| 697 | |||
| 698 | if (asset_manager && (name = android_get_asset_name (filename))) | ||
| 699 | { | ||
| 700 | /* If Emacs is trying to write to the file, return NULL. */ | ||
| 701 | |||
| 702 | if (oflag & O_WRONLY || oflag & O_RDWR) | ||
| 703 | { | ||
| 704 | errno = EROFS; | ||
| 705 | return -1; | ||
| 706 | } | ||
| 707 | |||
| 708 | if (oflag & O_DIRECTORY) | ||
| 709 | { | ||
| 710 | errno = EINVAL; | ||
| 711 | return -1; | ||
| 712 | } | ||
| 713 | |||
| 714 | asset = AAssetManager_open (asset_manager, name, | ||
| 715 | AASSET_MODE_BUFFER); | ||
| 716 | |||
| 717 | if (!asset) | ||
| 718 | { | ||
| 719 | errno = ENOENT; | ||
| 720 | return -1; | ||
| 721 | } | ||
| 722 | |||
| 723 | /* Try to obtain the file descriptor corresponding to this | ||
| 724 | asset. */ | ||
| 725 | fd = AAsset_openFileDescriptor (asset, &out_start, | ||
| 726 | &out_length); | ||
| 727 | |||
| 728 | if (fd == -1) | ||
| 729 | { | ||
| 730 | /* The asset can't be accessed for some reason. Try to | ||
| 731 | create a shared memory file descriptor. */ | ||
| 732 | fd = android_hack_asset_fd (asset); | ||
| 733 | |||
| 734 | if (fd == -1) | ||
| 735 | { | ||
| 736 | AAsset_close (asset); | ||
| 737 | errno = ENXIO; | ||
| 738 | return -1; | ||
| 739 | } | ||
| 740 | |||
| 741 | fd_hacked = true; | ||
| 742 | } | ||
| 743 | |||
| 744 | /* Duplicate the file descriptor and then close the asset, | ||
| 745 | which will close the original file descriptor. */ | ||
| 746 | |||
| 747 | if (!fd_hacked) | ||
| 748 | fd = fcntl (fd, F_DUPFD_CLOEXEC); | ||
| 749 | |||
| 750 | if (fd >= ANDROID_MAX_ASSET_FD || fd < 0) | ||
| 751 | { | ||
| 752 | /* Too bad. You lose. */ | ||
| 753 | errno = ENOMEM; | ||
| 754 | |||
| 755 | if (fd >= 0) | ||
| 756 | close (fd); | ||
| 757 | |||
| 758 | fd = -1; | ||
| 759 | } | ||
| 760 | else | ||
| 761 | { | ||
| 762 | assert (!(android_table[fd].flags | ||
| 763 | & ANDROID_FD_TABLE_ENTRY_IS_VALID)); | ||
| 764 | android_table[fd].flags = ANDROID_FD_TABLE_ENTRY_IS_VALID; | ||
| 765 | memset (&android_table[fd].statb, 0, | ||
| 766 | sizeof android_table[fd].statb); | ||
| 767 | |||
| 768 | /* Fill in some information that will be reported to | ||
| 769 | callers of android_fstat, among others. */ | ||
| 770 | android_table[fd].statb.st_mode = S_IFREG; | ||
| 771 | |||
| 772 | /* Owned by root. */ | ||
| 773 | android_table[fd].statb.st_uid = 0; | ||
| 774 | android_table[fd].statb.st_gid = 0; | ||
| 775 | |||
| 776 | /* Size of the file. */ | ||
| 777 | android_table[fd].statb.st_size | ||
| 778 | = AAsset_getLength (asset); | ||
| 779 | } | ||
| 780 | |||
| 781 | AAsset_close (asset); | ||
| 782 | return fd; | ||
| 783 | } | ||
| 784 | |||
| 785 | return open (filename, oflag, mode); | ||
| 786 | } | ||
| 787 | |||
| 788 | /* Like close. However, remove the file descriptor from the asset | ||
| 789 | table as well. */ | ||
| 790 | |||
| 791 | int | ||
| 792 | android_close (int fd) | ||
| 793 | { | ||
| 794 | if (fd < ANDROID_MAX_ASSET_FD | ||
| 795 | && (android_table[fd].flags & ANDROID_FD_TABLE_ENTRY_IS_VALID)) | ||
| 796 | { | ||
| 797 | __android_log_print (ANDROID_LOG_INFO, __func__, | ||
| 798 | "closing android file descriptor %d", | ||
| 799 | fd); | ||
| 800 | android_table[fd].flags = 0; | ||
| 801 | } | ||
| 802 | |||
| 803 | return close (fd); | ||
| 804 | } | ||
| 805 | |||
| 806 | |||
| 807 | |||
| 808 | /* JNI functions called by Java. */ | ||
| 809 | |||
| 810 | #pragma clang diagnostic push | ||
| 811 | #pragma clang diagnostic ignored "-Wmissing-prototypes" | ||
| 812 | |||
| 813 | JNIEXPORT void JNICALL | ||
| 814 | NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, | ||
| 815 | jobject local_asset_manager, | ||
| 816 | jobject files_dir, jobject libs_dir, | ||
| 817 | jobject emacs_service_object) | ||
| 818 | { | ||
| 819 | int pipefd[2]; | ||
| 820 | pthread_t thread; | ||
| 821 | const char *java_string; | ||
| 822 | |||
| 823 | /* This may be called from multiple threads. setEmacsParams should | ||
| 824 | only ever be called once. */ | ||
| 825 | if (__atomic_fetch_add (&emacs_initialized, -1, __ATOMIC_RELAXED)) | ||
| 826 | { | ||
| 827 | ANDROID_THROW (env, "java/lang/IllegalArgumentException", | ||
| 828 | "Emacs was already initialized!"); | ||
| 829 | return; | ||
| 830 | } | ||
| 831 | |||
| 832 | __android_log_print (ANDROID_LOG_INFO, __func__, | ||
| 833 | "Initializing "PACKAGE_STRING"...\nPlease report bugs to " | ||
| 834 | PACKAGE_BUGREPORT". Thanks.\n"); | ||
| 835 | |||
| 836 | /* Set the asset manager. */ | ||
| 837 | asset_manager = AAssetManager_fromJava (env, local_asset_manager); | ||
| 838 | |||
| 839 | /* Hold a VM reference to the asset manager to prevent the native | ||
| 840 | object from being deleted. */ | ||
| 841 | (*env)->NewGlobalRef (env, local_asset_manager); | ||
| 842 | |||
| 843 | /* Create a pipe and duplicate it to stdout and stderr. Next, make | ||
| 844 | a thread that prints stderr to the system log. */ | ||
| 845 | |||
| 846 | if (pipe2 (pipefd, O_CLOEXEC) < 0) | ||
| 847 | emacs_abort (); | ||
| 848 | |||
| 849 | if (dup2 (pipefd[1], 2) < 0) | ||
| 850 | emacs_abort (); | ||
| 851 | close (pipefd[1]); | ||
| 852 | |||
| 853 | if (pthread_create (&thread, NULL, android_run_debug_thread, | ||
| 854 | (void *) pipefd[0])) | ||
| 855 | emacs_abort (); | ||
| 856 | |||
| 857 | /* Now set the path to the site load directory. */ | ||
| 858 | |||
| 859 | java_string = (*env)->GetStringUTFChars (env, (jstring) files_dir, | ||
| 860 | NULL); | ||
| 861 | |||
| 862 | if (!java_string) | ||
| 863 | emacs_abort (); | ||
| 864 | |||
| 865 | android_files_dir = strdup ((const char *) java_string); | ||
| 866 | |||
| 867 | if (!android_files_dir) | ||
| 868 | emacs_abort (); | ||
| 869 | |||
| 870 | (*env)->ReleaseStringUTFChars (env, (jstring) files_dir, | ||
| 871 | java_string); | ||
| 872 | |||
| 873 | java_string = (*env)->GetStringUTFChars (env, (jstring) libs_dir, | ||
| 874 | NULL); | ||
| 875 | |||
| 876 | if (!java_string) | ||
| 877 | emacs_abort (); | ||
| 878 | |||
| 879 | android_lib_dir = strdup ((const char *) java_string); | ||
| 880 | |||
| 881 | if (!android_files_dir) | ||
| 882 | emacs_abort (); | ||
| 883 | |||
| 884 | (*env)->ReleaseStringUTFChars (env, (jstring) libs_dir, | ||
| 885 | java_string); | ||
| 886 | |||
| 887 | /* Calculate the site-lisp path. */ | ||
| 888 | |||
| 889 | android_site_load_path = malloc (PATH_MAX + 1); | ||
| 890 | |||
| 891 | if (!android_site_load_path) | ||
| 892 | emacs_abort (); | ||
| 893 | |||
| 894 | snprintf (android_site_load_path, PATH_MAX, "%s/site-lisp", | ||
| 895 | android_files_dir); | ||
| 896 | __android_log_print (ANDROID_LOG_INFO, __func__, | ||
| 897 | "Site-lisp directory: %s\n" | ||
| 898 | "Files directory: %s\n" | ||
| 899 | "Native code directory: %s", | ||
| 900 | android_site_load_path, | ||
| 901 | android_files_dir, | ||
| 902 | android_lib_dir); | ||
| 903 | |||
| 904 | /* Make a reference to the Emacs service. */ | ||
| 905 | emacs_service = (*env)->NewGlobalRef (env, emacs_service_object); | ||
| 906 | |||
| 907 | if (!emacs_service) | ||
| 908 | emacs_abort (); | ||
| 909 | |||
| 910 | /* Set up events. */ | ||
| 911 | android_init_events (); | ||
| 912 | |||
| 913 | /* OK, setup is now complete. The caller may start the Emacs thread | ||
| 914 | now. */ | ||
| 915 | } | ||
| 916 | |||
| 917 | /* Initialize service_class, aborting if something goes wrong. */ | ||
| 918 | |||
| 919 | static void | ||
| 920 | android_init_emacs_service (void) | ||
| 921 | { | ||
| 922 | jclass old; | ||
| 923 | |||
| 924 | service_class.class | ||
| 925 | = (*android_java_env)->FindClass (android_java_env, | ||
| 926 | "org/gnu/emacs/EmacsService"); | ||
| 927 | eassert (service_class.class); | ||
| 928 | |||
| 929 | old = service_class.class; | ||
| 930 | service_class.class | ||
| 931 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 932 | (jobject) old); | ||
| 933 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 934 | |||
| 935 | if (!service_class.class) | ||
| 936 | emacs_abort (); | ||
| 937 | |||
| 938 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 939 | service_class.c_name \ | ||
| 940 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 941 | service_class.class, \ | ||
| 942 | name, signature); \ | ||
| 943 | assert (service_class.c_name); | ||
| 944 | |||
| 945 | FIND_METHOD (fill_rectangle, "fillRectangle", | ||
| 946 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 947 | "Lorg/gnu/emacs/EmacsGC;IIII)V"); | ||
| 948 | FIND_METHOD (fill_polygon, "fillPolygon", | ||
| 949 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 950 | "Lorg/gnu/emacs/EmacsGC;" | ||
| 951 | "[Landroid/graphics/Point;)V"); | ||
| 952 | FIND_METHOD (draw_rectangle, "drawRectangle", | ||
| 953 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 954 | "Lorg/gnu/emacs/EmacsGC;IIII)V"); | ||
| 955 | FIND_METHOD (draw_line, "drawLine", | ||
| 956 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 957 | "Lorg/gnu/emacs/EmacsGC;IIII)V"); | ||
| 958 | FIND_METHOD (draw_point, "drawPoint", | ||
| 959 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 960 | "Lorg/gnu/emacs/EmacsGC;II)V"); | ||
| 961 | FIND_METHOD (copy_area, "copyArea", | ||
| 962 | "(Lorg/gnu/emacs/EmacsDrawable;" | ||
| 963 | "Lorg/gnu/emacs/EmacsDrawable;" | ||
| 964 | "Lorg/gnu/emacs/EmacsGC;IIIIII)V"); | ||
| 965 | FIND_METHOD (clear_window, "clearWindow", | ||
| 966 | "(Lorg/gnu/emacs/EmacsWindow;)V"); | ||
| 967 | FIND_METHOD (clear_area, "clearArea", | ||
| 968 | "(Lorg/gnu/emacs/EmacsWindow;IIII)V"); | ||
| 969 | |||
| 970 | #undef FIND_METHOD | ||
| 971 | } | ||
| 972 | |||
| 973 | static void | ||
| 974 | android_init_emacs_pixmap (void) | ||
| 975 | { | ||
| 976 | jclass old; | ||
| 977 | |||
| 978 | pixmap_class.class | ||
| 979 | = (*android_java_env)->FindClass (android_java_env, | ||
| 980 | "org/gnu/emacs/EmacsPixmap"); | ||
| 981 | eassert (pixmap_class.class); | ||
| 982 | |||
| 983 | old = pixmap_class.class; | ||
| 984 | pixmap_class.class | ||
| 985 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 986 | (jobject) old); | ||
| 987 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 988 | |||
| 989 | if (!pixmap_class.class) | ||
| 990 | emacs_abort (); | ||
| 991 | |||
| 992 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 993 | pixmap_class.c_name \ | ||
| 994 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 995 | pixmap_class.class, \ | ||
| 996 | name, signature); \ | ||
| 997 | assert (pixmap_class.c_name); | ||
| 998 | |||
| 999 | FIND_METHOD (constructor, "<init>", "(S[IIII)V"); | ||
| 1000 | |||
| 1001 | #undef FIND_METHOD | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | static void | ||
| 1005 | android_init_graphics_point (void) | ||
| 1006 | { | ||
| 1007 | jclass old; | ||
| 1008 | |||
| 1009 | point_class.class | ||
| 1010 | = (*android_java_env)->FindClass (android_java_env, | ||
| 1011 | "android/graphics/Point"); | ||
| 1012 | eassert (point_class.class); | ||
| 1013 | |||
| 1014 | old = point_class.class; | ||
| 1015 | point_class.class | ||
| 1016 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 1017 | (jobject) old); | ||
| 1018 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 1019 | |||
| 1020 | if (!point_class.class) | ||
| 1021 | emacs_abort (); | ||
| 1022 | |||
| 1023 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 1024 | point_class.c_name \ | ||
| 1025 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 1026 | point_class.class, \ | ||
| 1027 | name, signature); \ | ||
| 1028 | assert (point_class.c_name); | ||
| 1029 | |||
| 1030 | FIND_METHOD (constructor, "<init>", "(II)V"); | ||
| 1031 | #undef FIND_METHOD | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | extern JNIEXPORT void JNICALL | ||
| 1035 | NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv) | ||
| 1036 | { | ||
| 1037 | char **c_argv; | ||
| 1038 | jsize nelements, i; | ||
| 1039 | jobject argument; | ||
| 1040 | const char *c_argument; | ||
| 1041 | |||
| 1042 | android_java_env = env; | ||
| 1043 | |||
| 1044 | nelements = (*env)->GetArrayLength (env, argv); | ||
| 1045 | c_argv = alloca (sizeof *c_argv * nelements); | ||
| 1046 | |||
| 1047 | for (i = 0; i < nelements; ++i) | ||
| 1048 | { | ||
| 1049 | argument = (*env)->GetObjectArrayElement (env, argv, i); | ||
| 1050 | c_argument = (*env)->GetStringUTFChars (env, (jstring) argument, | ||
| 1051 | NULL); | ||
| 1052 | |||
| 1053 | if (!c_argument) | ||
| 1054 | emacs_abort (); | ||
| 1055 | |||
| 1056 | /* Note that c_argument is in ``modified UTF-8 encoding'', but | ||
| 1057 | we don't care as NUL bytes are not being specified inside. */ | ||
| 1058 | c_argv[i] = alloca (strlen (c_argument) + 1); | ||
| 1059 | strcpy (c_argv[i], c_argument); | ||
| 1060 | (*env)->ReleaseStringUTFChars (env, (jstring) argument, c_argument); | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | android_init_emacs_service (); | ||
| 1064 | android_init_emacs_pixmap (); | ||
| 1065 | android_init_graphics_point (); | ||
| 1066 | |||
| 1067 | /* Initialize the Android GUI. */ | ||
| 1068 | android_init_gui = true; | ||
| 1069 | android_emacs_init (nelements, c_argv); | ||
| 1070 | /* android_emacs_init should never return. */ | ||
| 1071 | emacs_abort (); | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | extern JNIEXPORT void JNICALL | ||
| 1075 | NATIVE_NAME (emacsAbort) (JNIEnv *env, jobject object) | ||
| 1076 | { | ||
| 1077 | emacs_abort (); | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | extern JNIEXPORT void JNICALL | ||
| 1081 | NATIVE_NAME (sendConfigureNotify) (JNIEnv *env, jobject object, | ||
| 1082 | jshort window, jlong time, | ||
| 1083 | jint x, jint y, jint width, | ||
| 1084 | jint height) | ||
| 1085 | { | ||
| 1086 | union android_event event; | ||
| 1087 | |||
| 1088 | event.xconfigure.type = ANDROID_CONFIGURE_NOTIFY; | ||
| 1089 | event.xconfigure.window = window; | ||
| 1090 | event.xconfigure.time = time; | ||
| 1091 | event.xconfigure.x = x; | ||
| 1092 | event.xconfigure.y = y; | ||
| 1093 | event.xconfigure.width = width; | ||
| 1094 | event.xconfigure.height = height; | ||
| 1095 | |||
| 1096 | android_write_event (&event); | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | extern JNIEXPORT void JNICALL | ||
| 1100 | NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object, | ||
| 1101 | jshort window, jlong time, | ||
| 1102 | jint state, jint keycode) | ||
| 1103 | { | ||
| 1104 | union android_event event; | ||
| 1105 | |||
| 1106 | event.xkey.type = ANDROID_KEY_PRESS; | ||
| 1107 | event.xkey.window = window; | ||
| 1108 | event.xkey.time = time; | ||
| 1109 | event.xkey.state = state; | ||
| 1110 | event.xkey.keycode = keycode; | ||
| 1111 | |||
| 1112 | android_write_event (&event); | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | extern JNIEXPORT void JNICALL | ||
| 1116 | NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object, | ||
| 1117 | jshort window, jlong time, | ||
| 1118 | jint state, jint keycode) | ||
| 1119 | { | ||
| 1120 | union android_event event; | ||
| 1121 | |||
| 1122 | event.xkey.type = ANDROID_KEY_RELEASE; | ||
| 1123 | event.xkey.window = window; | ||
| 1124 | event.xkey.time = time; | ||
| 1125 | event.xkey.state = state; | ||
| 1126 | event.xkey.keycode = keycode; | ||
| 1127 | |||
| 1128 | android_write_event (&event); | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | #pragma clang diagnostic pop | ||
| 1132 | |||
| 1133 | |||
| 1134 | |||
| 1135 | /* Java functions called by C. | ||
| 1136 | |||
| 1137 | Because all C code runs in the native function initEmacs, ALL LOCAL | ||
| 1138 | REFERENCES WILL PERSIST! | ||
| 1139 | |||
| 1140 | This means that every local reference must be explicitly destroyed | ||
| 1141 | with DeleteLocalRef. A helper macro is provided to do this. */ | ||
| 1142 | |||
| 1143 | #define MAX_HANDLE 65535 | ||
| 1144 | |||
| 1145 | enum android_handle_type | ||
| 1146 | { | ||
| 1147 | ANDROID_HANDLE_WINDOW, | ||
| 1148 | ANDROID_HANDLE_GCONTEXT, | ||
| 1149 | ANDROID_HANDLE_PIXMAP, | ||
| 1150 | }; | ||
| 1151 | |||
| 1152 | struct android_handle_entry | ||
| 1153 | { | ||
| 1154 | /* The type. */ | ||
| 1155 | enum android_handle_type type; | ||
| 1156 | |||
| 1157 | /* The handle. */ | ||
| 1158 | jobject handle; | ||
| 1159 | }; | ||
| 1160 | |||
| 1161 | /* Table of handles MAX_HANDLE long. */ | ||
| 1162 | struct android_handle_entry android_handles[USHRT_MAX]; | ||
| 1163 | |||
| 1164 | /* The largest handle ID currently known, but subject to | ||
| 1165 | wraparound. */ | ||
| 1166 | static android_handle max_handle; | ||
| 1167 | |||
| 1168 | /* Allocate a new, unused, handle identifier. If Emacs is out of | ||
| 1169 | identifiers, return 0. */ | ||
| 1170 | |||
| 1171 | static android_handle | ||
| 1172 | android_alloc_id (void) | ||
| 1173 | { | ||
| 1174 | android_handle handle; | ||
| 1175 | |||
| 1176 | /* 0 is never a valid handle ID. */ | ||
| 1177 | if (!max_handle) | ||
| 1178 | max_handle++; | ||
| 1179 | |||
| 1180 | if (android_handles[max_handle].handle) | ||
| 1181 | { | ||
| 1182 | handle = max_handle + 1; | ||
| 1183 | |||
| 1184 | while (max_handle < handle) | ||
| 1185 | { | ||
| 1186 | ++max_handle; | ||
| 1187 | |||
| 1188 | if (!max_handle) | ||
| 1189 | ++max_handle; | ||
| 1190 | |||
| 1191 | if (!android_handles[max_handle].handle) | ||
| 1192 | return 0; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | return 0; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | return max_handle++; | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | /* Destroy the specified handle and mark it as free on the Java side | ||
| 1202 | as well. */ | ||
| 1203 | |||
| 1204 | static void | ||
| 1205 | android_destroy_handle (android_handle handle) | ||
| 1206 | { | ||
| 1207 | static jclass old, class; | ||
| 1208 | static jmethodID method; | ||
| 1209 | |||
| 1210 | if (!android_handles[handle].handle) | ||
| 1211 | { | ||
| 1212 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1213 | "Trying to destroy free handle!"); | ||
| 1214 | emacs_abort (); | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | if (!class) | ||
| 1218 | { | ||
| 1219 | class | ||
| 1220 | = (*android_java_env)->FindClass (android_java_env, | ||
| 1221 | "org/gnu/emacs/EmacsHandleObject"); | ||
| 1222 | assert (class != NULL); | ||
| 1223 | |||
| 1224 | method | ||
| 1225 | = (*android_java_env)->GetMethodID (android_java_env, class, | ||
| 1226 | "destroyHandle", "()V"); | ||
| 1227 | assert (method != NULL); | ||
| 1228 | |||
| 1229 | old = class; | ||
| 1230 | class | ||
| 1231 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 1232 | (jobject) class); | ||
| 1233 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1234 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 1235 | |||
| 1236 | if (!class) | ||
| 1237 | memory_full (0); | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1241 | android_handles[handle].handle, | ||
| 1242 | method); | ||
| 1243 | (*android_java_env)->DeleteGlobalRef (android_java_env, | ||
| 1244 | android_handles[handle].handle); | ||
| 1245 | android_handles[handle].handle = NULL; | ||
| 1246 | } | ||
| 1247 | |||
| 1248 | static jobject | ||
| 1249 | android_resolve_handle (android_handle handle, | ||
| 1250 | enum android_handle_type type) | ||
| 1251 | { | ||
| 1252 | if (!handle) | ||
| 1253 | /* ANDROID_NONE. */ | ||
| 1254 | return NULL; | ||
| 1255 | |||
| 1256 | if (!android_handles[handle].handle) | ||
| 1257 | { | ||
| 1258 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1259 | "Trying to resolve free handle!"); | ||
| 1260 | emacs_abort (); | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | if (android_handles[handle].type != type) | ||
| 1264 | { | ||
| 1265 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1266 | "Handle has wrong type!"); | ||
| 1267 | emacs_abort (); | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | return android_handles[handle].handle; | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | static jobject | ||
| 1274 | android_resolve_handle2 (android_handle handle, | ||
| 1275 | enum android_handle_type type, | ||
| 1276 | enum android_handle_type type2) | ||
| 1277 | { | ||
| 1278 | if (!handle) | ||
| 1279 | return NULL; | ||
| 1280 | |||
| 1281 | if (!android_handles[handle].handle) | ||
| 1282 | { | ||
| 1283 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1284 | "Trying to resolve free handle!"); | ||
| 1285 | emacs_abort (); | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | if (android_handles[handle].type != type | ||
| 1289 | && android_handles[handle].type != type2) | ||
| 1290 | { | ||
| 1291 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1292 | "Handle has wrong type!"); | ||
| 1293 | emacs_abort (); | ||
| 1294 | } | ||
| 1295 | |||
| 1296 | return android_handles[handle].handle; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | static jmethodID android_lookup_method (const char *, const char *, | ||
| 1300 | const char *); | ||
| 1301 | |||
| 1302 | void | ||
| 1303 | android_change_window_attributes (android_window handle, | ||
| 1304 | enum android_window_value_mask value_mask, | ||
| 1305 | struct android_set_window_attributes *attrs) | ||
| 1306 | { | ||
| 1307 | jmethodID method; | ||
| 1308 | jobject window; | ||
| 1309 | |||
| 1310 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1311 | |||
| 1312 | if (value_mask & ANDROID_CW_BACK_PIXEL) | ||
| 1313 | { | ||
| 1314 | method = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1315 | "changeWindowBackground", "(I)V"); | ||
| 1316 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1317 | window, method, | ||
| 1318 | (jint) attrs->background_pixel); | ||
| 1319 | } | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | /* Create a new window with the given width, height and | ||
| 1323 | attributes. */ | ||
| 1324 | |||
| 1325 | android_window | ||
| 1326 | android_create_window (android_window parent, int x, int y, | ||
| 1327 | int width, int height, | ||
| 1328 | enum android_window_value_mask value_mask, | ||
| 1329 | struct android_set_window_attributes *attrs) | ||
| 1330 | { | ||
| 1331 | static jclass class; | ||
| 1332 | static jmethodID constructor; | ||
| 1333 | jobject object, parent_object, old; | ||
| 1334 | android_window window; | ||
| 1335 | android_handle prev_max_handle; | ||
| 1336 | |||
| 1337 | parent_object = android_resolve_handle (parent, ANDROID_HANDLE_WINDOW); | ||
| 1338 | |||
| 1339 | prev_max_handle = max_handle; | ||
| 1340 | window = android_alloc_id (); | ||
| 1341 | |||
| 1342 | if (!window) | ||
| 1343 | error ("Out of window handles!"); | ||
| 1344 | |||
| 1345 | if (!class) | ||
| 1346 | { | ||
| 1347 | class = (*android_java_env)->FindClass (android_java_env, | ||
| 1348 | "org/gnu/emacs/EmacsWindow"); | ||
| 1349 | assert (class != NULL); | ||
| 1350 | |||
| 1351 | constructor | ||
| 1352 | = (*android_java_env)->GetMethodID (android_java_env, class, "<init>", | ||
| 1353 | "(SLorg/gnu/emacs/EmacsWindow;IIII)V"); | ||
| 1354 | assert (constructor != NULL); | ||
| 1355 | |||
| 1356 | old = class; | ||
| 1357 | class = (*android_java_env)->NewGlobalRef (android_java_env, class); | ||
| 1358 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1359 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 1360 | |||
| 1361 | if (!class) | ||
| 1362 | memory_full (0); | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | object = (*android_java_env)->NewObject (android_java_env, class, | ||
| 1366 | constructor, (jshort) window, | ||
| 1367 | parent_object, (jint) x, (jint) y, | ||
| 1368 | (jint) width, (jint) height); | ||
| 1369 | if (!object) | ||
| 1370 | { | ||
| 1371 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1372 | |||
| 1373 | max_handle = prev_max_handle; | ||
| 1374 | memory_full (0); | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | android_handles[window].type = ANDROID_HANDLE_WINDOW; | ||
| 1378 | android_handles[window].handle | ||
| 1379 | = (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 1380 | object); | ||
| 1381 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1382 | ANDROID_DELETE_LOCAL_REF (object); | ||
| 1383 | |||
| 1384 | if (!android_handles[window].handle) | ||
| 1385 | memory_full (0); | ||
| 1386 | |||
| 1387 | android_change_window_attributes (window, value_mask, attrs); | ||
| 1388 | return window; | ||
| 1389 | } | ||
| 1390 | |||
| 1391 | void | ||
| 1392 | android_set_window_background (android_window window, unsigned long pixel) | ||
| 1393 | { | ||
| 1394 | struct android_set_window_attributes attrs; | ||
| 1395 | |||
| 1396 | attrs.background_pixel = pixel; | ||
| 1397 | android_change_window_attributes (window, ANDROID_CW_BACK_PIXEL, | ||
| 1398 | &attrs); | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | void | ||
| 1402 | android_destroy_window (android_window window) | ||
| 1403 | { | ||
| 1404 | if (android_handles[window].type != ANDROID_HANDLE_WINDOW) | ||
| 1405 | { | ||
| 1406 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1407 | "Trying to destroy something not a window!"); | ||
| 1408 | emacs_abort (); | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | android_destroy_handle (window); | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | static void | ||
| 1415 | android_init_android_rect_class (void) | ||
| 1416 | { | ||
| 1417 | jclass old; | ||
| 1418 | |||
| 1419 | if (android_rect_class) | ||
| 1420 | /* Already initialized. */ | ||
| 1421 | return; | ||
| 1422 | |||
| 1423 | android_rect_class | ||
| 1424 | = (*android_java_env)->FindClass (android_java_env, | ||
| 1425 | "android/graphics/Rect"); | ||
| 1426 | assert (android_rect_class); | ||
| 1427 | |||
| 1428 | android_rect_constructor | ||
| 1429 | = (*android_java_env)->GetMethodID (android_java_env, android_rect_class, | ||
| 1430 | "<init>", "(IIII)V"); | ||
| 1431 | assert (emacs_gc_constructor); | ||
| 1432 | |||
| 1433 | old = android_rect_class; | ||
| 1434 | android_rect_class | ||
| 1435 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 1436 | (jobject) android_rect_class); | ||
| 1437 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1438 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 1439 | |||
| 1440 | if (!android_rect_class) | ||
| 1441 | memory_full (0); | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | static void | ||
| 1445 | android_init_emacs_gc_class (void) | ||
| 1446 | { | ||
| 1447 | jclass old; | ||
| 1448 | |||
| 1449 | if (emacs_gc_class) | ||
| 1450 | /* Already initialized. */ | ||
| 1451 | return; | ||
| 1452 | |||
| 1453 | emacs_gc_class | ||
| 1454 | = (*android_java_env)->FindClass (android_java_env, | ||
| 1455 | "org/gnu/emacs/EmacsGC"); | ||
| 1456 | assert (emacs_gc_class); | ||
| 1457 | |||
| 1458 | emacs_gc_constructor | ||
| 1459 | = (*android_java_env)->GetMethodID (android_java_env, | ||
| 1460 | emacs_gc_class, | ||
| 1461 | "<init>", "(S)V"); | ||
| 1462 | assert (emacs_gc_constructor); | ||
| 1463 | |||
| 1464 | emacs_gc_mark_dirty | ||
| 1465 | = (*android_java_env)->GetMethodID (android_java_env, | ||
| 1466 | emacs_gc_class, | ||
| 1467 | "markDirty", "()V"); | ||
| 1468 | assert (emacs_gc_mark_dirty); | ||
| 1469 | |||
| 1470 | old = emacs_gc_class; | ||
| 1471 | emacs_gc_class | ||
| 1472 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 1473 | (jobject) emacs_gc_class); | ||
| 1474 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1475 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 1476 | if (!emacs_gc_class) | ||
| 1477 | memory_full (0); | ||
| 1478 | |||
| 1479 | emacs_gc_foreground | ||
| 1480 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1481 | emacs_gc_class, | ||
| 1482 | "foreground", "I"); | ||
| 1483 | emacs_gc_background | ||
| 1484 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1485 | emacs_gc_class, | ||
| 1486 | "background", "I"); | ||
| 1487 | emacs_gc_function | ||
| 1488 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1489 | emacs_gc_class, | ||
| 1490 | "function", "I"); | ||
| 1491 | emacs_gc_clip_rects | ||
| 1492 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1493 | emacs_gc_class, | ||
| 1494 | "clip_rects", | ||
| 1495 | "[Landroid/graphics/Rect;"); | ||
| 1496 | emacs_gc_clip_x_origin | ||
| 1497 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1498 | emacs_gc_class, | ||
| 1499 | "clip_x_origin", "I"); | ||
| 1500 | emacs_gc_clip_y_origin | ||
| 1501 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1502 | emacs_gc_class, | ||
| 1503 | "clip_y_origin", "I"); | ||
| 1504 | emacs_gc_stipple | ||
| 1505 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1506 | emacs_gc_class, | ||
| 1507 | "stipple", | ||
| 1508 | "Lorg/gnu/emacs/EmacsPixmap;"); | ||
| 1509 | emacs_gc_clip_mask | ||
| 1510 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1511 | emacs_gc_class, | ||
| 1512 | "clip_mask", | ||
| 1513 | "Lorg/gnu/emacs/EmacsPixmap;"); | ||
| 1514 | emacs_gc_fill_style | ||
| 1515 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1516 | emacs_gc_class, | ||
| 1517 | "fill_style", "I"); | ||
| 1518 | emacs_gc_ts_origin_x | ||
| 1519 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1520 | emacs_gc_class, | ||
| 1521 | "ts_origin_x", "I"); | ||
| 1522 | emacs_gc_ts_origin_y | ||
| 1523 | = (*android_java_env)->GetFieldID (android_java_env, | ||
| 1524 | emacs_gc_class, | ||
| 1525 | "ts_origin_y", "I"); | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | struct android_gc * | ||
| 1529 | android_create_gc (enum android_gc_value_mask mask, | ||
| 1530 | struct android_gc_values *values) | ||
| 1531 | { | ||
| 1532 | struct android_gc *gc; | ||
| 1533 | android_handle prev_max_handle; | ||
| 1534 | jobject object; | ||
| 1535 | |||
| 1536 | android_init_emacs_gc_class (); | ||
| 1537 | |||
| 1538 | gc = xmalloc (sizeof *gc); | ||
| 1539 | prev_max_handle = max_handle; | ||
| 1540 | gc->gcontext = android_alloc_id (); | ||
| 1541 | |||
| 1542 | if (!gc->gcontext) | ||
| 1543 | { | ||
| 1544 | xfree (gc); | ||
| 1545 | error ("Out of GContext handles!"); | ||
| 1546 | } | ||
| 1547 | |||
| 1548 | object = (*android_java_env)->NewObject (android_java_env, | ||
| 1549 | emacs_gc_class, | ||
| 1550 | emacs_gc_constructor, | ||
| 1551 | (jshort) gc->gcontext); | ||
| 1552 | |||
| 1553 | if (!object) | ||
| 1554 | { | ||
| 1555 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1556 | |||
| 1557 | max_handle = prev_max_handle; | ||
| 1558 | memory_full (0); | ||
| 1559 | } | ||
| 1560 | |||
| 1561 | android_handles[gc->gcontext].type = ANDROID_HANDLE_GCONTEXT; | ||
| 1562 | android_handles[gc->gcontext].handle | ||
| 1563 | = (*android_java_env)->NewGlobalRef (android_java_env, object); | ||
| 1564 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1565 | ANDROID_DELETE_LOCAL_REF (object); | ||
| 1566 | |||
| 1567 | if (!android_handles[gc->gcontext].handle) | ||
| 1568 | memory_full (0); | ||
| 1569 | |||
| 1570 | android_change_gc (gc, mask, values); | ||
| 1571 | return gc; | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | void | ||
| 1575 | android_free_gc (struct android_gc *gc) | ||
| 1576 | { | ||
| 1577 | android_destroy_handle (gc->gcontext); | ||
| 1578 | xfree (gc); | ||
| 1579 | } | ||
| 1580 | |||
| 1581 | void | ||
| 1582 | android_change_gc (struct android_gc *gc, | ||
| 1583 | enum android_gc_value_mask mask, | ||
| 1584 | struct android_gc_values *values) | ||
| 1585 | { | ||
| 1586 | jobject what, gcontext; | ||
| 1587 | |||
| 1588 | android_init_emacs_gc_class (); | ||
| 1589 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 1590 | ANDROID_HANDLE_GCONTEXT); | ||
| 1591 | |||
| 1592 | if (mask & ANDROID_GC_FOREGROUND) | ||
| 1593 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1594 | gcontext, | ||
| 1595 | emacs_gc_foreground, | ||
| 1596 | values->foreground); | ||
| 1597 | |||
| 1598 | if (mask & ANDROID_GC_BACKGROUND) | ||
| 1599 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1600 | gcontext, | ||
| 1601 | emacs_gc_background, | ||
| 1602 | values->background); | ||
| 1603 | |||
| 1604 | if (mask & ANDROID_GC_FUNCTION) | ||
| 1605 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1606 | gcontext, | ||
| 1607 | emacs_gc_function, | ||
| 1608 | values->function); | ||
| 1609 | |||
| 1610 | if (mask & ANDROID_GC_CLIP_X_ORIGIN) | ||
| 1611 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1612 | gcontext, | ||
| 1613 | emacs_gc_clip_x_origin, | ||
| 1614 | values->clip_x_origin); | ||
| 1615 | |||
| 1616 | if (mask & ANDROID_GC_CLIP_Y_ORIGIN) | ||
| 1617 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1618 | gcontext, | ||
| 1619 | emacs_gc_clip_y_origin, | ||
| 1620 | values->clip_y_origin); | ||
| 1621 | |||
| 1622 | if (mask & ANDROID_GC_CLIP_MASK) | ||
| 1623 | { | ||
| 1624 | what = android_resolve_handle (values->clip_mask, | ||
| 1625 | ANDROID_HANDLE_PIXMAP); | ||
| 1626 | (*android_java_env)->SetObjectField (android_java_env, | ||
| 1627 | gcontext, | ||
| 1628 | emacs_gc_stipple, | ||
| 1629 | what); | ||
| 1630 | |||
| 1631 | /* Clearing GCClipMask also clears the clip rectangles. */ | ||
| 1632 | (*android_java_env)->SetObjectField (android_java_env, | ||
| 1633 | gcontext, | ||
| 1634 | emacs_gc_clip_rects, | ||
| 1635 | NULL); | ||
| 1636 | } | ||
| 1637 | |||
| 1638 | if (mask & ANDROID_GC_STIPPLE) | ||
| 1639 | { | ||
| 1640 | what = android_resolve_handle (values->stipple, | ||
| 1641 | ANDROID_HANDLE_PIXMAP); | ||
| 1642 | (*android_java_env)->SetObjectField (android_java_env, | ||
| 1643 | gcontext, | ||
| 1644 | emacs_gc_stipple, | ||
| 1645 | what); | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | if (mask & ANDROID_GC_FILL_STYLE) | ||
| 1649 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1650 | gcontext, | ||
| 1651 | emacs_gc_fill_style, | ||
| 1652 | values->fill_style); | ||
| 1653 | |||
| 1654 | if (mask & ANDROID_GC_TILE_STIP_X_ORIGIN) | ||
| 1655 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1656 | gcontext, | ||
| 1657 | emacs_gc_ts_origin_x, | ||
| 1658 | values->ts_x_origin); | ||
| 1659 | |||
| 1660 | if (mask & ANDROID_GC_TILE_STIP_Y_ORIGIN) | ||
| 1661 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1662 | gcontext, | ||
| 1663 | emacs_gc_ts_origin_y, | ||
| 1664 | values->ts_y_origin); | ||
| 1665 | |||
| 1666 | if (mask) | ||
| 1667 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1668 | gcontext, | ||
| 1669 | emacs_gc_mark_dirty); | ||
| 1670 | } | ||
| 1671 | |||
| 1672 | void | ||
| 1673 | android_set_clip_rectangles (struct android_gc *gc, int clip_x_origin, | ||
| 1674 | int clip_y_origin, | ||
| 1675 | struct android_rectangle *clip_rects, | ||
| 1676 | int n_clip_rects) | ||
| 1677 | { | ||
| 1678 | jobjectArray array; | ||
| 1679 | jobject rect, gcontext; | ||
| 1680 | int i; | ||
| 1681 | |||
| 1682 | android_init_android_rect_class (); | ||
| 1683 | android_init_emacs_gc_class (); | ||
| 1684 | |||
| 1685 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 1686 | ANDROID_HANDLE_GCONTEXT); | ||
| 1687 | |||
| 1688 | array = (*android_java_env)->NewObjectArray (android_java_env, | ||
| 1689 | n_clip_rects, | ||
| 1690 | android_rect_class, | ||
| 1691 | NULL); | ||
| 1692 | |||
| 1693 | if (!array) | ||
| 1694 | { | ||
| 1695 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1696 | memory_full (0); | ||
| 1697 | } | ||
| 1698 | |||
| 1699 | for (i = 0; i < n_clip_rects; ++i) | ||
| 1700 | { | ||
| 1701 | rect = (*android_java_env)->NewObject (android_java_env, | ||
| 1702 | android_rect_class, | ||
| 1703 | android_rect_constructor, | ||
| 1704 | (jint) clip_rects[i].x, | ||
| 1705 | (jint) clip_rects[i].y, | ||
| 1706 | (jint) (clip_rects[i].x | ||
| 1707 | + clip_rects[i].width), | ||
| 1708 | (jint) (clip_rects[i].y | ||
| 1709 | + clip_rects[i].height)); | ||
| 1710 | |||
| 1711 | if (!rect) | ||
| 1712 | { | ||
| 1713 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 1714 | ANDROID_DELETE_LOCAL_REF (array); | ||
| 1715 | memory_full (0); | ||
| 1716 | } | ||
| 1717 | |||
| 1718 | (*android_java_env)->SetObjectArrayElement (android_java_env, | ||
| 1719 | array, i, rect); | ||
| 1720 | ANDROID_DELETE_LOCAL_REF (rect); | ||
| 1721 | } | ||
| 1722 | |||
| 1723 | (*android_java_env)->SetObjectField (android_java_env, | ||
| 1724 | gcontext, | ||
| 1725 | emacs_gc_clip_rects, | ||
| 1726 | (jobject) array); | ||
| 1727 | ANDROID_DELETE_LOCAL_REF (array); | ||
| 1728 | |||
| 1729 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1730 | gcontext, | ||
| 1731 | emacs_gc_clip_x_origin, | ||
| 1732 | clip_x_origin); | ||
| 1733 | (*android_java_env)->SetIntField (android_java_env, | ||
| 1734 | gcontext, | ||
| 1735 | emacs_gc_clip_y_origin, | ||
| 1736 | clip_y_origin); | ||
| 1737 | |||
| 1738 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1739 | gcontext, | ||
| 1740 | emacs_gc_mark_dirty); | ||
| 1741 | } | ||
| 1742 | |||
| 1743 | void | ||
| 1744 | android_reparent_window (android_window w, android_window parent, | ||
| 1745 | int x, int y) | ||
| 1746 | { | ||
| 1747 | /* TODO */ | ||
| 1748 | } | ||
| 1749 | |||
| 1750 | /* Look up the method with SIGNATURE by NAME in CLASS. Abort if it | ||
| 1751 | could not be found. This should be used for functions which are | ||
| 1752 | not called very often. | ||
| 1753 | |||
| 1754 | CLASS must never be unloaded, or the behavior is undefined. */ | ||
| 1755 | |||
| 1756 | static jmethodID | ||
| 1757 | android_lookup_method (const char *class, const char *name, | ||
| 1758 | const char *signature) | ||
| 1759 | { | ||
| 1760 | jclass java_class; | ||
| 1761 | jmethodID method; | ||
| 1762 | |||
| 1763 | java_class | ||
| 1764 | = (*android_java_env)->FindClass (android_java_env, class); | ||
| 1765 | |||
| 1766 | if (!java_class) | ||
| 1767 | { | ||
| 1768 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1769 | "Failed to find class %s", class); | ||
| 1770 | emacs_abort (); | ||
| 1771 | } | ||
| 1772 | |||
| 1773 | method | ||
| 1774 | = (*android_java_env)->GetMethodID (android_java_env, | ||
| 1775 | java_class, name, | ||
| 1776 | signature); | ||
| 1777 | |||
| 1778 | if (!method) | ||
| 1779 | { | ||
| 1780 | __android_log_print (ANDROID_LOG_ERROR, __func__, | ||
| 1781 | "Failed to find method %s in class %s" | ||
| 1782 | " with signature %s", | ||
| 1783 | name, class, signature); | ||
| 1784 | emacs_abort (); | ||
| 1785 | } | ||
| 1786 | |||
| 1787 | ANDROID_DELETE_LOCAL_REF (java_class); | ||
| 1788 | return method; | ||
| 1789 | } | ||
| 1790 | |||
| 1791 | void | ||
| 1792 | android_clear_window (android_window handle) | ||
| 1793 | { | ||
| 1794 | jobject window; | ||
| 1795 | |||
| 1796 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1797 | |||
| 1798 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1799 | emacs_service, | ||
| 1800 | service_class.clear_window, | ||
| 1801 | window); | ||
| 1802 | } | ||
| 1803 | |||
| 1804 | void | ||
| 1805 | android_map_window (android_window handle) | ||
| 1806 | { | ||
| 1807 | jobject window; | ||
| 1808 | jmethodID map_window; | ||
| 1809 | |||
| 1810 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1811 | map_window = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1812 | "mapWindow", "()V"); | ||
| 1813 | |||
| 1814 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1815 | window, map_window); | ||
| 1816 | } | ||
| 1817 | |||
| 1818 | void | ||
| 1819 | android_unmap_window (android_window handle) | ||
| 1820 | { | ||
| 1821 | jobject window; | ||
| 1822 | jmethodID unmap_window; | ||
| 1823 | |||
| 1824 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1825 | unmap_window = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1826 | "unmapWindow", "()V"); | ||
| 1827 | |||
| 1828 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1829 | window, unmap_window); | ||
| 1830 | } | ||
| 1831 | |||
| 1832 | void | ||
| 1833 | android_resize_window (android_window handle, unsigned int width, | ||
| 1834 | unsigned int height) | ||
| 1835 | { | ||
| 1836 | jobject window; | ||
| 1837 | jmethodID resize_window; | ||
| 1838 | |||
| 1839 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1840 | resize_window = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1841 | "resizeWindow", "(II)V"); | ||
| 1842 | |||
| 1843 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1844 | window, resize_window, | ||
| 1845 | (jint) width, (jint) height); | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | void | ||
| 1849 | android_move_window (android_window handle, int x, int y) | ||
| 1850 | { | ||
| 1851 | jobject window; | ||
| 1852 | jmethodID move_window; | ||
| 1853 | |||
| 1854 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 1855 | move_window = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1856 | "moveWindow", "(II)V"); | ||
| 1857 | |||
| 1858 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1859 | window, move_window, | ||
| 1860 | (jint) x, (jint) y); | ||
| 1861 | } | ||
| 1862 | |||
| 1863 | void | ||
| 1864 | android_swap_buffers (struct android_swap_info *swap_info, | ||
| 1865 | int num_windows) | ||
| 1866 | { | ||
| 1867 | jobject window; | ||
| 1868 | jmethodID swap_buffers; | ||
| 1869 | int i; | ||
| 1870 | |||
| 1871 | swap_buffers = android_lookup_method ("org/gnu/emacs/EmacsWindow", | ||
| 1872 | "swapBuffers", "()V"); | ||
| 1873 | |||
| 1874 | for (i = 0; i < num_windows; ++i) | ||
| 1875 | { | ||
| 1876 | window = android_resolve_handle (swap_info[i].swap_window, | ||
| 1877 | ANDROID_HANDLE_WINDOW); | ||
| 1878 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1879 | window, swap_buffers); | ||
| 1880 | } | ||
| 1881 | } | ||
| 1882 | |||
| 1883 | void | ||
| 1884 | android_get_gc_values (struct android_gc *gc, | ||
| 1885 | enum android_gc_value_mask mask, | ||
| 1886 | struct android_gc_values *values) | ||
| 1887 | { | ||
| 1888 | jobject gcontext; | ||
| 1889 | |||
| 1890 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 1891 | ANDROID_HANDLE_GCONTEXT); | ||
| 1892 | |||
| 1893 | if (mask & ANDROID_GC_FOREGROUND) | ||
| 1894 | /* GCs never have 32 bit colors, so we don't have to worry about | ||
| 1895 | sign extension here. */ | ||
| 1896 | values->foreground | ||
| 1897 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1898 | gcontext, | ||
| 1899 | emacs_gc_foreground); | ||
| 1900 | |||
| 1901 | if (mask & ANDROID_GC_BACKGROUND) | ||
| 1902 | values->background | ||
| 1903 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1904 | gcontext, | ||
| 1905 | emacs_gc_background); | ||
| 1906 | |||
| 1907 | if (mask & ANDROID_GC_FUNCTION) | ||
| 1908 | values->function | ||
| 1909 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1910 | gcontext, | ||
| 1911 | emacs_gc_function); | ||
| 1912 | |||
| 1913 | if (mask & ANDROID_GC_CLIP_X_ORIGIN) | ||
| 1914 | values->clip_x_origin | ||
| 1915 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1916 | gcontext, | ||
| 1917 | emacs_gc_clip_x_origin); | ||
| 1918 | |||
| 1919 | if (mask & ANDROID_GC_CLIP_Y_ORIGIN) | ||
| 1920 | values->clip_y_origin | ||
| 1921 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1922 | gcontext, | ||
| 1923 | emacs_gc_clip_y_origin); | ||
| 1924 | |||
| 1925 | if (mask & ANDROID_GC_FILL_STYLE) | ||
| 1926 | values->fill_style | ||
| 1927 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1928 | gcontext, | ||
| 1929 | emacs_gc_fill_style); | ||
| 1930 | |||
| 1931 | if (mask & ANDROID_GC_TILE_STIP_X_ORIGIN) | ||
| 1932 | values->ts_x_origin | ||
| 1933 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1934 | gcontext, | ||
| 1935 | emacs_gc_ts_origin_x); | ||
| 1936 | |||
| 1937 | if (mask & ANDROID_GC_TILE_STIP_Y_ORIGIN) | ||
| 1938 | values->ts_y_origin | ||
| 1939 | = (*android_java_env)->GetIntField (android_java_env, | ||
| 1940 | gcontext, | ||
| 1941 | emacs_gc_ts_origin_y); | ||
| 1942 | |||
| 1943 | /* Fields involving handles are not used by Emacs, and thus not | ||
| 1944 | implemented */ | ||
| 1945 | } | ||
| 1946 | |||
| 1947 | void | ||
| 1948 | android_set_foreground (struct android_gc *gc, unsigned long foreground) | ||
| 1949 | { | ||
| 1950 | struct android_gc_values gcv; | ||
| 1951 | |||
| 1952 | gcv.foreground = foreground; | ||
| 1953 | android_change_gc (gc, ANDROID_GC_FOREGROUND, &gcv); | ||
| 1954 | } | ||
| 1955 | |||
| 1956 | void | ||
| 1957 | android_fill_rectangle (android_drawable handle, struct android_gc *gc, | ||
| 1958 | int x, int y, unsigned int width, | ||
| 1959 | unsigned int height) | ||
| 1960 | { | ||
| 1961 | jobject drawable, gcontext; | ||
| 1962 | |||
| 1963 | drawable = android_resolve_handle2 (handle, | ||
| 1964 | ANDROID_HANDLE_WINDOW, | ||
| 1965 | ANDROID_HANDLE_PIXMAP); | ||
| 1966 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 1967 | ANDROID_HANDLE_GCONTEXT); | ||
| 1968 | |||
| 1969 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 1970 | emacs_service, | ||
| 1971 | service_class.fill_rectangle, | ||
| 1972 | drawable, | ||
| 1973 | gcontext, | ||
| 1974 | (jint) x, (jint) y, | ||
| 1975 | (jint) width, | ||
| 1976 | (jint) height); | ||
| 1977 | } | ||
| 1978 | |||
| 1979 | android_pixmap | ||
| 1980 | android_create_pixmap_from_bitmap_data (char *data, unsigned int width, | ||
| 1981 | unsigned int height, | ||
| 1982 | unsigned long foreground, | ||
| 1983 | unsigned long background, | ||
| 1984 | unsigned int depth) | ||
| 1985 | { | ||
| 1986 | android_handle prev_max_handle; | ||
| 1987 | jobject object; | ||
| 1988 | jintArray colors; | ||
| 1989 | android_pixmap pixmap; | ||
| 1990 | unsigned int x, y; | ||
| 1991 | jint *region; | ||
| 1992 | |||
| 1993 | USE_SAFE_ALLOCA; | ||
| 1994 | |||
| 1995 | /* Create the color array holding the data. */ | ||
| 1996 | colors = (*android_java_env)->NewIntArray (android_java_env, | ||
| 1997 | width * height); | ||
| 1998 | |||
| 1999 | if (!colors) | ||
| 2000 | { | ||
| 2001 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2002 | memory_full (0); | ||
| 2003 | } | ||
| 2004 | |||
| 2005 | SAFE_NALLOCA (region, sizeof *region, width); | ||
| 2006 | |||
| 2007 | for (y = 0; y < height; ++y) | ||
| 2008 | { | ||
| 2009 | for (x = 0; x < width; ++x) | ||
| 2010 | { | ||
| 2011 | if (data[y / 8] & (1 << (x % 8))) | ||
| 2012 | region[x] = foreground; | ||
| 2013 | else | ||
| 2014 | region[x] = background; | ||
| 2015 | } | ||
| 2016 | |||
| 2017 | (*android_java_env)->SetIntArrayRegion (android_java_env, | ||
| 2018 | colors, | ||
| 2019 | width * y, width, | ||
| 2020 | region); | ||
| 2021 | } | ||
| 2022 | |||
| 2023 | /* First, allocate the pixmap handle. */ | ||
| 2024 | prev_max_handle = max_handle; | ||
| 2025 | pixmap = android_alloc_id (); | ||
| 2026 | |||
| 2027 | if (!pixmap) | ||
| 2028 | { | ||
| 2029 | ANDROID_DELETE_LOCAL_REF ((jobject) colors); | ||
| 2030 | error ("Out of pixmap handles!"); | ||
| 2031 | } | ||
| 2032 | |||
| 2033 | object = (*android_java_env)->NewObject (android_java_env, | ||
| 2034 | pixmap_class.class, | ||
| 2035 | pixmap_class.constructor, | ||
| 2036 | (jshort) pixmap, colors, | ||
| 2037 | (jint) width, (jint) height, | ||
| 2038 | (jint) depth); | ||
| 2039 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2040 | ANDROID_DELETE_LOCAL_REF ((jobject) colors); | ||
| 2041 | |||
| 2042 | if (!object) | ||
| 2043 | { | ||
| 2044 | max_handle = prev_max_handle; | ||
| 2045 | memory_full (0); | ||
| 2046 | } | ||
| 2047 | |||
| 2048 | android_handles[pixmap].type = ANDROID_HANDLE_PIXMAP; | ||
| 2049 | android_handles[pixmap].handle | ||
| 2050 | = (*android_java_env)->NewGlobalRef (android_java_env, object); | ||
| 2051 | ANDROID_DELETE_LOCAL_REF (object); | ||
| 2052 | |||
| 2053 | if (!android_handles[pixmap].handle) | ||
| 2054 | memory_full (0); | ||
| 2055 | |||
| 2056 | SAFE_FREE (); | ||
| 2057 | return pixmap; | ||
| 2058 | } | ||
| 2059 | |||
| 2060 | void | ||
| 2061 | android_set_clip_mask (struct android_gc *gc, android_pixmap pixmap) | ||
| 2062 | { | ||
| 2063 | struct android_gc_values gcv; | ||
| 2064 | |||
| 2065 | gcv.clip_mask = pixmap; | ||
| 2066 | android_change_gc (gc, ANDROID_GC_CLIP_MASK, &gcv); | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | void | ||
| 2070 | android_set_fill_style (struct android_gc *gc, | ||
| 2071 | enum android_fill_style fill_style) | ||
| 2072 | { | ||
| 2073 | struct android_gc_values gcv; | ||
| 2074 | |||
| 2075 | gcv.fill_style = fill_style; | ||
| 2076 | android_change_gc (gc, ANDROID_GC_FILL_STYLE, &gcv); | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | void | ||
| 2080 | android_copy_area (android_drawable src, android_drawable dest, | ||
| 2081 | struct android_gc *gc, int src_x, int src_y, | ||
| 2082 | unsigned int width, unsigned int height, | ||
| 2083 | int dest_x, int dest_y) | ||
| 2084 | { | ||
| 2085 | jobject src_object, dest_object, gcontext; | ||
| 2086 | |||
| 2087 | src_object = android_resolve_handle2 (src, ANDROID_HANDLE_WINDOW, | ||
| 2088 | ANDROID_HANDLE_PIXMAP); | ||
| 2089 | dest_object = android_resolve_handle2 (dest, ANDROID_HANDLE_WINDOW, | ||
| 2090 | ANDROID_HANDLE_PIXMAP); | ||
| 2091 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 2092 | ANDROID_HANDLE_GCONTEXT); | ||
| 2093 | |||
| 2094 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2095 | emacs_service, | ||
| 2096 | service_class.copy_area, | ||
| 2097 | src_object, | ||
| 2098 | dest_object, | ||
| 2099 | gcontext, | ||
| 2100 | (jint) src_x, (jint) src_y, | ||
| 2101 | (jint) width, (jint) height, | ||
| 2102 | (jint) dest_x, (jint) dest_y); | ||
| 2103 | } | ||
| 2104 | |||
| 2105 | void | ||
| 2106 | android_free_pixmap (android_pixmap pixmap) | ||
| 2107 | { | ||
| 2108 | android_destroy_handle (pixmap); | ||
| 2109 | } | ||
| 2110 | |||
| 2111 | void | ||
| 2112 | android_set_background (struct android_gc *gc, unsigned long background) | ||
| 2113 | { | ||
| 2114 | struct android_gc_values gcv; | ||
| 2115 | |||
| 2116 | gcv.background = background; | ||
| 2117 | android_change_gc (gc, ANDROID_GC_BACKGROUND, &gcv); | ||
| 2118 | } | ||
| 2119 | |||
| 2120 | void | ||
| 2121 | android_fill_polygon (android_drawable drawable, struct android_gc *gc, | ||
| 2122 | struct android_point *points, int npoints, | ||
| 2123 | enum android_shape shape, enum android_coord_mode mode) | ||
| 2124 | { | ||
| 2125 | jobjectArray array; | ||
| 2126 | jobject point, drawable_object, gcontext; | ||
| 2127 | int i; | ||
| 2128 | |||
| 2129 | drawable_object = android_resolve_handle2 (drawable, | ||
| 2130 | ANDROID_HANDLE_WINDOW, | ||
| 2131 | ANDROID_HANDLE_PIXMAP); | ||
| 2132 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 2133 | ANDROID_HANDLE_GCONTEXT); | ||
| 2134 | |||
| 2135 | array = (*android_java_env)->NewObjectArray (android_java_env, | ||
| 2136 | npoints, | ||
| 2137 | point_class.class, | ||
| 2138 | NULL); | ||
| 2139 | |||
| 2140 | if (!array) | ||
| 2141 | { | ||
| 2142 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2143 | memory_full (0); | ||
| 2144 | } | ||
| 2145 | |||
| 2146 | for (i = 0; i < npoints; ++i) | ||
| 2147 | { | ||
| 2148 | point = (*android_java_env)->NewObject (android_java_env, | ||
| 2149 | point_class.class, | ||
| 2150 | point_class.constructor, | ||
| 2151 | (jint) points[i].x, | ||
| 2152 | (jint) points[i].y); | ||
| 2153 | |||
| 2154 | if (!point) | ||
| 2155 | { | ||
| 2156 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2157 | ANDROID_DELETE_LOCAL_REF (array); | ||
| 2158 | memory_full (0); | ||
| 2159 | } | ||
| 2160 | |||
| 2161 | (*android_java_env)->SetObjectArrayElement (android_java_env, | ||
| 2162 | array, i, point); | ||
| 2163 | ANDROID_DELETE_LOCAL_REF (point); | ||
| 2164 | } | ||
| 2165 | |||
| 2166 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2167 | emacs_service, | ||
| 2168 | service_class.fill_polygon, | ||
| 2169 | drawable_object, | ||
| 2170 | gcontext, array); | ||
| 2171 | ANDROID_DELETE_LOCAL_REF (array); | ||
| 2172 | } | ||
| 2173 | |||
| 2174 | void | ||
| 2175 | android_draw_rectangle (android_drawable handle, struct android_gc *gc, | ||
| 2176 | int x, int y, unsigned int width, unsigned int height) | ||
| 2177 | { | ||
| 2178 | jobject drawable, gcontext; | ||
| 2179 | |||
| 2180 | drawable = android_resolve_handle2 (handle, | ||
| 2181 | ANDROID_HANDLE_WINDOW, | ||
| 2182 | ANDROID_HANDLE_PIXMAP); | ||
| 2183 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 2184 | ANDROID_HANDLE_GCONTEXT); | ||
| 2185 | |||
| 2186 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2187 | emacs_service, | ||
| 2188 | service_class.draw_rectangle, | ||
| 2189 | drawable, gcontext, | ||
| 2190 | (jint) x, (jint) y, | ||
| 2191 | (jint) width, (jint) height); | ||
| 2192 | } | ||
| 2193 | |||
| 2194 | void | ||
| 2195 | android_draw_point (android_drawable handle, struct android_gc *gc, | ||
| 2196 | int x, int y) | ||
| 2197 | { | ||
| 2198 | jobject drawable, gcontext; | ||
| 2199 | |||
| 2200 | drawable = android_resolve_handle2 (handle, | ||
| 2201 | ANDROID_HANDLE_WINDOW, | ||
| 2202 | ANDROID_HANDLE_PIXMAP); | ||
| 2203 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 2204 | ANDROID_HANDLE_GCONTEXT); | ||
| 2205 | |||
| 2206 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2207 | emacs_service, | ||
| 2208 | service_class.draw_point, | ||
| 2209 | drawable, gcontext, | ||
| 2210 | (jint) x, (jint) y); | ||
| 2211 | } | ||
| 2212 | |||
| 2213 | void | ||
| 2214 | android_draw_line (android_drawable handle, struct android_gc *gc, | ||
| 2215 | int x, int y, int x2, int y2) | ||
| 2216 | { | ||
| 2217 | jobject drawable, gcontext; | ||
| 2218 | |||
| 2219 | drawable = android_resolve_handle2 (handle, | ||
| 2220 | ANDROID_HANDLE_WINDOW, | ||
| 2221 | ANDROID_HANDLE_PIXMAP); | ||
| 2222 | gcontext = android_resolve_handle (gc->gcontext, | ||
| 2223 | ANDROID_HANDLE_GCONTEXT); | ||
| 2224 | |||
| 2225 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2226 | emacs_service, | ||
| 2227 | service_class.draw_line, | ||
| 2228 | drawable, gcontext, | ||
| 2229 | (jint) x, (jint) y, | ||
| 2230 | (jint) x2, (jint) y2); | ||
| 2231 | } | ||
| 2232 | |||
| 2233 | android_pixmap | ||
| 2234 | android_create_pixmap (unsigned int width, unsigned int height, | ||
| 2235 | int depth) | ||
| 2236 | { | ||
| 2237 | android_handle prev_max_handle; | ||
| 2238 | jobject object; | ||
| 2239 | jintArray colors; | ||
| 2240 | android_pixmap pixmap; | ||
| 2241 | |||
| 2242 | /* Create the color array holding the data. */ | ||
| 2243 | colors = (*android_java_env)->NewIntArray (android_java_env, | ||
| 2244 | width * height); | ||
| 2245 | |||
| 2246 | if (!colors) | ||
| 2247 | { | ||
| 2248 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2249 | memory_full (0); | ||
| 2250 | } | ||
| 2251 | |||
| 2252 | /* First, allocate the pixmap handle. */ | ||
| 2253 | prev_max_handle = max_handle; | ||
| 2254 | pixmap = android_alloc_id (); | ||
| 2255 | |||
| 2256 | if (!pixmap) | ||
| 2257 | { | ||
| 2258 | ANDROID_DELETE_LOCAL_REF ((jobject) colors); | ||
| 2259 | error ("Out of pixmap handles!"); | ||
| 2260 | } | ||
| 2261 | |||
| 2262 | object = (*android_java_env)->NewObject (android_java_env, | ||
| 2263 | pixmap_class.class, | ||
| 2264 | pixmap_class.constructor, | ||
| 2265 | (jshort) pixmap, colors, | ||
| 2266 | (jint) width, (jint) height, | ||
| 2267 | (jint) depth); | ||
| 2268 | ANDROID_DELETE_LOCAL_REF ((jobject) colors); | ||
| 2269 | |||
| 2270 | if (!object) | ||
| 2271 | { | ||
| 2272 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2273 | max_handle = prev_max_handle; | ||
| 2274 | memory_full (0); | ||
| 2275 | } | ||
| 2276 | |||
| 2277 | android_handles[pixmap].type = ANDROID_HANDLE_PIXMAP; | ||
| 2278 | android_handles[pixmap].handle | ||
| 2279 | = (*android_java_env)->NewGlobalRef (android_java_env, object); | ||
| 2280 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 2281 | ANDROID_DELETE_LOCAL_REF (object); | ||
| 2282 | |||
| 2283 | if (!android_handles[pixmap].handle) | ||
| 2284 | memory_full (0); | ||
| 2285 | |||
| 2286 | return pixmap; | ||
| 2287 | } | ||
| 2288 | |||
| 2289 | void | ||
| 2290 | android_set_ts_origin (struct android_gc *gc, int x, int y) | ||
| 2291 | { | ||
| 2292 | struct android_gc_values gcv; | ||
| 2293 | |||
| 2294 | gcv.ts_x_origin = x; | ||
| 2295 | gcv.ts_y_origin = y; | ||
| 2296 | android_change_gc (gc, (ANDROID_GC_TILE_STIP_X_ORIGIN | ||
| 2297 | | ANDROID_GC_TILE_STIP_Y_ORIGIN), | ||
| 2298 | &gcv); | ||
| 2299 | } | ||
| 2300 | |||
| 2301 | void | ||
| 2302 | android_clear_area (android_window handle, int x, int y, | ||
| 2303 | unsigned int width, unsigned int height) | ||
| 2304 | { | ||
| 2305 | jobject window; | ||
| 2306 | |||
| 2307 | window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW); | ||
| 2308 | |||
| 2309 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 2310 | emacs_service, | ||
| 2311 | service_class.clear_area, | ||
| 2312 | window, (jint) x, (jint) y, | ||
| 2313 | (jint) width, (jint) height); | ||
| 2314 | } | ||
| 2315 | |||
| 2316 | #else /* ANDROID_STUBIFY */ | ||
| 2317 | |||
| 2318 | /* X emulation functions for Android. */ | ||
| 2319 | |||
| 2320 | struct android_gc * | ||
| 2321 | android_create_gc (enum android_gc_value_mask mask, | ||
| 2322 | struct android_gc_values *values) | ||
| 2323 | { | ||
| 2324 | /* This function should never be called when building stubs. */ | ||
| 2325 | emacs_abort (); | ||
| 2326 | } | ||
| 2327 | |||
| 2328 | void | ||
| 2329 | android_free_gc (struct android_gc *gc) | ||
| 2330 | { | ||
| 2331 | /* This function should never be called when building stubs. */ | ||
| 2332 | emacs_abort (); | ||
| 2333 | } | ||
| 2334 | |||
| 2335 | #endif | ||
diff --git a/src/android.h b/src/android.h new file mode 100644 index 00000000000..6bdcd38ed68 --- /dev/null +++ b/src/android.h | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | /* Android initialization for GNU Emacs. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | /* On Android, Emacs is built as a shared library loaded from Java | ||
| 21 | using the Java Native Interface. Emacs's `main' function is | ||
| 22 | renamed `android_emacs_init', and runs with some modifications | ||
| 23 | inside a separate thread, communicating with the Java code through | ||
| 24 | a table of function pointers. */ | ||
| 25 | |||
| 26 | #ifndef _ANDROID_H_ | ||
| 27 | #ifndef ANDROID_STUBIFY | ||
| 28 | #include <jni.h> | ||
| 29 | #include <pwd.h> | ||
| 30 | #include <sys/stat.h> | ||
| 31 | #endif | ||
| 32 | |||
| 33 | /* This must be used in every symbol declaration to export it to the | ||
| 34 | JNI Emacs wrapper. */ | ||
| 35 | #define ANDROID_EXPORT __attribute__ ((visibility ("default"))) | ||
| 36 | |||
| 37 | extern bool ANDROID_EXPORT android_init_gui; | ||
| 38 | extern int ANDROID_EXPORT android_emacs_init (int, char **); | ||
| 39 | |||
| 40 | #ifndef ANDROID_STUBIFY | ||
| 41 | |||
| 42 | extern int android_select (int, fd_set *, fd_set *, fd_set *, | ||
| 43 | struct timespec *, const sigset_t *); | ||
| 44 | |||
| 45 | extern bool android_file_access_p (const char *, int); | ||
| 46 | extern int android_open (const char *, int, int); | ||
| 47 | extern char *android_user_full_name (struct passwd *); | ||
| 48 | extern int android_fstat (int, struct stat *); | ||
| 49 | extern int android_fstatat (int, const char *restrict, | ||
| 50 | struct stat *restrict, int); | ||
| 51 | extern int android_close (int); | ||
| 52 | |||
| 53 | #endif | ||
| 54 | |||
| 55 | /* JNI functions should not be built when Emacs is stubbed out for the | ||
| 56 | build. These should be documented in EmacsNative.java. */ | ||
| 57 | |||
| 58 | #ifndef ANDROID_STUBIFY | ||
| 59 | #include <jni.h> | ||
| 60 | |||
| 61 | extern JNIEnv *android_java_env; | ||
| 62 | |||
| 63 | #define ANDROID_DELETE_LOCAL_REF(ref) \ | ||
| 64 | ((*android_java_env)->DeleteLocalRef (android_java_env, \ | ||
| 65 | (ref))) | ||
| 66 | |||
| 67 | #define NATIVE_NAME(name) Java_org_gnu_emacs_EmacsNative_##name | ||
| 68 | |||
| 69 | #endif | ||
| 70 | #endif /* _ANDROID_H_ */ | ||
diff --git a/src/androidfns.c b/src/androidfns.c new file mode 100644 index 00000000000..e9e1ae3d52e --- /dev/null +++ b/src/androidfns.c | |||
| @@ -0,0 +1,1779 @@ | |||
| 1 | /* Communication module for Android terminals. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | #include <math.h> | ||
| 22 | |||
| 23 | #include "lisp.h" | ||
| 24 | #include "androidterm.h" | ||
| 25 | #include "blockinput.h" | ||
| 26 | #include "keyboard.h" | ||
| 27 | |||
| 28 | #ifndef ANDROID_STUBIFY | ||
| 29 | |||
| 30 | /* Some kind of reference count for the image cache. */ | ||
| 31 | static ptrdiff_t image_cache_refcount; | ||
| 32 | |||
| 33 | #endif | ||
| 34 | |||
| 35 | static struct android_display_info * | ||
| 36 | android_display_info_for_name (Lisp_Object name) | ||
| 37 | { | ||
| 38 | struct android_display_info *dpyinfo; | ||
| 39 | |||
| 40 | CHECK_STRING (name); | ||
| 41 | |||
| 42 | for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) | ||
| 43 | { | ||
| 44 | if (!NILP (Fstring_equal (XCAR (dpyinfo->name_list_element), | ||
| 45 | name))) | ||
| 46 | return dpyinfo; | ||
| 47 | } | ||
| 48 | |||
| 49 | error ("Cannot connect to Android if it was not initialized" | ||
| 50 | " at startup"); | ||
| 51 | } | ||
| 52 | |||
| 53 | static struct android_display_info * | ||
| 54 | check_android_display_info (Lisp_Object object) | ||
| 55 | { | ||
| 56 | struct android_display_info *dpyinfo; | ||
| 57 | struct frame *sf, *f; | ||
| 58 | struct terminal *t; | ||
| 59 | |||
| 60 | if (NILP (object)) | ||
| 61 | { | ||
| 62 | sf = XFRAME (selected_frame); | ||
| 63 | |||
| 64 | if (FRAME_ANDROID_P (sf) && FRAME_LIVE_P (sf)) | ||
| 65 | dpyinfo = FRAME_DISPLAY_INFO (sf); | ||
| 66 | else if (x_display_list) | ||
| 67 | dpyinfo = x_display_list; | ||
| 68 | else | ||
| 69 | error ("Android windows are not in use or not initialized"); | ||
| 70 | } | ||
| 71 | else if (TERMINALP (object)) | ||
| 72 | { | ||
| 73 | t = decode_live_terminal (object); | ||
| 74 | |||
| 75 | if (t->type != output_android) | ||
| 76 | error ("Terminal %d is not an Android display", t->id); | ||
| 77 | |||
| 78 | dpyinfo = t->display_info.android; | ||
| 79 | } | ||
| 80 | else if (STRINGP (object)) | ||
| 81 | dpyinfo = android_display_info_for_name (object); | ||
| 82 | else | ||
| 83 | { | ||
| 84 | f = decode_window_system_frame (object); | ||
| 85 | dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 86 | } | ||
| 87 | |||
| 88 | return dpyinfo; | ||
| 89 | } | ||
| 90 | |||
| 91 | Display_Info * | ||
| 92 | check_x_display_info (Lisp_Object object) | ||
| 93 | { | ||
| 94 | return check_android_display_info (object); | ||
| 95 | } | ||
| 96 | |||
| 97 | |||
| 98 | |||
| 99 | #ifndef ANDROID_STUBIFY | ||
| 100 | |||
| 101 | void | ||
| 102 | gamma_correct (struct frame *f, Emacs_Color *color) | ||
| 103 | { | ||
| 104 | if (f->gamma) | ||
| 105 | { | ||
| 106 | color->red = pow (color->red / 65535.0, f->gamma) * 65535.0 + 0.5; | ||
| 107 | color->green = pow (color->green / 65535.0, f->gamma) * 65535.0 + 0.5; | ||
| 108 | color->blue = pow (color->blue / 65535.0, f->gamma) * 65535.0 + 0.5; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | /* Decide if color named COLOR_NAME is valid for use on frame F. If | ||
| 113 | so, return the RGB values in COLOR. If ALLOC_P, allocate the | ||
| 114 | color. Value is false if COLOR_NAME is invalid, or no color could | ||
| 115 | be allocated. MAKE_INDEX is some mysterious argument used on | ||
| 116 | NS. */ | ||
| 117 | |||
| 118 | bool | ||
| 119 | android_defined_color (struct frame *f, const char *color_name, | ||
| 120 | Emacs_Color *color, bool alloc_p, | ||
| 121 | bool make_index) | ||
| 122 | { | ||
| 123 | bool success_p; | ||
| 124 | |||
| 125 | success_p = false; | ||
| 126 | |||
| 127 | block_input (); | ||
| 128 | success_p = android_parse_color (f, color_name, color); | ||
| 129 | if (success_p && alloc_p) | ||
| 130 | success_p = android_alloc_nearest_color (f, color); | ||
| 131 | unblock_input (); | ||
| 132 | |||
| 133 | return success_p; | ||
| 134 | } | ||
| 135 | |||
| 136 | /* Return the pixel color value for color COLOR_NAME on frame F. If F | ||
| 137 | is a monochrome frame, return MONO_COLOR regardless of what ARG | ||
| 138 | says. Signal an error if color can't be allocated. */ | ||
| 139 | |||
| 140 | static unsigned long | ||
| 141 | android_decode_color (struct frame *f, Lisp_Object color_name, int mono_color) | ||
| 142 | { | ||
| 143 | Emacs_Color cdef; | ||
| 144 | |||
| 145 | CHECK_STRING (color_name); | ||
| 146 | |||
| 147 | if (android_defined_color (f, SSDATA (color_name), &cdef, | ||
| 148 | true, false)) | ||
| 149 | return cdef.pixel; | ||
| 150 | |||
| 151 | signal_error ("Undefined color", color_name); | ||
| 152 | } | ||
| 153 | |||
| 154 | void | ||
| 155 | android_implicitly_set_name (struct frame *f, Lisp_Object arg, | ||
| 156 | Lisp_Object oldval) | ||
| 157 | { | ||
| 158 | |||
| 159 | } | ||
| 160 | |||
| 161 | void | ||
| 162 | android_explicitly_set_name (struct frame *f, Lisp_Object arg, | ||
| 163 | Lisp_Object oldval) | ||
| 164 | { | ||
| 165 | |||
| 166 | } | ||
| 167 | |||
| 168 | /* Set the number of lines used for the tool bar of frame F to VALUE. | ||
| 169 | VALUE not an integer, or < 0 means set the lines to zero. OLDVAL | ||
| 170 | is the old number of tool bar lines. This function changes the | ||
| 171 | height of all windows on frame F to match the new tool bar height. | ||
| 172 | The frame's height doesn't change. */ | ||
| 173 | |||
| 174 | static void | ||
| 175 | android_set_tool_bar_lines (struct frame *f, Lisp_Object value, | ||
| 176 | Lisp_Object oldval) | ||
| 177 | { | ||
| 178 | int nlines; | ||
| 179 | |||
| 180 | /* Treat tool bars like menu bars. */ | ||
| 181 | if (FRAME_MINIBUF_ONLY_P (f)) | ||
| 182 | return; | ||
| 183 | |||
| 184 | /* Use VALUE only if an int >= 0. */ | ||
| 185 | if (RANGED_FIXNUMP (0, value, INT_MAX)) | ||
| 186 | nlines = XFIXNAT (value); | ||
| 187 | else | ||
| 188 | nlines = 0; | ||
| 189 | |||
| 190 | android_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); | ||
| 191 | } | ||
| 192 | |||
| 193 | void | ||
| 194 | android_change_tool_bar_height (struct frame *f, int height) | ||
| 195 | { | ||
| 196 | int unit = FRAME_LINE_HEIGHT (f); | ||
| 197 | int old_height = FRAME_TOOL_BAR_HEIGHT (f); | ||
| 198 | int lines = (height + unit - 1) / unit; | ||
| 199 | Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); | ||
| 200 | |||
| 201 | /* Make sure we redisplay all windows in this frame. */ | ||
| 202 | fset_redisplay (f); | ||
| 203 | |||
| 204 | FRAME_TOOL_BAR_HEIGHT (f) = height; | ||
| 205 | FRAME_TOOL_BAR_LINES (f) = lines; | ||
| 206 | store_frame_param (f, Qtool_bar_lines, make_fixnum (lines)); | ||
| 207 | |||
| 208 | if (FRAME_ANDROID_WINDOW (f) && FRAME_TOOL_BAR_HEIGHT (f) == 0) | ||
| 209 | { | ||
| 210 | clear_frame (f); | ||
| 211 | clear_current_matrices (f); | ||
| 212 | } | ||
| 213 | |||
| 214 | if ((height < old_height) && WINDOWP (f->tool_bar_window)) | ||
| 215 | clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix); | ||
| 216 | |||
| 217 | if (!f->tool_bar_resized) | ||
| 218 | { | ||
| 219 | /* As long as tool_bar_resized is false, effectively try to change | ||
| 220 | F's native height. */ | ||
| 221 | if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth)) | ||
| 222 | adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), | ||
| 223 | 1, false, Qtool_bar_lines); | ||
| 224 | else | ||
| 225 | adjust_frame_size (f, -1, -1, 4, false, Qtool_bar_lines); | ||
| 226 | |||
| 227 | f->tool_bar_resized = f->tool_bar_redisplayed; | ||
| 228 | } | ||
| 229 | else | ||
| 230 | /* Any other change may leave the native size of F alone. */ | ||
| 231 | adjust_frame_size (f, -1, -1, 3, false, Qtool_bar_lines); | ||
| 232 | |||
| 233 | /* adjust_frame_size might not have done anything, garbage frame | ||
| 234 | here. */ | ||
| 235 | adjust_frame_glyphs (f); | ||
| 236 | SET_FRAME_GARBAGED (f); | ||
| 237 | } | ||
| 238 | |||
| 239 | /* Set the number of lines used for the tab bar of frame F to VALUE. | ||
| 240 | VALUE not an integer, or < 0 means set the lines to zero. OLDVAL | ||
| 241 | is the old number of tab bar lines. This function may change the | ||
| 242 | height of all windows on frame F to match the new tab bar height. | ||
| 243 | The frame's height may change if frame_inhibit_implied_resize was | ||
| 244 | set accordingly. */ | ||
| 245 | |||
| 246 | static void | ||
| 247 | android_set_tab_bar_lines (struct frame *f, Lisp_Object value, | ||
| 248 | Lisp_Object oldval) | ||
| 249 | { | ||
| 250 | int olines; | ||
| 251 | int nlines; | ||
| 252 | |||
| 253 | olines = FRAME_TAB_BAR_LINES (f); | ||
| 254 | |||
| 255 | /* Treat tab bars like menu bars. */ | ||
| 256 | if (FRAME_MINIBUF_ONLY_P (f)) | ||
| 257 | return; | ||
| 258 | |||
| 259 | /* Use VALUE only if an int >= 0. */ | ||
| 260 | if (RANGED_FIXNUMP (0, value, INT_MAX)) | ||
| 261 | nlines = XFIXNAT (value); | ||
| 262 | else | ||
| 263 | nlines = 0; | ||
| 264 | |||
| 265 | if (nlines != olines && (olines == 0 || nlines == 0)) | ||
| 266 | android_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); | ||
| 267 | } | ||
| 268 | |||
| 269 | void | ||
| 270 | android_change_tab_bar_height (struct frame *f, int height) | ||
| 271 | { | ||
| 272 | int unit, old_height, lines; | ||
| 273 | Lisp_Object fullscreen; | ||
| 274 | |||
| 275 | unit = FRAME_LINE_HEIGHT (f); | ||
| 276 | old_height = FRAME_TAB_BAR_HEIGHT (f); | ||
| 277 | fullscreen = get_frame_param (f, Qfullscreen); | ||
| 278 | |||
| 279 | /* This differs from the tool bar code in that the tab bar height is | ||
| 280 | not rounded up. Otherwise, if redisplay_tab_bar decides to grow | ||
| 281 | the tab bar by even 1 pixel, FRAME_TAB_BAR_LINES will be changed, | ||
| 282 | leading to the tab bar height being incorrectly set upon the next | ||
| 283 | call to android_set_font. (bug#59285) */ | ||
| 284 | lines = height / unit; | ||
| 285 | |||
| 286 | /* Make sure we redisplay all windows in this frame. */ | ||
| 287 | fset_redisplay (f); | ||
| 288 | |||
| 289 | /* Recalculate tab bar and frame text sizes. */ | ||
| 290 | FRAME_TAB_BAR_HEIGHT (f) = height; | ||
| 291 | FRAME_TAB_BAR_LINES (f) = lines; | ||
| 292 | store_frame_param (f, Qtab_bar_lines, make_fixnum (lines)); | ||
| 293 | |||
| 294 | if (FRAME_ANDROID_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0) | ||
| 295 | { | ||
| 296 | clear_frame (f); | ||
| 297 | clear_current_matrices (f); | ||
| 298 | } | ||
| 299 | |||
| 300 | if ((height < old_height) && WINDOWP (f->tab_bar_window)) | ||
| 301 | clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix); | ||
| 302 | |||
| 303 | if (!f->tab_bar_resized) | ||
| 304 | { | ||
| 305 | /* As long as tab_bar_resized is false, effectively try to change | ||
| 306 | F's native height. */ | ||
| 307 | if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth)) | ||
| 308 | adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), | ||
| 309 | 1, false, Qtab_bar_lines); | ||
| 310 | else | ||
| 311 | adjust_frame_size (f, -1, -1, 4, false, Qtab_bar_lines); | ||
| 312 | |||
| 313 | f->tab_bar_resized = f->tab_bar_redisplayed; | ||
| 314 | } | ||
| 315 | else | ||
| 316 | /* Any other change may leave the native size of F alone. */ | ||
| 317 | adjust_frame_size (f, -1, -1, 3, false, Qtab_bar_lines); | ||
| 318 | |||
| 319 | /* adjust_frame_size might not have done anything, garbage frame | ||
| 320 | here. */ | ||
| 321 | adjust_frame_glyphs (f); | ||
| 322 | SET_FRAME_GARBAGED (f); | ||
| 323 | } | ||
| 324 | |||
| 325 | void | ||
| 326 | android_set_scroll_bar_default_height (struct frame *f) | ||
| 327 | { | ||
| 328 | int height; | ||
| 329 | |||
| 330 | height = FRAME_LINE_HEIGHT (f); | ||
| 331 | |||
| 332 | /* The height of a non-toolkit scrollbar is 14 pixels. */ | ||
| 333 | FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height; | ||
| 334 | |||
| 335 | /* Use all of that space (aside from required margins) for the | ||
| 336 | scroll bar. */ | ||
| 337 | FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = 14; | ||
| 338 | } | ||
| 339 | |||
| 340 | void | ||
| 341 | android_set_scroll_bar_default_width (struct frame *f) | ||
| 342 | { | ||
| 343 | int unit; | ||
| 344 | |||
| 345 | unit = FRAME_COLUMN_WIDTH (f); | ||
| 346 | |||
| 347 | FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit; | ||
| 348 | FRAME_CONFIG_SCROLL_BAR_WIDTH (f) | ||
| 349 | = FRAME_CONFIG_SCROLL_BAR_COLS (f) * unit; | ||
| 350 | } | ||
| 351 | |||
| 352 | |||
| 353 | /* Verify that the icon position args for this window are valid. */ | ||
| 354 | |||
| 355 | static void | ||
| 356 | android_icon_verify (struct frame *f, Lisp_Object parms) | ||
| 357 | { | ||
| 358 | Lisp_Object icon_x, icon_y; | ||
| 359 | |||
| 360 | /* Set the position of the icon. Note that twm groups all | ||
| 361 | icons in an icon window. */ | ||
| 362 | icon_x = gui_frame_get_and_record_arg (f, parms, Qicon_left, 0, 0, | ||
| 363 | RES_TYPE_NUMBER); | ||
| 364 | icon_y = gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0, | ||
| 365 | RES_TYPE_NUMBER); | ||
| 366 | |||
| 367 | if (!BASE_EQ (icon_x, Qunbound) && !BASE_EQ (icon_y, Qunbound)) | ||
| 368 | { | ||
| 369 | CHECK_FIXNUM (icon_x); | ||
| 370 | CHECK_FIXNUM (icon_y); | ||
| 371 | } | ||
| 372 | else if (!BASE_EQ (icon_x, Qunbound) || !BASE_EQ (icon_y, Qunbound)) | ||
| 373 | error ("Both left and top icon corners of icon must be specified"); | ||
| 374 | } | ||
| 375 | |||
| 376 | /* Handle the icon stuff for this window. Perhaps later we might | ||
| 377 | want an x_set_icon_position which can be called interactively as | ||
| 378 | well. */ | ||
| 379 | |||
| 380 | static void | ||
| 381 | android_icon (struct frame *f, Lisp_Object parms) | ||
| 382 | { | ||
| 383 | /* Set the position of the icon. Note that twm groups all | ||
| 384 | icons in an icon window. */ | ||
| 385 | Lisp_Object icon_x | ||
| 386 | = gui_frame_get_and_record_arg (f, parms, Qicon_left, 0, 0, | ||
| 387 | RES_TYPE_NUMBER); | ||
| 388 | Lisp_Object icon_y | ||
| 389 | = gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0, | ||
| 390 | RES_TYPE_NUMBER); | ||
| 391 | |||
| 392 | bool xgiven = !BASE_EQ (icon_x, Qunbound); | ||
| 393 | bool ygiven = !BASE_EQ (icon_y, Qunbound); | ||
| 394 | |||
| 395 | if (xgiven != ygiven) | ||
| 396 | error ("Both left and top icon corners of icon must be specified"); | ||
| 397 | |||
| 398 | if (xgiven) | ||
| 399 | { | ||
| 400 | check_integer_range (icon_x, INT_MIN, INT_MAX); | ||
| 401 | check_integer_range (icon_y, INT_MIN, INT_MAX); | ||
| 402 | } | ||
| 403 | |||
| 404 | /* Now return as this is not supported on Android. */ | ||
| 405 | } | ||
| 406 | |||
| 407 | /* Make the GCs needed for this window, setting the background | ||
| 408 | color. */ | ||
| 409 | |||
| 410 | static void | ||
| 411 | android_make_gc (struct frame *f) | ||
| 412 | { | ||
| 413 | struct android_gc_values gc_values; | ||
| 414 | |||
| 415 | block_input (); | ||
| 416 | |||
| 417 | /* Create the GCs of this frame. | ||
| 418 | Note that many default values are used. */ | ||
| 419 | |||
| 420 | gc_values.foreground = FRAME_FOREGROUND_PIXEL (f); | ||
| 421 | gc_values.background = FRAME_BACKGROUND_PIXEL (f); | ||
| 422 | f->output_data.android->normal_gc | ||
| 423 | = android_create_gc (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND, | ||
| 424 | &gc_values); | ||
| 425 | |||
| 426 | /* Reverse video style. */ | ||
| 427 | gc_values.foreground = FRAME_BACKGROUND_PIXEL (f); | ||
| 428 | gc_values.background = FRAME_FOREGROUND_PIXEL (f); | ||
| 429 | f->output_data.android->reverse_gc | ||
| 430 | = android_create_gc (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND, | ||
| 431 | &gc_values); | ||
| 432 | |||
| 433 | /* Cursor has cursor-color background, background-color foreground. */ | ||
| 434 | gc_values.foreground = FRAME_BACKGROUND_PIXEL (f); | ||
| 435 | gc_values.background = f->output_data.android->cursor_pixel; | ||
| 436 | f->output_data.android->cursor_gc | ||
| 437 | = android_create_gc (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND, | ||
| 438 | &gc_values); | ||
| 439 | unblock_input (); | ||
| 440 | } | ||
| 441 | |||
| 442 | |||
| 443 | /* Free what was allocated in android_make_gc. */ | ||
| 444 | |||
| 445 | void | ||
| 446 | android_free_gcs (struct frame *f) | ||
| 447 | { | ||
| 448 | block_input (); | ||
| 449 | |||
| 450 | if (f->output_data.android->normal_gc) | ||
| 451 | { | ||
| 452 | android_free_gc (f->output_data.android->normal_gc); | ||
| 453 | f->output_data.android->normal_gc = 0; | ||
| 454 | } | ||
| 455 | |||
| 456 | if (f->output_data.android->reverse_gc) | ||
| 457 | { | ||
| 458 | android_free_gc (f->output_data.android->reverse_gc); | ||
| 459 | f->output_data.android->reverse_gc = 0; | ||
| 460 | } | ||
| 461 | |||
| 462 | if (f->output_data.android->cursor_gc) | ||
| 463 | { | ||
| 464 | android_free_gc (f->output_data.android->cursor_gc); | ||
| 465 | f->output_data.android->cursor_gc = 0; | ||
| 466 | } | ||
| 467 | |||
| 468 | unblock_input (); | ||
| 469 | } | ||
| 470 | |||
| 471 | /* Handler for signals raised during x_create_frame and | ||
| 472 | Fx_create_tip_frame. FRAME is the frame which is partially | ||
| 473 | constructed. */ | ||
| 474 | |||
| 475 | static Lisp_Object | ||
| 476 | unwind_create_frame (Lisp_Object frame) | ||
| 477 | { | ||
| 478 | struct frame *f = XFRAME (frame); | ||
| 479 | |||
| 480 | /* If frame is already dead, nothing to do. This can happen if the | ||
| 481 | display is disconnected after the frame has become official, but | ||
| 482 | before Fx_create_frame removes the unwind protect. */ | ||
| 483 | if (!FRAME_LIVE_P (f)) | ||
| 484 | return Qnil; | ||
| 485 | |||
| 486 | /* If frame is ``official'', nothing to do. */ | ||
| 487 | if (NILP (Fmemq (frame, Vframe_list))) | ||
| 488 | { | ||
| 489 | /* If the frame's image cache refcount is still the same as our | ||
| 490 | private shadow variable, it means we are unwinding a frame | ||
| 491 | for which we didn't yet call init_frame_faces, where the | ||
| 492 | refcount is incremented. Therefore, we increment it here, so | ||
| 493 | that free_frame_faces, called in x_free_frame_resources | ||
| 494 | below, will not mistakenly decrement the counter that was not | ||
| 495 | incremented yet to account for this new frame. */ | ||
| 496 | if (FRAME_IMAGE_CACHE (f) != NULL | ||
| 497 | && FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount) | ||
| 498 | FRAME_IMAGE_CACHE (f)->refcount++; | ||
| 499 | |||
| 500 | android_free_frame_resources (f); | ||
| 501 | free_glyphs (f); | ||
| 502 | return Qt; | ||
| 503 | } | ||
| 504 | |||
| 505 | return Qnil; | ||
| 506 | } | ||
| 507 | |||
| 508 | static void | ||
| 509 | do_unwind_create_frame (Lisp_Object frame) | ||
| 510 | { | ||
| 511 | unwind_create_frame (frame); | ||
| 512 | } | ||
| 513 | |||
| 514 | void | ||
| 515 | android_default_font_parameter (struct frame *f, Lisp_Object parms) | ||
| 516 | { | ||
| 517 | struct android_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 518 | Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL, | ||
| 519 | RES_TYPE_STRING); | ||
| 520 | Lisp_Object font = Qnil; | ||
| 521 | if (BASE_EQ (font_param, Qunbound)) | ||
| 522 | font_param = Qnil; | ||
| 523 | |||
| 524 | if (NILP (font)) | ||
| 525 | font = (!NILP (font_param) | ||
| 526 | ? font_param | ||
| 527 | : gui_display_get_arg (dpyinfo, parms, | ||
| 528 | Qfont, "font", "Font", | ||
| 529 | RES_TYPE_STRING)); | ||
| 530 | |||
| 531 | if (! FONTP (font) && ! STRINGP (font)) | ||
| 532 | { | ||
| 533 | const char *names[] = { | ||
| 534 | /* This will find the normal font. */ | ||
| 535 | "DroidSansMono", | ||
| 536 | "monospace", | ||
| 537 | NULL | ||
| 538 | }; | ||
| 539 | int i; | ||
| 540 | |||
| 541 | for (i = 0; names[i]; i++) | ||
| 542 | { | ||
| 543 | font = font_open_by_name (f, build_unibyte_string (names[i])); | ||
| 544 | if (! NILP (font)) | ||
| 545 | break; | ||
| 546 | } | ||
| 547 | |||
| 548 | if (NILP (font)) | ||
| 549 | error ("No suitable font was found"); | ||
| 550 | } | ||
| 551 | |||
| 552 | gui_default_parameter (f, parms, Qfont, font, "font", "Font", RES_TYPE_STRING); | ||
| 553 | } | ||
| 554 | |||
| 555 | static void | ||
| 556 | android_create_frame_window (struct frame *f) | ||
| 557 | { | ||
| 558 | struct android_set_window_attributes attributes; | ||
| 559 | enum android_window_value_mask attribute_mask; | ||
| 560 | |||
| 561 | attributes.background_pixel = FRAME_BACKGROUND_PIXEL (f); | ||
| 562 | attribute_mask = ANDROID_CW_BACK_PIXEL; | ||
| 563 | |||
| 564 | block_input (); | ||
| 565 | FRAME_ANDROID_WINDOW (f) | ||
| 566 | = android_create_window (FRAME_DISPLAY_INFO (f)->root_window, | ||
| 567 | f->left_pos, | ||
| 568 | f->top_pos, | ||
| 569 | FRAME_PIXEL_WIDTH (f), | ||
| 570 | FRAME_PIXEL_HEIGHT (f), | ||
| 571 | attribute_mask, &attributes); | ||
| 572 | unblock_input (); | ||
| 573 | } | ||
| 574 | |||
| 575 | #endif /* ANDROID_STUBIFY */ | ||
| 576 | |||
| 577 | |||
| 578 | |||
| 579 | DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, | ||
| 580 | 1, 1, 0, | ||
| 581 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 582 | (Lisp_Object parms) | ||
| 583 | { | ||
| 584 | #ifdef ANDROID_STUBIFY | ||
| 585 | error ("Android cross-compilation stub called!"); | ||
| 586 | return Qnil; | ||
| 587 | #else | ||
| 588 | struct frame *f; | ||
| 589 | Lisp_Object frame, tem; | ||
| 590 | Lisp_Object name; | ||
| 591 | bool minibuffer_only; | ||
| 592 | bool undecorated, override_redirect; | ||
| 593 | long window_prompting; | ||
| 594 | specpdl_ref count; | ||
| 595 | Lisp_Object display; | ||
| 596 | struct android_display_info *dpyinfo; | ||
| 597 | Lisp_Object parent, parent_frame; | ||
| 598 | struct kboard *kb; | ||
| 599 | |||
| 600 | minibuffer_only = false; | ||
| 601 | undecorated = false; | ||
| 602 | override_redirect = false; | ||
| 603 | window_prompting = 0; | ||
| 604 | count = SPECPDL_INDEX (); | ||
| 605 | dpyinfo = NULL; | ||
| 606 | |||
| 607 | /* Not actually used, but be consistent with X. */ | ||
| 608 | ((void) window_prompting); | ||
| 609 | |||
| 610 | parms = Fcopy_alist (parms); | ||
| 611 | |||
| 612 | /* Use this general default value to start with | ||
| 613 | until we know if this frame has a specified name. */ | ||
| 614 | Vx_resource_name = Vinvocation_name; | ||
| 615 | |||
| 616 | display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0, | ||
| 617 | RES_TYPE_NUMBER); | ||
| 618 | if (BASE_EQ (display, Qunbound)) | ||
| 619 | display = gui_display_get_arg (dpyinfo, parms, Qdisplay, 0, 0, | ||
| 620 | RES_TYPE_STRING); | ||
| 621 | if (BASE_EQ (display, Qunbound)) | ||
| 622 | display = Qnil; | ||
| 623 | dpyinfo = check_android_display_info (display); | ||
| 624 | kb = dpyinfo->terminal->kboard; | ||
| 625 | |||
| 626 | if (!dpyinfo->terminal->name) | ||
| 627 | error ("Terminal is not live, can't create new frames on it"); | ||
| 628 | |||
| 629 | name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name", | ||
| 630 | RES_TYPE_STRING); | ||
| 631 | if (!STRINGP (name) | ||
| 632 | && ! BASE_EQ (name, Qunbound) | ||
| 633 | && ! NILP (name)) | ||
| 634 | error ("Invalid frame name--not a string or nil"); | ||
| 635 | |||
| 636 | if (STRINGP (name)) | ||
| 637 | Vx_resource_name = name; | ||
| 638 | |||
| 639 | /* See if parent window is specified. */ | ||
| 640 | parent = gui_display_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL, | ||
| 641 | RES_TYPE_NUMBER); | ||
| 642 | if (BASE_EQ (parent, Qunbound)) | ||
| 643 | parent = Qnil; | ||
| 644 | if (! NILP (parent)) | ||
| 645 | CHECK_FIXNUM (parent); | ||
| 646 | |||
| 647 | frame = Qnil; | ||
| 648 | tem = gui_display_get_arg (dpyinfo, | ||
| 649 | parms, Qminibuffer, "minibuffer", "Minibuffer", | ||
| 650 | RES_TYPE_SYMBOL); | ||
| 651 | if (EQ (tem, Qnone) || NILP (tem)) | ||
| 652 | f = make_frame_without_minibuffer (Qnil, kb, display); | ||
| 653 | else if (EQ (tem, Qonly)) | ||
| 654 | { | ||
| 655 | f = make_minibuffer_frame (); | ||
| 656 | minibuffer_only = true; | ||
| 657 | } | ||
| 658 | else if (WINDOWP (tem)) | ||
| 659 | f = make_frame_without_minibuffer (tem, kb, display); | ||
| 660 | else | ||
| 661 | f = make_frame (true); | ||
| 662 | |||
| 663 | parent_frame = gui_display_get_arg (dpyinfo, | ||
| 664 | parms, | ||
| 665 | Qparent_frame, | ||
| 666 | NULL, | ||
| 667 | NULL, | ||
| 668 | RES_TYPE_SYMBOL); | ||
| 669 | /* Accept parent-frame iff parent-id was not specified. */ | ||
| 670 | if (!NILP (parent) | ||
| 671 | || BASE_EQ (parent_frame, Qunbound) | ||
| 672 | || NILP (parent_frame) | ||
| 673 | || !FRAMEP (parent_frame) | ||
| 674 | || !FRAME_LIVE_P (XFRAME (parent_frame)) | ||
| 675 | || !FRAME_ANDROID_P (XFRAME (parent_frame))) | ||
| 676 | parent_frame = Qnil; | ||
| 677 | |||
| 678 | fset_parent_frame (f, parent_frame); | ||
| 679 | store_frame_param (f, Qparent_frame, parent_frame); | ||
| 680 | |||
| 681 | if (!NILP (tem = (gui_display_get_arg (dpyinfo, | ||
| 682 | parms, | ||
| 683 | Qundecorated, | ||
| 684 | NULL, | ||
| 685 | NULL, | ||
| 686 | RES_TYPE_BOOLEAN))) | ||
| 687 | && !(BASE_EQ (tem, Qunbound))) | ||
| 688 | undecorated = true; | ||
| 689 | |||
| 690 | FRAME_UNDECORATED (f) = undecorated; | ||
| 691 | store_frame_param (f, Qundecorated, undecorated ? Qt : Qnil); | ||
| 692 | |||
| 693 | if (!NILP (tem = (gui_display_get_arg (dpyinfo, | ||
| 694 | parms, | ||
| 695 | Qoverride_redirect, | ||
| 696 | NULL, | ||
| 697 | NULL, | ||
| 698 | RES_TYPE_BOOLEAN))) | ||
| 699 | && !(BASE_EQ (tem, Qunbound))) | ||
| 700 | override_redirect = true; | ||
| 701 | |||
| 702 | FRAME_OVERRIDE_REDIRECT (f) = override_redirect; | ||
| 703 | store_frame_param (f, Qoverride_redirect, override_redirect ? Qt : Qnil); | ||
| 704 | |||
| 705 | XSETFRAME (frame, f); | ||
| 706 | |||
| 707 | f->terminal = dpyinfo->terminal; | ||
| 708 | |||
| 709 | f->output_method = output_android; | ||
| 710 | f->output_data.android = xzalloc (sizeof *f->output_data.android); | ||
| 711 | FRAME_FONTSET (f) = -1; | ||
| 712 | f->output_data.android->scroll_bar_foreground_pixel = -1; | ||
| 713 | f->output_data.android->scroll_bar_background_pixel = -1; | ||
| 714 | f->output_data.android->white_relief.pixel = -1; | ||
| 715 | f->output_data.android->black_relief.pixel = -1; | ||
| 716 | |||
| 717 | fset_icon_name (f, gui_display_get_arg (dpyinfo, | ||
| 718 | parms, | ||
| 719 | Qicon_name, | ||
| 720 | "iconName", | ||
| 721 | "Title", | ||
| 722 | RES_TYPE_STRING)); | ||
| 723 | if (! STRINGP (f->icon_name)) | ||
| 724 | fset_icon_name (f, Qnil); | ||
| 725 | |||
| 726 | FRAME_DISPLAY_INFO (f) = dpyinfo; | ||
| 727 | |||
| 728 | /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */ | ||
| 729 | record_unwind_protect (do_unwind_create_frame, frame); | ||
| 730 | |||
| 731 | /* These colors will be set anyway later, but it's important | ||
| 732 | to get the color reference counts right, so initialize them! | ||
| 733 | |||
| 734 | (Not really on Android, but it's best to be consistent with | ||
| 735 | X.) */ | ||
| 736 | { | ||
| 737 | Lisp_Object black; | ||
| 738 | |||
| 739 | /* Function x_decode_color can signal an error. Make | ||
| 740 | sure to initialize color slots so that we won't try | ||
| 741 | to free colors we haven't allocated. */ | ||
| 742 | FRAME_FOREGROUND_PIXEL (f) = -1; | ||
| 743 | FRAME_BACKGROUND_PIXEL (f) = -1; | ||
| 744 | f->output_data.android->cursor_pixel = -1; | ||
| 745 | f->output_data.android->cursor_foreground_pixel = -1; | ||
| 746 | |||
| 747 | black = build_string ("black"); | ||
| 748 | FRAME_FOREGROUND_PIXEL (f) | ||
| 749 | = android_decode_color (f, black, BLACK_PIX_DEFAULT (f)); | ||
| 750 | FRAME_BACKGROUND_PIXEL (f) | ||
| 751 | = android_decode_color (f, black, BLACK_PIX_DEFAULT (f)); | ||
| 752 | f->output_data.android->cursor_pixel | ||
| 753 | = android_decode_color (f, black, BLACK_PIX_DEFAULT (f)); | ||
| 754 | f->output_data.android->cursor_foreground_pixel | ||
| 755 | = android_decode_color (f, black, BLACK_PIX_DEFAULT (f)); | ||
| 756 | } | ||
| 757 | |||
| 758 | /* Set the name; the functions to which we pass f expect the name to | ||
| 759 | be set. */ | ||
| 760 | if (BASE_EQ (name, Qunbound) || NILP (name)) | ||
| 761 | { | ||
| 762 | fset_name (f, build_string ("GNU Emacs")); | ||
| 763 | f->explicit_name = false; | ||
| 764 | } | ||
| 765 | else | ||
| 766 | { | ||
| 767 | fset_name (f, name); | ||
| 768 | f->explicit_name = true; | ||
| 769 | /* Use the frame's title when getting resources for this frame. */ | ||
| 770 | specbind (Qx_resource_name, name); | ||
| 771 | } | ||
| 772 | |||
| 773 | register_font_driver (&androidfont_driver, f); | ||
| 774 | |||
| 775 | image_cache_refcount = (FRAME_IMAGE_CACHE (f) | ||
| 776 | ? FRAME_IMAGE_CACHE (f)->refcount | ||
| 777 | : 0); | ||
| 778 | |||
| 779 | gui_default_parameter (f, parms, Qfont_backend, Qnil, | ||
| 780 | "fontBackend", "FontBackend", RES_TYPE_STRING); | ||
| 781 | |||
| 782 | /* Extract the window parameters from the supplied values | ||
| 783 | that are needed to determine window geometry. */ | ||
| 784 | android_default_font_parameter (f, parms); | ||
| 785 | if (!FRAME_FONT (f)) | ||
| 786 | { | ||
| 787 | delete_frame (frame, Qnoelisp); | ||
| 788 | error ("Invalid frame font"); | ||
| 789 | } | ||
| 790 | |||
| 791 | if (NILP (Fassq (Qinternal_border_width, parms))) | ||
| 792 | { | ||
| 793 | Lisp_Object value; | ||
| 794 | |||
| 795 | value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width, | ||
| 796 | "internalBorder", "internalBorder", | ||
| 797 | RES_TYPE_NUMBER); | ||
| 798 | if (! BASE_EQ (value, Qunbound)) | ||
| 799 | parms = Fcons (Fcons (Qinternal_border_width, value), | ||
| 800 | parms); | ||
| 801 | } | ||
| 802 | |||
| 803 | gui_default_parameter (f, parms, Qinternal_border_width, | ||
| 804 | make_fixnum (0), | ||
| 805 | "internalBorderWidth", "internalBorderWidth", | ||
| 806 | RES_TYPE_NUMBER); | ||
| 807 | |||
| 808 | /* Same for child frames. */ | ||
| 809 | if (NILP (Fassq (Qchild_frame_border_width, parms))) | ||
| 810 | { | ||
| 811 | Lisp_Object value; | ||
| 812 | |||
| 813 | value = gui_display_get_arg (dpyinfo, parms, Qchild_frame_border_width, | ||
| 814 | "childFrameBorder", "childFrameBorder", | ||
| 815 | RES_TYPE_NUMBER); | ||
| 816 | if (! BASE_EQ (value, Qunbound)) | ||
| 817 | parms = Fcons (Fcons (Qchild_frame_border_width, value), | ||
| 818 | parms); | ||
| 819 | } | ||
| 820 | |||
| 821 | gui_default_parameter (f, parms, Qchild_frame_border_width, Qnil, | ||
| 822 | "childFrameBorderWidth", "childFrameBorderWidth", | ||
| 823 | RES_TYPE_NUMBER); | ||
| 824 | gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0), | ||
| 825 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 826 | gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0), | ||
| 827 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 828 | |||
| 829 | /* gui_default_parameter (f, parms, Qvertical_scroll_bars, */ | ||
| 830 | /* Qleft, */ | ||
| 831 | /* "verticalScrollBars", "ScrollBars", */ | ||
| 832 | /* RES_TYPE_SYMBOL); */ | ||
| 833 | /* gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil, */ | ||
| 834 | /* "horizontalScrollBars", "ScrollBars", */ | ||
| 835 | /* RES_TYPE_SYMBOL); TODO */ | ||
| 836 | |||
| 837 | /* Also do the stuff which must be set before the window exists. */ | ||
| 838 | gui_default_parameter (f, parms, Qforeground_color, build_string ("black"), | ||
| 839 | "foreground", "Foreground", RES_TYPE_STRING); | ||
| 840 | gui_default_parameter (f, parms, Qbackground_color, build_string ("white"), | ||
| 841 | "background", "Background", RES_TYPE_STRING); | ||
| 842 | gui_default_parameter (f, parms, Qmouse_color, build_string ("black"), | ||
| 843 | "pointerColor", "Foreground", RES_TYPE_STRING); | ||
| 844 | gui_default_parameter (f, parms, Qborder_color, build_string ("black"), | ||
| 845 | "borderColor", "BorderColor", RES_TYPE_STRING); | ||
| 846 | gui_default_parameter (f, parms, Qscreen_gamma, Qnil, | ||
| 847 | "screenGamma", "ScreenGamma", RES_TYPE_FLOAT); | ||
| 848 | gui_default_parameter (f, parms, Qline_spacing, Qnil, | ||
| 849 | "lineSpacing", "LineSpacing", RES_TYPE_NUMBER); | ||
| 850 | gui_default_parameter (f, parms, Qleft_fringe, Qnil, | ||
| 851 | "leftFringe", "LeftFringe", RES_TYPE_NUMBER); | ||
| 852 | gui_default_parameter (f, parms, Qright_fringe, Qnil, | ||
| 853 | "rightFringe", "RightFringe", RES_TYPE_NUMBER); | ||
| 854 | gui_default_parameter (f, parms, Qno_special_glyphs, Qnil, | ||
| 855 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 856 | |||
| 857 | #if 0 | ||
| 858 | android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground, | ||
| 859 | "scrollBarForeground", | ||
| 860 | "ScrollBarForeground", true); | ||
| 861 | android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background, | ||
| 862 | "scrollBarBackground", | ||
| 863 | "ScrollBarBackground", false); | ||
| 864 | #endif /* TODO */ | ||
| 865 | |||
| 866 | /* Init faces before gui_default_parameter is called for the | ||
| 867 | scroll-bar-width parameter because otherwise we end up in | ||
| 868 | init_iterator with a null face cache, which should not | ||
| 869 | happen. */ | ||
| 870 | |||
| 871 | init_frame_faces (f); | ||
| 872 | |||
| 873 | tem = gui_display_get_arg (dpyinfo, parms, Qmin_width, NULL, NULL, | ||
| 874 | RES_TYPE_NUMBER); | ||
| 875 | if (FIXNUMP (tem)) | ||
| 876 | store_frame_param (f, Qmin_width, tem); | ||
| 877 | tem = gui_display_get_arg (dpyinfo, parms, Qmin_height, NULL, NULL, | ||
| 878 | RES_TYPE_NUMBER); | ||
| 879 | if (FIXNUMP (tem)) | ||
| 880 | store_frame_param (f, Qmin_height, tem); | ||
| 881 | |||
| 882 | adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), | ||
| 883 | FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, true, | ||
| 884 | Qx_create_frame_1); | ||
| 885 | |||
| 886 | /* Set the menu-bar-lines and tool-bar-lines parameters. We don't | ||
| 887 | look up the X resources controlling the menu-bar and tool-bar | ||
| 888 | here; they are processed specially at startup, and reflected in | ||
| 889 | the values of the mode variables. */ | ||
| 890 | |||
| 891 | gui_default_parameter (f, parms, Qmenu_bar_lines, | ||
| 892 | NILP (Vmenu_bar_mode) | ||
| 893 | ? make_fixnum (0) : make_fixnum (1), | ||
| 894 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 895 | gui_default_parameter (f, parms, Qtab_bar_lines, | ||
| 896 | NILP (Vtab_bar_mode) | ||
| 897 | ? make_fixnum (0) : make_fixnum (1), | ||
| 898 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 899 | gui_default_parameter (f, parms, Qtool_bar_lines, | ||
| 900 | NILP (Vtool_bar_mode) | ||
| 901 | ? make_fixnum (0) : make_fixnum (1), | ||
| 902 | NULL, NULL, RES_TYPE_NUMBER); | ||
| 903 | |||
| 904 | gui_default_parameter (f, parms, Qbuffer_predicate, Qnil, | ||
| 905 | "bufferPredicate", "BufferPredicate", | ||
| 906 | RES_TYPE_SYMBOL); | ||
| 907 | gui_default_parameter (f, parms, Qtitle, Qnil, | ||
| 908 | "title", "Title", RES_TYPE_STRING); | ||
| 909 | gui_default_parameter (f, parms, Qwait_for_wm, Qt, | ||
| 910 | "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN); | ||
| 911 | gui_default_parameter (f, parms, Qtool_bar_position, | ||
| 912 | FRAME_TOOL_BAR_POSITION (f), 0, 0, RES_TYPE_SYMBOL); | ||
| 913 | gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil, | ||
| 914 | "inhibitDoubleBuffering", "InhibitDoubleBuffering", | ||
| 915 | RES_TYPE_BOOLEAN); | ||
| 916 | |||
| 917 | /* Compute the size of the X window. */ | ||
| 918 | window_prompting = gui_figure_window_size (f, parms, true, true); | ||
| 919 | |||
| 920 | tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, | ||
| 921 | RES_TYPE_BOOLEAN); | ||
| 922 | f->no_split = minibuffer_only || EQ (tem, Qt); | ||
| 923 | |||
| 924 | android_icon_verify (f, parms); | ||
| 925 | android_create_frame_window (f); | ||
| 926 | android_icon (f, parms); | ||
| 927 | android_make_gc (f); | ||
| 928 | |||
| 929 | /* Now consider the frame official. */ | ||
| 930 | f->terminal->reference_count++; | ||
| 931 | Vframe_list = Fcons (frame, Vframe_list); | ||
| 932 | |||
| 933 | /* We need to do this after creating the window, so that the | ||
| 934 | icon-creation functions can say whose icon they're | ||
| 935 | describing. */ | ||
| 936 | gui_default_parameter (f, parms, Qicon_type, Qt, | ||
| 937 | "bitmapIcon", "BitmapIcon", RES_TYPE_BOOLEAN); | ||
| 938 | |||
| 939 | gui_default_parameter (f, parms, Qauto_raise, Qnil, | ||
| 940 | "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN); | ||
| 941 | gui_default_parameter (f, parms, Qauto_lower, Qnil, | ||
| 942 | "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN); | ||
| 943 | gui_default_parameter (f, parms, Qcursor_type, Qbox, | ||
| 944 | "cursorType", "CursorType", RES_TYPE_SYMBOL); | ||
| 945 | gui_default_parameter (f, parms, Qscroll_bar_width, Qnil, | ||
| 946 | "scrollBarWidth", "ScrollBarWidth", | ||
| 947 | RES_TYPE_NUMBER); | ||
| 948 | gui_default_parameter (f, parms, Qscroll_bar_height, Qnil, | ||
| 949 | "scrollBarHeight", "ScrollBarHeight", | ||
| 950 | RES_TYPE_NUMBER); | ||
| 951 | gui_default_parameter (f, parms, Qalpha, Qnil, | ||
| 952 | "alpha", "Alpha", RES_TYPE_NUMBER); | ||
| 953 | gui_default_parameter (f, parms, Qalpha_background, Qnil, | ||
| 954 | "alphaBackground", "AlphaBackground", RES_TYPE_NUMBER); | ||
| 955 | |||
| 956 | if (!NILP (parent_frame)) | ||
| 957 | { | ||
| 958 | struct frame *p = XFRAME (parent_frame); | ||
| 959 | |||
| 960 | block_input (); | ||
| 961 | android_reparent_window (FRAME_ANDROID_WINDOW (f), | ||
| 962 | FRAME_ANDROID_WINDOW (p), | ||
| 963 | f->left_pos, f->top_pos); | ||
| 964 | unblock_input (); | ||
| 965 | } | ||
| 966 | |||
| 967 | gui_default_parameter (f, parms, Qno_focus_on_map, Qnil, | ||
| 968 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 969 | gui_default_parameter (f, parms, Qno_accept_focus, Qnil, | ||
| 970 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 971 | |||
| 972 | /* Consider frame official, now. */ | ||
| 973 | f->can_set_window_size = true; | ||
| 974 | |||
| 975 | adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), | ||
| 976 | 0, true, Qx_create_frame_2); | ||
| 977 | |||
| 978 | /* Process fullscreen parameter here in the hope that normalizing a | ||
| 979 | fullheight/fullwidth frame will produce the size set by the last | ||
| 980 | adjust_frame_size call. */ | ||
| 981 | gui_default_parameter (f, parms, Qfullscreen, Qnil, | ||
| 982 | "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); | ||
| 983 | |||
| 984 | /* When called from `x-create-frame-with-faces' visibility is | ||
| 985 | always explicitly nil. */ | ||
| 986 | Lisp_Object visibility | ||
| 987 | = gui_display_get_arg (dpyinfo, parms, Qvisibility, 0, 0, | ||
| 988 | RES_TYPE_SYMBOL); | ||
| 989 | Lisp_Object height | ||
| 990 | = gui_display_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER); | ||
| 991 | Lisp_Object width | ||
| 992 | = gui_display_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER); | ||
| 993 | |||
| 994 | if (EQ (visibility, Qicon)) | ||
| 995 | { | ||
| 996 | f->was_invisible = true; | ||
| 997 | android_iconify_frame (f); | ||
| 998 | } | ||
| 999 | else | ||
| 1000 | { | ||
| 1001 | if (BASE_EQ (visibility, Qunbound)) | ||
| 1002 | visibility = Qt; | ||
| 1003 | |||
| 1004 | if (!NILP (visibility)) | ||
| 1005 | android_make_frame_visible (f); | ||
| 1006 | else | ||
| 1007 | f->was_invisible = true; | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | /* Leave f->was_invisible true only if height or width were | ||
| 1011 | specified too. This takes effect only when we are not called | ||
| 1012 | from `x-create-frame-with-faces' (see above comment). */ | ||
| 1013 | f->was_invisible | ||
| 1014 | = (f->was_invisible | ||
| 1015 | && (!BASE_EQ (height, Qunbound) || !BASE_EQ (width, Qunbound))); | ||
| 1016 | |||
| 1017 | store_frame_param (f, Qvisibility, visibility); | ||
| 1018 | |||
| 1019 | /* Set whether or not frame synchronization is enabled. */ | ||
| 1020 | gui_default_parameter (f, parms, Quse_frame_synchronization, Qt, | ||
| 1021 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 1022 | |||
| 1023 | /* Works iff frame has been already mapped. */ | ||
| 1024 | gui_default_parameter (f, parms, Qskip_taskbar, Qnil, | ||
| 1025 | NULL, NULL, RES_TYPE_BOOLEAN); | ||
| 1026 | /* The `z-group' parameter works only for visible frames. */ | ||
| 1027 | gui_default_parameter (f, parms, Qz_group, Qnil, | ||
| 1028 | NULL, NULL, RES_TYPE_SYMBOL); | ||
| 1029 | |||
| 1030 | /* Initialize `default-minibuffer-frame' in case this is the first | ||
| 1031 | frame on this terminal. */ | ||
| 1032 | if (FRAME_HAS_MINIBUF_P (f) | ||
| 1033 | && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame)) | ||
| 1034 | || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame))))) | ||
| 1035 | kset_default_minibuffer_frame (kb, frame); | ||
| 1036 | |||
| 1037 | /* All remaining specified parameters, which have not been "used" by | ||
| 1038 | gui_display_get_arg and friends, now go in the misc. alist of the | ||
| 1039 | frame. */ | ||
| 1040 | for (tem = parms; CONSP (tem); tem = XCDR (tem)) | ||
| 1041 | if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem)))) | ||
| 1042 | fset_param_alist (f, Fcons (XCAR (tem), f->param_alist)); | ||
| 1043 | |||
| 1044 | /* Make sure windows on this frame appear in calls to next-window | ||
| 1045 | and similar functions. */ | ||
| 1046 | Vwindow_list = Qnil; | ||
| 1047 | |||
| 1048 | return unbind_to (count, frame); | ||
| 1049 | #endif | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, | ||
| 1053 | 1, 2, 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1054 | (Lisp_Object color, Lisp_Object frame) | ||
| 1055 | { | ||
| 1056 | #ifdef ANDROID_STUBIFY | ||
| 1057 | error ("Android cross-compilation stub called!"); | ||
| 1058 | return Qnil; | ||
| 1059 | #else | ||
| 1060 | Emacs_Color foo; | ||
| 1061 | struct frame *f; | ||
| 1062 | |||
| 1063 | f = decode_window_system_frame (frame); | ||
| 1064 | |||
| 1065 | CHECK_STRING (color); | ||
| 1066 | |||
| 1067 | if (android_defined_color (f, SSDATA (color), &foo, false, false)) | ||
| 1068 | return Qt; | ||
| 1069 | else | ||
| 1070 | return Qnil; | ||
| 1071 | #endif | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, | ||
| 1075 | 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1076 | (Lisp_Object color, Lisp_Object frame) | ||
| 1077 | { | ||
| 1078 | #ifdef ANDROID_STUBIFY | ||
| 1079 | error ("Android cross-compilation stub called!"); | ||
| 1080 | return Qnil; | ||
| 1081 | #else | ||
| 1082 | Emacs_Color foo; | ||
| 1083 | struct frame *f; | ||
| 1084 | |||
| 1085 | f = decode_window_system_frame (frame); | ||
| 1086 | |||
| 1087 | CHECK_STRING (color); | ||
| 1088 | |||
| 1089 | if (android_defined_color (f, SSDATA (color), &foo, false, false)) | ||
| 1090 | return list3i (foo.red, foo.green, foo.blue); | ||
| 1091 | else | ||
| 1092 | return Qnil; | ||
| 1093 | #endif | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | DEFUN ("xw-display-color-p", Fxw_display_color_p, | ||
| 1097 | Sxw_display_color_p, 0, 1, 0, | ||
| 1098 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1099 | (Lisp_Object terminal) | ||
| 1100 | { | ||
| 1101 | return Qt; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, | ||
| 1105 | Sx_display_grayscale_p, 0, 1, 0, | ||
| 1106 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1107 | (Lisp_Object terminal) | ||
| 1108 | { | ||
| 1109 | return Qnil; | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | DEFUN ("x-display-pixel-width", Fx_display_pixel_width, | ||
| 1113 | Sx_display_pixel_width, 0, 1, 0, | ||
| 1114 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1115 | (Lisp_Object terminal) | ||
| 1116 | { | ||
| 1117 | #ifdef ANDROID_STUBIFY | ||
| 1118 | error ("Android cross-compilation stub called!"); | ||
| 1119 | return Qnil; | ||
| 1120 | #else | ||
| 1121 | error ("Not implemented"); | ||
| 1122 | return Qnil; | ||
| 1123 | #endif | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | DEFUN ("x-display-pixel-height", Fx_display_pixel_height, | ||
| 1127 | Sx_display_pixel_height, 0, 1, 0, | ||
| 1128 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1129 | (Lisp_Object terminal) | ||
| 1130 | { | ||
| 1131 | #ifdef ANDROID_STUBIFY | ||
| 1132 | error ("Android cross-compilation stub called!"); | ||
| 1133 | return Qnil; | ||
| 1134 | #else | ||
| 1135 | error ("Not implemented"); | ||
| 1136 | return Qnil; | ||
| 1137 | #endif | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes, | ||
| 1141 | 0, 1, 0, | ||
| 1142 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1143 | (Lisp_Object terminal) | ||
| 1144 | { | ||
| 1145 | struct android_display_info *dpyinfo; | ||
| 1146 | |||
| 1147 | dpyinfo = check_android_display_info (terminal); | ||
| 1148 | |||
| 1149 | return make_fixnum (dpyinfo->n_planes); | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells, | ||
| 1153 | 0, 1, 0, | ||
| 1154 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1155 | (Lisp_Object terminal) | ||
| 1156 | { | ||
| 1157 | struct android_display_info *dpyinfo; | ||
| 1158 | int nr_planes; | ||
| 1159 | |||
| 1160 | dpyinfo = check_android_display_info (terminal); | ||
| 1161 | nr_planes = dpyinfo->n_planes; | ||
| 1162 | |||
| 1163 | /* Truncate nr_planes to 24 to avoid integer overflow. */ | ||
| 1164 | |||
| 1165 | if (nr_planes > 24) | ||
| 1166 | nr_planes = 24; | ||
| 1167 | |||
| 1168 | return make_fixnum (1 << nr_planes); | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, | ||
| 1172 | 0, 1, 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1173 | (Lisp_Object terminal) | ||
| 1174 | { | ||
| 1175 | check_android_display_info (terminal); | ||
| 1176 | return make_fixnum (1); | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, | ||
| 1180 | 0, 1, 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1181 | (Lisp_Object terminal) | ||
| 1182 | { | ||
| 1183 | #ifdef ANDROID_STUBIFY | ||
| 1184 | error ("Android cross-compilation stub called!"); | ||
| 1185 | return Qnil; | ||
| 1186 | #else | ||
| 1187 | error ("Not implemented"); | ||
| 1188 | return Qnil; | ||
| 1189 | #endif | ||
| 1190 | } | ||
| 1191 | |||
| 1192 | DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, | ||
| 1193 | 0, 1, 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1194 | (Lisp_Object terminal) | ||
| 1195 | { | ||
| 1196 | #ifdef ANDROID_STUBIFY | ||
| 1197 | error ("Android cross-compilation stub called!"); | ||
| 1198 | return Qnil; | ||
| 1199 | #else | ||
| 1200 | error ("Not implemented"); | ||
| 1201 | return Qnil; | ||
| 1202 | #endif | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | DEFUN ("x-display-backing-store", Fx_display_backing_store, | ||
| 1206 | Sx_display_backing_store, 0, 1, 0, | ||
| 1207 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1208 | (Lisp_Object terminal) | ||
| 1209 | { | ||
| 1210 | check_android_display_info (terminal); | ||
| 1211 | |||
| 1212 | /* The Java part is implemented in a way that it always does the | ||
| 1213 | equivalent of backing store. */ | ||
| 1214 | return Qalways; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | DEFUN ("x-display-visual-class", Fx_display_visual_class, | ||
| 1218 | Sx_display_visual_class, 0, 1, 0, | ||
| 1219 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1220 | (Lisp_Object terminal) | ||
| 1221 | { | ||
| 1222 | check_android_display_info (terminal); | ||
| 1223 | |||
| 1224 | return Qtrue_color; | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list, | ||
| 1228 | Sx_display_monitor_attributes_list, | ||
| 1229 | 0, 1, 0, | ||
| 1230 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1231 | (Lisp_Object terminal) | ||
| 1232 | { | ||
| 1233 | #ifdef ANDROID_STUBIFY | ||
| 1234 | error ("Android cross-compilation stub called!"); | ||
| 1235 | return Qnil; | ||
| 1236 | #else | ||
| 1237 | error ("Not implemented"); | ||
| 1238 | return Qnil; | ||
| 1239 | #endif | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | DEFUN ("x-frame-geometry", Fx_frame_geometry, Sx_frame_geometry, | ||
| 1243 | 0, 1, 0, doc: /* SKIP: real doc in xfns.c. */) | ||
| 1244 | (Lisp_Object terminal) | ||
| 1245 | { | ||
| 1246 | #ifdef ANDROID_STUBIFY | ||
| 1247 | error ("Android cross-compilation stub called!"); | ||
| 1248 | return Qnil; | ||
| 1249 | #else | ||
| 1250 | error ("Not implemented"); | ||
| 1251 | return Qnil; | ||
| 1252 | #endif | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | DEFUN ("x-frame-list-z-order", Fx_frame_list_z_order, | ||
| 1256 | Sx_frame_list_z_order, 0, 1, 0, | ||
| 1257 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1258 | (Lisp_Object terminal) | ||
| 1259 | { | ||
| 1260 | #ifdef ANDROID_STUBIFY | ||
| 1261 | error ("Android cross-compilation stub called!"); | ||
| 1262 | return Qnil; | ||
| 1263 | #else | ||
| 1264 | error ("Not implemented"); | ||
| 1265 | return Qnil; | ||
| 1266 | #endif | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | DEFUN ("x-frame-restack", Fx_frame_restack, Sx_frame_restack, 2, 3, 0, | ||
| 1270 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1271 | (Lisp_Object frame1, Lisp_Object frame2, Lisp_Object frame3) | ||
| 1272 | { | ||
| 1273 | #ifdef ANDROID_STUBIFY | ||
| 1274 | error ("Android cross-compilation stub called!"); | ||
| 1275 | return Qnil; | ||
| 1276 | #else | ||
| 1277 | error ("Not implemented"); | ||
| 1278 | return Qnil; | ||
| 1279 | #endif | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | DEFUN ("x-mouse-absolute-pixel-position", Fx_mouse_absolute_pixel_position, | ||
| 1283 | Sx_mouse_absolute_pixel_position, 0, 0, 0, | ||
| 1284 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1285 | (void) | ||
| 1286 | { | ||
| 1287 | /* TODO: figure out how to implement this. */ | ||
| 1288 | return Qnil; | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | DEFUN ("x-set-mouse-absolute-pixel-position", | ||
| 1292 | Fx_set_mouse_absolute_pixel_position, | ||
| 1293 | Sx_set_mouse_absolute_pixel_position, 2, 2, 0, | ||
| 1294 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1295 | (Lisp_Object x, Lisp_Object y) | ||
| 1296 | { | ||
| 1297 | /* TODO: figure out how to implement this. */ | ||
| 1298 | return Qnil; | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | DEFUN ("android-get-connection", Fandroid_get_connection, | ||
| 1302 | Sandroid_get_connection, 0, 0, 0, | ||
| 1303 | doc: /* Get the connection to the display server. | ||
| 1304 | Return the terminal if it exists, else nil. | ||
| 1305 | |||
| 1306 | Emacs cannot open a connection to the display server itself under | ||
| 1307 | Android, so there is no equivalent of `x-open-connection'. */) | ||
| 1308 | (void) | ||
| 1309 | { | ||
| 1310 | #ifdef ANDROID_STUBIFY | ||
| 1311 | error ("Android cross-compilation stub called!"); | ||
| 1312 | return Qnil; | ||
| 1313 | #else | ||
| 1314 | Lisp_Object terminal; | ||
| 1315 | |||
| 1316 | terminal = Qnil; | ||
| 1317 | |||
| 1318 | if (x_display_list) | ||
| 1319 | XSETTERMINAL (terminal, x_display_list->terminal); | ||
| 1320 | |||
| 1321 | return terminal; | ||
| 1322 | #endif | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0, | ||
| 1326 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1327 | (void) | ||
| 1328 | { | ||
| 1329 | Lisp_Object result; | ||
| 1330 | |||
| 1331 | result = Qnil; | ||
| 1332 | |||
| 1333 | if (x_display_list) | ||
| 1334 | result = Fcons (XCAR (x_display_list->name_list_element), | ||
| 1335 | result); | ||
| 1336 | |||
| 1337 | return result; | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, | ||
| 1341 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1342 | (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, | ||
| 1343 | Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) | ||
| 1344 | { | ||
| 1345 | #ifdef ANDROID_STUBIFY | ||
| 1346 | error ("Android cross-compilation stub called!"); | ||
| 1347 | return Qnil; | ||
| 1348 | #else | ||
| 1349 | error ("Not implemented"); | ||
| 1350 | return Qnil; | ||
| 1351 | #endif | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, | ||
| 1355 | doc: /* SKIP: real doc in xfns.c. */) | ||
| 1356 | (void) | ||
| 1357 | { | ||
| 1358 | #ifdef ANDROID_STUBIFY | ||
| 1359 | error ("Android cross-compilation stub called!"); | ||
| 1360 | return Qnil; | ||
| 1361 | #else | ||
| 1362 | error ("Not implemented"); | ||
| 1363 | return Qnil; | ||
| 1364 | #endif | ||
| 1365 | } | ||
| 1366 | |||
| 1367 | |||
| 1368 | |||
| 1369 | #ifndef ANDROID_STUBIFY | ||
| 1370 | |||
| 1371 | static void | ||
| 1372 | android_set_background_color (struct frame *f, Lisp_Object arg, | ||
| 1373 | Lisp_Object oldval) | ||
| 1374 | { | ||
| 1375 | struct android_output *x; | ||
| 1376 | unsigned long bg; | ||
| 1377 | |||
| 1378 | x = f->output_data.android; | ||
| 1379 | bg = android_decode_color (f, arg, WHITE_PIX_DEFAULT (f)); | ||
| 1380 | FRAME_BACKGROUND_PIXEL (f) = bg; | ||
| 1381 | |||
| 1382 | if (FRAME_ANDROID_WINDOW (f) != 0) | ||
| 1383 | { | ||
| 1384 | block_input (); | ||
| 1385 | android_set_background (x->normal_gc, bg); | ||
| 1386 | android_set_foreground (x->reverse_gc, bg); | ||
| 1387 | android_set_window_background (FRAME_ANDROID_WINDOW (f), bg); | ||
| 1388 | android_set_foreground (x->cursor_gc, bg); | ||
| 1389 | unblock_input (); | ||
| 1390 | |||
| 1391 | update_face_from_frame_parameter (f, Qbackground_color, arg); | ||
| 1392 | |||
| 1393 | if (FRAME_VISIBLE_P (f)) | ||
| 1394 | redraw_frame (f); | ||
| 1395 | } | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | static void | ||
| 1399 | android_set_border_color (struct frame *f, Lisp_Object arg, | ||
| 1400 | Lisp_Object oldval) | ||
| 1401 | { | ||
| 1402 | /* Left unimplemented because Android has no window borders. */ | ||
| 1403 | CHECK_STRING (arg); | ||
| 1404 | android_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); | ||
| 1405 | update_face_from_frame_parameter (f, Qborder_color, arg); | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | static void | ||
| 1409 | android_set_cursor_color (struct frame *f, Lisp_Object arg, | ||
| 1410 | Lisp_Object oldval) | ||
| 1411 | { | ||
| 1412 | unsigned long fore_pixel, pixel; | ||
| 1413 | struct android_output *x; | ||
| 1414 | |||
| 1415 | x = f->output_data.android; | ||
| 1416 | |||
| 1417 | if (!NILP (Vx_cursor_fore_pixel)) | ||
| 1418 | fore_pixel = android_decode_color (f, Vx_cursor_fore_pixel, | ||
| 1419 | WHITE_PIX_DEFAULT (f)); | ||
| 1420 | else | ||
| 1421 | fore_pixel = FRAME_BACKGROUND_PIXEL (f); | ||
| 1422 | |||
| 1423 | pixel = android_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); | ||
| 1424 | |||
| 1425 | /* Make sure that the cursor color differs from the background color. */ | ||
| 1426 | if (pixel == FRAME_BACKGROUND_PIXEL (f)) | ||
| 1427 | { | ||
| 1428 | pixel = FRAME_FOREGROUND_PIXEL (f); | ||
| 1429 | if (pixel == fore_pixel) | ||
| 1430 | fore_pixel = FRAME_BACKGROUND_PIXEL (f); | ||
| 1431 | } | ||
| 1432 | |||
| 1433 | x->cursor_foreground_pixel = fore_pixel; | ||
| 1434 | x->cursor_pixel = pixel; | ||
| 1435 | |||
| 1436 | if (FRAME_ANDROID_WINDOW (f) != 0) | ||
| 1437 | { | ||
| 1438 | block_input (); | ||
| 1439 | android_set_background (x->cursor_gc, x->cursor_pixel); | ||
| 1440 | android_set_foreground (x->cursor_gc, fore_pixel); | ||
| 1441 | unblock_input (); | ||
| 1442 | |||
| 1443 | if (FRAME_VISIBLE_P (f)) | ||
| 1444 | { | ||
| 1445 | gui_update_cursor (f, false); | ||
| 1446 | gui_update_cursor (f, true); | ||
| 1447 | } | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | update_face_from_frame_parameter (f, Qcursor_color, arg); | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | static void | ||
| 1454 | android_set_cursor_type (struct frame *f, Lisp_Object arg, | ||
| 1455 | Lisp_Object oldval) | ||
| 1456 | { | ||
| 1457 | set_frame_cursor_types (f, arg); | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | static void | ||
| 1461 | android_set_foreground_color (struct frame *f, Lisp_Object arg, | ||
| 1462 | Lisp_Object oldval) | ||
| 1463 | { | ||
| 1464 | struct android_output *x; | ||
| 1465 | unsigned long fg, old_fg; | ||
| 1466 | |||
| 1467 | x = f->output_data.android; | ||
| 1468 | |||
| 1469 | fg = android_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); | ||
| 1470 | old_fg = FRAME_FOREGROUND_PIXEL (f); | ||
| 1471 | FRAME_FOREGROUND_PIXEL (f) = fg; | ||
| 1472 | |||
| 1473 | if (FRAME_ANDROID_WINDOW (f) != 0) | ||
| 1474 | { | ||
| 1475 | block_input (); | ||
| 1476 | android_set_foreground (x->normal_gc, fg); | ||
| 1477 | android_set_background (x->reverse_gc, fg); | ||
| 1478 | |||
| 1479 | if (x->cursor_pixel == old_fg) | ||
| 1480 | { | ||
| 1481 | x->cursor_pixel = fg; | ||
| 1482 | android_set_background (x->cursor_gc, x->cursor_pixel); | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | unblock_input (); | ||
| 1486 | |||
| 1487 | update_face_from_frame_parameter (f, Qforeground_color, arg); | ||
| 1488 | |||
| 1489 | if (FRAME_VISIBLE_P (f)) | ||
| 1490 | redraw_frame (f); | ||
| 1491 | } | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | static void | ||
| 1495 | android_set_child_frame_border_width (struct frame *f, Lisp_Object arg, | ||
| 1496 | Lisp_Object oldval) | ||
| 1497 | { | ||
| 1498 | int border; | ||
| 1499 | |||
| 1500 | if (NILP (arg)) | ||
| 1501 | border = -1; | ||
| 1502 | else if (RANGED_FIXNUMP (0, arg, INT_MAX)) | ||
| 1503 | border = XFIXNAT (arg); | ||
| 1504 | else | ||
| 1505 | signal_error ("Invalid child frame border width", arg); | ||
| 1506 | |||
| 1507 | if (border != FRAME_CHILD_FRAME_BORDER_WIDTH (f)) | ||
| 1508 | { | ||
| 1509 | f->child_frame_border_width = border; | ||
| 1510 | |||
| 1511 | if (FRAME_ANDROID_WINDOW (f)) | ||
| 1512 | { | ||
| 1513 | adjust_frame_size (f, -1, -1, 3, false, Qchild_frame_border_width); | ||
| 1514 | android_clear_under_internal_border (f); | ||
| 1515 | } | ||
| 1516 | } | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | static void | ||
| 1520 | android_set_internal_border_width (struct frame *f, Lisp_Object arg, | ||
| 1521 | Lisp_Object oldval) | ||
| 1522 | { | ||
| 1523 | int border = check_int_nonnegative (arg); | ||
| 1524 | |||
| 1525 | if (border != FRAME_INTERNAL_BORDER_WIDTH (f)) | ||
| 1526 | { | ||
| 1527 | f->internal_border_width = border; | ||
| 1528 | |||
| 1529 | if (FRAME_ANDROID_WINDOW (f)) | ||
| 1530 | { | ||
| 1531 | adjust_frame_size (f, -1, -1, 3, false, Qinternal_border_width); | ||
| 1532 | android_clear_under_internal_border (f); | ||
| 1533 | } | ||
| 1534 | } | ||
| 1535 | } | ||
| 1536 | |||
| 1537 | static void | ||
| 1538 | android_set_menu_bar_lines (struct frame *f, Lisp_Object value, | ||
| 1539 | Lisp_Object oldval) | ||
| 1540 | { | ||
| 1541 | int nlines; | ||
| 1542 | int olines = FRAME_MENU_BAR_LINES (f); | ||
| 1543 | |||
| 1544 | /* Right now, menu bars don't work properly in minibuf-only frames; | ||
| 1545 | most of the commands try to apply themselves to the minibuffer | ||
| 1546 | frame itself, and get an error because you can't switch buffers | ||
| 1547 | in or split the minibuffer window. */ | ||
| 1548 | if (FRAME_MINIBUF_ONLY_P (f) || FRAME_PARENT_FRAME (f)) | ||
| 1549 | return; | ||
| 1550 | |||
| 1551 | if (TYPE_RANGED_FIXNUMP (int, value)) | ||
| 1552 | nlines = XFIXNUM (value); | ||
| 1553 | else | ||
| 1554 | nlines = 0; | ||
| 1555 | |||
| 1556 | /* Make sure we redisplay all windows in this frame. */ | ||
| 1557 | fset_redisplay (f); | ||
| 1558 | |||
| 1559 | FRAME_MENU_BAR_LINES (f) = nlines; | ||
| 1560 | FRAME_MENU_BAR_HEIGHT (f) = nlines * FRAME_LINE_HEIGHT (f); | ||
| 1561 | if (FRAME_ANDROID_WINDOW (f)) | ||
| 1562 | android_clear_under_internal_border (f); | ||
| 1563 | |||
| 1564 | /* If the menu bar height gets changed, the internal border below | ||
| 1565 | the top margin has to be cleared. Also, if the menu bar gets | ||
| 1566 | larger, the area for the added lines has to be cleared except for | ||
| 1567 | the first menu bar line that is to be drawn later. */ | ||
| 1568 | if (nlines != olines) | ||
| 1569 | { | ||
| 1570 | int height = FRAME_INTERNAL_BORDER_WIDTH (f); | ||
| 1571 | int width = FRAME_PIXEL_WIDTH (f); | ||
| 1572 | int y; | ||
| 1573 | |||
| 1574 | adjust_frame_size (f, -1, -1, 3, true, Qmenu_bar_lines); | ||
| 1575 | |||
| 1576 | /* height can be zero here. */ | ||
| 1577 | if (FRAME_ANDROID_WINDOW (f) && height > 0 && width > 0) | ||
| 1578 | { | ||
| 1579 | y = FRAME_TOP_MARGIN_HEIGHT (f); | ||
| 1580 | |||
| 1581 | block_input (); | ||
| 1582 | android_clear_area (FRAME_ANDROID_WINDOW (f), | ||
| 1583 | 0, y, width, height); | ||
| 1584 | unblock_input (); | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | if (nlines > 1 && nlines > olines) | ||
| 1588 | { | ||
| 1589 | y = (olines == 0 ? 1 : olines) * FRAME_LINE_HEIGHT (f); | ||
| 1590 | height = nlines * FRAME_LINE_HEIGHT (f) - y; | ||
| 1591 | |||
| 1592 | block_input (); | ||
| 1593 | android_clear_area (FRAME_ANDROID_WINDOW (f), 0, y, | ||
| 1594 | width, height); | ||
| 1595 | unblock_input (); | ||
| 1596 | } | ||
| 1597 | |||
| 1598 | if (nlines == 0 && WINDOWP (f->menu_bar_window)) | ||
| 1599 | clear_glyph_matrix (XWINDOW (f->menu_bar_window)->current_matrix); | ||
| 1600 | } | ||
| 1601 | |||
| 1602 | adjust_frame_glyphs (f); | ||
| 1603 | } | ||
| 1604 | |||
| 1605 | static void | ||
| 1606 | android_set_mouse_color (struct frame *f, Lisp_Object arg, | ||
| 1607 | Lisp_Object oldval) | ||
| 1608 | { | ||
| 1609 | /* Changing the mouse color is unsupported under Android, so this is | ||
| 1610 | left intact. */ | ||
| 1611 | android_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); | ||
| 1612 | } | ||
| 1613 | |||
| 1614 | static void | ||
| 1615 | android_set_title (struct frame *f, Lisp_Object name, | ||
| 1616 | Lisp_Object old_name) | ||
| 1617 | { | ||
| 1618 | /* Don't change the title if it's already NAME. */ | ||
| 1619 | if (EQ (name, f->title)) | ||
| 1620 | return; | ||
| 1621 | |||
| 1622 | update_mode_lines = 38; | ||
| 1623 | |||
| 1624 | fset_title (f, name); | ||
| 1625 | |||
| 1626 | if (NILP (name)) | ||
| 1627 | name = f->name; | ||
| 1628 | else | ||
| 1629 | CHECK_STRING (name); | ||
| 1630 | } | ||
| 1631 | |||
| 1632 | static void | ||
| 1633 | android_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval) | ||
| 1634 | { | ||
| 1635 | double alpha = 1.0; | ||
| 1636 | double newval[2]; | ||
| 1637 | int i; | ||
| 1638 | Lisp_Object item; | ||
| 1639 | |||
| 1640 | /* N.B. that setting the window alpha is actually unsupported under | ||
| 1641 | Android. */ | ||
| 1642 | |||
| 1643 | for (i = 0; i < 2; i++) | ||
| 1644 | { | ||
| 1645 | newval[i] = 1.0; | ||
| 1646 | if (CONSP (arg)) | ||
| 1647 | { | ||
| 1648 | item = CAR (arg); | ||
| 1649 | arg = CDR (arg); | ||
| 1650 | } | ||
| 1651 | else | ||
| 1652 | item = arg; | ||
| 1653 | |||
| 1654 | if (NILP (item)) | ||
| 1655 | alpha = - 1.0; | ||
| 1656 | else if (FLOATP (item)) | ||
| 1657 | { | ||
| 1658 | alpha = XFLOAT_DATA (item); | ||
| 1659 | if (! (0 <= alpha && alpha <= 1.0)) | ||
| 1660 | args_out_of_range (make_float (0.0), make_float (1.0)); | ||
| 1661 | } | ||
| 1662 | else if (FIXNUMP (item)) | ||
| 1663 | { | ||
| 1664 | EMACS_INT ialpha = XFIXNUM (item); | ||
| 1665 | if (! (0 <= ialpha && ialpha <= 100)) | ||
| 1666 | args_out_of_range (make_fixnum (0), make_fixnum (100)); | ||
| 1667 | alpha = ialpha / 100.0; | ||
| 1668 | } | ||
| 1669 | else | ||
| 1670 | wrong_type_argument (Qnumberp, item); | ||
| 1671 | newval[i] = alpha; | ||
| 1672 | } | ||
| 1673 | |||
| 1674 | for (i = 0; i < 2; i++) | ||
| 1675 | f->alpha[i] = newval[i]; | ||
| 1676 | |||
| 1677 | if (FRAME_TERMINAL (f)->set_frame_alpha_hook) | ||
| 1678 | { | ||
| 1679 | block_input (); | ||
| 1680 | FRAME_TERMINAL (f)->set_frame_alpha_hook (f); | ||
| 1681 | unblock_input (); | ||
| 1682 | } | ||
| 1683 | } | ||
| 1684 | |||
| 1685 | frame_parm_handler android_frame_parm_handlers[] = | ||
| 1686 | { | ||
| 1687 | gui_set_autoraise, | ||
| 1688 | gui_set_autolower, | ||
| 1689 | android_set_background_color, | ||
| 1690 | android_set_border_color, | ||
| 1691 | gui_set_border_width, | ||
| 1692 | android_set_cursor_color, | ||
| 1693 | android_set_cursor_type, | ||
| 1694 | gui_set_font, | ||
| 1695 | android_set_foreground_color, | ||
| 1696 | NULL, | ||
| 1697 | NULL, | ||
| 1698 | android_set_child_frame_border_width, | ||
| 1699 | android_set_internal_border_width, | ||
| 1700 | gui_set_right_divider_width, | ||
| 1701 | gui_set_bottom_divider_width, | ||
| 1702 | android_set_menu_bar_lines, | ||
| 1703 | android_set_mouse_color, | ||
| 1704 | android_explicitly_set_name, | ||
| 1705 | gui_set_scroll_bar_width, | ||
| 1706 | gui_set_scroll_bar_height, | ||
| 1707 | android_set_title, | ||
| 1708 | gui_set_unsplittable, | ||
| 1709 | gui_set_vertical_scroll_bars, | ||
| 1710 | gui_set_horizontal_scroll_bars, | ||
| 1711 | gui_set_visibility, | ||
| 1712 | android_set_tab_bar_lines, | ||
| 1713 | android_set_tool_bar_lines, | ||
| 1714 | NULL, | ||
| 1715 | NULL, | ||
| 1716 | gui_set_screen_gamma, | ||
| 1717 | gui_set_line_spacing, | ||
| 1718 | gui_set_left_fringe, | ||
| 1719 | gui_set_right_fringe, | ||
| 1720 | NULL, | ||
| 1721 | gui_set_fullscreen, | ||
| 1722 | gui_set_font_backend, | ||
| 1723 | android_set_alpha, | ||
| 1724 | NULL, | ||
| 1725 | NULL, | ||
| 1726 | NULL, | ||
| 1727 | NULL, /* x_set_undecorated, */ | ||
| 1728 | NULL, /* x_set_parent_frame, */ | ||
| 1729 | NULL, /* x_set_skip_taskbar, */ | ||
| 1730 | NULL, /* x_set_no_focus_on_map, */ | ||
| 1731 | NULL, /* x_set_no_accept_focus, */ | ||
| 1732 | NULL, /* x_set_z_group, */ | ||
| 1733 | NULL, /* x_set_override_redirect, */ | ||
| 1734 | gui_set_no_special_glyphs, | ||
| 1735 | NULL, /* x_set_alpha_background, */ | ||
| 1736 | NULL, /* x_set_use_frame_synchronization, */ | ||
| 1737 | }; | ||
| 1738 | |||
| 1739 | #endif | ||
| 1740 | |||
| 1741 | |||
| 1742 | |||
| 1743 | void | ||
| 1744 | syms_of_androidfns (void) | ||
| 1745 | { | ||
| 1746 | /* Miscellaneous symbols used by some functions here. */ | ||
| 1747 | DEFSYM (Qtrue_color, "true-color"); | ||
| 1748 | DEFSYM (Qalways, "always"); | ||
| 1749 | |||
| 1750 | DEFVAR_LISP ("x-cursor-fore-pixel", Vx_cursor_fore_pixel, | ||
| 1751 | doc: /* SKIP: real doc in xfns.c. */); | ||
| 1752 | Vx_cursor_fore_pixel = Qnil; | ||
| 1753 | |||
| 1754 | /* Functions defined. */ | ||
| 1755 | defsubr (&Sx_create_frame); | ||
| 1756 | defsubr (&Sxw_color_defined_p); | ||
| 1757 | defsubr (&Sxw_color_values); | ||
| 1758 | defsubr (&Sxw_display_color_p); | ||
| 1759 | defsubr (&Sx_display_grayscale_p); | ||
| 1760 | defsubr (&Sx_display_pixel_width); | ||
| 1761 | defsubr (&Sx_display_pixel_height); | ||
| 1762 | defsubr (&Sx_display_planes); | ||
| 1763 | defsubr (&Sx_display_color_cells); | ||
| 1764 | defsubr (&Sx_display_screens); | ||
| 1765 | defsubr (&Sx_display_mm_width); | ||
| 1766 | defsubr (&Sx_display_mm_height); | ||
| 1767 | defsubr (&Sx_display_backing_store); | ||
| 1768 | defsubr (&Sx_display_visual_class); | ||
| 1769 | defsubr (&Sx_display_monitor_attributes_list); | ||
| 1770 | defsubr (&Sx_frame_geometry); | ||
| 1771 | defsubr (&Sx_frame_list_z_order); | ||
| 1772 | defsubr (&Sx_frame_restack); | ||
| 1773 | defsubr (&Sx_mouse_absolute_pixel_position); | ||
| 1774 | defsubr (&Sx_set_mouse_absolute_pixel_position); | ||
| 1775 | defsubr (&Sandroid_get_connection); | ||
| 1776 | defsubr (&Sx_display_list); | ||
| 1777 | defsubr (&Sx_show_tip); | ||
| 1778 | defsubr (&Sx_hide_tip); | ||
| 1779 | } | ||
diff --git a/src/androidfont.c b/src/androidfont.c new file mode 100644 index 00000000000..e312e55c54a --- /dev/null +++ b/src/androidfont.c | |||
| @@ -0,0 +1,955 @@ | |||
| 1 | /* Communication module for Android terminals. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | |||
| 22 | #include "lisp.h" | ||
| 23 | #include "dispextern.h" | ||
| 24 | #include "composite.h" | ||
| 25 | #include "blockinput.h" | ||
| 26 | #include "charset.h" | ||
| 27 | #include "frame.h" | ||
| 28 | #include "window.h" | ||
| 29 | #include "fontset.h" | ||
| 30 | #include "androidterm.h" | ||
| 31 | #include "character.h" | ||
| 32 | #include "coding.h" | ||
| 33 | #include "font.h" | ||
| 34 | #include "termchar.h" | ||
| 35 | #include "pdumper.h" | ||
| 36 | #include "android.h" | ||
| 37 | |||
| 38 | #ifndef ANDROID_STUBIFY | ||
| 39 | |||
| 40 | #include <android/log.h> | ||
| 41 | |||
| 42 | struct android_emacs_font_driver | ||
| 43 | { | ||
| 44 | jclass class; | ||
| 45 | jmethodID list; | ||
| 46 | jmethodID match; | ||
| 47 | jmethodID list_families; | ||
| 48 | jmethodID open_font; | ||
| 49 | jmethodID has_char; | ||
| 50 | jmethodID text_extents; | ||
| 51 | jmethodID encode_char; | ||
| 52 | |||
| 53 | /* Static methods. */ | ||
| 54 | jmethodID create_font_driver; | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct android_emacs_font_spec | ||
| 58 | { | ||
| 59 | jclass class; | ||
| 60 | jfieldID foundry; | ||
| 61 | jfieldID family; | ||
| 62 | jfieldID adstyle; | ||
| 63 | jfieldID registry; | ||
| 64 | jfieldID width; | ||
| 65 | jfieldID weight; | ||
| 66 | jfieldID slant; | ||
| 67 | jfieldID size; | ||
| 68 | jfieldID spacing; | ||
| 69 | jfieldID avgwidth; | ||
| 70 | }; | ||
| 71 | |||
| 72 | struct android_emacs_font_metrics | ||
| 73 | { | ||
| 74 | jclass class; | ||
| 75 | jfieldID lbearing; | ||
| 76 | jfieldID rbearing; | ||
| 77 | jfieldID width; | ||
| 78 | jfieldID ascent; | ||
| 79 | jfieldID descent; | ||
| 80 | }; | ||
| 81 | |||
| 82 | struct android_emacs_font_object | ||
| 83 | { | ||
| 84 | jclass class; | ||
| 85 | jfieldID min_width; | ||
| 86 | jfieldID max_width; | ||
| 87 | jfieldID pixel_size; | ||
| 88 | jfieldID height; | ||
| 89 | jfieldID space_width; | ||
| 90 | jfieldID average_width; | ||
| 91 | jfieldID ascent; | ||
| 92 | jfieldID descent; | ||
| 93 | jfieldID underline_thickness; | ||
| 94 | jfieldID underline_position; | ||
| 95 | jfieldID baseline_offset; | ||
| 96 | jfieldID relative_compose; | ||
| 97 | jfieldID default_ascent; | ||
| 98 | jfieldID encoding_charset; | ||
| 99 | jfieldID repertory_charset; | ||
| 100 | }; | ||
| 101 | |||
| 102 | struct android_integer | ||
| 103 | { | ||
| 104 | jclass class; | ||
| 105 | jmethodID constructor; | ||
| 106 | jmethodID int_value; | ||
| 107 | }; | ||
| 108 | |||
| 109 | struct androidfont_info | ||
| 110 | { | ||
| 111 | /* The font pseudo-vector object. */ | ||
| 112 | struct font font; | ||
| 113 | |||
| 114 | /* The Java-side font. */ | ||
| 115 | jobject object; | ||
| 116 | }; | ||
| 117 | |||
| 118 | struct androidfont_entity | ||
| 119 | { | ||
| 120 | /* The font entity pvec. */ | ||
| 121 | struct font_entity font; | ||
| 122 | |||
| 123 | /* The Java-side font entity. */ | ||
| 124 | jobject object; | ||
| 125 | }; | ||
| 126 | |||
| 127 | /* Method and class identifiers associated with the EmacsFontDriver | ||
| 128 | class. */ | ||
| 129 | |||
| 130 | struct android_emacs_font_driver font_driver_class; | ||
| 131 | |||
| 132 | /* Field and class identifiers associated with the | ||
| 133 | EmacsFontDriver$FontSpec class. */ | ||
| 134 | |||
| 135 | struct android_emacs_font_spec font_spec_class; | ||
| 136 | |||
| 137 | /* Method and class identifiers associated with the Integer class. */ | ||
| 138 | |||
| 139 | struct android_integer integer_class; | ||
| 140 | |||
| 141 | /* Field and class identifiers associated with the | ||
| 142 | EmacsFontDriver$FontMetrics class. */ | ||
| 143 | |||
| 144 | struct android_emacs_font_metrics font_metrics_class; | ||
| 145 | |||
| 146 | /* Field and class identifiers associated with the | ||
| 147 | EmacsFontDriver$FontObject class. */ | ||
| 148 | |||
| 149 | struct android_emacs_font_object font_object_class; | ||
| 150 | |||
| 151 | /* The font cache. */ | ||
| 152 | |||
| 153 | static Lisp_Object font_cache; | ||
| 154 | |||
| 155 | /* The Java-side font driver. */ | ||
| 156 | |||
| 157 | static jobject font_driver; | ||
| 158 | |||
| 159 | |||
| 160 | |||
| 161 | /* Initialize the class and method identifiers for functions in the | ||
| 162 | EmacsFontDriver class, and place them in `font_driver_class'. */ | ||
| 163 | |||
| 164 | static void | ||
| 165 | android_init_font_driver (void) | ||
| 166 | { | ||
| 167 | jclass old; | ||
| 168 | |||
| 169 | font_driver_class.class | ||
| 170 | = (*android_java_env)->FindClass (android_java_env, | ||
| 171 | "org/gnu/emacs/EmacsFontDriver"); | ||
| 172 | eassert (font_driver_class.class); | ||
| 173 | |||
| 174 | old = font_driver_class.class; | ||
| 175 | font_driver_class.class | ||
| 176 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 177 | (jobject) old); | ||
| 178 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 179 | |||
| 180 | if (!font_driver_class.class) | ||
| 181 | emacs_abort (); | ||
| 182 | |||
| 183 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 184 | font_driver_class.c_name \ | ||
| 185 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 186 | font_driver_class.class, \ | ||
| 187 | name, signature); \ | ||
| 188 | eassert (font_driver_class.c_name); | ||
| 189 | |||
| 190 | FIND_METHOD (list, "list", "(Lorg/gnu/emacs/EmacsFontDriver$FontSpec;)" | ||
| 191 | "[Lorg/gnu/emacs/EmacsFontDriver$FontEntity;"); | ||
| 192 | FIND_METHOD (match, "match", "(Lorg/gnu/emacs/EmacsFontDriver$FontSpec;)" | ||
| 193 | "Lorg/gnu/emacs/EmacsFontDriver$FontEntity;"); | ||
| 194 | FIND_METHOD (list_families, "listFamilies", "()[Ljava/lang/String;"); | ||
| 195 | FIND_METHOD (open_font, "openFont", "(Lorg/gnu/emacs/EmacsFontDriver$Font" | ||
| 196 | "Entity;I)Lorg/gnu/emacs/EmacsFontDriver$FontObject;"); | ||
| 197 | FIND_METHOD (has_char, "hasChar", "(Lorg/gnu/emacs/EmacsFontDriver$Font" | ||
| 198 | "Spec;C)I"); | ||
| 199 | FIND_METHOD (text_extents, "textExtents", "(Lorg/gnu/emacs/EmacsFontDriver" | ||
| 200 | "$FontObject;[I[Lorg/gnu/emacs/EmacsFontDriver$FontMetrics;)V"); | ||
| 201 | FIND_METHOD (encode_char, "encodeChar", "(Lorg/gnu/emacs/EmacsFontDriver" | ||
| 202 | "$FontObject;C)I"); | ||
| 203 | |||
| 204 | font_driver_class.create_font_driver | ||
| 205 | = (*android_java_env)->GetStaticMethodID (android_java_env, | ||
| 206 | font_driver_class.class, | ||
| 207 | "createFontDriver", | ||
| 208 | "()Lorg/gnu/emacs/" | ||
| 209 | "EmacsFontDriver;"); | ||
| 210 | eassert (font_driver_class.create_font_driver); | ||
| 211 | #undef FIND_METHOD | ||
| 212 | } | ||
| 213 | |||
| 214 | /* Initialize the class and field identifiers for functions in the | ||
| 215 | EmacsFontDriver$FontSpec class, and place them in | ||
| 216 | `font_spec_class'. */ | ||
| 217 | |||
| 218 | static void | ||
| 219 | android_init_font_spec (void) | ||
| 220 | { | ||
| 221 | jclass old; | ||
| 222 | |||
| 223 | font_spec_class.class | ||
| 224 | = (*android_java_env)->FindClass (android_java_env, | ||
| 225 | "org/gnu/emacs/EmacsFontDriver" | ||
| 226 | "$FontSpec"); | ||
| 227 | eassert (font_spec_class.class); | ||
| 228 | |||
| 229 | old = font_spec_class.class; | ||
| 230 | font_spec_class.class | ||
| 231 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 232 | (jobject) old); | ||
| 233 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 234 | |||
| 235 | if (!font_spec_class.class) | ||
| 236 | emacs_abort (); | ||
| 237 | |||
| 238 | #define FIND_FIELD(c_name, name, signature) \ | ||
| 239 | font_spec_class.c_name \ | ||
| 240 | = (*android_java_env)->GetFieldID (android_java_env, \ | ||
| 241 | font_spec_class.class, \ | ||
| 242 | name, signature); \ | ||
| 243 | eassert (font_spec_class.c_name); | ||
| 244 | |||
| 245 | FIND_FIELD (foundry, "foundry", "Ljava/lang/String;"); | ||
| 246 | FIND_FIELD (family, "family", "Ljava/lang/String;"); | ||
| 247 | FIND_FIELD (adstyle, "adstyle", "Ljava/lang/String;"); | ||
| 248 | FIND_FIELD (registry, "registry", "Ljava/lang/String;"); | ||
| 249 | FIND_FIELD (width, "width", "Ljava/lang/Integer;"); | ||
| 250 | FIND_FIELD (weight, "weight", "Ljava/lang/Integer;"); | ||
| 251 | FIND_FIELD (slant, "slant", "Ljava/lang/Integer;"); | ||
| 252 | FIND_FIELD (size, "size", "Ljava/lang/Integer;"); | ||
| 253 | FIND_FIELD (spacing, "spacing", "Ljava/lang/Integer;"); | ||
| 254 | FIND_FIELD (avgwidth, "avgwidth", "Ljava/lang/Integer;"); | ||
| 255 | #undef FIND_FIELD | ||
| 256 | } | ||
| 257 | |||
| 258 | static void | ||
| 259 | android_init_font_metrics (void) | ||
| 260 | { | ||
| 261 | jclass old; | ||
| 262 | |||
| 263 | font_metrics_class.class | ||
| 264 | = (*android_java_env)->FindClass (android_java_env, | ||
| 265 | "org/gnu/emacs/EmacsFontDriver" | ||
| 266 | "$FontMetrics"); | ||
| 267 | eassert (font_metrics_class.class); | ||
| 268 | |||
| 269 | old = font_metrics_class.class; | ||
| 270 | font_metrics_class.class | ||
| 271 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 272 | (jobject) old); | ||
| 273 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 274 | |||
| 275 | if (!font_metrics_class.class) | ||
| 276 | emacs_abort (); | ||
| 277 | |||
| 278 | #define FIND_FIELD(c_name, name, signature) \ | ||
| 279 | font_metrics_class.c_name \ | ||
| 280 | = (*android_java_env)->GetFieldID (android_java_env, \ | ||
| 281 | font_metrics_class.class, \ | ||
| 282 | name, signature); \ | ||
| 283 | eassert (font_metrics_class.c_name); | ||
| 284 | |||
| 285 | FIND_FIELD (lbearing, "lbearing", "S"); | ||
| 286 | FIND_FIELD (rbearing, "rbearing", "S"); | ||
| 287 | FIND_FIELD (width, "width", "S"); | ||
| 288 | FIND_FIELD (ascent, "ascent", "S"); | ||
| 289 | FIND_FIELD (descent, "descent", "S"); | ||
| 290 | #undef FIND_FIELD | ||
| 291 | } | ||
| 292 | |||
| 293 | static void | ||
| 294 | android_init_integer (void) | ||
| 295 | { | ||
| 296 | jclass old; | ||
| 297 | |||
| 298 | integer_class.class | ||
| 299 | = (*android_java_env)->FindClass (android_java_env, | ||
| 300 | "java/lang/Integer"); | ||
| 301 | eassert (integer_class.class); | ||
| 302 | |||
| 303 | old = integer_class.class; | ||
| 304 | integer_class.class | ||
| 305 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 306 | (jobject) old); | ||
| 307 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 308 | |||
| 309 | if (!integer_class.class) | ||
| 310 | emacs_abort (); | ||
| 311 | |||
| 312 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 313 | integer_class.c_name \ | ||
| 314 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 315 | integer_class.class, \ | ||
| 316 | name, signature); \ | ||
| 317 | eassert (integer_class.c_name); | ||
| 318 | |||
| 319 | FIND_METHOD (constructor, "<init>", "(I)V"); | ||
| 320 | FIND_METHOD (int_value, "intValue", "()I"); | ||
| 321 | #undef FIND_METHOD | ||
| 322 | } | ||
| 323 | |||
| 324 | static void | ||
| 325 | android_init_font_object (void) | ||
| 326 | { | ||
| 327 | jclass old; | ||
| 328 | |||
| 329 | font_object_class.class | ||
| 330 | = (*android_java_env)->FindClass (android_java_env, | ||
| 331 | "org/gnu/emacs/EmacsFontDriver" | ||
| 332 | "$FontObject"); | ||
| 333 | eassert (font_object_class.class); | ||
| 334 | |||
| 335 | old = font_object_class.class; | ||
| 336 | font_object_class.class | ||
| 337 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 338 | (jobject) old); | ||
| 339 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 340 | |||
| 341 | if (!font_object_class.class) | ||
| 342 | emacs_abort (); | ||
| 343 | |||
| 344 | #define FIND_FIELD(c_name, name, signature) \ | ||
| 345 | font_object_class.c_name \ | ||
| 346 | = (*android_java_env)->GetFieldID (android_java_env, \ | ||
| 347 | font_object_class.class, \ | ||
| 348 | name, signature); \ | ||
| 349 | eassert (font_object_class.c_name); | ||
| 350 | |||
| 351 | FIND_FIELD (min_width, "minWidth", "I"); | ||
| 352 | FIND_FIELD (max_width, "maxWidth", "I"); | ||
| 353 | FIND_FIELD (pixel_size, "pixelSize", "I"); | ||
| 354 | FIND_FIELD (height, "height", "I"); | ||
| 355 | FIND_FIELD (space_width, "spaceWidth", "I"); | ||
| 356 | FIND_FIELD (average_width, "averageWidth", "I"); | ||
| 357 | FIND_FIELD (ascent, "ascent", "I"); | ||
| 358 | FIND_FIELD (descent, "descent", "I"); | ||
| 359 | FIND_FIELD (underline_thickness, "underlineThickness", "I"); | ||
| 360 | FIND_FIELD (underline_position, "underlinePosition", "I"); | ||
| 361 | FIND_FIELD (baseline_offset, "baselineOffset", "I"); | ||
| 362 | FIND_FIELD (relative_compose, "relativeCompose", "I"); | ||
| 363 | FIND_FIELD (default_ascent, "defaultAscent", "I"); | ||
| 364 | FIND_FIELD (encoding_charset, "encodingCharset", "I"); | ||
| 365 | FIND_FIELD (repertory_charset, "repertoryCharset", "I"); | ||
| 366 | #undef FIND_FIELD | ||
| 367 | } | ||
| 368 | |||
| 369 | static Lisp_Object | ||
| 370 | androidfont_get_cache (struct frame *frame) | ||
| 371 | { | ||
| 372 | return font_cache; | ||
| 373 | } | ||
| 374 | |||
| 375 | /* Return a local reference to an instance of EmacsFontDriver$FontSpec | ||
| 376 | with the same values as FONT. */ | ||
| 377 | |||
| 378 | static jobject | ||
| 379 | androidfont_from_lisp (Lisp_Object font) | ||
| 380 | { | ||
| 381 | jobject spec, integer; | ||
| 382 | jstring string; | ||
| 383 | Lisp_Object tem; | ||
| 384 | |||
| 385 | spec = (*android_java_env)->AllocObject (android_java_env, | ||
| 386 | font_spec_class.class); | ||
| 387 | |||
| 388 | if (!spec) | ||
| 389 | { | ||
| 390 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 391 | memory_full (0); | ||
| 392 | } | ||
| 393 | |||
| 394 | #define DO_SYMBOL_FIELD(field, index) \ | ||
| 395 | tem = AREF (font, index); \ | ||
| 396 | if (SYMBOLP (tem)) \ | ||
| 397 | { \ | ||
| 398 | /* Java seems to DTRT with the Emacs string encoding, so this does \ | ||
| 399 | not matter at all. */ \ | ||
| 400 | string = (*android_java_env)->NewStringUTF (android_java_env, \ | ||
| 401 | SSDATA (SYMBOL_NAME (tem))); \ | ||
| 402 | if (!string) \ | ||
| 403 | { \ | ||
| 404 | (*android_java_env)->ExceptionClear (android_java_env); \ | ||
| 405 | memory_full (0); \ | ||
| 406 | } \ | ||
| 407 | \ | ||
| 408 | (*android_java_env)->SetObjectField (android_java_env, spec, \ | ||
| 409 | font_spec_class.field, \ | ||
| 410 | string); \ | ||
| 411 | ANDROID_DELETE_LOCAL_REF (string); \ | ||
| 412 | } \ | ||
| 413 | |||
| 414 | DO_SYMBOL_FIELD (foundry, FONT_FOUNDRY_INDEX); | ||
| 415 | DO_SYMBOL_FIELD (family, FONT_FAMILY_INDEX); | ||
| 416 | DO_SYMBOL_FIELD (adstyle, FONT_ADSTYLE_INDEX); | ||
| 417 | DO_SYMBOL_FIELD (registry, FONT_REGISTRY_INDEX); | ||
| 418 | |||
| 419 | #undef DO_SYMBOL_FIELD | ||
| 420 | |||
| 421 | #define DO_CARDINAL_FIELD(field, value) \ | ||
| 422 | if (value != -1) \ | ||
| 423 | { \ | ||
| 424 | integer = (*android_java_env)->NewObject (android_java_env, \ | ||
| 425 | integer_class.class, \ | ||
| 426 | integer_class.constructor, \ | ||
| 427 | (jint) value); \ | ||
| 428 | if (!integer) \ | ||
| 429 | { \ | ||
| 430 | (*android_java_env)->ExceptionClear (android_java_env); \ | ||
| 431 | memory_full (0); \ | ||
| 432 | } \ | ||
| 433 | \ | ||
| 434 | (*android_java_env)->SetObjectField (android_java_env, spec, \ | ||
| 435 | font_spec_class.field, \ | ||
| 436 | integer); \ | ||
| 437 | ANDROID_DELETE_LOCAL_REF (integer); \ | ||
| 438 | } | ||
| 439 | |||
| 440 | DO_CARDINAL_FIELD (width, FONT_WIDTH_NUMERIC (font)); | ||
| 441 | DO_CARDINAL_FIELD (weight, FONT_WEIGHT_NUMERIC (font)); | ||
| 442 | DO_CARDINAL_FIELD (slant, FONT_SLANT_NUMERIC (font)); | ||
| 443 | DO_CARDINAL_FIELD (size, (FIXNUMP (AREF (font, FONT_SIZE_INDEX)) | ||
| 444 | ? XFIXNUM (AREF (font, FONT_SIZE_INDEX)) | ||
| 445 | : -1)); | ||
| 446 | DO_CARDINAL_FIELD (spacing, (FIXNUMP (AREF (font, FONT_SPACING_INDEX)) | ||
| 447 | ? XFIXNUM (AREF (font, FONT_SPACING_INDEX)) | ||
| 448 | : -1)); | ||
| 449 | DO_CARDINAL_FIELD (avgwidth, (FIXNUMP (AREF (font, FONT_AVGWIDTH_INDEX)) | ||
| 450 | ? XFIXNUM (AREF (font, FONT_AVGWIDTH_INDEX)) | ||
| 451 | : -1)); | ||
| 452 | |||
| 453 | #undef DO_CARDINAL_FIELD | ||
| 454 | |||
| 455 | return spec; | ||
| 456 | } | ||
| 457 | |||
| 458 | static void | ||
| 459 | androidfont_from_java (jobject spec, Lisp_Object entity) | ||
| 460 | { | ||
| 461 | jobject tem; | ||
| 462 | jint value; | ||
| 463 | const char *string; | ||
| 464 | |||
| 465 | #define DO_SYMBOL_FIELD(field, index) \ | ||
| 466 | tem = (*android_java_env)->GetObjectField (android_java_env, \ | ||
| 467 | spec, \ | ||
| 468 | font_spec_class.field); \ | ||
| 469 | if (tem) \ | ||
| 470 | { \ | ||
| 471 | string = (*android_java_env)->GetStringUTFChars (android_java_env, \ | ||
| 472 | tem, NULL); \ | ||
| 473 | if (!string) \ | ||
| 474 | memory_full (0); \ | ||
| 475 | ASET (entity, index, intern (string)); \ | ||
| 476 | (*android_java_env)->ReleaseStringUTFChars (android_java_env, \ | ||
| 477 | tem, string); \ | ||
| 478 | ANDROID_DELETE_LOCAL_REF (tem); \ | ||
| 479 | } | ||
| 480 | |||
| 481 | DO_SYMBOL_FIELD (foundry, FONT_FOUNDRY_INDEX); | ||
| 482 | DO_SYMBOL_FIELD (family, FONT_FAMILY_INDEX); | ||
| 483 | DO_SYMBOL_FIELD (adstyle, FONT_ADSTYLE_INDEX); | ||
| 484 | DO_SYMBOL_FIELD (registry, FONT_REGISTRY_INDEX); | ||
| 485 | |||
| 486 | #undef DO_SYMBOL_FIELD | ||
| 487 | #define DO_CARDINAL_FIELD(field, index, is_style) \ | ||
| 488 | tem = (*android_java_env)->GetObjectField (android_java_env, \ | ||
| 489 | spec, \ | ||
| 490 | font_spec_class.field); \ | ||
| 491 | if (tem) \ | ||
| 492 | { \ | ||
| 493 | value \ | ||
| 494 | = (*android_java_env)->CallIntMethod (android_java_env, \ | ||
| 495 | tem, \ | ||
| 496 | integer_class.int_value); \ | ||
| 497 | if (!is_style) \ | ||
| 498 | ASET (entity, index, make_fixnum (value)); \ | ||
| 499 | else \ | ||
| 500 | FONT_SET_STYLE (entity, index, make_fixnum (value)); \ | ||
| 501 | ANDROID_DELETE_LOCAL_REF (tem); \ | ||
| 502 | } | ||
| 503 | |||
| 504 | DO_CARDINAL_FIELD (width, FONT_WIDTH_INDEX, true); | ||
| 505 | DO_CARDINAL_FIELD (weight, FONT_WEIGHT_INDEX, true); | ||
| 506 | DO_CARDINAL_FIELD (slant, FONT_SLANT_INDEX, true); | ||
| 507 | DO_CARDINAL_FIELD (size, FONT_SIZE_INDEX, false); | ||
| 508 | DO_CARDINAL_FIELD (spacing, FONT_SPACING_INDEX, false); | ||
| 509 | DO_CARDINAL_FIELD (avgwidth, FONT_AVGWIDTH_INDEX, false); | ||
| 510 | #undef DO_CARDINAL_FIELD | ||
| 511 | } | ||
| 512 | |||
| 513 | /* Transfer the values from FONT, which must be some kind of font | ||
| 514 | entity, */ | ||
| 515 | |||
| 516 | static Lisp_Object | ||
| 517 | androidfont_list (struct frame *f, Lisp_Object font_spec) | ||
| 518 | { | ||
| 519 | jobject spec, array, tem; | ||
| 520 | jarray entities; | ||
| 521 | jsize i, size; | ||
| 522 | Lisp_Object value, entity; | ||
| 523 | struct androidfont_entity *info; | ||
| 524 | |||
| 525 | spec = androidfont_from_lisp (font_spec); | ||
| 526 | array = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 527 | font_driver, | ||
| 528 | font_driver_class.list, | ||
| 529 | spec); | ||
| 530 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 531 | ANDROID_DELETE_LOCAL_REF (spec); | ||
| 532 | |||
| 533 | if (!array) | ||
| 534 | memory_full (0); | ||
| 535 | |||
| 536 | entities = (jarray) array; | ||
| 537 | size = (*android_java_env)->GetArrayLength (android_java_env, | ||
| 538 | entities); | ||
| 539 | value = Qnil; | ||
| 540 | |||
| 541 | for (i = 0; i < size; ++i) | ||
| 542 | { | ||
| 543 | entity = font_make_entity_android (VECSIZE (struct androidfont_entity)); | ||
| 544 | info = (struct androidfont_entity *) XFONT_ENTITY (entity); | ||
| 545 | |||
| 546 | /* The type must be set correctly, or font_open_entity won't be | ||
| 547 | able to find the right font driver. */ | ||
| 548 | ASET (entity, FONT_TYPE_INDEX, Qandroid); | ||
| 549 | |||
| 550 | /* Clear this now in case GC happens without it set, which can | ||
| 551 | happen if androidfont_from_java runs out of memory. */ | ||
| 552 | info->object = NULL; | ||
| 553 | |||
| 554 | tem = (*android_java_env)->GetObjectArrayElement (android_java_env, | ||
| 555 | entities, i); | ||
| 556 | androidfont_from_java (tem, entity); | ||
| 557 | |||
| 558 | /* Now, make a global reference to the Java font entity. */ | ||
| 559 | info->object = (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 560 | (jobject) tem); | ||
| 561 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 562 | ANDROID_DELETE_LOCAL_REF (tem); | ||
| 563 | |||
| 564 | if (!info->object) | ||
| 565 | memory_full (0); | ||
| 566 | |||
| 567 | value = Fcons (entity, value); | ||
| 568 | } | ||
| 569 | |||
| 570 | ANDROID_DELETE_LOCAL_REF (entities); | ||
| 571 | return Fnreverse (value); | ||
| 572 | } | ||
| 573 | |||
| 574 | static Lisp_Object | ||
| 575 | androidfont_match (struct frame *f, Lisp_Object font_spec) | ||
| 576 | { | ||
| 577 | jobject spec, result; | ||
| 578 | Lisp_Object entity; | ||
| 579 | struct androidfont_entity *info; | ||
| 580 | |||
| 581 | spec = androidfont_from_lisp (font_spec); | ||
| 582 | result = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 583 | font_driver, | ||
| 584 | font_driver_class.match, | ||
| 585 | spec); | ||
| 586 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 587 | ANDROID_DELETE_LOCAL_REF (spec); | ||
| 588 | |||
| 589 | if (!result) | ||
| 590 | memory_full (0); | ||
| 591 | |||
| 592 | entity = font_make_entity_android (VECSIZE (struct androidfont_entity)); | ||
| 593 | info = (struct androidfont_entity *) XFONT_ENTITY (entity); | ||
| 594 | |||
| 595 | /* The type must be set correctly, or font_open_entity won't be able | ||
| 596 | to find the right font driver. */ | ||
| 597 | ASET (entity, FONT_TYPE_INDEX, Qandroid); | ||
| 598 | |||
| 599 | info->object = NULL; | ||
| 600 | androidfont_from_java (result, entity); | ||
| 601 | info->object = (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 602 | (jobject) result); | ||
| 603 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 604 | ANDROID_DELETE_LOCAL_REF (result); | ||
| 605 | |||
| 606 | if (!info->object) | ||
| 607 | memory_full (0); | ||
| 608 | |||
| 609 | return entity; | ||
| 610 | } | ||
| 611 | |||
| 612 | static int | ||
| 613 | androidfont_draw (struct glyph_string *s, int from, int to, | ||
| 614 | int x, int y, bool with_background) | ||
| 615 | { | ||
| 616 | return 0; | ||
| 617 | } | ||
| 618 | |||
| 619 | static Lisp_Object | ||
| 620 | androidfont_open_font (struct frame *f, Lisp_Object font_entity, int x) | ||
| 621 | { | ||
| 622 | struct androidfont_info *font_info; | ||
| 623 | struct androidfont_entity *entity; | ||
| 624 | struct font *font; | ||
| 625 | Lisp_Object font_object, tem; | ||
| 626 | jobject old; | ||
| 627 | jint value; | ||
| 628 | |||
| 629 | if (x <= 0) | ||
| 630 | { | ||
| 631 | /* Get pixel size from frame instead. */ | ||
| 632 | tem = get_frame_param (f, Qfontsize); | ||
| 633 | x = NILP (tem) ? 0 : XFIXNAT (tem); | ||
| 634 | } | ||
| 635 | |||
| 636 | __android_log_print (ANDROID_LOG_DEBUG, __func__, | ||
| 637 | "opening font entity %"pI"x:%d", | ||
| 638 | (EMACS_INT) font_entity, x); | ||
| 639 | |||
| 640 | entity = (struct androidfont_entity *) XFONT_ENTITY (font_entity); | ||
| 641 | |||
| 642 | block_input (); | ||
| 643 | font_object = font_make_object (VECSIZE (struct androidfont_info), | ||
| 644 | font_entity, x); | ||
| 645 | ASET (font_object, FONT_TYPE_INDEX, Qandroid); | ||
| 646 | font_info = (struct androidfont_info *) XFONT_OBJECT (font_object); | ||
| 647 | font = &font_info->font; | ||
| 648 | font->driver = &androidfont_driver; | ||
| 649 | |||
| 650 | /* Clear font_info->object early in case GC happens later on! */ | ||
| 651 | font_info->object = NULL; | ||
| 652 | unblock_input (); | ||
| 653 | |||
| 654 | font_info->object | ||
| 655 | = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 656 | font_driver, | ||
| 657 | font_driver_class.open_font, | ||
| 658 | entity->object, (jint) x); | ||
| 659 | if (!font_info->object) | ||
| 660 | { | ||
| 661 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 662 | return Qnil; | ||
| 663 | } | ||
| 664 | |||
| 665 | old = font_info->object; | ||
| 666 | font_info->object | ||
| 667 | = (*android_java_env)->NewGlobalRef (android_java_env, old); | ||
| 668 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 669 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 670 | |||
| 671 | if (!font_info->object) | ||
| 672 | return Qnil; | ||
| 673 | |||
| 674 | /* Copy the font attributes from the Java object. */ | ||
| 675 | androidfont_from_java (font_info->object, font_object); | ||
| 676 | |||
| 677 | /* Copy font attributes inside EmacsFontDriver$FontObject. */ | ||
| 678 | #define DO_CARDINAL_FIELD(field) \ | ||
| 679 | value \ | ||
| 680 | = (*android_java_env)->GetIntField (android_java_env, \ | ||
| 681 | font_info->object, \ | ||
| 682 | font_object_class.field); \ | ||
| 683 | font->field = value; | ||
| 684 | |||
| 685 | DO_CARDINAL_FIELD (min_width); | ||
| 686 | DO_CARDINAL_FIELD (max_width); | ||
| 687 | DO_CARDINAL_FIELD (pixel_size); | ||
| 688 | DO_CARDINAL_FIELD (height); | ||
| 689 | DO_CARDINAL_FIELD (space_width); | ||
| 690 | DO_CARDINAL_FIELD (average_width); | ||
| 691 | DO_CARDINAL_FIELD (ascent); | ||
| 692 | DO_CARDINAL_FIELD (descent); | ||
| 693 | DO_CARDINAL_FIELD (underline_thickness); | ||
| 694 | DO_CARDINAL_FIELD (underline_position); | ||
| 695 | DO_CARDINAL_FIELD (baseline_offset); | ||
| 696 | DO_CARDINAL_FIELD (relative_compose); | ||
| 697 | DO_CARDINAL_FIELD (default_ascent); | ||
| 698 | DO_CARDINAL_FIELD (encoding_charset); | ||
| 699 | DO_CARDINAL_FIELD (repertory_charset); | ||
| 700 | |||
| 701 | #undef DO_CARDINAL_FIELD | ||
| 702 | |||
| 703 | /* This should eventually become unnecessary. */ | ||
| 704 | font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil); | ||
| 705 | |||
| 706 | return font_object; | ||
| 707 | } | ||
| 708 | |||
| 709 | static void | ||
| 710 | androidfont_close_font (struct font *font) | ||
| 711 | { | ||
| 712 | struct androidfont_info *info; | ||
| 713 | |||
| 714 | info = (struct androidfont_info *) font; | ||
| 715 | |||
| 716 | /* If info->object is NULL, then FONT was unsuccessfully created, | ||
| 717 | and there is no global reference that has to be deleted. */ | ||
| 718 | |||
| 719 | if (!info->object) | ||
| 720 | return; | ||
| 721 | |||
| 722 | (*android_java_env)->DeleteGlobalRef (android_java_env, | ||
| 723 | info->object); | ||
| 724 | } | ||
| 725 | |||
| 726 | static int | ||
| 727 | androidfont_has_char (Lisp_Object font, int c) | ||
| 728 | { | ||
| 729 | struct androidfont_info *info; | ||
| 730 | struct androidfont_entity *entity; | ||
| 731 | |||
| 732 | if (FONT_ENTITY_P (font)) | ||
| 733 | { | ||
| 734 | entity = (struct androidfont_entity *) XFONT_ENTITY (font); | ||
| 735 | |||
| 736 | return (*android_java_env)->CallIntMethod (android_java_env, | ||
| 737 | font_driver, | ||
| 738 | font_driver_class.has_char, | ||
| 739 | entity->object, (jint) c); | ||
| 740 | } | ||
| 741 | else | ||
| 742 | { | ||
| 743 | info = (struct androidfont_info *) XFONT_OBJECT (font); | ||
| 744 | |||
| 745 | return (*android_java_env)->CallIntMethod (android_java_env, | ||
| 746 | font_driver, | ||
| 747 | font_driver_class.has_char, | ||
| 748 | info->object, (jint) c); | ||
| 749 | } | ||
| 750 | } | ||
| 751 | |||
| 752 | static unsigned | ||
| 753 | androidfont_encode_char (struct font *font, int c) | ||
| 754 | { | ||
| 755 | struct androidfont_info *info; | ||
| 756 | |||
| 757 | info = (struct androidfont_info *) font; | ||
| 758 | |||
| 759 | return (*android_java_env)->CallIntMethod (android_java_env, | ||
| 760 | font_driver, | ||
| 761 | font_driver_class.encode_char, | ||
| 762 | info->object, (jchar) c); | ||
| 763 | } | ||
| 764 | |||
| 765 | static void | ||
| 766 | androidfont_text_extents (struct font *font, const unsigned int *code, | ||
| 767 | int nglyphs, struct font_metrics *metrics) | ||
| 768 | { | ||
| 769 | struct androidfont_info *info; | ||
| 770 | jarray codepoint_array, metrics_array; | ||
| 771 | jobject metrics_object; | ||
| 772 | int i; | ||
| 773 | short value; | ||
| 774 | |||
| 775 | info = (struct androidfont_info *) font; | ||
| 776 | |||
| 777 | /* Allocate the arrays of code points and font metrics. */ | ||
| 778 | codepoint_array | ||
| 779 | = (*android_java_env)->NewIntArray (android_java_env, | ||
| 780 | nglyphs); | ||
| 781 | if (!codepoint_array) | ||
| 782 | { | ||
| 783 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 784 | memory_full (0); | ||
| 785 | } | ||
| 786 | |||
| 787 | metrics_array | ||
| 788 | = (*android_java_env)->NewObjectArray (android_java_env, | ||
| 789 | nglyphs, | ||
| 790 | font_metrics_class.class, | ||
| 791 | NULL); | ||
| 792 | if (!metrics_array) | ||
| 793 | { | ||
| 794 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 795 | ANDROID_DELETE_LOCAL_REF (metrics_array); | ||
| 796 | memory_full (0); | ||
| 797 | } | ||
| 798 | |||
| 799 | if (sizeof (unsigned int) == sizeof (jint)) | ||
| 800 | /* Always true on every Android device. */ | ||
| 801 | (*android_java_env)->SetIntArrayRegion (android_java_env, | ||
| 802 | codepoint_array, | ||
| 803 | 0, nglyphs, | ||
| 804 | (jint *) code); | ||
| 805 | else | ||
| 806 | emacs_abort (); | ||
| 807 | |||
| 808 | for (i = 0; i < nglyphs; ++i) | ||
| 809 | { | ||
| 810 | metrics_object | ||
| 811 | = (*android_java_env)->AllocObject (android_java_env, | ||
| 812 | font_metrics_class.class); | ||
| 813 | |||
| 814 | if (!metrics_object) | ||
| 815 | { | ||
| 816 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 817 | ANDROID_DELETE_LOCAL_REF (metrics_array); | ||
| 818 | ANDROID_DELETE_LOCAL_REF (codepoint_array); | ||
| 819 | memory_full (0); | ||
| 820 | } | ||
| 821 | |||
| 822 | (*android_java_env)->SetObjectArrayElement (android_java_env, | ||
| 823 | metrics_array, i, | ||
| 824 | metrics_object); | ||
| 825 | ANDROID_DELETE_LOCAL_REF (metrics_object); | ||
| 826 | } | ||
| 827 | |||
| 828 | (*android_java_env)->CallVoidMethod (android_java_env, | ||
| 829 | font_driver, | ||
| 830 | font_driver_class.text_extents, | ||
| 831 | info->object, codepoint_array, | ||
| 832 | metrics_array); | ||
| 833 | |||
| 834 | if ((*android_java_env)->ExceptionCheck (android_java_env)) | ||
| 835 | { | ||
| 836 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 837 | ANDROID_DELETE_LOCAL_REF (metrics_array); | ||
| 838 | ANDROID_DELETE_LOCAL_REF (codepoint_array); | ||
| 839 | memory_full (0); | ||
| 840 | } | ||
| 841 | |||
| 842 | for (i = 0; i < nglyphs; ++i) | ||
| 843 | { | ||
| 844 | metrics_object | ||
| 845 | = (*android_java_env)->GetObjectArrayElement (android_java_env, | ||
| 846 | metrics_array, i); | ||
| 847 | #define DO_CARDINAL_FIELD(field) \ | ||
| 848 | value \ | ||
| 849 | = (*android_java_env)->GetShortField (android_java_env, \ | ||
| 850 | metrics_object, \ | ||
| 851 | font_metrics_class.field); \ | ||
| 852 | metrics[i].field = value; | ||
| 853 | |||
| 854 | DO_CARDINAL_FIELD (lbearing); | ||
| 855 | DO_CARDINAL_FIELD (rbearing); | ||
| 856 | DO_CARDINAL_FIELD (width); | ||
| 857 | DO_CARDINAL_FIELD (ascent); | ||
| 858 | DO_CARDINAL_FIELD (descent); | ||
| 859 | |||
| 860 | #undef DO_CARDINAL_FIELD | ||
| 861 | |||
| 862 | ANDROID_DELETE_LOCAL_REF (metrics_object); | ||
| 863 | } | ||
| 864 | |||
| 865 | ANDROID_DELETE_LOCAL_REF (metrics_array); | ||
| 866 | ANDROID_DELETE_LOCAL_REF (codepoint_array); | ||
| 867 | } | ||
| 868 | |||
| 869 | static Lisp_Object | ||
| 870 | androidfont_list_family (struct frame *f) | ||
| 871 | { | ||
| 872 | return Qnil; | ||
| 873 | } | ||
| 874 | |||
| 875 | struct font_driver androidfont_driver = | ||
| 876 | { | ||
| 877 | .type = LISPSYM_INITIALLY (Qandroid), | ||
| 878 | .case_sensitive = true, | ||
| 879 | .get_cache = androidfont_get_cache, | ||
| 880 | .list = androidfont_list, | ||
| 881 | .match = androidfont_match, | ||
| 882 | .draw = androidfont_draw, | ||
| 883 | .open_font = androidfont_open_font, | ||
| 884 | .close_font = androidfont_close_font, | ||
| 885 | .has_char = androidfont_has_char, | ||
| 886 | .encode_char = androidfont_encode_char, | ||
| 887 | .text_extents = androidfont_text_extents, | ||
| 888 | .list_family = androidfont_list_family, | ||
| 889 | }; | ||
| 890 | |||
| 891 | static void | ||
| 892 | syms_of_androidfont_for_pdumper (void) | ||
| 893 | { | ||
| 894 | register_font_driver (&androidfont_driver, NULL); | ||
| 895 | } | ||
| 896 | |||
| 897 | void | ||
| 898 | syms_of_androidfont (void) | ||
| 899 | { | ||
| 900 | DEFSYM (Qfontsize, "fontsize"); | ||
| 901 | |||
| 902 | pdumper_do_now_and_after_load (syms_of_androidfont_for_pdumper); | ||
| 903 | |||
| 904 | font_cache = list (Qnil); | ||
| 905 | staticpro (&font_cache); | ||
| 906 | } | ||
| 907 | |||
| 908 | void | ||
| 909 | init_androidfont (void) | ||
| 910 | { | ||
| 911 | jmethodID method; | ||
| 912 | jobject old; | ||
| 913 | |||
| 914 | android_init_font_driver (); | ||
| 915 | android_init_font_spec (); | ||
| 916 | android_init_font_metrics (); | ||
| 917 | android_init_font_object (); | ||
| 918 | android_init_integer (); | ||
| 919 | |||
| 920 | method = font_driver_class.create_font_driver; | ||
| 921 | |||
| 922 | /* Initialize the font driver on the Java side. */ | ||
| 923 | font_driver | ||
| 924 | = (*android_java_env)->CallStaticObjectMethod (android_java_env, | ||
| 925 | font_driver_class.class, | ||
| 926 | method); | ||
| 927 | |||
| 928 | if (!font_driver) | ||
| 929 | memory_full (0); | ||
| 930 | |||
| 931 | old = font_driver; | ||
| 932 | font_driver | ||
| 933 | = (*android_java_env)->NewGlobalRef (android_java_env, font_driver); | ||
| 934 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 935 | |||
| 936 | if (!font_driver) | ||
| 937 | memory_full (0); | ||
| 938 | } | ||
| 939 | |||
| 940 | void | ||
| 941 | android_finalize_font_entity (struct font_entity *entity) | ||
| 942 | { | ||
| 943 | struct androidfont_entity *info; | ||
| 944 | |||
| 945 | info = (struct androidfont_entity *) entity; | ||
| 946 | |||
| 947 | if (info->object) | ||
| 948 | (*android_java_env)->DeleteGlobalRef (android_java_env, | ||
| 949 | info->object); | ||
| 950 | |||
| 951 | /* Not sure if this can be called twice. */ | ||
| 952 | info->object = NULL; | ||
| 953 | } | ||
| 954 | |||
| 955 | #endif | ||
diff --git a/src/androidgui.h b/src/androidgui.h new file mode 100644 index 00000000000..43ccc86e5c7 --- /dev/null +++ b/src/androidgui.h | |||
| @@ -0,0 +1,315 @@ | |||
| 1 | /* Android window system support. | ||
| 2 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 18 | |||
| 19 | #ifndef _ANDROID_GUI_H_ | ||
| 20 | #define _ANDROID_GUI_H_ | ||
| 21 | |||
| 22 | struct android_char_struct | ||
| 23 | { | ||
| 24 | int rbearing; | ||
| 25 | int lbearing; | ||
| 26 | int width; | ||
| 27 | int ascent; | ||
| 28 | int descent; | ||
| 29 | }; | ||
| 30 | |||
| 31 | typedef struct android_char_struct XCharStruct; | ||
| 32 | |||
| 33 | typedef unsigned short android_handle; | ||
| 34 | |||
| 35 | typedef android_handle android_pixmap, Emacs_Pixmap; | ||
| 36 | typedef android_handle android_window, Emacs_Window; | ||
| 37 | typedef android_handle android_gcontext, GContext; | ||
| 38 | typedef android_handle android_drawable, Drawable; | ||
| 39 | |||
| 40 | typedef unsigned int android_time; | ||
| 41 | |||
| 42 | struct android_rectangle | ||
| 43 | { | ||
| 44 | int x, y; | ||
| 45 | unsigned width, height; | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct android_point | ||
| 49 | { | ||
| 50 | int x, y; | ||
| 51 | }; | ||
| 52 | |||
| 53 | /* Keep this in sync with EmacsGC.java! */ | ||
| 54 | |||
| 55 | enum android_gc_function | ||
| 56 | { | ||
| 57 | ANDROID_GC_COPY = 0, | ||
| 58 | ANDROID_GC_XOR = 1, | ||
| 59 | }; | ||
| 60 | |||
| 61 | enum android_gc_value_mask | ||
| 62 | { | ||
| 63 | ANDROID_GC_FOREGROUND = (1 << 0), | ||
| 64 | ANDROID_GC_BACKGROUND = (1 << 1), | ||
| 65 | ANDROID_GC_FUNCTION = (1 << 2), | ||
| 66 | ANDROID_GC_CLIP_X_ORIGIN = (1 << 3), | ||
| 67 | ANDROID_GC_CLIP_Y_ORIGIN = (1 << 4), | ||
| 68 | ANDROID_GC_CLIP_MASK = (1 << 5), | ||
| 69 | ANDROID_GC_STIPPLE = (1 << 6), | ||
| 70 | ANDROID_GC_FILL_STYLE = (1 << 7), | ||
| 71 | ANDROID_GC_TILE_STIP_X_ORIGIN = (1 << 8), | ||
| 72 | ANDROID_GC_TILE_STIP_Y_ORIGIN = (1 << 9), | ||
| 73 | }; | ||
| 74 | |||
| 75 | enum android_fill_style | ||
| 76 | { | ||
| 77 | ANDROID_FILL_SOLID = 0, | ||
| 78 | ANDROID_FILL_OPAQUE_STIPPLED = 1, | ||
| 79 | }; | ||
| 80 | |||
| 81 | enum android_window_value_mask | ||
| 82 | { | ||
| 83 | ANDROID_CW_BACK_PIXEL = (1 << 1), | ||
| 84 | }; | ||
| 85 | |||
| 86 | struct android_set_window_attributes | ||
| 87 | { | ||
| 88 | /* The background pixel. */ | ||
| 89 | unsigned long background_pixel; | ||
| 90 | }; | ||
| 91 | |||
| 92 | struct android_gc_values | ||
| 93 | { | ||
| 94 | /* The foreground and background. */ | ||
| 95 | unsigned long foreground, background; | ||
| 96 | |||
| 97 | /* The function. */ | ||
| 98 | enum android_gc_function function; | ||
| 99 | |||
| 100 | /* The fill style. */ | ||
| 101 | enum android_fill_style fill_style; | ||
| 102 | |||
| 103 | /* The clip X and Y origin. */ | ||
| 104 | int clip_x_origin, clip_y_origin; | ||
| 105 | |||
| 106 | /* The clip mask image and stipple. */ | ||
| 107 | android_pixmap clip_mask, stipple; | ||
| 108 | |||
| 109 | /* The tile-stipple X and Y origins. */ | ||
| 110 | int ts_x_origin, ts_y_origin; | ||
| 111 | }; | ||
| 112 | |||
| 113 | /* X-like graphics context structure. This is implemented in | ||
| 114 | EmacsGC.java, but a copy is kept here to avoid sending changes all | ||
| 115 | the time. */ | ||
| 116 | |||
| 117 | struct android_gc | ||
| 118 | { | ||
| 119 | /* The Java-side handle. */ | ||
| 120 | android_gcontext gcontext; | ||
| 121 | }; | ||
| 122 | |||
| 123 | enum android_swap_action | ||
| 124 | { | ||
| 125 | ANDROID_COPIED, | ||
| 126 | }; | ||
| 127 | |||
| 128 | enum android_shape | ||
| 129 | { | ||
| 130 | ANDROID_CONVEX, | ||
| 131 | }; | ||
| 132 | |||
| 133 | enum android_coord_mode | ||
| 134 | { | ||
| 135 | ANDROID_COORD_MODE_ORIGIN, | ||
| 136 | }; | ||
| 137 | |||
| 138 | struct android_swap_info | ||
| 139 | { | ||
| 140 | /* The window to swap. */ | ||
| 141 | android_window swap_window; | ||
| 142 | |||
| 143 | /* Unused field present only for consistency with X. */ | ||
| 144 | enum android_swap_action swap_action; | ||
| 145 | }; | ||
| 146 | |||
| 147 | /* Android doesn't support cursors, so define this to something | ||
| 148 | unused. */ | ||
| 149 | typedef char Emacs_Cursor; | ||
| 150 | |||
| 151 | #define NativeRectangle Emacs_Rectangle | ||
| 152 | #define CONVERT_TO_NATIVE_RECT(xr, nr) ((xr) = (nr)) | ||
| 153 | #define CONVERT_FROM_EMACS_RECT(xr, nr) ((nr) = (xr)) | ||
| 154 | |||
| 155 | #define STORE_NATIVE_RECT(nr, rx, ry, rwidth, rheight) \ | ||
| 156 | ((nr).x = (rx), (nr).y = (ry), \ | ||
| 157 | (nr).width = (rwidth), (nr).height = (rheight)) \ | ||
| 158 | |||
| 159 | #define ForgetGravity 0 | ||
| 160 | #define NorthWestGravity 1 | ||
| 161 | #define NorthGravity 2 | ||
| 162 | #define NorthEastGravity 3 | ||
| 163 | #define WestGravity 4 | ||
| 164 | #define CenterGravity 5 | ||
| 165 | #define EastGravity 6 | ||
| 166 | #define SouthWestGravity 7 | ||
| 167 | #define SouthGravity 8 | ||
| 168 | #define SouthEastGravity 9 | ||
| 169 | #define StaticGravity 10 | ||
| 170 | |||
| 171 | #define NoValue 0x0000 | ||
| 172 | #define XValue 0x0001 | ||
| 173 | #define YValue 0x0002 | ||
| 174 | #define WidthValue 0x0004 | ||
| 175 | #define HeightValue 0x0008 | ||
| 176 | #define AllValues 0x000F | ||
| 177 | #define XNegative 0x0010 | ||
| 178 | #define YNegative 0x0020 | ||
| 179 | |||
| 180 | #define USPosition (1L << 0) /* user specified x, y */ | ||
| 181 | #define USSize (1L << 1) /* user specified width, height */ | ||
| 182 | #define PPosition (1L << 2) /* program specified position */ | ||
| 183 | #define PSize (1L << 3) /* program specified size */ | ||
| 184 | #define PMinSize (1L << 4) /* program specified minimum size */ | ||
| 185 | #define PMaxSize (1L << 5) /* program specified maximum size */ | ||
| 186 | #define PResizeInc (1L << 6) /* program specified resize increments */ | ||
| 187 | #define PAspect (1L << 7) /* program specified min, max aspect ratios */ | ||
| 188 | #define PBaseSize (1L << 8) /* program specified base for incrementing */ | ||
| 189 | #define PWinGravity (1L << 9) /* program specified window gravity */ | ||
| 190 | |||
| 191 | #ifndef ANDROID_STUBIFY | ||
| 192 | |||
| 193 | /* Universal NULL handle. */ | ||
| 194 | static const int ANDROID_NONE; | ||
| 195 | |||
| 196 | /* Keep these as conceptually close to X as possible: that makes | ||
| 197 | synchronizing code between the ports much easier. */ | ||
| 198 | |||
| 199 | enum android_event_type | ||
| 200 | { | ||
| 201 | ANDROID_KEY_PRESS, | ||
| 202 | ANDROID_KEY_RELEASE, | ||
| 203 | ANDROID_CONFIGURE_NOTIFY, | ||
| 204 | }; | ||
| 205 | |||
| 206 | struct android_any_event | ||
| 207 | { | ||
| 208 | enum android_event_type type; | ||
| 209 | android_window window; | ||
| 210 | }; | ||
| 211 | |||
| 212 | struct android_key_event | ||
| 213 | { | ||
| 214 | enum android_event_type type; | ||
| 215 | android_window window; | ||
| 216 | android_time time; | ||
| 217 | unsigned int state; | ||
| 218 | unsigned int keycode; | ||
| 219 | }; | ||
| 220 | |||
| 221 | struct android_configure_event | ||
| 222 | { | ||
| 223 | enum android_event_type type; | ||
| 224 | android_window window; | ||
| 225 | android_time time; | ||
| 226 | int x, y; | ||
| 227 | int width, height; | ||
| 228 | }; | ||
| 229 | |||
| 230 | union android_event | ||
| 231 | { | ||
| 232 | enum android_event_type type; | ||
| 233 | struct android_any_event xany; | ||
| 234 | struct android_key_event xkey; | ||
| 235 | struct android_configure_event xconfigure; | ||
| 236 | }; | ||
| 237 | |||
| 238 | extern int android_pending (void); | ||
| 239 | extern void android_next_event (union android_event *); | ||
| 240 | |||
| 241 | extern android_window android_create_window (android_window, int, | ||
| 242 | int, int, int, | ||
| 243 | enum android_window_value_mask, | ||
| 244 | struct | ||
| 245 | android_set_window_attributes *); | ||
| 246 | extern void android_change_window_attributes (android_window, | ||
| 247 | enum android_window_value_mask, | ||
| 248 | struct | ||
| 249 | android_set_window_attributes *); | ||
| 250 | extern void android_set_window_background (android_window, unsigned long); | ||
| 251 | extern void android_destroy_window (android_window); | ||
| 252 | extern void android_reparent_window (android_window, android_window, | ||
| 253 | int, int); | ||
| 254 | extern void android_set_clip_rectangles (struct android_gc *, | ||
| 255 | int, int, | ||
| 256 | struct android_rectangle *, | ||
| 257 | int); | ||
| 258 | extern void android_change_gc (struct android_gc *, | ||
| 259 | enum android_gc_value_mask, | ||
| 260 | struct android_gc_values *); | ||
| 261 | |||
| 262 | extern void android_clear_window (android_window); | ||
| 263 | extern void android_map_window (android_window); | ||
| 264 | extern void android_unmap_window (android_window); | ||
| 265 | extern void android_resize_window (android_window, unsigned int, | ||
| 266 | unsigned int); | ||
| 267 | extern void android_move_window (android_window, int, int); | ||
| 268 | extern void android_swap_buffers (struct android_swap_info *, int); | ||
| 269 | extern void android_get_gc_values (struct android_gc *, | ||
| 270 | enum android_gc_value_mask, | ||
| 271 | struct android_gc_values *); | ||
| 272 | extern void android_set_foreground (struct android_gc *, | ||
| 273 | unsigned long); | ||
| 274 | extern void android_fill_rectangle (android_drawable, struct android_gc *, | ||
| 275 | int, int, unsigned int, unsigned int); | ||
| 276 | extern android_pixmap android_create_pixmap_from_bitmap_data (char *, | ||
| 277 | unsigned int, | ||
| 278 | unsigned int, | ||
| 279 | unsigned long, | ||
| 280 | unsigned long, | ||
| 281 | unsigned int); | ||
| 282 | extern void android_set_clip_mask (struct android_gc *, android_pixmap); | ||
| 283 | extern void android_set_fill_style (struct android_gc *, | ||
| 284 | enum android_fill_style); | ||
| 285 | extern void android_copy_area (android_drawable, android_drawable, | ||
| 286 | struct android_gc *, int, int, | ||
| 287 | unsigned int, unsigned int, int, int); | ||
| 288 | extern void android_free_pixmap (android_drawable); | ||
| 289 | |||
| 290 | extern void android_set_background (struct android_gc *, unsigned long); | ||
| 291 | extern void android_fill_polygon (android_drawable, struct android_gc *, | ||
| 292 | struct android_point *, int, | ||
| 293 | enum android_shape, | ||
| 294 | enum android_coord_mode); | ||
| 295 | extern void android_draw_rectangle (android_drawable, struct android_gc *, | ||
| 296 | int, int, unsigned int, unsigned int); | ||
| 297 | extern void android_draw_point (android_window, struct android_gc *, | ||
| 298 | int, int); | ||
| 299 | extern void android_draw_line (android_window, struct android_gc *, | ||
| 300 | int, int, int, int); | ||
| 301 | extern android_pixmap android_create_pixmap (unsigned int, unsigned int, | ||
| 302 | int); | ||
| 303 | extern void android_set_ts_origin (struct android_gc *, int, int); | ||
| 304 | extern void android_clear_area (android_window, int, int, unsigned int, | ||
| 305 | unsigned int); | ||
| 306 | |||
| 307 | #endif | ||
| 308 | |||
| 309 | /* X emulation stuff also needed while building stubs. */ | ||
| 310 | |||
| 311 | extern struct android_gc *android_create_gc (enum android_gc_value_mask, | ||
| 312 | struct android_gc_values *); | ||
| 313 | extern void android_free_gc (struct android_gc *); | ||
| 314 | |||
| 315 | #endif /* _ANDROID_GUI_H_ */ | ||
diff --git a/src/androidterm.c b/src/androidterm.c new file mode 100644 index 00000000000..bb3c2a29737 --- /dev/null +++ b/src/androidterm.c | |||
| @@ -0,0 +1,3161 @@ | |||
| 1 | /* Communication module for Android terminals. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | #include <stdio.h> | ||
| 22 | |||
| 23 | #include "lisp.h" | ||
| 24 | #include "androidterm.h" | ||
| 25 | #include "keyboard.h" | ||
| 26 | #include "blockinput.h" | ||
| 27 | #include "android.h" | ||
| 28 | #include "buffer.h" | ||
| 29 | #include "window.h" | ||
| 30 | |||
| 31 | /* This is a chain of structures for all the X displays currently in | ||
| 32 | use. */ | ||
| 33 | |||
| 34 | struct android_display_info *x_display_list; | ||
| 35 | |||
| 36 | |||
| 37 | |||
| 38 | /* Android terminal interface functions. */ | ||
| 39 | |||
| 40 | #ifndef ANDROID_STUBIFY | ||
| 41 | |||
| 42 | enum | ||
| 43 | { | ||
| 44 | ANDROID_EVENT_NORMAL, | ||
| 45 | ANDROID_EVENT_GOTO_OUT, | ||
| 46 | ANDROID_EVENT_DROP, | ||
| 47 | }; | ||
| 48 | |||
| 49 | static struct frame * | ||
| 50 | android_window_to_frame (struct android_display_info *dpyinfo, | ||
| 51 | android_window wdesc) | ||
| 52 | { | ||
| 53 | Lisp_Object tail, frame; | ||
| 54 | struct frame *f; | ||
| 55 | |||
| 56 | if (wdesc == ANDROID_NONE) | ||
| 57 | return NULL; | ||
| 58 | |||
| 59 | FOR_EACH_FRAME (tail, frame) | ||
| 60 | { | ||
| 61 | f = XFRAME (frame); | ||
| 62 | |||
| 63 | if (!FRAME_ANDROID_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo) | ||
| 64 | continue; | ||
| 65 | |||
| 66 | if (FRAME_ANDROID_WINDOW (f) == wdesc) | ||
| 67 | return f; | ||
| 68 | } | ||
| 69 | |||
| 70 | return NULL; | ||
| 71 | } | ||
| 72 | |||
| 73 | static void | ||
| 74 | android_clear_frame (struct frame *f) | ||
| 75 | { | ||
| 76 | /* Clearing the frame will erase any cursor, so mark them all as no | ||
| 77 | longer visible. */ | ||
| 78 | mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f))); | ||
| 79 | android_clear_window (FRAME_ANDROID_WINDOW (f)); | ||
| 80 | } | ||
| 81 | |||
| 82 | static void | ||
| 83 | android_ring_bell (struct frame *f) | ||
| 84 | { | ||
| 85 | /* TODO */ | ||
| 86 | } | ||
| 87 | |||
| 88 | static void | ||
| 89 | android_toggle_invisible_pointer (struct frame *f, bool invisible) | ||
| 90 | { | ||
| 91 | /* TODO */ | ||
| 92 | } | ||
| 93 | |||
| 94 | /* Start an update of frame F. This function is installed as a hook | ||
| 95 | for update_begin, i.e. it is called when update_begin is called. | ||
| 96 | This function is called prior to calls to gui_update_window_begin | ||
| 97 | for each window being updated. Currently, there is nothing to do | ||
| 98 | here because all interesting stuff is done on a window basis. */ | ||
| 99 | |||
| 100 | static void | ||
| 101 | android_update_begin (struct frame *f) | ||
| 102 | { | ||
| 103 | /* The frame is no longer complete, as it is in the midst of an | ||
| 104 | update. */ | ||
| 105 | FRAME_ANDROID_COMPLETE_P (f) = false; | ||
| 106 | } | ||
| 107 | |||
| 108 | /* End update of frame F. This function is installed as a hook in | ||
| 109 | update_end. */ | ||
| 110 | |||
| 111 | static void | ||
| 112 | android_update_end (struct frame *f) | ||
| 113 | { | ||
| 114 | /* Mouse highlight may be displayed again. */ | ||
| 115 | MOUSE_HL_INFO (f)->mouse_face_defer = false; | ||
| 116 | } | ||
| 117 | |||
| 118 | static void | ||
| 119 | show_back_buffer (struct frame *f) | ||
| 120 | { | ||
| 121 | struct android_swap_info swap_info; | ||
| 122 | |||
| 123 | memset (&swap_info, 0, sizeof (swap_info)); | ||
| 124 | swap_info.swap_window = FRAME_ANDROID_WINDOW (f); | ||
| 125 | swap_info.swap_action = ANDROID_COPIED; | ||
| 126 | android_swap_buffers (&swap_info, 1); | ||
| 127 | } | ||
| 128 | |||
| 129 | /* Flip back buffers on F if it has undrawn content. */ | ||
| 130 | |||
| 131 | static void | ||
| 132 | android_flush_dirty_back_buffer_on (struct frame *f) | ||
| 133 | { | ||
| 134 | if (FRAME_GARBAGED_P (f) | ||
| 135 | || buffer_flipping_blocked_p () | ||
| 136 | /* If the frame is not already up to date, do not flush buffers | ||
| 137 | on input, as that will result in flicker. */ | ||
| 138 | || !FRAME_ANDROID_COMPLETE_P (f)) | ||
| 139 | return; | ||
| 140 | |||
| 141 | show_back_buffer (f); | ||
| 142 | } | ||
| 143 | |||
| 144 | static int | ||
| 145 | handle_one_android_event (struct android_display_info *dpyinfo, | ||
| 146 | union android_event *event, int *finish, | ||
| 147 | struct input_event *hold_quit) | ||
| 148 | { | ||
| 149 | union android_event configureEvent; | ||
| 150 | struct frame *f, *any, *mouse_frame; | ||
| 151 | Mouse_HLInfo *hlinfo; | ||
| 152 | |||
| 153 | hlinfo = &dpyinfo->mouse_highlight; | ||
| 154 | *finish = ANDROID_EVENT_NORMAL; | ||
| 155 | any = android_window_to_frame (dpyinfo, event->xany.window); | ||
| 156 | |||
| 157 | switch (event->type) | ||
| 158 | { | ||
| 159 | case ANDROID_CONFIGURE_NOTIFY: | ||
| 160 | configureEvent = *event; | ||
| 161 | |||
| 162 | f = android_window_to_frame (dpyinfo, | ||
| 163 | configureEvent.xconfigure.window); | ||
| 164 | |||
| 165 | int width = configureEvent.xconfigure.width; | ||
| 166 | int height = configureEvent.xconfigure.height; | ||
| 167 | |||
| 168 | if (CONSP (frame_size_history)) | ||
| 169 | frame_size_history_extra (f, build_string ("ConfigureNotify"), | ||
| 170 | FRAME_PIXEL_WIDTH (f), | ||
| 171 | FRAME_PIXEL_HEIGHT (f), | ||
| 172 | width, height, f->new_width, | ||
| 173 | f->new_height); | ||
| 174 | |||
| 175 | /* Even if the number of character rows and columns has | ||
| 176 | not changed, the font size may have changed, so we need | ||
| 177 | to check the pixel dimensions as well. */ | ||
| 178 | |||
| 179 | if (width != FRAME_PIXEL_WIDTH (f) | ||
| 180 | || height != FRAME_PIXEL_HEIGHT (f) | ||
| 181 | || (f->new_size_p | ||
| 182 | && ((f->new_width >= 0 && width != f->new_width) | ||
| 183 | || (f->new_height >= 0 && height != f->new_height)))) | ||
| 184 | { | ||
| 185 | change_frame_size (f, width, height, false, true, false); | ||
| 186 | android_clear_under_internal_border (f); | ||
| 187 | SET_FRAME_GARBAGED (f); | ||
| 188 | cancel_mouse_face (f); | ||
| 189 | } | ||
| 190 | |||
| 191 | goto OTHER; | ||
| 192 | |||
| 193 | case ANDROID_KEY_PRESS: | ||
| 194 | |||
| 195 | /* If mouse-highlight is an integer, input clears out | ||
| 196 | mouse highlighting. */ | ||
| 197 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) | ||
| 198 | && (any == 0 | ||
| 199 | || !EQ (f->tool_bar_window, hlinfo->mouse_face_window) | ||
| 200 | || !EQ (f->tab_bar_window, hlinfo->mouse_face_window))) | ||
| 201 | { | ||
| 202 | mouse_frame = hlinfo->mouse_face_mouse_frame; | ||
| 203 | |||
| 204 | clear_mouse_face (hlinfo); | ||
| 205 | hlinfo->mouse_face_hidden = true; | ||
| 206 | |||
| 207 | if (mouse_frame) | ||
| 208 | android_flush_dirty_back_buffer_on (mouse_frame); | ||
| 209 | } | ||
| 210 | |||
| 211 | default: | ||
| 212 | goto OTHER; | ||
| 213 | } | ||
| 214 | |||
| 215 | OTHER: | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int | ||
| 221 | android_read_socket (struct terminal *terminal, | ||
| 222 | struct input_event *hold_quit) | ||
| 223 | { | ||
| 224 | int count = 0; | ||
| 225 | struct android_display_info *dpyinfo; | ||
| 226 | |||
| 227 | dpyinfo = terminal->display_info.android; | ||
| 228 | |||
| 229 | block_input (); | ||
| 230 | while (android_pending ()) | ||
| 231 | { | ||
| 232 | int finish; | ||
| 233 | union android_event event; | ||
| 234 | |||
| 235 | android_next_event (&event); | ||
| 236 | count += handle_one_android_event (dpyinfo, &event, &finish, | ||
| 237 | hold_quit); | ||
| 238 | |||
| 239 | if (finish == ANDROID_EVENT_GOTO_OUT) | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | unblock_input (); | ||
| 243 | |||
| 244 | /* If the focus was just given to an auto-raising frame, raise it | ||
| 245 | now. */ | ||
| 246 | if (dpyinfo->pending_autoraise_frame) | ||
| 247 | { | ||
| 248 | /* android_raise_frame (dpyinfo->pending_autoraise_frame); | ||
| 249 | TODO */ | ||
| 250 | dpyinfo->pending_autoraise_frame = NULL; | ||
| 251 | } | ||
| 252 | |||
| 253 | return count; | ||
| 254 | } | ||
| 255 | |||
| 256 | static void | ||
| 257 | android_frame_up_to_date (struct frame *f) | ||
| 258 | { | ||
| 259 | eassert (FRAME_ANDROID_P (f)); | ||
| 260 | block_input (); | ||
| 261 | FRAME_MOUSE_UPDATE (f); | ||
| 262 | |||
| 263 | if (!buffer_flipping_blocked_p ()) | ||
| 264 | show_back_buffer (f); | ||
| 265 | |||
| 266 | /* The frame is now complete, as its contents have been drawn. */ | ||
| 267 | FRAME_ANDROID_COMPLETE_P (f) = true; | ||
| 268 | unblock_input (); | ||
| 269 | } | ||
| 270 | |||
| 271 | static void | ||
| 272 | android_buffer_flipping_unblocked_hook (struct frame *f) | ||
| 273 | { | ||
| 274 | block_input (); | ||
| 275 | show_back_buffer (f); | ||
| 276 | unblock_input (); | ||
| 277 | } | ||
| 278 | |||
| 279 | static void | ||
| 280 | android_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor) | ||
| 281 | { | ||
| 282 | unsigned long background; | ||
| 283 | |||
| 284 | background = FRAME_BACKGROUND_PIXEL (f); | ||
| 285 | bgcolor->pixel = background; | ||
| 286 | |||
| 287 | android_query_colors (f, bgcolor, 1); | ||
| 288 | } | ||
| 289 | |||
| 290 | int | ||
| 291 | android_parse_color (struct frame *f, const char *color_name, | ||
| 292 | Emacs_Color *color) | ||
| 293 | { | ||
| 294 | unsigned short r, g, b; | ||
| 295 | Lisp_Object tem, tem1; | ||
| 296 | unsigned long lisp_color; | ||
| 297 | |||
| 298 | if (parse_color_spec (color_name, &r, &g, &b)) | ||
| 299 | { | ||
| 300 | color->red = r; | ||
| 301 | color->green = g; | ||
| 302 | color->blue = b; | ||
| 303 | |||
| 304 | return 1; | ||
| 305 | } | ||
| 306 | |||
| 307 | tem = x_display_list->color_map; | ||
| 308 | for (; CONSP (tem); tem = XCDR (tem)) | ||
| 309 | { | ||
| 310 | tem1 = XCAR (tem); | ||
| 311 | |||
| 312 | if (CONSP (tem1) | ||
| 313 | && !xstrcasecmp (SSDATA (XCAR (tem1)), color_name)) | ||
| 314 | { | ||
| 315 | lisp_color = XFIXNUM (XCDR (tem1)); | ||
| 316 | color->red = RED_FROM_ULONG (lisp_color) * 257; | ||
| 317 | color->green = GREEN_FROM_ULONG (lisp_color) * 257; | ||
| 318 | color->blue = BLUE_FROM_ULONG (lisp_color) * 257; | ||
| 319 | return 1; | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | bool | ||
| 327 | android_alloc_nearest_color (struct frame *f, Emacs_Color *color) | ||
| 328 | { | ||
| 329 | gamma_correct (f, color); | ||
| 330 | color->pixel = RGB_TO_ULONG (color->red / 256, | ||
| 331 | color->green / 256, | ||
| 332 | color->blue / 256); | ||
| 333 | |||
| 334 | return true; | ||
| 335 | } | ||
| 336 | |||
| 337 | void | ||
| 338 | android_query_colors (struct frame *f, Emacs_Color *colors, int ncolors) | ||
| 339 | { | ||
| 340 | int i; | ||
| 341 | |||
| 342 | for (i = 0; i < ncolors; ++i) | ||
| 343 | { | ||
| 344 | colors[i].red = RED_FROM_ULONG (colors[i].pixel) * 257; | ||
| 345 | colors[i].green = RED_FROM_ULONG (colors[i].pixel) * 257; | ||
| 346 | colors[i].blue = RED_FROM_ULONG (colors[i].pixel) * 257; | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | static void | ||
| 351 | android_mouse_position (struct frame **fp, int insist, | ||
| 352 | Lisp_Object *bar_window, | ||
| 353 | enum scroll_bar_part *part, Lisp_Object *x, | ||
| 354 | Lisp_Object *y, Time *timestamp) | ||
| 355 | { | ||
| 356 | /* TODO */ | ||
| 357 | } | ||
| 358 | |||
| 359 | static Lisp_Object | ||
| 360 | android_get_focus_frame (struct frame *f) | ||
| 361 | { | ||
| 362 | Lisp_Object lisp_focus; | ||
| 363 | struct frame *focus; | ||
| 364 | |||
| 365 | focus = FRAME_DISPLAY_INFO (f)->focus_frame; | ||
| 366 | |||
| 367 | if (!focus) | ||
| 368 | return Qnil; | ||
| 369 | |||
| 370 | XSETFRAME (lisp_focus, focus); | ||
| 371 | return lisp_focus; | ||
| 372 | } | ||
| 373 | |||
| 374 | static void | ||
| 375 | android_focus_frame (struct frame *f, bool noactivate) | ||
| 376 | { | ||
| 377 | /* TODO */ | ||
| 378 | } | ||
| 379 | |||
| 380 | static void | ||
| 381 | android_frame_rehighlight (struct frame *f) | ||
| 382 | { | ||
| 383 | /* TODO */ | ||
| 384 | } | ||
| 385 | |||
| 386 | static void | ||
| 387 | android_frame_raise_lower (struct frame *f, bool raise_flag) | ||
| 388 | { | ||
| 389 | /* TODO */ | ||
| 390 | } | ||
| 391 | |||
| 392 | void | ||
| 393 | android_make_frame_visible (struct frame *f) | ||
| 394 | { | ||
| 395 | android_map_window (FRAME_ANDROID_WINDOW (f)); | ||
| 396 | |||
| 397 | SET_FRAME_VISIBLE (f, true); | ||
| 398 | SET_FRAME_ICONIFIED (f, false); | ||
| 399 | } | ||
| 400 | |||
| 401 | void | ||
| 402 | android_make_frame_invisible (struct frame *f) | ||
| 403 | { | ||
| 404 | android_unmap_window (FRAME_ANDROID_WINDOW (f)); | ||
| 405 | |||
| 406 | SET_FRAME_VISIBLE (f, false); | ||
| 407 | SET_FRAME_ICONIFIED (f, false); | ||
| 408 | } | ||
| 409 | |||
| 410 | static void | ||
| 411 | android_make_frame_visible_invisible (struct frame *f, bool visible) | ||
| 412 | { | ||
| 413 | if (visible) | ||
| 414 | android_make_frame_visible (f); | ||
| 415 | else | ||
| 416 | android_make_frame_invisible (f); | ||
| 417 | } | ||
| 418 | |||
| 419 | static void | ||
| 420 | android_fullscreen_hook (struct frame *f) | ||
| 421 | { | ||
| 422 | /* TODO */ | ||
| 423 | } | ||
| 424 | |||
| 425 | void | ||
| 426 | android_iconify_frame (struct frame *f) | ||
| 427 | { | ||
| 428 | /* TODO */ | ||
| 429 | } | ||
| 430 | |||
| 431 | static void | ||
| 432 | android_set_window_size_1 (struct frame *f, bool change_gravity, | ||
| 433 | int width, int height) | ||
| 434 | { | ||
| 435 | if (change_gravity) | ||
| 436 | f->win_gravity = NorthWestGravity; | ||
| 437 | |||
| 438 | android_resize_window (FRAME_ANDROID_WINDOW (f), width, | ||
| 439 | height); | ||
| 440 | |||
| 441 | /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to | ||
| 442 | receive in the ConfigureNotify event; if we get what we asked | ||
| 443 | for, then the event won't cause the screen to become garbaged, so | ||
| 444 | we have to make sure to do it here. */ | ||
| 445 | SET_FRAME_GARBAGED (f); | ||
| 446 | } | ||
| 447 | |||
| 448 | void | ||
| 449 | android_set_window_size (struct frame *f, bool change_gravity, | ||
| 450 | int width, int height) | ||
| 451 | { | ||
| 452 | block_input (); | ||
| 453 | |||
| 454 | android_set_window_size_1 (f, change_gravity, width, height); | ||
| 455 | android_clear_under_internal_border (f); | ||
| 456 | |||
| 457 | /* If cursor was outside the new size, mark it as off. */ | ||
| 458 | mark_window_cursors_off (XWINDOW (f->root_window)); | ||
| 459 | |||
| 460 | /* Clear out any recollection of where the mouse highlighting was, | ||
| 461 | since it might be in a place that's outside the new frame size. | ||
| 462 | Actually checking whether it is outside is a pain in the neck, | ||
| 463 | so don't try--just let the highlighting be done afresh with new size. */ | ||
| 464 | cancel_mouse_face (f); | ||
| 465 | |||
| 466 | unblock_input (); | ||
| 467 | |||
| 468 | do_pending_window_change (false); | ||
| 469 | } | ||
| 470 | |||
| 471 | static void | ||
| 472 | android_set_offset (struct frame *f, int xoff, int yoff, | ||
| 473 | int change_gravity) | ||
| 474 | { | ||
| 475 | if (change_gravity > 0) | ||
| 476 | { | ||
| 477 | f->top_pos = yoff; | ||
| 478 | f->left_pos = xoff; | ||
| 479 | f->size_hint_flags &= ~ (XNegative | YNegative); | ||
| 480 | if (xoff < 0) | ||
| 481 | f->size_hint_flags |= XNegative; | ||
| 482 | if (yoff < 0) | ||
| 483 | f->size_hint_flags |= YNegative; | ||
| 484 | f->win_gravity = NorthWestGravity; | ||
| 485 | } | ||
| 486 | |||
| 487 | android_move_window (FRAME_ANDROID_WINDOW (f), xoff, yoff); | ||
| 488 | } | ||
| 489 | |||
| 490 | static void | ||
| 491 | android_set_alpha (struct frame *f) | ||
| 492 | { | ||
| 493 | /* TODO */ | ||
| 494 | } | ||
| 495 | |||
| 496 | static Lisp_Object | ||
| 497 | android_new_font (struct frame *f, Lisp_Object font_object, int fontset) | ||
| 498 | { | ||
| 499 | struct font *font = XFONT_OBJECT (font_object); | ||
| 500 | int unit, font_ascent, font_descent; | ||
| 501 | |||
| 502 | if (fontset < 0) | ||
| 503 | fontset = fontset_from_font (font_object); | ||
| 504 | FRAME_FONTSET (f) = fontset; | ||
| 505 | if (FRAME_FONT (f) == font) | ||
| 506 | /* This font is already set in frame F. There's nothing more to | ||
| 507 | do. */ | ||
| 508 | return font_object; | ||
| 509 | |||
| 510 | FRAME_FONT (f) = font; | ||
| 511 | FRAME_BASELINE_OFFSET (f) = font->baseline_offset; | ||
| 512 | FRAME_COLUMN_WIDTH (f) = font->average_width; | ||
| 513 | get_font_ascent_descent (font, &font_ascent, &font_descent); | ||
| 514 | FRAME_LINE_HEIGHT (f) = font_ascent + font_descent; | ||
| 515 | |||
| 516 | /* We could use a more elaborate calculation here. */ | ||
| 517 | FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); | ||
| 518 | |||
| 519 | /* Compute character columns occupied by scrollbar. | ||
| 520 | |||
| 521 | Don't do things differently for non-toolkit scrollbars | ||
| 522 | (Bug#17163). */ | ||
| 523 | unit = FRAME_COLUMN_WIDTH (f); | ||
| 524 | if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0) | ||
| 525 | FRAME_CONFIG_SCROLL_BAR_COLS (f) | ||
| 526 | = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit; | ||
| 527 | else | ||
| 528 | FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit; | ||
| 529 | |||
| 530 | |||
| 531 | /* Don't change the size of a tip frame; there's no point in doing it | ||
| 532 | because it's done in Fx_show_tip, and it leads to problems because | ||
| 533 | the tip frame has no widget. */ | ||
| 534 | if (FRAME_ANDROID_WINDOW (f) != 0 && !FRAME_TOOLTIP_P (f)) | ||
| 535 | adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), | ||
| 536 | FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, | ||
| 537 | false, Qfont); | ||
| 538 | |||
| 539 | return font_object; | ||
| 540 | } | ||
| 541 | |||
| 542 | static bool | ||
| 543 | android_bitmap_icon (struct frame *f, Lisp_Object file) | ||
| 544 | { | ||
| 545 | /* TODO */ | ||
| 546 | return false; | ||
| 547 | } | ||
| 548 | |||
| 549 | static void | ||
| 550 | android_free_pixmap_hook (struct frame *f, Emacs_Pixmap pixmap) | ||
| 551 | { | ||
| 552 | android_free_pixmap (pixmap); | ||
| 553 | } | ||
| 554 | |||
| 555 | void | ||
| 556 | android_free_frame_resources (struct frame *f) | ||
| 557 | { | ||
| 558 | struct android_display_info *dpyinfo; | ||
| 559 | Mouse_HLInfo *hlinfo; | ||
| 560 | |||
| 561 | dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 562 | hlinfo = &dpyinfo->mouse_highlight; | ||
| 563 | |||
| 564 | block_input (); | ||
| 565 | free_frame_faces (f); | ||
| 566 | |||
| 567 | /* FRAME_ANDROID_WINDOW can be 0 if frame creation failed. */ | ||
| 568 | if (FRAME_ANDROID_WINDOW (f)) | ||
| 569 | android_destroy_window (FRAME_ANDROID_WINDOW (f)); | ||
| 570 | |||
| 571 | android_free_gcs (f); | ||
| 572 | |||
| 573 | /* Free extra GCs allocated by android_setup_relief_colors. */ | ||
| 574 | if (f->output_data.android->white_relief.gc) | ||
| 575 | { | ||
| 576 | android_free_gc (f->output_data.android->white_relief.gc); | ||
| 577 | f->output_data.android->white_relief.gc = 0; | ||
| 578 | } | ||
| 579 | if (f->output_data.android->black_relief.gc) | ||
| 580 | { | ||
| 581 | android_free_gc (f->output_data.android->black_relief.gc); | ||
| 582 | f->output_data.android->black_relief.gc = 0; | ||
| 583 | } | ||
| 584 | |||
| 585 | if (f == dpyinfo->focus_frame) | ||
| 586 | dpyinfo->focus_frame = 0; | ||
| 587 | if (f == dpyinfo->highlight_frame) | ||
| 588 | dpyinfo->highlight_frame = 0; | ||
| 589 | if (f == hlinfo->mouse_face_mouse_frame) | ||
| 590 | reset_mouse_highlight (hlinfo); | ||
| 591 | |||
| 592 | unblock_input (); | ||
| 593 | } | ||
| 594 | |||
| 595 | static void | ||
| 596 | android_delete_frame (struct frame *f) | ||
| 597 | { | ||
| 598 | android_free_frame_resources (f); | ||
| 599 | xfree (f->output_data.android); | ||
| 600 | f->output_data.android = NULL; | ||
| 601 | } | ||
| 602 | |||
| 603 | static void | ||
| 604 | android_delete_terminal (struct terminal *terminal) | ||
| 605 | { | ||
| 606 | error ("Cannot terminate connection to Android display server"); | ||
| 607 | } | ||
| 608 | |||
| 609 | |||
| 610 | |||
| 611 | /* RIF functions. */ | ||
| 612 | |||
| 613 | static void | ||
| 614 | android_scroll_run (struct window *w, struct run *run) | ||
| 615 | { | ||
| 616 | struct frame *f = XFRAME (w->frame); | ||
| 617 | int x, y, width, height, from_y, to_y, bottom_y; | ||
| 618 | |||
| 619 | /* Get frame-relative bounding box of the text display area of W, | ||
| 620 | without mode lines. Include in this box the left and right | ||
| 621 | fringe of W. */ | ||
| 622 | window_box (w, ANY_AREA, &x, &y, &width, &height); | ||
| 623 | |||
| 624 | from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y); | ||
| 625 | to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y); | ||
| 626 | bottom_y = y + height; | ||
| 627 | |||
| 628 | if (to_y < from_y) | ||
| 629 | { | ||
| 630 | /* Scrolling up. Make sure we don't copy part of the mode | ||
| 631 | line at the bottom. */ | ||
| 632 | if (from_y + run->height > bottom_y) | ||
| 633 | height = bottom_y - from_y; | ||
| 634 | else | ||
| 635 | height = run->height; | ||
| 636 | } | ||
| 637 | else | ||
| 638 | { | ||
| 639 | /* Scrolling down. Make sure we don't copy over the mode line. | ||
| 640 | at the bottom. */ | ||
| 641 | if (to_y + run->height > bottom_y) | ||
| 642 | height = bottom_y - to_y; | ||
| 643 | else | ||
| 644 | height = run->height; | ||
| 645 | } | ||
| 646 | |||
| 647 | block_input (); | ||
| 648 | |||
| 649 | /* Cursor off. Will be switched on again in gui_update_window_end. */ | ||
| 650 | gui_clear_cursor (w); | ||
| 651 | |||
| 652 | android_copy_area (FRAME_ANDROID_WINDOW (f), | ||
| 653 | FRAME_ANDROID_WINDOW (f), | ||
| 654 | f->output_data.android->normal_gc, | ||
| 655 | x, from_y, width, height, x, to_y); | ||
| 656 | |||
| 657 | unblock_input (); | ||
| 658 | } | ||
| 659 | |||
| 660 | static void | ||
| 661 | android_after_update_window_line (struct window *w, struct glyph_row *desired_row) | ||
| 662 | { | ||
| 663 | eassert (w); | ||
| 664 | |||
| 665 | if (!desired_row->mode_line_p && !w->pseudo_window_p) | ||
| 666 | desired_row->redraw_fringe_bitmaps_p = true; | ||
| 667 | } | ||
| 668 | |||
| 669 | static void | ||
| 670 | android_flip_and_flush (struct frame *f) | ||
| 671 | { | ||
| 672 | block_input (); | ||
| 673 | show_back_buffer (f); | ||
| 674 | |||
| 675 | /* The frame is complete again as its contents were just | ||
| 676 | flushed. */ | ||
| 677 | FRAME_ANDROID_COMPLETE_P (f) = true; | ||
| 678 | unblock_input (); | ||
| 679 | } | ||
| 680 | |||
| 681 | static void | ||
| 682 | android_clear_rectangle (struct frame *f, struct android_gc *gc, int x, | ||
| 683 | int y, int width, int height) | ||
| 684 | { | ||
| 685 | struct android_gc_values xgcv; | ||
| 686 | |||
| 687 | android_get_gc_values (gc, (ANDROID_GC_BACKGROUND | ||
| 688 | | ANDROID_GC_FOREGROUND), | ||
| 689 | &xgcv); | ||
| 690 | android_set_foreground (gc, xgcv.background); | ||
| 691 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, | ||
| 692 | x, y, width, height); | ||
| 693 | android_set_foreground (gc, xgcv.foreground); | ||
| 694 | } | ||
| 695 | |||
| 696 | static void | ||
| 697 | android_reset_clip_rectangles (struct frame *f, struct android_gc *gc) | ||
| 698 | { | ||
| 699 | android_set_clip_mask (gc, ANDROID_NONE); | ||
| 700 | } | ||
| 701 | |||
| 702 | static void | ||
| 703 | android_clip_to_row (struct window *w, struct glyph_row *row, | ||
| 704 | enum glyph_row_area area, struct android_gc *gc) | ||
| 705 | { | ||
| 706 | struct android_rectangle clip_rect; | ||
| 707 | int window_x, window_y, window_width; | ||
| 708 | |||
| 709 | window_box (w, area, &window_x, &window_y, &window_width, 0); | ||
| 710 | |||
| 711 | clip_rect.x = window_x; | ||
| 712 | clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y)); | ||
| 713 | clip_rect.y = max (clip_rect.y, window_y); | ||
| 714 | clip_rect.width = window_width; | ||
| 715 | clip_rect.height = row->visible_height; | ||
| 716 | |||
| 717 | android_set_clip_rectangles (gc, 0, 0, &clip_rect, 1); | ||
| 718 | } | ||
| 719 | |||
| 720 | static void | ||
| 721 | android_draw_fringe_bitmap (struct window *w, struct glyph_row *row, | ||
| 722 | struct draw_fringe_bitmap_params *p) | ||
| 723 | { | ||
| 724 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 725 | struct android_gc *gc = f->output_data.android->normal_gc; | ||
| 726 | struct face *face = p->face; | ||
| 727 | |||
| 728 | /* Must clip because of partially visible lines. */ | ||
| 729 | android_clip_to_row (w, row, ANY_AREA, gc); | ||
| 730 | |||
| 731 | if (p->bx >= 0 && !p->overlay_p) | ||
| 732 | { | ||
| 733 | /* In case the same realized face is used for fringes and for | ||
| 734 | something displayed in the text (e.g. face `region' on | ||
| 735 | mono-displays, the fill style may have been changed to | ||
| 736 | ANDROID_FILL_SOLID in | ||
| 737 | android_draw_glyph_string_background. */ | ||
| 738 | if (face->stipple) | ||
| 739 | { | ||
| 740 | android_set_fill_style (face->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 741 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), face->gc, | ||
| 742 | p->bx, p->by, p->nx, p->ny); | ||
| 743 | android_set_fill_style (face->gc, ANDROID_FILL_SOLID); | ||
| 744 | |||
| 745 | row->stipple_p = true; | ||
| 746 | } | ||
| 747 | else | ||
| 748 | { | ||
| 749 | android_set_background (face->gc, face->background); | ||
| 750 | android_clear_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny); | ||
| 751 | android_set_foreground (face->gc, face->foreground); | ||
| 752 | } | ||
| 753 | } | ||
| 754 | |||
| 755 | if (p->which) | ||
| 756 | { | ||
| 757 | android_drawable drawable; | ||
| 758 | char *bits; | ||
| 759 | android_pixmap pixmap, clipmask; | ||
| 760 | struct android_gc_values gcv; | ||
| 761 | unsigned long background, cursor_pixel; | ||
| 762 | int depth; | ||
| 763 | |||
| 764 | drawable = FRAME_ANDROID_WINDOW (f); | ||
| 765 | clipmask = ANDROID_NONE; | ||
| 766 | background = face->background; | ||
| 767 | cursor_pixel = f->output_data.android->cursor_pixel; | ||
| 768 | depth = FRAME_DISPLAY_INFO (f)->n_planes; | ||
| 769 | |||
| 770 | if (p->wd > 8) | ||
| 771 | bits = (char *) (p->bits + p->dh); | ||
| 772 | else | ||
| 773 | bits = (char *) p->bits + p->dh; | ||
| 774 | |||
| 775 | pixmap = android_create_pixmap_from_bitmap_data (bits, p->wd, p->h, | ||
| 776 | (p->cursor_p | ||
| 777 | ? (p->overlay_p | ||
| 778 | ? face->background | ||
| 779 | : cursor_pixel) | ||
| 780 | : face->foreground), | ||
| 781 | background, depth); | ||
| 782 | |||
| 783 | if (p->overlay_p) | ||
| 784 | { | ||
| 785 | clipmask = android_create_pixmap_from_bitmap_data (bits, p->wd, p->h, | ||
| 786 | 1, 0, 0); | ||
| 787 | |||
| 788 | gcv.clip_mask = clipmask; | ||
| 789 | gcv.clip_x_origin = p->x; | ||
| 790 | gcv.clip_y_origin = p->y; | ||
| 791 | android_change_gc (gc, (ANDROID_GC_CLIP_MASK | ||
| 792 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 793 | | ANDROID_GC_CLIP_Y_ORIGIN), | ||
| 794 | &gcv); | ||
| 795 | } | ||
| 796 | |||
| 797 | android_copy_area (pixmap, drawable, gc, 0, 0, p->wd, p->h, | ||
| 798 | p->x, p->y); | ||
| 799 | android_free_pixmap (pixmap); | ||
| 800 | |||
| 801 | if (p->overlay_p) | ||
| 802 | { | ||
| 803 | gcv.clip_mask = ANDROID_NONE; | ||
| 804 | android_change_gc (gc, ANDROID_GC_CLIP_MASK, &gcv); | ||
| 805 | android_free_pixmap (clipmask); | ||
| 806 | } | ||
| 807 | } | ||
| 808 | |||
| 809 | android_reset_clip_rectangles (f, gc); | ||
| 810 | } | ||
| 811 | |||
| 812 | /* Set S->gc to a suitable GC for drawing glyph string S in cursor | ||
| 813 | face. */ | ||
| 814 | |||
| 815 | static void | ||
| 816 | android_set_cursor_gc (struct glyph_string *s) | ||
| 817 | { | ||
| 818 | if (s->font == FRAME_FONT (s->f) | ||
| 819 | && s->face->background == FRAME_BACKGROUND_PIXEL (s->f) | ||
| 820 | && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f) | ||
| 821 | && !s->cmp) | ||
| 822 | s->gc = s->f->output_data.android->cursor_gc; | ||
| 823 | else | ||
| 824 | { | ||
| 825 | /* Cursor on non-default face: must merge. */ | ||
| 826 | struct android_gc_values xgcv; | ||
| 827 | unsigned long mask; | ||
| 828 | |||
| 829 | xgcv.background = s->f->output_data.android->cursor_pixel; | ||
| 830 | xgcv.foreground = s->face->background; | ||
| 831 | |||
| 832 | /* If the glyph would be invisible, try a different foreground. */ | ||
| 833 | if (xgcv.foreground == xgcv.background) | ||
| 834 | xgcv.foreground = s->face->foreground; | ||
| 835 | if (xgcv.foreground == xgcv.background) | ||
| 836 | xgcv.foreground = s->f->output_data.android->cursor_foreground_pixel; | ||
| 837 | if (xgcv.foreground == xgcv.background) | ||
| 838 | xgcv.foreground = s->face->foreground; | ||
| 839 | |||
| 840 | /* Make sure the cursor is distinct from text in this face. */ | ||
| 841 | if (xgcv.background == s->face->background | ||
| 842 | && xgcv.foreground == s->face->foreground) | ||
| 843 | { | ||
| 844 | xgcv.background = s->face->foreground; | ||
| 845 | xgcv.foreground = s->face->background; | ||
| 846 | } | ||
| 847 | |||
| 848 | mask = (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND); | ||
| 849 | |||
| 850 | if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc) | ||
| 851 | android_change_gc (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc, | ||
| 852 | mask, &xgcv); | ||
| 853 | else | ||
| 854 | FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc | ||
| 855 | = android_create_gc (mask, &xgcv); | ||
| 856 | |||
| 857 | s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc; | ||
| 858 | } | ||
| 859 | } | ||
| 860 | |||
| 861 | |||
| 862 | /* Set up S->gc of glyph string S for drawing text in mouse face. */ | ||
| 863 | |||
| 864 | static void | ||
| 865 | android_set_mouse_face_gc (struct glyph_string *s) | ||
| 866 | { | ||
| 867 | if (s->font == s->face->font) | ||
| 868 | s->gc = s->face->gc; | ||
| 869 | else | ||
| 870 | { | ||
| 871 | /* Otherwise construct scratch_cursor_gc with values from FACE | ||
| 872 | except for FONT. */ | ||
| 873 | struct android_gc_values xgcv; | ||
| 874 | unsigned long mask; | ||
| 875 | |||
| 876 | xgcv.background = s->face->background; | ||
| 877 | xgcv.foreground = s->face->foreground; | ||
| 878 | |||
| 879 | mask = (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND); | ||
| 880 | |||
| 881 | if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc) | ||
| 882 | android_change_gc (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc, | ||
| 883 | mask, &xgcv); | ||
| 884 | else | ||
| 885 | FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc | ||
| 886 | = android_create_gc (mask, &xgcv); | ||
| 887 | |||
| 888 | s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc; | ||
| 889 | } | ||
| 890 | |||
| 891 | eassert (s->gc != 0); | ||
| 892 | } | ||
| 893 | |||
| 894 | |||
| 895 | /* Set S->gc of glyph string S to a GC suitable for drawing a mode line. | ||
| 896 | Faces to use in the mode line have already been computed when the | ||
| 897 | matrix was built, so there isn't much to do, here. */ | ||
| 898 | |||
| 899 | static void | ||
| 900 | android_set_mode_line_face_gc (struct glyph_string *s) | ||
| 901 | { | ||
| 902 | s->gc = s->face->gc; | ||
| 903 | } | ||
| 904 | |||
| 905 | /* Set S->gc of glyph string S for drawing that glyph string. Set | ||
| 906 | S->stippled_p to a non-zero value if the face of S has a stipple | ||
| 907 | pattern. */ | ||
| 908 | |||
| 909 | static void | ||
| 910 | android_set_glyph_string_gc (struct glyph_string *s) | ||
| 911 | { | ||
| 912 | prepare_face_for_display (s->f, s->face); | ||
| 913 | |||
| 914 | if (s->hl == DRAW_NORMAL_TEXT) | ||
| 915 | { | ||
| 916 | s->gc = s->face->gc; | ||
| 917 | s->stippled_p = s->face->stipple != 0; | ||
| 918 | } | ||
| 919 | else if (s->hl == DRAW_INVERSE_VIDEO) | ||
| 920 | { | ||
| 921 | android_set_mode_line_face_gc (s); | ||
| 922 | s->stippled_p = s->face->stipple != 0; | ||
| 923 | } | ||
| 924 | else if (s->hl == DRAW_CURSOR) | ||
| 925 | { | ||
| 926 | android_set_cursor_gc (s); | ||
| 927 | s->stippled_p = false; | ||
| 928 | } | ||
| 929 | else if (s->hl == DRAW_MOUSE_FACE) | ||
| 930 | { | ||
| 931 | android_set_mouse_face_gc (s); | ||
| 932 | s->stippled_p = s->face->stipple != 0; | ||
| 933 | } | ||
| 934 | else if (s->hl == DRAW_IMAGE_RAISED | ||
| 935 | || s->hl == DRAW_IMAGE_SUNKEN) | ||
| 936 | { | ||
| 937 | s->gc = s->face->gc; | ||
| 938 | s->stippled_p = s->face->stipple != 0; | ||
| 939 | } | ||
| 940 | else | ||
| 941 | emacs_abort (); | ||
| 942 | |||
| 943 | /* GC must have been set. */ | ||
| 944 | eassert (s->gc != 0); | ||
| 945 | } | ||
| 946 | |||
| 947 | |||
| 948 | /* Set clipping for output of glyph string S. S may be part of a mode | ||
| 949 | line or menu if we don't have X toolkit support. */ | ||
| 950 | |||
| 951 | static void | ||
| 952 | android_set_glyph_string_clipping (struct glyph_string *s) | ||
| 953 | { | ||
| 954 | struct android_rectangle *r = s->clip; | ||
| 955 | int n = get_glyph_string_clip_rects (s, r, 2); | ||
| 956 | |||
| 957 | if (n > 0) | ||
| 958 | android_set_clip_rectangles (s->gc, 0, 0, r, n); | ||
| 959 | s->num_clips = n; | ||
| 960 | } | ||
| 961 | |||
| 962 | |||
| 963 | /* Set SRC's clipping for output of glyph string DST. This is called | ||
| 964 | when we are drawing DST's left_overhang or right_overhang only in | ||
| 965 | the area of SRC. */ | ||
| 966 | |||
| 967 | static void | ||
| 968 | android_set_glyph_string_clipping_exactly (struct glyph_string *src, | ||
| 969 | struct glyph_string *dst) | ||
| 970 | { | ||
| 971 | struct android_rectangle r; | ||
| 972 | |||
| 973 | r.x = src->x; | ||
| 974 | r.width = src->width; | ||
| 975 | r.y = src->y; | ||
| 976 | r.height = src->height; | ||
| 977 | dst->clip[0] = r; | ||
| 978 | dst->num_clips = 1; | ||
| 979 | android_set_clip_rectangles (dst->gc, 0, 0, &r, 1); | ||
| 980 | } | ||
| 981 | |||
| 982 | static void | ||
| 983 | android_compute_glyph_string_overhangs (struct glyph_string *s) | ||
| 984 | { | ||
| 985 | if (s->cmp == NULL | ||
| 986 | && (s->first_glyph->type == CHAR_GLYPH | ||
| 987 | || s->first_glyph->type == COMPOSITE_GLYPH)) | ||
| 988 | { | ||
| 989 | struct font_metrics metrics; | ||
| 990 | |||
| 991 | if (s->first_glyph->type == CHAR_GLYPH) | ||
| 992 | { | ||
| 993 | struct font *font = s->font; | ||
| 994 | font->driver->text_extents (font, s->char2b, s->nchars, &metrics); | ||
| 995 | } | ||
| 996 | else | ||
| 997 | { | ||
| 998 | Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); | ||
| 999 | |||
| 1000 | composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); | ||
| 1001 | } | ||
| 1002 | s->right_overhang = (metrics.rbearing > metrics.width | ||
| 1003 | ? metrics.rbearing - metrics.width : 0); | ||
| 1004 | s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; | ||
| 1005 | } | ||
| 1006 | else if (s->cmp) | ||
| 1007 | { | ||
| 1008 | s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; | ||
| 1009 | s->left_overhang = - s->cmp->lbearing; | ||
| 1010 | } | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | static void | ||
| 1014 | android_clear_glyph_string_rect (struct glyph_string *s, int x, int y, | ||
| 1015 | int w, int h) | ||
| 1016 | { | ||
| 1017 | android_clear_rectangle (s->f, s->gc, x, y, w, h); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | static void | ||
| 1021 | android_draw_glyph_string_background (struct glyph_string *s, bool force_p) | ||
| 1022 | { | ||
| 1023 | /* Nothing to do if background has already been drawn or if it | ||
| 1024 | shouldn't be drawn in the first place. */ | ||
| 1025 | if (!s->background_filled_p) | ||
| 1026 | { | ||
| 1027 | int box_line_width = max (s->face->box_horizontal_line_width, 0); | ||
| 1028 | |||
| 1029 | if (s->stippled_p) | ||
| 1030 | { | ||
| 1031 | /* Fill background with a stipple pattern. */ | ||
| 1032 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1033 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1034 | s->x, s->y + box_line_width, | ||
| 1035 | s->background_width, | ||
| 1036 | s->height - 2 * box_line_width); | ||
| 1037 | android_set_fill_style (s->gc, ANDROID_FILL_SOLID); | ||
| 1038 | s->background_filled_p = true; | ||
| 1039 | } | ||
| 1040 | else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width | ||
| 1041 | /* When xdisp.c ignores FONT_HEIGHT, we cannot trust | ||
| 1042 | font dimensions, since the actual glyphs might be | ||
| 1043 | much smaller. So in that case we always clear the | ||
| 1044 | rectangle with background color. */ | ||
| 1045 | || FONT_TOO_HIGH (s->font) | ||
| 1046 | || s->font_not_found_p | ||
| 1047 | || s->extends_to_end_of_line_p | ||
| 1048 | || force_p) | ||
| 1049 | { | ||
| 1050 | android_clear_glyph_string_rect (s, s->x, s->y + box_line_width, | ||
| 1051 | s->background_width, | ||
| 1052 | s->height - 2 * box_line_width); | ||
| 1053 | s->background_filled_p = true; | ||
| 1054 | } | ||
| 1055 | } | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | static void | ||
| 1059 | android_fill_triangle (struct frame *f, struct android_gc *gc, | ||
| 1060 | struct android_point point1, | ||
| 1061 | struct android_point point2, | ||
| 1062 | struct android_point point3) | ||
| 1063 | { | ||
| 1064 | struct android_point abc[3]; | ||
| 1065 | |||
| 1066 | abc[0] = point1; | ||
| 1067 | abc[1] = point2; | ||
| 1068 | abc[2] = point3; | ||
| 1069 | |||
| 1070 | android_fill_polygon (FRAME_ANDROID_WINDOW (f), | ||
| 1071 | gc, abc, 3, ANDROID_CONVEX, | ||
| 1072 | ANDROID_COORD_MODE_ORIGIN); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | static struct android_point | ||
| 1076 | android_make_point (int x, int y) | ||
| 1077 | { | ||
| 1078 | struct android_point pt; | ||
| 1079 | |||
| 1080 | pt.x = x; | ||
| 1081 | pt.y = y; | ||
| 1082 | |||
| 1083 | return pt; | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | static bool | ||
| 1087 | android_inside_rect_p (struct android_rectangle *rects, int nrects, int x, | ||
| 1088 | int y) | ||
| 1089 | { | ||
| 1090 | int i; | ||
| 1091 | |||
| 1092 | for (i = 0; i < nrects; ++i) | ||
| 1093 | { | ||
| 1094 | if (x >= rects[i].x && y >= rects[i].y | ||
| 1095 | && x < rects[i].x + rects[i].width | ||
| 1096 | && y < rects[i].y + rects[i].height) | ||
| 1097 | return true; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | return false; | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | static void | ||
| 1104 | android_clear_point (struct frame *f, struct android_gc *gc, | ||
| 1105 | int x, int y) | ||
| 1106 | { | ||
| 1107 | struct android_gc_values xgcv; | ||
| 1108 | |||
| 1109 | android_get_gc_values (gc, ANDROID_GC_BACKGROUND | ANDROID_GC_FOREGROUND, | ||
| 1110 | &xgcv); | ||
| 1111 | android_set_foreground (gc, xgcv.background); | ||
| 1112 | android_draw_point (FRAME_ANDROID_WINDOW (f), gc, x, y); | ||
| 1113 | android_set_foreground (gc, xgcv.foreground); | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | static void | ||
| 1117 | android_draw_relief_rect (struct frame *f, int left_x, int top_y, int right_x, | ||
| 1118 | int bottom_y, int hwidth, int vwidth, bool raised_p, | ||
| 1119 | bool top_p, bool bot_p, bool left_p, bool right_p, | ||
| 1120 | struct android_rectangle *clip_rect) | ||
| 1121 | { | ||
| 1122 | struct android_gc *gc, *white_gc, *black_gc, *normal_gc; | ||
| 1123 | android_drawable drawable; | ||
| 1124 | |||
| 1125 | /* This code is more complicated than it has to be, because of two | ||
| 1126 | minor hacks to make the boxes look nicer: (i) if width > 1, draw | ||
| 1127 | the outermost line using the black relief. (ii) Omit the four | ||
| 1128 | corner pixels. */ | ||
| 1129 | |||
| 1130 | white_gc = f->output_data.android->white_relief.gc; | ||
| 1131 | black_gc = f->output_data.android->black_relief.gc; | ||
| 1132 | normal_gc = f->output_data.android->normal_gc; | ||
| 1133 | |||
| 1134 | drawable = FRAME_ANDROID_WINDOW (f); | ||
| 1135 | |||
| 1136 | android_set_clip_rectangles (white_gc, 0, 0, clip_rect, 1); | ||
| 1137 | android_set_clip_rectangles (black_gc, 0, 0, clip_rect, 1); | ||
| 1138 | |||
| 1139 | if (raised_p) | ||
| 1140 | gc = white_gc; | ||
| 1141 | else | ||
| 1142 | gc = black_gc; | ||
| 1143 | |||
| 1144 | /* Draw lines. */ | ||
| 1145 | |||
| 1146 | if (top_p) | ||
| 1147 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x, top_y, | ||
| 1148 | right_x - left_x + 1, hwidth); | ||
| 1149 | |||
| 1150 | if (left_p) | ||
| 1151 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x, top_y, | ||
| 1152 | vwidth, bottom_y - top_y + 1); | ||
| 1153 | |||
| 1154 | if (raised_p) | ||
| 1155 | gc = black_gc; | ||
| 1156 | else | ||
| 1157 | gc = white_gc; | ||
| 1158 | |||
| 1159 | if (bot_p) | ||
| 1160 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x, | ||
| 1161 | bottom_y - hwidth + 1, | ||
| 1162 | right_x - left_x + 1, hwidth); | ||
| 1163 | |||
| 1164 | if (right_p) | ||
| 1165 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, | ||
| 1166 | right_x - vwidth + 1, | ||
| 1167 | top_y, vwidth, bottom_y - top_y + 1); | ||
| 1168 | |||
| 1169 | /* Draw corners. */ | ||
| 1170 | |||
| 1171 | if (bot_p && left_p) | ||
| 1172 | android_fill_triangle (f, raised_p ? white_gc : black_gc, | ||
| 1173 | android_make_point (left_x, bottom_y - hwidth), | ||
| 1174 | android_make_point (left_x + vwidth, | ||
| 1175 | bottom_y - hwidth), | ||
| 1176 | android_make_point (left_x, bottom_y)); | ||
| 1177 | |||
| 1178 | if (top_p && right_p) | ||
| 1179 | android_fill_triangle (f, raised_p ? white_gc : black_gc, | ||
| 1180 | android_make_point (right_x - vwidth, top_y), | ||
| 1181 | android_make_point (right_x, top_y), | ||
| 1182 | android_make_point (right_x - vwidth, | ||
| 1183 | top_y + hwidth)); | ||
| 1184 | |||
| 1185 | /* Draw outer line. */ | ||
| 1186 | |||
| 1187 | if (top_p && left_p && bot_p && right_p | ||
| 1188 | && hwidth > 1 && vwidth > 1) | ||
| 1189 | android_draw_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 1190 | black_gc, left_x, top_y, | ||
| 1191 | right_x - left_x, bottom_y - top_y); | ||
| 1192 | else | ||
| 1193 | { | ||
| 1194 | if (top_p && hwidth > 1) | ||
| 1195 | android_draw_line (drawable, black_gc, left_x, top_y, | ||
| 1196 | right_x + 1, top_y); | ||
| 1197 | |||
| 1198 | if (bot_p && hwidth > 1) | ||
| 1199 | android_draw_line (drawable, black_gc, left_x, bottom_y, | ||
| 1200 | right_x + 1, bottom_y); | ||
| 1201 | |||
| 1202 | if (left_p && vwidth > 1) | ||
| 1203 | android_draw_line (drawable, black_gc, left_x, top_y, | ||
| 1204 | left_x, bottom_y + 1); | ||
| 1205 | |||
| 1206 | if (right_p && vwidth > 1) | ||
| 1207 | android_draw_line (drawable, black_gc, right_x, top_y, | ||
| 1208 | right_x, bottom_y + 1); | ||
| 1209 | } | ||
| 1210 | |||
| 1211 | /* Erase corners. */ | ||
| 1212 | |||
| 1213 | if (hwidth > 1 && vwidth > 1) | ||
| 1214 | { | ||
| 1215 | if (left_p && top_p && android_inside_rect_p (clip_rect, 1, | ||
| 1216 | left_x, top_y)) | ||
| 1217 | android_clear_point (f, normal_gc, left_x, top_y); | ||
| 1218 | |||
| 1219 | if (left_p && bot_p && android_inside_rect_p (clip_rect, 1, | ||
| 1220 | left_x, bottom_y)) | ||
| 1221 | android_clear_point (f, normal_gc, left_x, bottom_y); | ||
| 1222 | |||
| 1223 | if (right_p && top_p && android_inside_rect_p (clip_rect, 1, | ||
| 1224 | right_x, top_y)) | ||
| 1225 | android_clear_point (f, normal_gc, right_x, top_y); | ||
| 1226 | |||
| 1227 | if (right_p && bot_p && android_inside_rect_p (clip_rect, 1, | ||
| 1228 | right_x, bottom_y)) | ||
| 1229 | android_clear_point (f, normal_gc, right_x, bottom_y); | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | android_reset_clip_rectangles (f, white_gc); | ||
| 1233 | android_reset_clip_rectangles (f, black_gc); | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | static void | ||
| 1237 | android_draw_box_rect (struct glyph_string *s, | ||
| 1238 | int left_x, int top_y, int right_x, int bottom_y, | ||
| 1239 | int hwidth, int vwidth, bool left_p, bool right_p, | ||
| 1240 | struct android_rectangle *clip_rect) | ||
| 1241 | { | ||
| 1242 | struct android_gc_values xgcv; | ||
| 1243 | |||
| 1244 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 1245 | android_set_foreground (s->gc, s->face->box_color); | ||
| 1246 | android_set_clip_rectangles (s->gc, 0, 0, clip_rect, 1); | ||
| 1247 | |||
| 1248 | /* Top. */ | ||
| 1249 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x, | ||
| 1250 | left_x, right_x - left_x + 1, hwidth); | ||
| 1251 | |||
| 1252 | /* Left. */ | ||
| 1253 | if (left_p) | ||
| 1254 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x, | ||
| 1255 | top_y, vwidth, bottom_y - top_y + 1); | ||
| 1256 | |||
| 1257 | /* Bottom. */ | ||
| 1258 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x, | ||
| 1259 | bottom_y - hwidth + 1, right_x - left_x + 1, | ||
| 1260 | hwidth); | ||
| 1261 | |||
| 1262 | /* Right. */ | ||
| 1263 | if (right_p) | ||
| 1264 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1265 | right_x - vwidth + 1, top_y, vwidth, | ||
| 1266 | bottom_y - top_y + 1); | ||
| 1267 | |||
| 1268 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 1269 | android_reset_clip_rectangles (s->f, s->gc); | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000 | ||
| 1273 | |||
| 1274 | static bool | ||
| 1275 | android_alloc_lighter_color (struct frame *f, unsigned long *pixel, | ||
| 1276 | double factor, int delta) | ||
| 1277 | { | ||
| 1278 | Emacs_Color color, new; | ||
| 1279 | long bright; | ||
| 1280 | bool success_p; | ||
| 1281 | |||
| 1282 | /* Get RGB color values. */ | ||
| 1283 | color.pixel = *pixel; | ||
| 1284 | android_query_colors (f, &color, 1); | ||
| 1285 | |||
| 1286 | /* Change RGB values by specified FACTOR. Avoid overflow! */ | ||
| 1287 | eassert (factor >= 0); | ||
| 1288 | new.red = min (0xffff, factor * color.red); | ||
| 1289 | new.green = min (0xffff, factor * color.green); | ||
| 1290 | new.blue = min (0xffff, factor * color.blue); | ||
| 1291 | |||
| 1292 | /* Calculate brightness of COLOR. */ | ||
| 1293 | bright = (2 * color.red + 3 * color.green + color.blue) / 6; | ||
| 1294 | |||
| 1295 | /* We only boost colors that are darker than | ||
| 1296 | HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */ | ||
| 1297 | if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT) | ||
| 1298 | /* Make an additive adjustment to NEW, because it's dark enough so | ||
| 1299 | that scaling by FACTOR alone isn't enough. */ | ||
| 1300 | { | ||
| 1301 | /* How far below the limit this color is (0 - 1, 1 being darker). */ | ||
| 1302 | double dimness = 1 - (double) bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT; | ||
| 1303 | /* The additive adjustment. */ | ||
| 1304 | int min_delta = delta * dimness * factor / 2; | ||
| 1305 | |||
| 1306 | if (factor < 1) | ||
| 1307 | { | ||
| 1308 | new.red = max (0, new.red - min_delta); | ||
| 1309 | new.green = max (0, new.green - min_delta); | ||
| 1310 | new.blue = max (0, new.blue - min_delta); | ||
| 1311 | } | ||
| 1312 | else | ||
| 1313 | { | ||
| 1314 | new.red = min (0xffff, min_delta + new.red); | ||
| 1315 | new.green = min (0xffff, min_delta + new.green); | ||
| 1316 | new.blue = min (0xffff, min_delta + new.blue); | ||
| 1317 | } | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | /* Try to allocate the color. */ | ||
| 1321 | success_p = android_alloc_nearest_color (f, &new); | ||
| 1322 | |||
| 1323 | if (success_p) | ||
| 1324 | { | ||
| 1325 | if (new.pixel == *pixel) | ||
| 1326 | { | ||
| 1327 | /* If we end up with the same color as before, try adding | ||
| 1328 | delta to the RGB values. */ | ||
| 1329 | new.red = min (0xffff, delta + color.red); | ||
| 1330 | new.green = min (0xffff, delta + color.green); | ||
| 1331 | new.blue = min (0xffff, delta + color.blue); | ||
| 1332 | success_p = android_alloc_nearest_color (f, &new); | ||
| 1333 | } | ||
| 1334 | else | ||
| 1335 | success_p = true; | ||
| 1336 | |||
| 1337 | *pixel = new.pixel; | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | return success_p; | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | /* Set up the foreground color for drawing relief lines of glyph | ||
| 1344 | string S. RELIEF is a pointer to a struct relief containing the GC | ||
| 1345 | with which lines will be drawn. Use a color that is FACTOR or | ||
| 1346 | DELTA lighter or darker than the relief's background which is found | ||
| 1347 | in S->f->output_data.android->relief_background. If such a color | ||
| 1348 | cannot be allocated, use DEFAULT_PIXEL, instead. */ | ||
| 1349 | |||
| 1350 | static void | ||
| 1351 | android_setup_relief_color (struct frame *f, struct relief *relief, | ||
| 1352 | double factor, int delta, | ||
| 1353 | unsigned long default_pixel) | ||
| 1354 | { | ||
| 1355 | struct android_gc_values xgcv; | ||
| 1356 | struct android_output *di = f->output_data.android; | ||
| 1357 | unsigned long mask = ANDROID_GC_FOREGROUND; | ||
| 1358 | unsigned long pixel; | ||
| 1359 | unsigned long background = di->relief_background; | ||
| 1360 | struct android_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 1361 | |||
| 1362 | if (relief->gc && relief->pixel != -1) | ||
| 1363 | relief->pixel = -1; | ||
| 1364 | |||
| 1365 | /* Allocate new color. */ | ||
| 1366 | xgcv.foreground = default_pixel; | ||
| 1367 | pixel = background; | ||
| 1368 | |||
| 1369 | if (dpyinfo->n_planes != 1 | ||
| 1370 | && android_alloc_lighter_color (f, &pixel, factor, delta)) | ||
| 1371 | xgcv.foreground = relief->pixel = pixel; | ||
| 1372 | |||
| 1373 | if (relief->gc == 0) | ||
| 1374 | relief->gc = android_create_gc (mask, &xgcv); | ||
| 1375 | else | ||
| 1376 | android_change_gc (relief->gc, mask, &xgcv); | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | /* Set up colors for the relief lines around glyph string S. */ | ||
| 1380 | |||
| 1381 | static void | ||
| 1382 | android_setup_relief_colors (struct glyph_string *s) | ||
| 1383 | { | ||
| 1384 | struct android_output *di; | ||
| 1385 | unsigned long color; | ||
| 1386 | |||
| 1387 | di = s->f->output_data.android; | ||
| 1388 | |||
| 1389 | if (s->face->use_box_color_for_shadows_p) | ||
| 1390 | color = s->face->box_color; | ||
| 1391 | else if (s->first_glyph->type == IMAGE_GLYPH | ||
| 1392 | && s->img->pixmap | ||
| 1393 | && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0)) | ||
| 1394 | color = IMAGE_BACKGROUND (s->img, s->f, 0); | ||
| 1395 | else | ||
| 1396 | { | ||
| 1397 | struct android_gc_values xgcv; | ||
| 1398 | |||
| 1399 | /* Get the background color of the face. */ | ||
| 1400 | android_get_gc_values (s->gc, ANDROID_GC_BACKGROUND, &xgcv); | ||
| 1401 | color = xgcv.background; | ||
| 1402 | } | ||
| 1403 | |||
| 1404 | if (di->white_relief.gc == 0 | ||
| 1405 | || color != di->relief_background) | ||
| 1406 | { | ||
| 1407 | di->relief_background = color; | ||
| 1408 | android_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000, | ||
| 1409 | WHITE_PIX_DEFAULT (s->f)); | ||
| 1410 | android_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000, | ||
| 1411 | BLACK_PIX_DEFAULT (s->f)); | ||
| 1412 | } | ||
| 1413 | } | ||
| 1414 | |||
| 1415 | static void | ||
| 1416 | android_draw_glyph_string_box (struct glyph_string *s) | ||
| 1417 | { | ||
| 1418 | int hwidth, vwidth, left_x, right_x, top_y, bottom_y, last_x; | ||
| 1419 | bool raised_p, left_p, right_p; | ||
| 1420 | struct glyph *last_glyph; | ||
| 1421 | struct android_rectangle clip_rect; | ||
| 1422 | |||
| 1423 | last_x = ((s->row->full_width_p && !s->w->pseudo_window_p) | ||
| 1424 | ? WINDOW_RIGHT_EDGE_X (s->w) | ||
| 1425 | : window_box_right (s->w, s->area)); | ||
| 1426 | |||
| 1427 | /* The glyph that may have a right box line. For static | ||
| 1428 | compositions and images, the right-box flag is on the first glyph | ||
| 1429 | of the glyph string; for other types it's on the last glyph. */ | ||
| 1430 | if (s->cmp || s->img) | ||
| 1431 | last_glyph = s->first_glyph; | ||
| 1432 | else if (s->first_glyph->type == COMPOSITE_GLYPH | ||
| 1433 | && s->first_glyph->u.cmp.automatic) | ||
| 1434 | { | ||
| 1435 | /* For automatic compositions, we need to look up the last glyph | ||
| 1436 | in the composition. */ | ||
| 1437 | struct glyph *end = s->row->glyphs[s->area] + s->row->used[s->area]; | ||
| 1438 | struct glyph *g = s->first_glyph; | ||
| 1439 | for (last_glyph = g++; | ||
| 1440 | g < end && g->u.cmp.automatic && g->u.cmp.id == s->cmp_id | ||
| 1441 | && g->slice.cmp.to < s->cmp_to; | ||
| 1442 | last_glyph = g++) | ||
| 1443 | ; | ||
| 1444 | } | ||
| 1445 | else | ||
| 1446 | last_glyph = s->first_glyph + s->nchars - 1; | ||
| 1447 | |||
| 1448 | vwidth = eabs (s->face->box_vertical_line_width); | ||
| 1449 | hwidth = eabs (s->face->box_horizontal_line_width); | ||
| 1450 | raised_p = s->face->box == FACE_RAISED_BOX; | ||
| 1451 | left_x = s->x; | ||
| 1452 | right_x = (s->row->full_width_p && s->extends_to_end_of_line_p | ||
| 1453 | ? last_x - 1 | ||
| 1454 | : min (last_x, s->x + s->background_width) - 1); | ||
| 1455 | top_y = s->y; | ||
| 1456 | bottom_y = top_y + s->height - 1; | ||
| 1457 | |||
| 1458 | left_p = (s->first_glyph->left_box_line_p | ||
| 1459 | || (s->hl == DRAW_MOUSE_FACE | ||
| 1460 | && (s->prev == NULL | ||
| 1461 | || s->prev->hl != s->hl))); | ||
| 1462 | right_p = (last_glyph->right_box_line_p | ||
| 1463 | || (s->hl == DRAW_MOUSE_FACE | ||
| 1464 | && (s->next == NULL | ||
| 1465 | || s->next->hl != s->hl))); | ||
| 1466 | |||
| 1467 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1468 | |||
| 1469 | if (s->face->box == FACE_SIMPLE_BOX) | ||
| 1470 | android_draw_box_rect (s, left_x, top_y, right_x, bottom_y, hwidth, | ||
| 1471 | vwidth, left_p, right_p, &clip_rect); | ||
| 1472 | else | ||
| 1473 | { | ||
| 1474 | android_setup_relief_colors (s); | ||
| 1475 | android_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y, hwidth, | ||
| 1476 | vwidth, raised_p, true, true, left_p, right_p, | ||
| 1477 | &clip_rect); | ||
| 1478 | } | ||
| 1479 | } | ||
| 1480 | |||
| 1481 | static void | ||
| 1482 | android_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, | ||
| 1483 | int w, int h) | ||
| 1484 | { | ||
| 1485 | if (s->stippled_p) | ||
| 1486 | { | ||
| 1487 | /* Fill background with a stipple pattern. */ | ||
| 1488 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1489 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, x, | ||
| 1490 | y, w, h); | ||
| 1491 | android_set_fill_style (s->gc, ANDROID_FILL_SOLID); | ||
| 1492 | } | ||
| 1493 | else | ||
| 1494 | android_clear_glyph_string_rect (s, x, y, w, h); | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | static void | ||
| 1498 | android_draw_image_relief (struct glyph_string *s) | ||
| 1499 | { | ||
| 1500 | int x1, y1, thick; | ||
| 1501 | bool raised_p, top_p, bot_p, left_p, right_p; | ||
| 1502 | int extra_x, extra_y; | ||
| 1503 | struct android_rectangle r; | ||
| 1504 | int x = s->x; | ||
| 1505 | int y = s->ybase - image_ascent (s->img, s->face, &s->slice); | ||
| 1506 | |||
| 1507 | /* If first glyph of S has a left box line, start drawing it to the | ||
| 1508 | right of that line. */ | ||
| 1509 | if (s->face->box != FACE_NO_BOX | ||
| 1510 | && s->first_glyph->left_box_line_p | ||
| 1511 | && s->slice.x == 0) | ||
| 1512 | x += max (s->face->box_vertical_line_width, 0); | ||
| 1513 | |||
| 1514 | /* If there is a margin around the image, adjust x- and y-position | ||
| 1515 | by that margin. */ | ||
| 1516 | if (s->slice.x == 0) | ||
| 1517 | x += s->img->hmargin; | ||
| 1518 | if (s->slice.y == 0) | ||
| 1519 | y += s->img->vmargin; | ||
| 1520 | |||
| 1521 | if (s->hl == DRAW_IMAGE_SUNKEN | ||
| 1522 | || s->hl == DRAW_IMAGE_RAISED) | ||
| 1523 | { | ||
| 1524 | if (s->face->id == TAB_BAR_FACE_ID) | ||
| 1525 | thick = (tab_bar_button_relief < 0 | ||
| 1526 | ? DEFAULT_TAB_BAR_BUTTON_RELIEF | ||
| 1527 | : min (tab_bar_button_relief, 1000000)); | ||
| 1528 | else | ||
| 1529 | thick = (tool_bar_button_relief < 0 | ||
| 1530 | ? DEFAULT_TOOL_BAR_BUTTON_RELIEF | ||
| 1531 | : min (tool_bar_button_relief, 1000000)); | ||
| 1532 | raised_p = s->hl == DRAW_IMAGE_RAISED; | ||
| 1533 | } | ||
| 1534 | else | ||
| 1535 | { | ||
| 1536 | thick = eabs (s->img->relief); | ||
| 1537 | raised_p = s->img->relief > 0; | ||
| 1538 | } | ||
| 1539 | |||
| 1540 | x1 = x + s->slice.width - 1; | ||
| 1541 | y1 = y + s->slice.height - 1; | ||
| 1542 | |||
| 1543 | extra_x = extra_y = 0; | ||
| 1544 | if (s->face->id == TAB_BAR_FACE_ID) | ||
| 1545 | { | ||
| 1546 | if (CONSP (Vtab_bar_button_margin) | ||
| 1547 | && FIXNUMP (XCAR (Vtab_bar_button_margin)) | ||
| 1548 | && FIXNUMP (XCDR (Vtab_bar_button_margin))) | ||
| 1549 | { | ||
| 1550 | extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)) - thick; | ||
| 1551 | extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)) - thick; | ||
| 1552 | } | ||
| 1553 | else if (FIXNUMP (Vtab_bar_button_margin)) | ||
| 1554 | extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin) - thick; | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | if (s->face->id == TOOL_BAR_FACE_ID) | ||
| 1558 | { | ||
| 1559 | if (CONSP (Vtool_bar_button_margin) | ||
| 1560 | && FIXNUMP (XCAR (Vtool_bar_button_margin)) | ||
| 1561 | && FIXNUMP (XCDR (Vtool_bar_button_margin))) | ||
| 1562 | { | ||
| 1563 | extra_x = XFIXNUM (XCAR (Vtool_bar_button_margin)); | ||
| 1564 | extra_y = XFIXNUM (XCDR (Vtool_bar_button_margin)); | ||
| 1565 | } | ||
| 1566 | else if (FIXNUMP (Vtool_bar_button_margin)) | ||
| 1567 | extra_x = extra_y = XFIXNUM (Vtool_bar_button_margin); | ||
| 1568 | } | ||
| 1569 | |||
| 1570 | top_p = bot_p = left_p = right_p = false; | ||
| 1571 | |||
| 1572 | if (s->slice.x == 0) | ||
| 1573 | x -= thick + extra_x, left_p = true; | ||
| 1574 | if (s->slice.y == 0) | ||
| 1575 | y -= thick + extra_y, top_p = true; | ||
| 1576 | if (s->slice.x + s->slice.width == s->img->width) | ||
| 1577 | x1 += thick + extra_x, right_p = true; | ||
| 1578 | if (s->slice.y + s->slice.height == s->img->height) | ||
| 1579 | y1 += thick + extra_y, bot_p = true; | ||
| 1580 | |||
| 1581 | android_setup_relief_colors (s); | ||
| 1582 | get_glyph_string_clip_rect (s, &r); | ||
| 1583 | android_draw_relief_rect (s->f, x, y, x1, y1, thick, thick, raised_p, | ||
| 1584 | top_p, bot_p, left_p, right_p, &r); | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | static void | ||
| 1588 | android_draw_image_foreground (struct glyph_string *s) | ||
| 1589 | { | ||
| 1590 | int x = s->x; | ||
| 1591 | int y = s->ybase - image_ascent (s->img, s->face, &s->slice); | ||
| 1592 | |||
| 1593 | /* If first glyph of S has a left box line, start drawing it to the | ||
| 1594 | right of that line. */ | ||
| 1595 | if (s->face->box != FACE_NO_BOX | ||
| 1596 | && s->first_glyph->left_box_line_p | ||
| 1597 | && s->slice.x == 0) | ||
| 1598 | x += max (s->face->box_vertical_line_width, 0); | ||
| 1599 | |||
| 1600 | /* If there is a margin around the image, adjust x- and y-position | ||
| 1601 | by that margin. */ | ||
| 1602 | if (s->slice.x == 0) | ||
| 1603 | x += s->img->hmargin; | ||
| 1604 | if (s->slice.y == 0) | ||
| 1605 | y += s->img->vmargin; | ||
| 1606 | |||
| 1607 | if (s->img->pixmap) | ||
| 1608 | { | ||
| 1609 | if (s->img->mask) | ||
| 1610 | { | ||
| 1611 | unsigned long mask = (ANDROID_GC_CLIP_MASK | ||
| 1612 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 1613 | | ANDROID_GC_CLIP_Y_ORIGIN | ||
| 1614 | | ANDROID_GC_FUNCTION); | ||
| 1615 | struct android_gc_values xgcv; | ||
| 1616 | struct android_rectangle clip_rect, image_rect, r; | ||
| 1617 | |||
| 1618 | xgcv.clip_mask = s->img->mask; | ||
| 1619 | xgcv.clip_x_origin = x - s->slice.x; | ||
| 1620 | xgcv.clip_y_origin = y - s->slice.y; | ||
| 1621 | xgcv.function = ANDROID_GC_COPY; | ||
| 1622 | android_change_gc (s->gc, mask, &xgcv); | ||
| 1623 | |||
| 1624 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1625 | image_rect.x = x; | ||
| 1626 | image_rect.y = y; | ||
| 1627 | image_rect.width = s->slice.width; | ||
| 1628 | image_rect.height = s->slice.height; | ||
| 1629 | |||
| 1630 | if (gui_intersect_rectangles (&clip_rect, &image_rect, &r)) | ||
| 1631 | android_copy_area (s->img->pixmap, FRAME_ANDROID_WINDOW (s->f), | ||
| 1632 | s->gc, s->slice.x + r.x - x, | ||
| 1633 | s->slice.y + r.y - y, | ||
| 1634 | r.x, r.y, r.width, r.height); | ||
| 1635 | } | ||
| 1636 | else | ||
| 1637 | { | ||
| 1638 | unsigned long mask = (ANDROID_GC_CLIP_MASK | ||
| 1639 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 1640 | | ANDROID_GC_CLIP_Y_ORIGIN | ||
| 1641 | | ANDROID_GC_FUNCTION); | ||
| 1642 | struct android_gc_values xgcv; | ||
| 1643 | struct android_rectangle clip_rect, image_rect, r; | ||
| 1644 | |||
| 1645 | xgcv.clip_mask = s->img->mask; | ||
| 1646 | xgcv.clip_x_origin = x - s->slice.x; | ||
| 1647 | xgcv.clip_y_origin = y - s->slice.y; | ||
| 1648 | xgcv.function = ANDROID_GC_COPY; | ||
| 1649 | android_change_gc (s->gc, mask, &xgcv); | ||
| 1650 | |||
| 1651 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1652 | image_rect.x = x; | ||
| 1653 | image_rect.y = y; | ||
| 1654 | image_rect.width = s->slice.width; | ||
| 1655 | image_rect.height = s->slice.height; | ||
| 1656 | |||
| 1657 | if (gui_intersect_rectangles (&clip_rect, &image_rect, &r)) | ||
| 1658 | android_copy_area (s->img->pixmap, | ||
| 1659 | FRAME_ANDROID_WINDOW (s->f), | ||
| 1660 | s->gc, s->slice.x + r.x - x, | ||
| 1661 | s->slice.y + r.y - y, | ||
| 1662 | r.x, r.y, r.width, r.height); | ||
| 1663 | |||
| 1664 | /* When the image has a mask, we can expect that at | ||
| 1665 | least part of a mouse highlight or a block cursor will | ||
| 1666 | be visible. If the image doesn't have a mask, make | ||
| 1667 | a block cursor visible by drawing a rectangle around | ||
| 1668 | the image. I believe it's looking better if we do | ||
| 1669 | nothing here for mouse-face. */ | ||
| 1670 | if (s->hl == DRAW_CURSOR) | ||
| 1671 | { | ||
| 1672 | int relief = eabs (s->img->relief); | ||
| 1673 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1674 | x - relief, y - relief, | ||
| 1675 | s->slice.width + relief*2 - 1, | ||
| 1676 | s->slice.height + relief*2 - 1); | ||
| 1677 | } | ||
| 1678 | } | ||
| 1679 | } | ||
| 1680 | else | ||
| 1681 | /* Draw a rectangle if image could not be loaded. */ | ||
| 1682 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, x, y, | ||
| 1683 | s->slice.width - 1, s->slice.height - 1); | ||
| 1684 | } | ||
| 1685 | |||
| 1686 | /* Draw the foreground of image glyph string S to PIXMAP. */ | ||
| 1687 | |||
| 1688 | static void | ||
| 1689 | android_draw_image_foreground_1 (struct glyph_string *s, | ||
| 1690 | android_pixmap pixmap) | ||
| 1691 | { | ||
| 1692 | int x = 0; | ||
| 1693 | int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice); | ||
| 1694 | |||
| 1695 | /* If first glyph of S has a left box line, start drawing it to the | ||
| 1696 | right of that line. */ | ||
| 1697 | if (s->face->box != FACE_NO_BOX | ||
| 1698 | && s->first_glyph->left_box_line_p | ||
| 1699 | && s->slice.x == 0) | ||
| 1700 | x += max (s->face->box_vertical_line_width, 0); | ||
| 1701 | |||
| 1702 | /* If there is a margin around the image, adjust x- and y-position | ||
| 1703 | by that margin. */ | ||
| 1704 | if (s->slice.x == 0) | ||
| 1705 | x += s->img->hmargin; | ||
| 1706 | if (s->slice.y == 0) | ||
| 1707 | y += s->img->vmargin; | ||
| 1708 | |||
| 1709 | if (s->img->pixmap) | ||
| 1710 | { | ||
| 1711 | if (s->img->mask) | ||
| 1712 | { | ||
| 1713 | unsigned long mask = (ANDROID_GC_CLIP_MASK | ||
| 1714 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 1715 | | ANDROID_GC_CLIP_Y_ORIGIN | ||
| 1716 | | ANDROID_GC_FUNCTION); | ||
| 1717 | struct android_gc_values xgcv; | ||
| 1718 | struct android_rectangle clip_rect, image_rect, r; | ||
| 1719 | |||
| 1720 | xgcv.clip_mask = s->img->mask; | ||
| 1721 | xgcv.clip_x_origin = x - s->slice.x; | ||
| 1722 | xgcv.clip_y_origin = y - s->slice.y; | ||
| 1723 | xgcv.function = ANDROID_GC_COPY; | ||
| 1724 | android_change_gc (s->gc, mask, &xgcv); | ||
| 1725 | |||
| 1726 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1727 | image_rect.x = x; | ||
| 1728 | image_rect.y = y; | ||
| 1729 | image_rect.width = s->slice.width; | ||
| 1730 | image_rect.height = s->slice.height; | ||
| 1731 | |||
| 1732 | if (gui_intersect_rectangles (&clip_rect, &image_rect, &r)) | ||
| 1733 | android_copy_area (s->img->pixmap, pixmap, s->gc, | ||
| 1734 | s->slice.x + r.x - x, | ||
| 1735 | s->slice.y + r.y - y, | ||
| 1736 | r.x, r.y, r.width, r.height); | ||
| 1737 | |||
| 1738 | android_set_clip_mask (s->gc, ANDROID_NONE); | ||
| 1739 | } | ||
| 1740 | else | ||
| 1741 | { | ||
| 1742 | android_copy_area (s->img->pixmap, pixmap, s->gc, | ||
| 1743 | s->slice.x, s->slice.y, | ||
| 1744 | s->slice.width, s->slice.height, x, y); | ||
| 1745 | |||
| 1746 | /* When the image has a mask, we can expect that at | ||
| 1747 | least part of a mouse highlight or a block cursor will | ||
| 1748 | be visible. If the image doesn't have a mask, make | ||
| 1749 | a block cursor visible by drawing a rectangle around | ||
| 1750 | the image. I believe it's looking better if we do | ||
| 1751 | nothing here for mouse-face. */ | ||
| 1752 | if (s->hl == DRAW_CURSOR) | ||
| 1753 | { | ||
| 1754 | int r = eabs (s->img->relief); | ||
| 1755 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 1756 | s->gc, x - r, y - r, | ||
| 1757 | s->slice.width + r*2 - 1, | ||
| 1758 | s->slice.height + r*2 - 1); | ||
| 1759 | } | ||
| 1760 | } | ||
| 1761 | } | ||
| 1762 | else | ||
| 1763 | /* Draw a rectangle if image could not be loaded. */ | ||
| 1764 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, x, y, | ||
| 1765 | s->slice.width - 1, s->slice.height - 1); | ||
| 1766 | } | ||
| 1767 | |||
| 1768 | static void | ||
| 1769 | android_draw_image_glyph_string (struct glyph_string *s) | ||
| 1770 | { | ||
| 1771 | int box_line_hwidth = max (s->face->box_vertical_line_width, 0); | ||
| 1772 | int box_line_vwidth = max (s->face->box_horizontal_line_width, 0); | ||
| 1773 | int height; | ||
| 1774 | android_pixmap pixmap = ANDROID_NONE; | ||
| 1775 | |||
| 1776 | height = s->height; | ||
| 1777 | if (s->slice.y == 0) | ||
| 1778 | height -= box_line_vwidth; | ||
| 1779 | if (s->slice.y + s->slice.height >= s->img->height) | ||
| 1780 | height -= box_line_vwidth; | ||
| 1781 | |||
| 1782 | /* Fill background with face under the image. Do it only if row is | ||
| 1783 | taller than image or if image has a clip mask to reduce | ||
| 1784 | flickering. */ | ||
| 1785 | s->stippled_p = s->face->stipple != 0; | ||
| 1786 | if (height > s->slice.height | ||
| 1787 | || s->img->hmargin | ||
| 1788 | || s->img->vmargin | ||
| 1789 | || s->img->mask | ||
| 1790 | || s->img->pixmap == 0 | ||
| 1791 | || s->width != s->background_width) | ||
| 1792 | { | ||
| 1793 | if (s->stippled_p) | ||
| 1794 | s->row->stipple_p = true; | ||
| 1795 | |||
| 1796 | if (s->img->mask) | ||
| 1797 | { | ||
| 1798 | /* Create a pixmap as large as the glyph string. Fill it | ||
| 1799 | with the background color. Copy the image to it, using | ||
| 1800 | its mask. Copy the temporary pixmap to the display. */ | ||
| 1801 | int depth = FRAME_DISPLAY_INFO (s->f)->n_planes; | ||
| 1802 | |||
| 1803 | /* Create a pixmap as large as the glyph string. */ | ||
| 1804 | pixmap = android_create_pixmap (s->background_width, | ||
| 1805 | s->height, depth); | ||
| 1806 | |||
| 1807 | /* Don't clip in the following because we're working on the | ||
| 1808 | pixmap. */ | ||
| 1809 | android_set_clip_mask (s->gc, ANDROID_NONE); | ||
| 1810 | |||
| 1811 | /* Fill the pixmap with the background color/stipple. */ | ||
| 1812 | if (s->stippled_p) | ||
| 1813 | { | ||
| 1814 | /* Fill background with a stipple pattern. */ | ||
| 1815 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1816 | android_set_ts_origin (s->gc, - s->x, - s->y); | ||
| 1817 | android_fill_rectangle (pixmap, s->gc, | ||
| 1818 | 0, 0, s->background_width, s->height); | ||
| 1819 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1820 | android_set_ts_origin (s->gc, 0, 0); | ||
| 1821 | } | ||
| 1822 | else | ||
| 1823 | { | ||
| 1824 | struct android_gc_values xgcv; | ||
| 1825 | |||
| 1826 | android_get_gc_values (s->gc, (ANDROID_GC_FOREGROUND | ||
| 1827 | | ANDROID_GC_BACKGROUND), | ||
| 1828 | &xgcv); | ||
| 1829 | android_set_foreground (s->gc, xgcv.background); | ||
| 1830 | android_fill_rectangle (pixmap, s->gc, | ||
| 1831 | 0, 0, s->background_width, s->height); | ||
| 1832 | android_set_background (s->gc, xgcv.foreground); | ||
| 1833 | } | ||
| 1834 | } | ||
| 1835 | else | ||
| 1836 | { | ||
| 1837 | int x = s->x; | ||
| 1838 | int y = s->y; | ||
| 1839 | int width = s->background_width; | ||
| 1840 | |||
| 1841 | if (s->first_glyph->left_box_line_p | ||
| 1842 | && s->slice.x == 0) | ||
| 1843 | { | ||
| 1844 | x += box_line_hwidth; | ||
| 1845 | width -= box_line_hwidth; | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | if (s->slice.y == 0) | ||
| 1849 | y += box_line_vwidth; | ||
| 1850 | |||
| 1851 | android_draw_glyph_string_bg_rect (s, x, y, width, height); | ||
| 1852 | } | ||
| 1853 | |||
| 1854 | s->background_filled_p = true; | ||
| 1855 | } | ||
| 1856 | |||
| 1857 | /* Draw the foreground. */ | ||
| 1858 | if (pixmap != ANDROID_NONE) | ||
| 1859 | { | ||
| 1860 | android_draw_image_foreground_1 (s, pixmap); | ||
| 1861 | android_set_glyph_string_clipping (s); | ||
| 1862 | android_copy_area (pixmap, FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1863 | 0, 0, s->background_width, s->height, s->x, | ||
| 1864 | s->y); | ||
| 1865 | android_free_pixmap (pixmap); | ||
| 1866 | } | ||
| 1867 | else | ||
| 1868 | android_draw_image_foreground (s); | ||
| 1869 | |||
| 1870 | /* If we must draw a relief around the image, do it. */ | ||
| 1871 | if (s->img->relief | ||
| 1872 | || s->hl == DRAW_IMAGE_RAISED | ||
| 1873 | || s->hl == DRAW_IMAGE_SUNKEN) | ||
| 1874 | android_draw_image_relief (s); | ||
| 1875 | } | ||
| 1876 | |||
| 1877 | static void | ||
| 1878 | android_draw_stretch_glyph_string (struct glyph_string *s) | ||
| 1879 | { | ||
| 1880 | eassert (s->first_glyph->type == STRETCH_GLYPH); | ||
| 1881 | |||
| 1882 | if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p) | ||
| 1883 | { | ||
| 1884 | /* If `x-stretch-cursor' is nil, don't draw a block cursor as | ||
| 1885 | wide as the stretch glyph. */ | ||
| 1886 | int width, background_width = s->background_width; | ||
| 1887 | int x = s->x; | ||
| 1888 | |||
| 1889 | if (!s->row->reversed_p) | ||
| 1890 | { | ||
| 1891 | int left_x = window_box_left_offset (s->w, TEXT_AREA); | ||
| 1892 | |||
| 1893 | if (x < left_x) | ||
| 1894 | { | ||
| 1895 | background_width -= left_x - x; | ||
| 1896 | x = left_x; | ||
| 1897 | } | ||
| 1898 | } | ||
| 1899 | else | ||
| 1900 | { | ||
| 1901 | /* In R2L rows, draw the cursor on the right edge of the | ||
| 1902 | stretch glyph. */ | ||
| 1903 | int right_x = window_box_right (s->w, TEXT_AREA); | ||
| 1904 | |||
| 1905 | if (x + background_width > right_x) | ||
| 1906 | background_width -= x - right_x; | ||
| 1907 | x += background_width; | ||
| 1908 | } | ||
| 1909 | width = min (FRAME_COLUMN_WIDTH (s->f), background_width); | ||
| 1910 | if (s->row->reversed_p) | ||
| 1911 | x -= width; | ||
| 1912 | |||
| 1913 | /* Draw cursor. */ | ||
| 1914 | android_draw_glyph_string_bg_rect (s, x, s->y, width, s->height); | ||
| 1915 | |||
| 1916 | /* Clear rest using the GC of the original non-cursor face. */ | ||
| 1917 | if (width < background_width) | ||
| 1918 | { | ||
| 1919 | int y = s->y; | ||
| 1920 | int w = background_width - width, h = s->height; | ||
| 1921 | struct android_rectangle r; | ||
| 1922 | struct android_gc *gc; | ||
| 1923 | |||
| 1924 | if (!s->row->reversed_p) | ||
| 1925 | x += width; | ||
| 1926 | else | ||
| 1927 | x = s->x; | ||
| 1928 | if (s->row->mouse_face_p | ||
| 1929 | && cursor_in_mouse_face_p (s->w)) | ||
| 1930 | { | ||
| 1931 | android_set_mouse_face_gc (s); | ||
| 1932 | gc = s->gc; | ||
| 1933 | } | ||
| 1934 | else | ||
| 1935 | gc = s->face->gc; | ||
| 1936 | |||
| 1937 | get_glyph_string_clip_rect (s, &r); | ||
| 1938 | android_set_clip_rectangles (gc, 0, 0, &r, 1); | ||
| 1939 | |||
| 1940 | if (s->face->stipple) | ||
| 1941 | { | ||
| 1942 | /* Fill background with a stipple pattern. */ | ||
| 1943 | android_set_fill_style (gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1944 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 1945 | gc, x, y, w, h); | ||
| 1946 | android_set_fill_style (gc, ANDROID_FILL_SOLID); | ||
| 1947 | |||
| 1948 | s->row->stipple_p = true; | ||
| 1949 | } | ||
| 1950 | else | ||
| 1951 | { | ||
| 1952 | struct android_gc_values xgcv; | ||
| 1953 | android_get_gc_values (gc, (ANDROID_GC_FOREGROUND | ||
| 1954 | | ANDROID_GC_BACKGROUND), | ||
| 1955 | &xgcv); | ||
| 1956 | android_set_foreground (gc, xgcv.background); | ||
| 1957 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 1958 | gc, x, y, w, h); | ||
| 1959 | android_set_foreground (gc, xgcv.foreground); | ||
| 1960 | } | ||
| 1961 | |||
| 1962 | android_reset_clip_rectangles (s->f, gc); | ||
| 1963 | } | ||
| 1964 | } | ||
| 1965 | else if (!s->background_filled_p) | ||
| 1966 | { | ||
| 1967 | int background_width = s->background_width; | ||
| 1968 | int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA); | ||
| 1969 | |||
| 1970 | /* Don't draw into left fringe or scrollbar area except for | ||
| 1971 | header line and mode line. */ | ||
| 1972 | if (s->area == TEXT_AREA | ||
| 1973 | && x < text_left_x && !s->row->mode_line_p) | ||
| 1974 | { | ||
| 1975 | background_width -= text_left_x - x; | ||
| 1976 | x = text_left_x; | ||
| 1977 | } | ||
| 1978 | |||
| 1979 | if (!s->row->stipple_p) | ||
| 1980 | s->row->stipple_p = s->stippled_p; | ||
| 1981 | |||
| 1982 | if (background_width > 0) | ||
| 1983 | android_draw_glyph_string_bg_rect (s, x, s->y, | ||
| 1984 | background_width, | ||
| 1985 | s->height); | ||
| 1986 | } | ||
| 1987 | |||
| 1988 | s->background_filled_p = true; | ||
| 1989 | } | ||
| 1990 | |||
| 1991 | static void | ||
| 1992 | android_draw_underwave (struct glyph_string *s, int decoration_width) | ||
| 1993 | { | ||
| 1994 | int wave_height = 3, wave_length = 2; | ||
| 1995 | int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax; | ||
| 1996 | bool odd; | ||
| 1997 | struct android_rectangle wave_clip, string_clip, final_clip; | ||
| 1998 | |||
| 1999 | dx = wave_length; | ||
| 2000 | dy = wave_height - 1; | ||
| 2001 | x0 = s->x; | ||
| 2002 | y0 = s->ybase + wave_height / 2; | ||
| 2003 | width = decoration_width; | ||
| 2004 | xmax = x0 + width; | ||
| 2005 | |||
| 2006 | /* Find and set clipping rectangle */ | ||
| 2007 | |||
| 2008 | wave_clip.x = x0; | ||
| 2009 | wave_clip.y = y0; | ||
| 2010 | wave_clip.width = width; | ||
| 2011 | wave_clip.height = wave_height; | ||
| 2012 | get_glyph_string_clip_rect (s, &string_clip); | ||
| 2013 | |||
| 2014 | if (!gui_intersect_rectangles (&wave_clip, &string_clip, &final_clip)) | ||
| 2015 | return; | ||
| 2016 | |||
| 2017 | android_set_clip_rectangles (s->gc, 0, 0, &final_clip, 1); | ||
| 2018 | |||
| 2019 | /* Draw the waves */ | ||
| 2020 | |||
| 2021 | x1 = x0 - (x0 % dx); | ||
| 2022 | x2 = x1 + dx; | ||
| 2023 | odd = (x1 / dx) & 1; | ||
| 2024 | y1 = y2 = y0; | ||
| 2025 | |||
| 2026 | if (odd) | ||
| 2027 | y1 += dy; | ||
| 2028 | else | ||
| 2029 | y2 += dy; | ||
| 2030 | |||
| 2031 | if (INT_MAX - dx < xmax) | ||
| 2032 | emacs_abort (); | ||
| 2033 | |||
| 2034 | while (x1 <= xmax) | ||
| 2035 | { | ||
| 2036 | android_draw_line (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2037 | x1, y1, x2, y2); | ||
| 2038 | x1 = x2, y1 = y2; | ||
| 2039 | x2 += dx, y2 = y0 + odd*dy; | ||
| 2040 | odd = !odd; | ||
| 2041 | } | ||
| 2042 | |||
| 2043 | /* Restore previous clipping rectangle(s) */ | ||
| 2044 | android_set_clip_rectangles (s->gc, 0, 0, s->clip, s->num_clips); | ||
| 2045 | } | ||
| 2046 | |||
| 2047 | static void | ||
| 2048 | android_draw_glyph_string_foreground (struct glyph_string *s) | ||
| 2049 | { | ||
| 2050 | int i, x; | ||
| 2051 | |||
| 2052 | /* If first glyph of S has a left box line, start drawing the text | ||
| 2053 | of S to the right of that box line. */ | ||
| 2054 | if (s->face->box != FACE_NO_BOX | ||
| 2055 | && s->first_glyph->left_box_line_p) | ||
| 2056 | x = s->x + max (s->face->box_vertical_line_width, 0); | ||
| 2057 | else | ||
| 2058 | x = s->x; | ||
| 2059 | |||
| 2060 | /* Draw characters of S as rectangles if S's font could not be | ||
| 2061 | loaded. */ | ||
| 2062 | if (s->font_not_found_p) | ||
| 2063 | { | ||
| 2064 | for (i = 0; i < s->nchars; ++i) | ||
| 2065 | { | ||
| 2066 | struct glyph *g = s->first_glyph + i; | ||
| 2067 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2068 | s->gc, x, s->y, | ||
| 2069 | g->pixel_width - 1, | ||
| 2070 | s->height - 1); | ||
| 2071 | x += g->pixel_width; | ||
| 2072 | } | ||
| 2073 | } | ||
| 2074 | else | ||
| 2075 | { | ||
| 2076 | struct font *font = s->font; | ||
| 2077 | int boff = font->baseline_offset; | ||
| 2078 | int y; | ||
| 2079 | |||
| 2080 | if (font->vertical_centering) | ||
| 2081 | boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff; | ||
| 2082 | |||
| 2083 | y = s->ybase - boff; | ||
| 2084 | if (s->for_overlaps | ||
| 2085 | || (s->background_filled_p && s->hl != DRAW_CURSOR)) | ||
| 2086 | font->driver->draw (s, 0, s->nchars, x, y, false); | ||
| 2087 | else | ||
| 2088 | font->driver->draw (s, 0, s->nchars, x, y, true); | ||
| 2089 | if (s->face->overstrike) | ||
| 2090 | font->driver->draw (s, 0, s->nchars, x + 1, y, false); | ||
| 2091 | } | ||
| 2092 | } | ||
| 2093 | |||
| 2094 | static void | ||
| 2095 | android_draw_composite_glyph_string_foreground (struct glyph_string *s) | ||
| 2096 | { | ||
| 2097 | int i, j, x; | ||
| 2098 | struct font *font = s->font; | ||
| 2099 | |||
| 2100 | /* If first glyph of S has a left box line, start drawing the text | ||
| 2101 | of S to the right of that box line. */ | ||
| 2102 | if (s->face && s->face->box != FACE_NO_BOX | ||
| 2103 | && s->first_glyph->left_box_line_p) | ||
| 2104 | x = s->x + max (s->face->box_vertical_line_width, 0); | ||
| 2105 | else | ||
| 2106 | x = s->x; | ||
| 2107 | |||
| 2108 | /* S is a glyph string for a composition. S->cmp_from is the index | ||
| 2109 | of the first character drawn for glyphs of this composition. | ||
| 2110 | S->cmp_from == 0 means we are drawing the very first character of | ||
| 2111 | this composition. */ | ||
| 2112 | |||
| 2113 | /* Draw a rectangle for the composition if the font for the very | ||
| 2114 | first character of the composition could not be loaded. */ | ||
| 2115 | if (s->font_not_found_p) | ||
| 2116 | { | ||
| 2117 | if (s->cmp_from == 0) | ||
| 2118 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2119 | s->gc, x, s->y, | ||
| 2120 | s->width - 1, s->height - 1); | ||
| 2121 | } | ||
| 2122 | else if (! s->first_glyph->u.cmp.automatic) | ||
| 2123 | { | ||
| 2124 | int y = s->ybase; | ||
| 2125 | |||
| 2126 | for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++) | ||
| 2127 | /* TAB in a composition means display glyphs with | ||
| 2128 | padding space on the left or right. */ | ||
| 2129 | if (COMPOSITION_GLYPH (s->cmp, j) != '\t') | ||
| 2130 | { | ||
| 2131 | int xx = x + s->cmp->offsets[j * 2]; | ||
| 2132 | int yy = y - s->cmp->offsets[j * 2 + 1]; | ||
| 2133 | |||
| 2134 | font->driver->draw (s, j, j + 1, xx, yy, false); | ||
| 2135 | if (s->face->overstrike) | ||
| 2136 | font->driver->draw (s, j, j + 1, xx + 1, yy, false); | ||
| 2137 | } | ||
| 2138 | } | ||
| 2139 | else | ||
| 2140 | { | ||
| 2141 | Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); | ||
| 2142 | Lisp_Object glyph; | ||
| 2143 | int y = s->ybase; | ||
| 2144 | int width = 0; | ||
| 2145 | |||
| 2146 | for (i = j = s->cmp_from; i < s->cmp_to; i++) | ||
| 2147 | { | ||
| 2148 | glyph = LGSTRING_GLYPH (gstring, i); | ||
| 2149 | if (NILP (LGLYPH_ADJUSTMENT (glyph))) | ||
| 2150 | width += LGLYPH_WIDTH (glyph); | ||
| 2151 | else | ||
| 2152 | { | ||
| 2153 | int xoff, yoff, wadjust; | ||
| 2154 | |||
| 2155 | if (j < i) | ||
| 2156 | { | ||
| 2157 | font->driver->draw (s, j, i, x, y, false); | ||
| 2158 | if (s->face->overstrike) | ||
| 2159 | font->driver->draw (s, j, i, x + 1, y, false); | ||
| 2160 | x += width; | ||
| 2161 | } | ||
| 2162 | xoff = LGLYPH_XOFF (glyph); | ||
| 2163 | yoff = LGLYPH_YOFF (glyph); | ||
| 2164 | wadjust = LGLYPH_WADJUST (glyph); | ||
| 2165 | font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false); | ||
| 2166 | if (s->face->overstrike) | ||
| 2167 | font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff, | ||
| 2168 | false); | ||
| 2169 | x += wadjust; | ||
| 2170 | j = i + 1; | ||
| 2171 | width = 0; | ||
| 2172 | } | ||
| 2173 | } | ||
| 2174 | if (j < i) | ||
| 2175 | { | ||
| 2176 | font->driver->draw (s, j, i, x, y, false); | ||
| 2177 | if (s->face->overstrike) | ||
| 2178 | font->driver->draw (s, j, i, x + 1, y, false); | ||
| 2179 | } | ||
| 2180 | } | ||
| 2181 | } | ||
| 2182 | |||
| 2183 | static void | ||
| 2184 | android_draw_glyphless_glyph_string_foreground (struct glyph_string *s) | ||
| 2185 | { | ||
| 2186 | struct glyph *glyph = s->first_glyph; | ||
| 2187 | unsigned char2b[8]; | ||
| 2188 | int x, i, j; | ||
| 2189 | |||
| 2190 | /* If first glyph of S has a left box line, start drawing the text | ||
| 2191 | of S to the right of that box line. */ | ||
| 2192 | if (s->face && s->face->box != FACE_NO_BOX | ||
| 2193 | && s->first_glyph->left_box_line_p) | ||
| 2194 | x = s->x + max (s->face->box_vertical_line_width, 0); | ||
| 2195 | else | ||
| 2196 | x = s->x; | ||
| 2197 | |||
| 2198 | s->char2b = char2b; | ||
| 2199 | |||
| 2200 | for (i = 0; i < s->nchars; i++, glyph++) | ||
| 2201 | { | ||
| 2202 | #ifdef GCC_LINT | ||
| 2203 | enum { PACIFY_GCC_BUG_81401 = 1 }; | ||
| 2204 | #else | ||
| 2205 | enum { PACIFY_GCC_BUG_81401 = 0 }; | ||
| 2206 | #endif | ||
| 2207 | char buf[7 + PACIFY_GCC_BUG_81401]; | ||
| 2208 | char *str = NULL; | ||
| 2209 | int len = glyph->u.glyphless.len; | ||
| 2210 | |||
| 2211 | if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM) | ||
| 2212 | { | ||
| 2213 | if (len > 0 | ||
| 2214 | && CHAR_TABLE_P (Vglyphless_char_display) | ||
| 2215 | && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) | ||
| 2216 | >= 1)) | ||
| 2217 | { | ||
| 2218 | Lisp_Object acronym | ||
| 2219 | = (! glyph->u.glyphless.for_no_font | ||
| 2220 | ? CHAR_TABLE_REF (Vglyphless_char_display, | ||
| 2221 | glyph->u.glyphless.ch) | ||
| 2222 | : XCHAR_TABLE (Vglyphless_char_display)->extras[0]); | ||
| 2223 | if (CONSP (acronym)) | ||
| 2224 | acronym = XCAR (acronym); | ||
| 2225 | if (STRINGP (acronym)) | ||
| 2226 | str = SSDATA (acronym); | ||
| 2227 | } | ||
| 2228 | } | ||
| 2229 | else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE) | ||
| 2230 | { | ||
| 2231 | unsigned int ch = glyph->u.glyphless.ch; | ||
| 2232 | eassume (ch <= MAX_CHAR); | ||
| 2233 | sprintf (buf, "%0*X", ch < 0x10000 ? 4 : 6, ch); | ||
| 2234 | str = buf; | ||
| 2235 | } | ||
| 2236 | |||
| 2237 | if (str) | ||
| 2238 | { | ||
| 2239 | int upper_len = (len + 1) / 2; | ||
| 2240 | |||
| 2241 | /* It is assured that all LEN characters in STR is ASCII. */ | ||
| 2242 | for (j = 0; j < len; j++) | ||
| 2243 | char2b[j] = s->font->driver->encode_char (s->font, str[j]) & 0xFFFF; | ||
| 2244 | s->font->driver->draw (s, 0, upper_len, | ||
| 2245 | x + glyph->slice.glyphless.upper_xoff, | ||
| 2246 | s->ybase + glyph->slice.glyphless.upper_yoff, | ||
| 2247 | false); | ||
| 2248 | s->font->driver->draw (s, upper_len, len, | ||
| 2249 | x + glyph->slice.glyphless.lower_xoff, | ||
| 2250 | s->ybase + glyph->slice.glyphless.lower_yoff, | ||
| 2251 | false); | ||
| 2252 | } | ||
| 2253 | if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE) | ||
| 2254 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2255 | x, s->ybase - glyph->ascent, | ||
| 2256 | glyph->pixel_width - 1, | ||
| 2257 | glyph->ascent + glyph->descent - 1); | ||
| 2258 | x += glyph->pixel_width; | ||
| 2259 | } | ||
| 2260 | |||
| 2261 | /* Defend against hypothetical bad code elsewhere that uses | ||
| 2262 | s->char2b after this function returns. */ | ||
| 2263 | s->char2b = NULL; | ||
| 2264 | } | ||
| 2265 | |||
| 2266 | static void | ||
| 2267 | android_draw_glyph_string (struct glyph_string *s) | ||
| 2268 | { | ||
| 2269 | bool relief_drawn_p = false; | ||
| 2270 | |||
| 2271 | /* If S draws into the background of its successors, draw the | ||
| 2272 | background of the successors first so that S can draw into it. | ||
| 2273 | This makes S->next use XDrawString instead of XDrawImageString. */ | ||
| 2274 | if (s->next && s->right_overhang && !s->for_overlaps) | ||
| 2275 | { | ||
| 2276 | int width; | ||
| 2277 | struct glyph_string *next; | ||
| 2278 | |||
| 2279 | for (width = 0, next = s->next; | ||
| 2280 | next && width < s->right_overhang; | ||
| 2281 | width += next->width, next = next->next) | ||
| 2282 | if (next->first_glyph->type != IMAGE_GLYPH) | ||
| 2283 | { | ||
| 2284 | android_set_glyph_string_gc (next); | ||
| 2285 | android_set_glyph_string_clipping (next); | ||
| 2286 | if (next->first_glyph->type == STRETCH_GLYPH) | ||
| 2287 | android_draw_stretch_glyph_string (next); | ||
| 2288 | else | ||
| 2289 | android_draw_glyph_string_background (next, true); | ||
| 2290 | next->num_clips = 0; | ||
| 2291 | } | ||
| 2292 | } | ||
| 2293 | |||
| 2294 | /* Set up S->gc, set clipping and draw S. */ | ||
| 2295 | android_set_glyph_string_gc (s); | ||
| 2296 | |||
| 2297 | /* Draw relief (if any) in advance for char/composition so that the | ||
| 2298 | glyph string can be drawn over it. */ | ||
| 2299 | if (!s->for_overlaps | ||
| 2300 | && s->face->box != FACE_NO_BOX | ||
| 2301 | && (s->first_glyph->type == CHAR_GLYPH | ||
| 2302 | || s->first_glyph->type == COMPOSITE_GLYPH)) | ||
| 2303 | |||
| 2304 | { | ||
| 2305 | android_set_glyph_string_clipping (s); | ||
| 2306 | android_draw_glyph_string_background (s, true); | ||
| 2307 | android_draw_glyph_string_box (s); | ||
| 2308 | android_set_glyph_string_clipping (s); | ||
| 2309 | relief_drawn_p = true; | ||
| 2310 | } | ||
| 2311 | else if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */ | ||
| 2312 | && !s->clip_tail | ||
| 2313 | && ((s->prev && s->prev->hl != s->hl && s->left_overhang) | ||
| 2314 | || (s->next && s->next->hl != s->hl && s->right_overhang))) | ||
| 2315 | /* We must clip just this glyph. left_overhang part has already | ||
| 2316 | drawn when s->prev was drawn, and right_overhang part will be | ||
| 2317 | drawn later when s->next is drawn. */ | ||
| 2318 | android_set_glyph_string_clipping_exactly (s, s); | ||
| 2319 | else | ||
| 2320 | android_set_glyph_string_clipping (s); | ||
| 2321 | |||
| 2322 | switch (s->first_glyph->type) | ||
| 2323 | { | ||
| 2324 | case IMAGE_GLYPH: | ||
| 2325 | android_draw_image_glyph_string (s); | ||
| 2326 | break; | ||
| 2327 | |||
| 2328 | case XWIDGET_GLYPH: | ||
| 2329 | emacs_abort (); | ||
| 2330 | break; | ||
| 2331 | |||
| 2332 | case STRETCH_GLYPH: | ||
| 2333 | android_draw_stretch_glyph_string (s); | ||
| 2334 | break; | ||
| 2335 | |||
| 2336 | case CHAR_GLYPH: | ||
| 2337 | if (s->for_overlaps) | ||
| 2338 | s->background_filled_p = true; | ||
| 2339 | else | ||
| 2340 | android_draw_glyph_string_background (s, false); | ||
| 2341 | android_draw_glyph_string_foreground (s); | ||
| 2342 | break; | ||
| 2343 | |||
| 2344 | case COMPOSITE_GLYPH: | ||
| 2345 | if (s->for_overlaps || (s->cmp_from > 0 | ||
| 2346 | && ! s->first_glyph->u.cmp.automatic)) | ||
| 2347 | s->background_filled_p = true; | ||
| 2348 | else | ||
| 2349 | android_draw_glyph_string_background (s, true); | ||
| 2350 | android_draw_composite_glyph_string_foreground (s); | ||
| 2351 | break; | ||
| 2352 | |||
| 2353 | case GLYPHLESS_GLYPH: | ||
| 2354 | if (s->for_overlaps) | ||
| 2355 | s->background_filled_p = true; | ||
| 2356 | else | ||
| 2357 | android_draw_glyph_string_background (s, true); | ||
| 2358 | android_draw_glyphless_glyph_string_foreground (s); | ||
| 2359 | break; | ||
| 2360 | |||
| 2361 | default: | ||
| 2362 | emacs_abort (); | ||
| 2363 | } | ||
| 2364 | |||
| 2365 | if (!s->for_overlaps) | ||
| 2366 | { | ||
| 2367 | int area_x, area_y, area_width, area_height; | ||
| 2368 | int area_max_x, decoration_width; | ||
| 2369 | |||
| 2370 | /* Prevent the underline from overwriting surrounding areas | ||
| 2371 | and the fringe. */ | ||
| 2372 | window_box (s->w, s->area, &area_x, &area_y, | ||
| 2373 | &area_width, &area_height); | ||
| 2374 | area_max_x = area_x + area_width - 1; | ||
| 2375 | |||
| 2376 | decoration_width = s->width; | ||
| 2377 | if (!s->row->mode_line_p | ||
| 2378 | && !s->row->tab_line_p | ||
| 2379 | && area_max_x < (s->x + decoration_width - 1)) | ||
| 2380 | decoration_width -= (s->x + decoration_width - 1) - area_max_x; | ||
| 2381 | |||
| 2382 | /* Draw relief if not yet drawn. */ | ||
| 2383 | if (!relief_drawn_p && s->face->box != FACE_NO_BOX) | ||
| 2384 | android_draw_glyph_string_box (s); | ||
| 2385 | |||
| 2386 | /* Draw underline. */ | ||
| 2387 | if (s->face->underline) | ||
| 2388 | { | ||
| 2389 | if (s->face->underline == FACE_UNDER_WAVE) | ||
| 2390 | { | ||
| 2391 | if (s->face->underline_defaulted_p) | ||
| 2392 | android_draw_underwave (s, decoration_width); | ||
| 2393 | else | ||
| 2394 | { | ||
| 2395 | struct android_gc_values xgcv; | ||
| 2396 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2397 | android_set_foreground (s->gc, s->face->underline_color); | ||
| 2398 | android_draw_underwave (s, decoration_width); | ||
| 2399 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2400 | } | ||
| 2401 | } | ||
| 2402 | else if (s->face->underline == FACE_UNDER_LINE) | ||
| 2403 | { | ||
| 2404 | unsigned long thickness, position; | ||
| 2405 | int y; | ||
| 2406 | |||
| 2407 | if (s->prev | ||
| 2408 | && s->prev->face->underline == FACE_UNDER_LINE | ||
| 2409 | && (s->prev->face->underline_at_descent_line_p | ||
| 2410 | == s->face->underline_at_descent_line_p) | ||
| 2411 | && (s->prev->face->underline_pixels_above_descent_line | ||
| 2412 | == s->face->underline_pixels_above_descent_line)) | ||
| 2413 | { | ||
| 2414 | /* We use the same underline style as the previous one. */ | ||
| 2415 | thickness = s->prev->underline_thickness; | ||
| 2416 | position = s->prev->underline_position; | ||
| 2417 | } | ||
| 2418 | else | ||
| 2419 | { | ||
| 2420 | struct font *font = font_for_underline_metrics (s); | ||
| 2421 | unsigned long minimum_offset; | ||
| 2422 | bool underline_at_descent_line; | ||
| 2423 | bool use_underline_position_properties; | ||
| 2424 | Lisp_Object val = (WINDOW_BUFFER_LOCAL_VALUE | ||
| 2425 | (Qunderline_minimum_offset, s->w)); | ||
| 2426 | |||
| 2427 | if (FIXNUMP (val)) | ||
| 2428 | minimum_offset = max (0, XFIXNUM (val)); | ||
| 2429 | else | ||
| 2430 | minimum_offset = 1; | ||
| 2431 | |||
| 2432 | val = (WINDOW_BUFFER_LOCAL_VALUE | ||
| 2433 | (Qx_underline_at_descent_line, s->w)); | ||
| 2434 | underline_at_descent_line | ||
| 2435 | = (!(NILP (val) || BASE_EQ (val, Qunbound)) | ||
| 2436 | || s->face->underline_at_descent_line_p); | ||
| 2437 | |||
| 2438 | val = (WINDOW_BUFFER_LOCAL_VALUE | ||
| 2439 | (Qx_use_underline_position_properties, s->w)); | ||
| 2440 | use_underline_position_properties | ||
| 2441 | = !(NILP (val) || BASE_EQ (val, Qunbound)); | ||
| 2442 | |||
| 2443 | /* Get the underline thickness. Default is 1 pixel. */ | ||
| 2444 | if (font && font->underline_thickness > 0) | ||
| 2445 | thickness = font->underline_thickness; | ||
| 2446 | else | ||
| 2447 | thickness = 1; | ||
| 2448 | if (underline_at_descent_line) | ||
| 2449 | position = ((s->height - thickness) | ||
| 2450 | - (s->ybase - s->y) | ||
| 2451 | - s->face->underline_pixels_above_descent_line); | ||
| 2452 | else | ||
| 2453 | { | ||
| 2454 | /* Get the underline position. This is the | ||
| 2455 | recommended vertical offset in pixels from | ||
| 2456 | the baseline to the top of the underline. | ||
| 2457 | This is a signed value according to the | ||
| 2458 | specs, and its default is | ||
| 2459 | |||
| 2460 | ROUND ((maximum descent) / 2), with | ||
| 2461 | ROUND(x) = floor (x + 0.5) */ | ||
| 2462 | |||
| 2463 | if (use_underline_position_properties | ||
| 2464 | && font && font->underline_position >= 0) | ||
| 2465 | position = font->underline_position; | ||
| 2466 | else if (font) | ||
| 2467 | position = (font->descent + 1) / 2; | ||
| 2468 | else | ||
| 2469 | position = minimum_offset; | ||
| 2470 | } | ||
| 2471 | |||
| 2472 | /* Ignore minimum_offset if the amount of pixels was | ||
| 2473 | explicitly specified. */ | ||
| 2474 | if (!s->face->underline_pixels_above_descent_line) | ||
| 2475 | position = max (position, minimum_offset); | ||
| 2476 | } | ||
| 2477 | /* Check the sanity of thickness and position. We should | ||
| 2478 | avoid drawing underline out of the current line area. */ | ||
| 2479 | if (s->y + s->height <= s->ybase + position) | ||
| 2480 | position = (s->height - 1) - (s->ybase - s->y); | ||
| 2481 | if (s->y + s->height < s->ybase + position + thickness) | ||
| 2482 | thickness = (s->y + s->height) - (s->ybase + position); | ||
| 2483 | s->underline_thickness = thickness; | ||
| 2484 | s->underline_position = position; | ||
| 2485 | y = s->ybase + position; | ||
| 2486 | if (s->face->underline_defaulted_p) | ||
| 2487 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2488 | s->x, y, decoration_width, thickness); | ||
| 2489 | else | ||
| 2490 | { | ||
| 2491 | struct android_gc_values xgcv; | ||
| 2492 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2493 | android_set_foreground (s->gc, s->face->underline_color); | ||
| 2494 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2495 | s->x, y, decoration_width, thickness); | ||
| 2496 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2497 | } | ||
| 2498 | } | ||
| 2499 | } | ||
| 2500 | /* Draw overline. */ | ||
| 2501 | if (s->face->overline_p) | ||
| 2502 | { | ||
| 2503 | unsigned long dy = 0, h = 1; | ||
| 2504 | |||
| 2505 | if (s->face->overline_color_defaulted_p) | ||
| 2506 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2507 | s->gc, s->x, s->y + dy, | ||
| 2508 | decoration_width, h); | ||
| 2509 | else | ||
| 2510 | { | ||
| 2511 | struct android_gc_values xgcv; | ||
| 2512 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2513 | android_set_foreground (s->gc, s->face->overline_color); | ||
| 2514 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, s->x, | ||
| 2515 | s->y + dy, decoration_width, h); | ||
| 2516 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2517 | } | ||
| 2518 | } | ||
| 2519 | |||
| 2520 | /* Draw strike-through. */ | ||
| 2521 | if (s->face->strike_through_p) | ||
| 2522 | { | ||
| 2523 | /* Y-coordinate and height of the glyph string's first | ||
| 2524 | glyph. We cannot use s->y and s->height because those | ||
| 2525 | could be larger if there are taller display elements | ||
| 2526 | (e.g., characters displayed with a larger font) in the | ||
| 2527 | same glyph row. */ | ||
| 2528 | int glyph_y = s->ybase - s->first_glyph->ascent; | ||
| 2529 | int glyph_height = s->first_glyph->ascent + s->first_glyph->descent; | ||
| 2530 | /* Strike-through width and offset from the glyph string's | ||
| 2531 | top edge. */ | ||
| 2532 | unsigned long h = 1; | ||
| 2533 | unsigned long dy = (glyph_height - h) / 2; | ||
| 2534 | |||
| 2535 | if (s->face->strike_through_color_defaulted_p) | ||
| 2536 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2537 | s->gc, s->x, glyph_y + dy, | ||
| 2538 | s->width, h); | ||
| 2539 | else | ||
| 2540 | { | ||
| 2541 | struct android_gc_values xgcv; | ||
| 2542 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2543 | android_set_foreground (s->gc, s->face->strike_through_color); | ||
| 2544 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, s->x, | ||
| 2545 | glyph_y + dy, decoration_width, h); | ||
| 2546 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2547 | } | ||
| 2548 | } | ||
| 2549 | |||
| 2550 | if (s->prev) | ||
| 2551 | { | ||
| 2552 | struct glyph_string *prev; | ||
| 2553 | |||
| 2554 | for (prev = s->prev; prev; prev = prev->prev) | ||
| 2555 | if (prev->hl != s->hl | ||
| 2556 | && prev->x + prev->width + prev->right_overhang > s->x) | ||
| 2557 | { | ||
| 2558 | /* As prev was drawn while clipped to its own area, we | ||
| 2559 | must draw the right_overhang part using s->hl now. */ | ||
| 2560 | enum draw_glyphs_face save = prev->hl; | ||
| 2561 | |||
| 2562 | prev->hl = s->hl; | ||
| 2563 | android_set_glyph_string_gc (prev); | ||
| 2564 | android_set_glyph_string_clipping_exactly (s, prev); | ||
| 2565 | if (prev->first_glyph->type == CHAR_GLYPH) | ||
| 2566 | android_draw_glyph_string_foreground (prev); | ||
| 2567 | else | ||
| 2568 | android_draw_composite_glyph_string_foreground (prev); | ||
| 2569 | android_reset_clip_rectangles (prev->f, prev->gc); | ||
| 2570 | prev->hl = save; | ||
| 2571 | prev->num_clips = 0; | ||
| 2572 | } | ||
| 2573 | } | ||
| 2574 | |||
| 2575 | if (s->next) | ||
| 2576 | { | ||
| 2577 | struct glyph_string *next; | ||
| 2578 | |||
| 2579 | for (next = s->next; next; next = next->next) | ||
| 2580 | if (next->hl != s->hl | ||
| 2581 | && next->x - next->left_overhang < s->x + s->width) | ||
| 2582 | { | ||
| 2583 | /* As next will be drawn while clipped to its own area, | ||
| 2584 | we must draw the left_overhang part using s->hl now. */ | ||
| 2585 | enum draw_glyphs_face save = next->hl; | ||
| 2586 | |||
| 2587 | next->hl = s->hl; | ||
| 2588 | android_set_glyph_string_gc (next); | ||
| 2589 | android_set_glyph_string_clipping_exactly (s, next); | ||
| 2590 | if (next->first_glyph->type == CHAR_GLYPH) | ||
| 2591 | android_draw_glyph_string_foreground (next); | ||
| 2592 | else | ||
| 2593 | android_draw_composite_glyph_string_foreground (next); | ||
| 2594 | android_reset_clip_rectangles (next->f, next->gc); | ||
| 2595 | next->hl = save; | ||
| 2596 | next->num_clips = 0; | ||
| 2597 | next->clip_head = s->next; | ||
| 2598 | } | ||
| 2599 | } | ||
| 2600 | } | ||
| 2601 | |||
| 2602 | /* Reset clipping. */ | ||
| 2603 | android_reset_clip_rectangles (s->f, s->gc); | ||
| 2604 | s->num_clips = 0; | ||
| 2605 | |||
| 2606 | /* Set the stippled flag that tells redisplay whether or not a | ||
| 2607 | stipple was actually draw. */ | ||
| 2608 | |||
| 2609 | if (s->first_glyph->type != STRETCH_GLYPH | ||
| 2610 | && s->first_glyph->type != IMAGE_GLYPH | ||
| 2611 | && !s->row->stipple_p) | ||
| 2612 | s->row->stipple_p = s->stippled_p; | ||
| 2613 | } | ||
| 2614 | |||
| 2615 | static void | ||
| 2616 | android_define_frame_cursor (struct frame *f, Emacs_Cursor cursor) | ||
| 2617 | { | ||
| 2618 | /* Not supported, because cursors are not supported on Android. */ | ||
| 2619 | } | ||
| 2620 | |||
| 2621 | static void | ||
| 2622 | android_clear_frame_area (struct frame *f, int x, int y, | ||
| 2623 | int width, int height) | ||
| 2624 | { | ||
| 2625 | android_clear_area (FRAME_ANDROID_WINDOW (f), | ||
| 2626 | x, y, width, height); | ||
| 2627 | } | ||
| 2628 | |||
| 2629 | void | ||
| 2630 | android_clear_under_internal_border (struct frame *f) | ||
| 2631 | { | ||
| 2632 | if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0) | ||
| 2633 | { | ||
| 2634 | int border = FRAME_INTERNAL_BORDER_WIDTH (f); | ||
| 2635 | int width = FRAME_PIXEL_WIDTH (f); | ||
| 2636 | int height = FRAME_PIXEL_HEIGHT (f); | ||
| 2637 | int margin = FRAME_TOP_MARGIN_HEIGHT (f); | ||
| 2638 | int face_id = | ||
| 2639 | (FRAME_PARENT_FRAME (f) | ||
| 2640 | ? (!NILP (Vface_remapping_alist) | ||
| 2641 | ? lookup_basic_face (NULL, f, CHILD_FRAME_BORDER_FACE_ID) | ||
| 2642 | : CHILD_FRAME_BORDER_FACE_ID) | ||
| 2643 | : (!NILP (Vface_remapping_alist) | ||
| 2644 | ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID) | ||
| 2645 | : INTERNAL_BORDER_FACE_ID)); | ||
| 2646 | struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); | ||
| 2647 | |||
| 2648 | if (face) | ||
| 2649 | { | ||
| 2650 | unsigned long color = face->background; | ||
| 2651 | struct android_gc *gc = f->output_data.android->normal_gc; | ||
| 2652 | |||
| 2653 | android_set_foreground (gc, color); | ||
| 2654 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0, margin, | ||
| 2655 | width, border); | ||
| 2656 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0, 0, | ||
| 2657 | border, height); | ||
| 2658 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, width - border, | ||
| 2659 | 0, border, height); | ||
| 2660 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0, | ||
| 2661 | height - border, width, border); | ||
| 2662 | android_set_foreground (gc, FRAME_FOREGROUND_PIXEL (f)); | ||
| 2663 | } | ||
| 2664 | else | ||
| 2665 | { | ||
| 2666 | android_clear_area (FRAME_ANDROID_WINDOW (f), 0, 0, | ||
| 2667 | border, height); | ||
| 2668 | android_clear_area (FRAME_ANDROID_WINDOW (f), 0, | ||
| 2669 | margin, width, border); | ||
| 2670 | android_clear_area (FRAME_ANDROID_WINDOW (f), width - border, | ||
| 2671 | 0, border, height); | ||
| 2672 | android_clear_area (FRAME_ANDROID_WINDOW (f), 0, | ||
| 2673 | height - border, width, border); | ||
| 2674 | } | ||
| 2675 | } | ||
| 2676 | } | ||
| 2677 | |||
| 2678 | static void | ||
| 2679 | android_draw_hollow_cursor (struct window *w, struct glyph_row *row) | ||
| 2680 | { | ||
| 2681 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 2682 | struct android_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 2683 | int x, y, wd, h; | ||
| 2684 | struct android_gc_values xgcv; | ||
| 2685 | struct glyph *cursor_glyph; | ||
| 2686 | struct android_gc *gc; | ||
| 2687 | |||
| 2688 | /* Get the glyph the cursor is on. If we can't tell because | ||
| 2689 | the current matrix is invalid or such, give up. */ | ||
| 2690 | cursor_glyph = get_phys_cursor_glyph (w); | ||
| 2691 | if (cursor_glyph == NULL) | ||
| 2692 | return; | ||
| 2693 | |||
| 2694 | /* Compute frame-relative coordinates for phys cursor. */ | ||
| 2695 | get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h); | ||
| 2696 | wd = w->phys_cursor_width - 1; | ||
| 2697 | |||
| 2698 | /* The foreground of cursor_gc is typically the same as the normal | ||
| 2699 | background color, which can cause the cursor box to be invisible. */ | ||
| 2700 | xgcv.foreground = f->output_data.android->cursor_pixel; | ||
| 2701 | if (dpyinfo->scratch_cursor_gc) | ||
| 2702 | android_change_gc (dpyinfo->scratch_cursor_gc, | ||
| 2703 | ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2704 | else | ||
| 2705 | dpyinfo->scratch_cursor_gc | ||
| 2706 | = android_create_gc (ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2707 | gc = dpyinfo->scratch_cursor_gc; | ||
| 2708 | |||
| 2709 | /* When on R2L character, show cursor at the right edge of the | ||
| 2710 | glyph, unless the cursor box is as wide as the glyph or wider | ||
| 2711 | (the latter happens when x-stretch-cursor is non-nil). */ | ||
| 2712 | if ((cursor_glyph->resolved_level & 1) != 0 | ||
| 2713 | && cursor_glyph->pixel_width > wd) | ||
| 2714 | { | ||
| 2715 | x += cursor_glyph->pixel_width - wd; | ||
| 2716 | if (wd > 0) | ||
| 2717 | wd -= 1; | ||
| 2718 | } | ||
| 2719 | /* Set clipping, draw the rectangle, and reset clipping again. */ | ||
| 2720 | android_clip_to_row (w, row, TEXT_AREA, gc); | ||
| 2721 | android_draw_rectangle (FRAME_ANDROID_WINDOW (f), gc, x, y, wd, h - 1); | ||
| 2722 | android_reset_clip_rectangles (f, gc); | ||
| 2723 | } | ||
| 2724 | |||
| 2725 | static void | ||
| 2726 | android_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, | ||
| 2727 | enum text_cursor_kinds kind) | ||
| 2728 | { | ||
| 2729 | struct frame *f = XFRAME (w->frame); | ||
| 2730 | struct glyph *cursor_glyph; | ||
| 2731 | int cursor_start_y; | ||
| 2732 | |||
| 2733 | /* If cursor is out of bounds, don't draw garbage. This can happen | ||
| 2734 | in mini-buffer windows when switching between echo area glyphs | ||
| 2735 | and mini-buffer. */ | ||
| 2736 | cursor_glyph = get_phys_cursor_glyph (w); | ||
| 2737 | if (cursor_glyph == NULL) | ||
| 2738 | return; | ||
| 2739 | |||
| 2740 | /* Experimental avoidance of cursor on xwidget. */ | ||
| 2741 | if (cursor_glyph->type == XWIDGET_GLYPH) | ||
| 2742 | return; | ||
| 2743 | |||
| 2744 | /* If on an image, draw like a normal cursor. That's usually better | ||
| 2745 | visible than drawing a bar, esp. if the image is large so that | ||
| 2746 | the bar might not be in the window. */ | ||
| 2747 | if (cursor_glyph->type == IMAGE_GLYPH) | ||
| 2748 | { | ||
| 2749 | struct glyph_row *r; | ||
| 2750 | r = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos); | ||
| 2751 | draw_phys_cursor_glyph (w, r, DRAW_CURSOR); | ||
| 2752 | } | ||
| 2753 | else | ||
| 2754 | { | ||
| 2755 | struct android_gc *gc = FRAME_DISPLAY_INFO (f)->scratch_cursor_gc; | ||
| 2756 | unsigned long mask = ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND; | ||
| 2757 | struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id); | ||
| 2758 | struct android_gc_values xgcv; | ||
| 2759 | |||
| 2760 | /* If the glyph's background equals the color we normally draw | ||
| 2761 | the bars cursor in, the bar cursor in its normal color is | ||
| 2762 | invisible. Use the glyph's foreground color instead in this | ||
| 2763 | case, on the assumption that the glyph's colors are chosen so | ||
| 2764 | that the glyph is legible. */ | ||
| 2765 | if (face->background == f->output_data.android->cursor_pixel) | ||
| 2766 | xgcv.background = xgcv.foreground = face->foreground; | ||
| 2767 | else | ||
| 2768 | xgcv.background = xgcv.foreground = f->output_data.android->cursor_pixel; | ||
| 2769 | |||
| 2770 | if (gc) | ||
| 2771 | android_change_gc (gc, mask, &xgcv); | ||
| 2772 | else | ||
| 2773 | { | ||
| 2774 | gc = android_create_gc (mask, &xgcv); | ||
| 2775 | FRAME_DISPLAY_INFO (f)->scratch_cursor_gc = gc; | ||
| 2776 | } | ||
| 2777 | |||
| 2778 | android_clip_to_row (w, row, TEXT_AREA, gc); | ||
| 2779 | |||
| 2780 | if (kind == BAR_CURSOR) | ||
| 2781 | { | ||
| 2782 | int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); | ||
| 2783 | |||
| 2784 | if (width < 0) | ||
| 2785 | width = FRAME_CURSOR_WIDTH (f); | ||
| 2786 | width = min (cursor_glyph->pixel_width, width); | ||
| 2787 | |||
| 2788 | w->phys_cursor_width = width; | ||
| 2789 | |||
| 2790 | /* If the character under cursor is R2L, draw the bar cursor | ||
| 2791 | on the right of its glyph, rather than on the left. */ | ||
| 2792 | if ((cursor_glyph->resolved_level & 1) != 0) | ||
| 2793 | x += cursor_glyph->pixel_width - width; | ||
| 2794 | |||
| 2795 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, x, | ||
| 2796 | WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), | ||
| 2797 | width, row->height); | ||
| 2798 | } | ||
| 2799 | else /* HBAR_CURSOR */ | ||
| 2800 | { | ||
| 2801 | int dummy_x, dummy_y, dummy_h; | ||
| 2802 | int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); | ||
| 2803 | |||
| 2804 | if (width < 0) | ||
| 2805 | width = row->height; | ||
| 2806 | |||
| 2807 | width = min (row->height, width); | ||
| 2808 | |||
| 2809 | get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x, | ||
| 2810 | &dummy_y, &dummy_h); | ||
| 2811 | |||
| 2812 | cursor_start_y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y | ||
| 2813 | + row->height - width); | ||
| 2814 | |||
| 2815 | if ((cursor_glyph->resolved_level & 1) != 0 | ||
| 2816 | && cursor_glyph->pixel_width > w->phys_cursor_width - 1) | ||
| 2817 | x += cursor_glyph->pixel_width - w->phys_cursor_width + 1; | ||
| 2818 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, x, | ||
| 2819 | cursor_start_y, | ||
| 2820 | w->phys_cursor_width - 1, width); | ||
| 2821 | } | ||
| 2822 | |||
| 2823 | android_reset_clip_rectangles (f, gc); | ||
| 2824 | } | ||
| 2825 | } | ||
| 2826 | |||
| 2827 | static void | ||
| 2828 | android_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, | ||
| 2829 | int x, int y, enum text_cursor_kinds cursor_type, | ||
| 2830 | int cursor_width, bool on_p, bool active_p) | ||
| 2831 | { | ||
| 2832 | if (on_p) | ||
| 2833 | { | ||
| 2834 | w->phys_cursor_type = cursor_type; | ||
| 2835 | w->phys_cursor_on_p = true; | ||
| 2836 | |||
| 2837 | if (glyph_row->exact_window_width_line_p | ||
| 2838 | && (glyph_row->reversed_p | ||
| 2839 | ? (w->phys_cursor.hpos < 0) | ||
| 2840 | : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]))) | ||
| 2841 | { | ||
| 2842 | glyph_row->cursor_in_fringe_p = true; | ||
| 2843 | draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p); | ||
| 2844 | } | ||
| 2845 | else | ||
| 2846 | { | ||
| 2847 | switch (cursor_type) | ||
| 2848 | { | ||
| 2849 | case HOLLOW_BOX_CURSOR: | ||
| 2850 | android_draw_hollow_cursor (w, glyph_row); | ||
| 2851 | break; | ||
| 2852 | |||
| 2853 | case FILLED_BOX_CURSOR: | ||
| 2854 | draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); | ||
| 2855 | break; | ||
| 2856 | |||
| 2857 | case BAR_CURSOR: | ||
| 2858 | android_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR); | ||
| 2859 | break; | ||
| 2860 | |||
| 2861 | case HBAR_CURSOR: | ||
| 2862 | android_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR); | ||
| 2863 | break; | ||
| 2864 | |||
| 2865 | case NO_CURSOR: | ||
| 2866 | w->phys_cursor_width = 0; | ||
| 2867 | break; | ||
| 2868 | |||
| 2869 | default: | ||
| 2870 | emacs_abort (); | ||
| 2871 | } | ||
| 2872 | } | ||
| 2873 | } | ||
| 2874 | } | ||
| 2875 | |||
| 2876 | static void | ||
| 2877 | android_draw_vertical_window_border (struct window *w, int x, int y0, int y1) | ||
| 2878 | { | ||
| 2879 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 2880 | struct face *face; | ||
| 2881 | |||
| 2882 | face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID); | ||
| 2883 | if (face) | ||
| 2884 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2885 | face->foreground); | ||
| 2886 | |||
| 2887 | android_draw_line (FRAME_ANDROID_WINDOW (f), | ||
| 2888 | f->output_data.android->normal_gc, | ||
| 2889 | x, y0, x, y1); | ||
| 2890 | } | ||
| 2891 | |||
| 2892 | static void | ||
| 2893 | android_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1) | ||
| 2894 | { | ||
| 2895 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 2896 | struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID); | ||
| 2897 | struct face *face_first | ||
| 2898 | = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID); | ||
| 2899 | struct face *face_last | ||
| 2900 | = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); | ||
| 2901 | unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f); | ||
| 2902 | unsigned long color_first = (face_first | ||
| 2903 | ? face_first->foreground | ||
| 2904 | : FRAME_FOREGROUND_PIXEL (f)); | ||
| 2905 | unsigned long color_last = (face_last | ||
| 2906 | ? face_last->foreground | ||
| 2907 | : FRAME_FOREGROUND_PIXEL (f)); | ||
| 2908 | |||
| 2909 | if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3)) | ||
| 2910 | /* A vertical divider, at least three pixels wide: Draw first and | ||
| 2911 | last pixels differently. */ | ||
| 2912 | { | ||
| 2913 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2914 | color_first); | ||
| 2915 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2916 | f->output_data.android->normal_gc, | ||
| 2917 | x0, y0, 1, y1 - y0); | ||
| 2918 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2919 | color); | ||
| 2920 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2921 | f->output_data.android->normal_gc, | ||
| 2922 | x0 + 1, y0, x1 - x0 - 2, y1 - y0); | ||
| 2923 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2924 | color_last); | ||
| 2925 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2926 | f->output_data.android->normal_gc, | ||
| 2927 | x1 - 1, y0, 1, y1 - y0); | ||
| 2928 | } | ||
| 2929 | else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3)) | ||
| 2930 | /* A horizontal divider, at least three pixels high: Draw first | ||
| 2931 | and last pixels differently. */ | ||
| 2932 | { | ||
| 2933 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2934 | color_first); | ||
| 2935 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2936 | f->output_data.android->normal_gc, | ||
| 2937 | x0, y0, x1 - x0, 1); | ||
| 2938 | android_set_foreground (f->output_data.android->normal_gc, color); | ||
| 2939 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2940 | f->output_data.android->normal_gc, | ||
| 2941 | x0, y0 + 1, x1 - x0, y1 - y0 - 2); | ||
| 2942 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2943 | color_last); | ||
| 2944 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2945 | f->output_data.android->normal_gc, | ||
| 2946 | x0, y1 - 1, x1 - x0, 1); | ||
| 2947 | } | ||
| 2948 | else | ||
| 2949 | { | ||
| 2950 | /* In any other case do not draw the first and last pixels | ||
| 2951 | differently. */ | ||
| 2952 | android_set_foreground (f->output_data.android->normal_gc, color); | ||
| 2953 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2954 | f->output_data.android->normal_gc, | ||
| 2955 | x0, y0, x1 - x0, y1 - y0); | ||
| 2956 | } | ||
| 2957 | } | ||
| 2958 | |||
| 2959 | |||
| 2960 | |||
| 2961 | extern frame_parm_handler android_frame_parm_handlers[]; | ||
| 2962 | |||
| 2963 | #endif /* !ANDROID_STUBIFY */ | ||
| 2964 | |||
| 2965 | static struct redisplay_interface android_redisplay_interface = | ||
| 2966 | { | ||
| 2967 | #ifndef ANDROID_STUBIFY | ||
| 2968 | android_frame_parm_handlers, | ||
| 2969 | gui_produce_glyphs, | ||
| 2970 | gui_write_glyphs, | ||
| 2971 | gui_insert_glyphs, | ||
| 2972 | gui_clear_end_of_line, | ||
| 2973 | android_scroll_run, | ||
| 2974 | android_after_update_window_line, | ||
| 2975 | NULL, /* update_window_begin */ | ||
| 2976 | NULL, /* update_window_end */ | ||
| 2977 | android_flip_and_flush, | ||
| 2978 | gui_clear_window_mouse_face, | ||
| 2979 | gui_get_glyph_overhangs, | ||
| 2980 | gui_fix_overlapping_area, | ||
| 2981 | android_draw_fringe_bitmap, | ||
| 2982 | NULL, /* define_fringe_bitmap */ | ||
| 2983 | NULL, /* destroy_fringe_bitmap */ | ||
| 2984 | android_compute_glyph_string_overhangs, | ||
| 2985 | android_draw_glyph_string, | ||
| 2986 | android_define_frame_cursor, | ||
| 2987 | android_clear_frame_area, | ||
| 2988 | android_clear_under_internal_border, | ||
| 2989 | android_draw_window_cursor, | ||
| 2990 | android_draw_vertical_window_border, | ||
| 2991 | android_draw_window_divider, | ||
| 2992 | NULL, | ||
| 2993 | NULL, | ||
| 2994 | NULL, | ||
| 2995 | android_default_font_parameter, | ||
| 2996 | #endif | ||
| 2997 | }; | ||
| 2998 | |||
| 2999 | |||
| 3000 | |||
| 3001 | void | ||
| 3002 | frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) | ||
| 3003 | { | ||
| 3004 | /* This cannot be implemented on Android, and as such is left | ||
| 3005 | blank. */ | ||
| 3006 | } | ||
| 3007 | |||
| 3008 | char * | ||
| 3009 | get_keysym_name (int keysym) | ||
| 3010 | { | ||
| 3011 | return (char *) "UNKNOWN KEYSYM"; | ||
| 3012 | } | ||
| 3013 | |||
| 3014 | |||
| 3015 | |||
| 3016 | /* Create a struct terminal, initialize it with the Android specific | ||
| 3017 | functions and make DISPLAY->TERMINAL point to it. */ | ||
| 3018 | |||
| 3019 | static struct terminal * | ||
| 3020 | android_create_terminal (struct android_display_info *dpyinfo) | ||
| 3021 | { | ||
| 3022 | struct terminal *terminal; | ||
| 3023 | |||
| 3024 | terminal = create_terminal (output_android, | ||
| 3025 | &android_redisplay_interface); | ||
| 3026 | terminal->display_info.android = dpyinfo; | ||
| 3027 | dpyinfo->terminal = terminal; | ||
| 3028 | |||
| 3029 | /* kboard is initialized in android_term_init. */ | ||
| 3030 | |||
| 3031 | #ifndef ANDROID_STUBIFY | ||
| 3032 | |||
| 3033 | terminal->clear_frame_hook = android_clear_frame; | ||
| 3034 | terminal->ring_bell_hook = android_ring_bell; | ||
| 3035 | terminal->toggle_invisible_pointer_hook | ||
| 3036 | = android_toggle_invisible_pointer; | ||
| 3037 | terminal->update_begin_hook = android_update_begin; | ||
| 3038 | terminal->update_end_hook = android_update_end; | ||
| 3039 | terminal->read_socket_hook = android_read_socket; | ||
| 3040 | terminal->frame_up_to_date_hook = android_frame_up_to_date; | ||
| 3041 | terminal->buffer_flipping_unblocked_hook | ||
| 3042 | = android_buffer_flipping_unblocked_hook; | ||
| 3043 | terminal->defined_color_hook = android_defined_color; | ||
| 3044 | terminal->query_frame_background_color | ||
| 3045 | = android_query_frame_background_color; | ||
| 3046 | terminal->query_colors = android_query_colors; | ||
| 3047 | terminal->mouse_position_hook = android_mouse_position; | ||
| 3048 | terminal->get_focus_frame = android_get_focus_frame; | ||
| 3049 | terminal->focus_frame_hook = android_focus_frame; | ||
| 3050 | terminal->frame_rehighlight_hook = android_frame_rehighlight; | ||
| 3051 | terminal->frame_raise_lower_hook = android_frame_raise_lower; | ||
| 3052 | terminal->frame_visible_invisible_hook | ||
| 3053 | = android_make_frame_visible_invisible; | ||
| 3054 | terminal->fullscreen_hook = android_fullscreen_hook; | ||
| 3055 | terminal->iconify_frame_hook = android_iconify_frame; | ||
| 3056 | terminal->set_window_size_hook = android_set_window_size; | ||
| 3057 | terminal->set_frame_offset_hook = android_set_offset; | ||
| 3058 | terminal->set_frame_alpha_hook = android_set_alpha; | ||
| 3059 | terminal->set_new_font_hook = android_new_font; | ||
| 3060 | terminal->set_bitmap_icon_hook = android_bitmap_icon; | ||
| 3061 | terminal->implicit_set_name_hook = android_implicitly_set_name; | ||
| 3062 | /* terminal->menu_show_hook = android_menu_show; XXX */ | ||
| 3063 | terminal->change_tab_bar_height_hook = android_change_tab_bar_height; | ||
| 3064 | terminal->change_tool_bar_height_hook = android_change_tool_bar_height; | ||
| 3065 | /* terminal->set_vertical_scroll_bar_hook */ | ||
| 3066 | /* = android_set_vertical_scroll_bar; */ | ||
| 3067 | /* terminal->set_horizontal_scroll_bar_hook */ | ||
| 3068 | /* = android_set_horizontal_scroll_bar; */ | ||
| 3069 | terminal->set_scroll_bar_default_width_hook | ||
| 3070 | = android_set_scroll_bar_default_width; | ||
| 3071 | terminal->set_scroll_bar_default_height_hook | ||
| 3072 | = android_set_scroll_bar_default_height; | ||
| 3073 | /* terminal->condemn_scroll_bars_hook = android_condemn_scroll_bars; */ | ||
| 3074 | /* terminal->redeem_scroll_bars_hook = android_redeem_scroll_bars; */ | ||
| 3075 | /* terminal->judge_scroll_bars_hook = android_judge_scroll_bars; */ | ||
| 3076 | terminal->free_pixmap = android_free_pixmap_hook; | ||
| 3077 | terminal->delete_frame_hook = android_delete_frame; | ||
| 3078 | terminal->delete_terminal_hook = android_delete_terminal; | ||
| 3079 | |||
| 3080 | #else | ||
| 3081 | emacs_abort (); | ||
| 3082 | #endif | ||
| 3083 | |||
| 3084 | return terminal; | ||
| 3085 | } | ||
| 3086 | |||
| 3087 | /* Initialize the Android terminal interface. The display connection | ||
| 3088 | has already been set up by the system at this point. */ | ||
| 3089 | |||
| 3090 | void | ||
| 3091 | android_term_init (void) | ||
| 3092 | { | ||
| 3093 | struct terminal *terminal; | ||
| 3094 | struct android_display_info *dpyinfo; | ||
| 3095 | Lisp_Object color_file, color_map; | ||
| 3096 | |||
| 3097 | dpyinfo = xzalloc (sizeof *dpyinfo); | ||
| 3098 | terminal = android_create_terminal (dpyinfo); | ||
| 3099 | terminal->kboard = allocate_kboard (Qandroid); | ||
| 3100 | terminal->kboard->reference_count++; | ||
| 3101 | |||
| 3102 | dpyinfo->n_planes = 24; | ||
| 3103 | |||
| 3104 | /* This function should only be called once at startup. */ | ||
| 3105 | eassert (!x_display_list); | ||
| 3106 | x_display_list = dpyinfo; | ||
| 3107 | |||
| 3108 | dpyinfo->name_list_element | ||
| 3109 | = Fcons (build_pure_c_string ("android"), Qnil); | ||
| 3110 | |||
| 3111 | color_file = Fexpand_file_name (build_string ("rgb.txt"), | ||
| 3112 | Vdata_directory); | ||
| 3113 | color_map = Fx_load_color_file (color_file); | ||
| 3114 | |||
| 3115 | if (NILP (color_map)) | ||
| 3116 | fatal ("Could not read %s.\n", SDATA (color_file)); | ||
| 3117 | |||
| 3118 | dpyinfo->color_map = color_map; | ||
| 3119 | |||
| 3120 | /* TODO! */ | ||
| 3121 | dpyinfo->resx = 96.0; | ||
| 3122 | dpyinfo->resy = 96.0; | ||
| 3123 | |||
| 3124 | /* https://lists.gnu.org/r/emacs-devel/2015-11/msg00194.html */ | ||
| 3125 | dpyinfo->smallest_font_height = 1; | ||
| 3126 | dpyinfo->smallest_char_width = 1; | ||
| 3127 | |||
| 3128 | terminal->name = xstrdup ("android"); | ||
| 3129 | |||
| 3130 | /* The display "connection" is now set up, and it must never go | ||
| 3131 | away. */ | ||
| 3132 | terminal->reference_count = 30000; | ||
| 3133 | } | ||
| 3134 | |||
| 3135 | |||
| 3136 | |||
| 3137 | void | ||
| 3138 | syms_of_androidterm (void) | ||
| 3139 | { | ||
| 3140 | Fprovide (Qandroid, Qnil); | ||
| 3141 | |||
| 3142 | DEFVAR_BOOL ("x-use-underline-position-properties", | ||
| 3143 | x_use_underline_position_properties, | ||
| 3144 | doc: /* SKIP: real doc in xterm.c. */); | ||
| 3145 | x_use_underline_position_properties = true; | ||
| 3146 | DEFSYM (Qx_use_underline_position_properties, | ||
| 3147 | "x-use-underline-position-properties"); | ||
| 3148 | |||
| 3149 | DEFVAR_BOOL ("x-underline-at-descent-line", | ||
| 3150 | x_underline_at_descent_line, | ||
| 3151 | doc: /* SKIP: real doc in xterm.c. */); | ||
| 3152 | x_underline_at_descent_line = false; | ||
| 3153 | DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line"); | ||
| 3154 | } | ||
| 3155 | |||
| 3156 | void | ||
| 3157 | mark_androidterm (void) | ||
| 3158 | { | ||
| 3159 | if (x_display_list) | ||
| 3160 | mark_object (x_display_list->color_map); | ||
| 3161 | } | ||
diff --git a/src/androidterm.h b/src/androidterm.h new file mode 100644 index 00000000000..3a0c9f60555 --- /dev/null +++ b/src/androidterm.h | |||
| @@ -0,0 +1,366 @@ | |||
| 1 | /* Communication module for Android terminals. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #ifndef _ANDROID_TERM_H_ | ||
| 21 | #define _ANDROID_TERM_H_ | ||
| 22 | |||
| 23 | #include "androidgui.h" | ||
| 24 | #include "frame.h" | ||
| 25 | #include "character.h" | ||
| 26 | #include "dispextern.h" | ||
| 27 | #include "font.h" | ||
| 28 | |||
| 29 | struct android_bitmap_record | ||
| 30 | { | ||
| 31 | /* The image backing the bitmap. */ | ||
| 32 | Emacs_Pixmap img; | ||
| 33 | |||
| 34 | /* The file from which it comes. */ | ||
| 35 | char *file; | ||
| 36 | |||
| 37 | /* The number of references to it. */ | ||
| 38 | int refcount; | ||
| 39 | |||
| 40 | /* The height and width. */ | ||
| 41 | int height, width; | ||
| 42 | }; | ||
| 43 | |||
| 44 | struct android_display_info | ||
| 45 | { | ||
| 46 | /* Chain of all struct android_display_info structures. */ | ||
| 47 | struct android_display_info *next; | ||
| 48 | |||
| 49 | /* The terminal. */ | ||
| 50 | struct terminal *terminal; | ||
| 51 | |||
| 52 | /* The root window. This field is unused. */ | ||
| 53 | Emacs_Window root_window; | ||
| 54 | |||
| 55 | /* List possibly used only for the font cache but probably used for | ||
| 56 | something else too. */ | ||
| 57 | Lisp_Object name_list_element; | ||
| 58 | |||
| 59 | /* List of predefined X colors. */ | ||
| 60 | Lisp_Object color_map; | ||
| 61 | |||
| 62 | /* DPI of the display. */ | ||
| 63 | double resx, resy; | ||
| 64 | |||
| 65 | /* Scratch GC for drawing a cursor in a non-default face. */ | ||
| 66 | struct android_gc *scratch_cursor_gc; | ||
| 67 | |||
| 68 | /* Mouse highlight information. */ | ||
| 69 | Mouse_HLInfo mouse_highlight; | ||
| 70 | |||
| 71 | /* Number of planes on this screen. Always 24. */ | ||
| 72 | int n_planes; | ||
| 73 | |||
| 74 | /* Mask of things causing the mouse to be grabbed. */ | ||
| 75 | int grabbed; | ||
| 76 | |||
| 77 | /* Minimum width over all characters in all fonts in font_table. */ | ||
| 78 | int smallest_char_width; | ||
| 79 | |||
| 80 | /* Minimum font height over all fonts in font_table. */ | ||
| 81 | int smallest_font_height; | ||
| 82 | |||
| 83 | /* The number of fonts opened for this display. */ | ||
| 84 | int n_fonts; | ||
| 85 | |||
| 86 | /* Pointer to bitmap records. */ | ||
| 87 | struct android_bitmap_record *bitmaps; | ||
| 88 | |||
| 89 | /* Allocated size of bitmaps field. */ | ||
| 90 | ptrdiff_t bitmaps_size; | ||
| 91 | |||
| 92 | /* Last used bitmap index. */ | ||
| 93 | ptrdiff_t bitmaps_last; | ||
| 94 | |||
| 95 | /* The frame currently with the input focus. */ | ||
| 96 | struct frame *focus_frame; | ||
| 97 | |||
| 98 | /* The frame which currently has the visual highlight, and should | ||
| 99 | get keyboard input. It points to the focus frame's selected | ||
| 100 | window's frame, but can differ. */ | ||
| 101 | struct frame *highlight_frame; | ||
| 102 | |||
| 103 | /* The frame waiting to be auto-raised in android_read_socket. */ | ||
| 104 | struct frame *pending_autoraise_frame; | ||
| 105 | |||
| 106 | /* The frame where the mouse was the last time a button event | ||
| 107 | happened. */ | ||
| 108 | struct frame *last_mouse_frame; | ||
| 109 | |||
| 110 | /* The frame where the mouse was the last time the mouse glyph | ||
| 111 | changed. */ | ||
| 112 | struct frame *last_mouse_glyph_frame; | ||
| 113 | |||
| 114 | /* The frame where the mouse was the last time mouse motion | ||
| 115 | happened. */ | ||
| 116 | struct frame *last_mouse_motion_frame; | ||
| 117 | |||
| 118 | /* Position where the mouse was last time we reported a motion. | ||
| 119 | This is a position on last_mouse_motion_frame. It is used in to | ||
| 120 | report the mouse position as well: see | ||
| 121 | android_mouse_position. */ | ||
| 122 | int last_mouse_motion_x, last_mouse_motion_y; | ||
| 123 | |||
| 124 | /* Where the mouse was the last time the mouse moved. */ | ||
| 125 | Emacs_Rectangle last_mouse_glyph; | ||
| 126 | }; | ||
| 127 | |||
| 128 | struct android_output | ||
| 129 | { | ||
| 130 | /* Graphics contexts for the default font. */ | ||
| 131 | struct android_gc *normal_gc, *reverse_gc, *cursor_gc; | ||
| 132 | |||
| 133 | /* The window used for this frame. */ | ||
| 134 | Emacs_Window window; | ||
| 135 | |||
| 136 | /* Unused field. */ | ||
| 137 | Emacs_Window parent_desc; | ||
| 138 | |||
| 139 | /* Default ASCII font of this frame. */ | ||
| 140 | struct font *font; | ||
| 141 | |||
| 142 | /* The baseline offset of the default ASCII font. */ | ||
| 143 | int baseline_offset; | ||
| 144 | |||
| 145 | /* If a fontset is specified for this frame instead of font, this | ||
| 146 | value contains an ID of the fontset, else -1. */ | ||
| 147 | int fontset; | ||
| 148 | |||
| 149 | /* Various colors. */ | ||
| 150 | unsigned long cursor_pixel; | ||
| 151 | unsigned long cursor_foreground_pixel; | ||
| 152 | |||
| 153 | /* Foreground color for scroll bars. A value of -1 means use the | ||
| 154 | default (black for non-toolkit scroll bars). */ | ||
| 155 | unsigned long scroll_bar_foreground_pixel; | ||
| 156 | |||
| 157 | /* Background color for scroll bars. A value of -1 means use the | ||
| 158 | default (background color of the frame for non-toolkit scroll | ||
| 159 | bars). */ | ||
| 160 | unsigned long scroll_bar_background_pixel; | ||
| 161 | |||
| 162 | /* Unused stuff (cursors). */ | ||
| 163 | Emacs_Cursor text_cursor; | ||
| 164 | Emacs_Cursor nontext_cursor; | ||
| 165 | Emacs_Cursor modeline_cursor; | ||
| 166 | Emacs_Cursor hand_cursor; | ||
| 167 | Emacs_Cursor hourglass_cursor; | ||
| 168 | Emacs_Cursor horizontal_drag_cursor; | ||
| 169 | Emacs_Cursor vertical_drag_cursor; | ||
| 170 | Emacs_Cursor current_cursor; | ||
| 171 | Emacs_Cursor left_edge_cursor; | ||
| 172 | Emacs_Cursor top_left_corner_cursor; | ||
| 173 | Emacs_Cursor top_edge_cursor; | ||
| 174 | Emacs_Cursor top_right_corner_cursor; | ||
| 175 | Emacs_Cursor right_edge_cursor; | ||
| 176 | Emacs_Cursor bottom_right_corner_cursor; | ||
| 177 | Emacs_Cursor bottom_edge_cursor; | ||
| 178 | Emacs_Cursor bottom_left_corner_cursor; | ||
| 179 | |||
| 180 | /* This is the Emacs structure for the display this frame is on. */ | ||
| 181 | struct android_display_info *display_info; | ||
| 182 | |||
| 183 | /* True if this frame was ever previously visible. */ | ||
| 184 | bool_bf has_been_visible : 1; | ||
| 185 | |||
| 186 | /* True if this frame's alpha value is the same for both the active | ||
| 187 | and inactive states. */ | ||
| 188 | bool_bf alpha_identical_p : 1; | ||
| 189 | |||
| 190 | /* Flag that indicates whether we've modified the back buffer and | ||
| 191 | need to publish our modifications to the front buffer at a | ||
| 192 | convenient time. */ | ||
| 193 | bool_bf need_buffer_flip : 1; | ||
| 194 | |||
| 195 | /* Flag that indicates whether or not the frame contents are | ||
| 196 | complete and can be safely flushed while handling async | ||
| 197 | input. */ | ||
| 198 | bool_bf complete : 1; | ||
| 199 | |||
| 200 | /* Relief GCs, colors etc. */ | ||
| 201 | struct relief { | ||
| 202 | struct android_gc *gc; | ||
| 203 | unsigned long pixel; | ||
| 204 | } black_relief, white_relief; | ||
| 205 | |||
| 206 | /* The background for which the above relief GCs were set up. | ||
| 207 | They are changed only when a different background is involved. */ | ||
| 208 | unsigned long relief_background; | ||
| 209 | }; | ||
| 210 | |||
| 211 | /* Return the Android output data for frame F. */ | ||
| 212 | #define FRAME_ANDROID_OUTPUT(f) ((f)->output_data.android) | ||
| 213 | #define FRAME_OUTPUT_DATA(f) ((f)->output_data.android) | ||
| 214 | |||
| 215 | /* Return the Android window used for displaying data in frame F. */ | ||
| 216 | #define FRAME_ANDROID_WINDOW(f) ((f)->output_data.android->window) | ||
| 217 | #define FRAME_NATIVE_WINDOW(f) ((f)->output_data.android->window) | ||
| 218 | |||
| 219 | /* Return the need-buffer-flip flag for frame F. */ | ||
| 220 | #define FRAME_ANDROID_NEED_BUFFER_FLIP(f) \ | ||
| 221 | ((f)->output_data.android->need_buffer_flip) | ||
| 222 | |||
| 223 | /* Return whether or not the frame F has been completely drawn. Used | ||
| 224 | while handling async input. */ | ||
| 225 | #define FRAME_ANDROID_COMPLETE_P(f) \ | ||
| 226 | ((f)->output_data.android->complete) | ||
| 227 | |||
| 228 | #define FRAME_FONT(f) ((f)->output_data.android->font) | ||
| 229 | #define FRAME_FONTSET(f) ((f)->output_data.android->fontset) | ||
| 230 | |||
| 231 | #define FRAME_BASELINE_OFFSET(f) \ | ||
| 232 | ((f)->output_data.android->baseline_offset) | ||
| 233 | |||
| 234 | /* This gives the android_display_info structure for the display F is | ||
| 235 | on. */ | ||
| 236 | #define FRAME_DISPLAY_INFO(f) ((f)->output_data.android->display_info) | ||
| 237 | |||
| 238 | /* Some things for X compatibility. */ | ||
| 239 | #define BLACK_PIX_DEFAULT(f) 0 | ||
| 240 | #define WHITE_PIX_DEFAULT(f) 0xffffffff | ||
| 241 | |||
| 242 | /* Android-specific scroll bar stuff. */ | ||
| 243 | |||
| 244 | /* We represent scroll bars as lisp vectors. This allows us to place | ||
| 245 | references to them in windows without worrying about whether we'll | ||
| 246 | end up with windows referring to dead scroll bars; the garbage | ||
| 247 | collector will free it when its time comes. | ||
| 248 | |||
| 249 | We use struct scroll_bar as a template for accessing fields of the | ||
| 250 | vector. */ | ||
| 251 | |||
| 252 | struct scroll_bar | ||
| 253 | { | ||
| 254 | /* These fields are shared by all vectors. */ | ||
| 255 | union vectorlike_header header; | ||
| 256 | |||
| 257 | /* The window we're a scroll bar for. */ | ||
| 258 | Lisp_Object window; | ||
| 259 | |||
| 260 | /* The next and previous in the chain of scroll bars in this frame. */ | ||
| 261 | Lisp_Object next, prev; | ||
| 262 | |||
| 263 | /* Fields after 'prev' are not traced by the GC. */ | ||
| 264 | |||
| 265 | /* The X window representing this scroll bar. */ | ||
| 266 | Emacs_Window x_window; | ||
| 267 | |||
| 268 | /* The position and size of the scroll bar in pixels, relative to the | ||
| 269 | frame. */ | ||
| 270 | int top, left, width, height; | ||
| 271 | |||
| 272 | /* The starting and ending positions of the handle, relative to the | ||
| 273 | handle area (i.e. zero is the top position, not | ||
| 274 | SCROLL_BAR_TOP_BORDER). If they're equal, that means the handle | ||
| 275 | hasn't been drawn yet. | ||
| 276 | |||
| 277 | These are not actually the locations where the beginning and end | ||
| 278 | are drawn; in order to keep handles from becoming invisible when | ||
| 279 | editing large files, we establish a minimum height by always | ||
| 280 | drawing handle bottoms VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below | ||
| 281 | where they would be normally; the bottom and top are in a | ||
| 282 | different coordinate system. */ | ||
| 283 | int start, end; | ||
| 284 | |||
| 285 | /* If the scroll bar handle is currently being dragged by the user, | ||
| 286 | this is the number of pixels from the top of the handle to the | ||
| 287 | place where the user grabbed it. If the handle isn't currently | ||
| 288 | being dragged, this is -1. */ | ||
| 289 | int dragging; | ||
| 290 | |||
| 291 | /* True if the scroll bar is horizontal. */ | ||
| 292 | bool horizontal; | ||
| 293 | }; | ||
| 294 | |||
| 295 | /* Turning a lisp vector value into a pointer to a struct scroll_bar. */ | ||
| 296 | #define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec)) | ||
| 297 | |||
| 298 | |||
| 299 | |||
| 300 | /* This is a chain of structures for all the Android displays | ||
| 301 | currently in use. There is only ever one, but the rest of Emacs is | ||
| 302 | written with systems on which there can be many in mind. */ | ||
| 303 | extern struct android_display_info *x_display_list; | ||
| 304 | |||
| 305 | |||
| 306 | |||
| 307 | /* Start of function definitions. These should be a neat subset of | ||
| 308 | the same ones in xterm.h, and come in the same order. */ | ||
| 309 | |||
| 310 | /* From androidfns.c. */ | ||
| 311 | |||
| 312 | extern void android_free_gcs (struct frame *); | ||
| 313 | extern void android_default_font_parameter (struct frame *, Lisp_Object); | ||
| 314 | |||
| 315 | /* Defined in androidterm.c. */ | ||
| 316 | |||
| 317 | extern void android_term_init (void); | ||
| 318 | extern void android_set_window_size (struct frame *, bool, int, int); | ||
| 319 | extern void android_iconify_frame (struct frame *); | ||
| 320 | extern void android_make_frame_visible (struct frame *); | ||
| 321 | extern void android_make_frame_invisible (struct frame *); | ||
| 322 | extern void android_free_frame_resources (struct frame *); | ||
| 323 | |||
| 324 | extern int android_parse_color (struct frame *, const char *, | ||
| 325 | Emacs_Color *); | ||
| 326 | extern bool android_alloc_nearest_color (struct frame *, Emacs_Color *); | ||
| 327 | extern void android_query_colors (struct frame *, Emacs_Color *, int); | ||
| 328 | extern void android_clear_under_internal_border (struct frame *); | ||
| 329 | |||
| 330 | extern void syms_of_androidterm (void); | ||
| 331 | extern void mark_androidterm (void); | ||
| 332 | |||
| 333 | /* Defined in androidfns.c. */ | ||
| 334 | |||
| 335 | extern void android_change_tab_bar_height (struct frame *, int); | ||
| 336 | extern void android_change_tool_bar_height (struct frame *, int); | ||
| 337 | extern void android_set_scroll_bar_default_width (struct frame *); | ||
| 338 | extern void android_set_scroll_bar_default_height (struct frame *); | ||
| 339 | extern bool android_defined_color (struct frame *, const char *, | ||
| 340 | Emacs_Color *, bool, bool); | ||
| 341 | extern void android_implicitly_set_name (struct frame *, Lisp_Object, | ||
| 342 | Lisp_Object); | ||
| 343 | extern void android_explicitly_set_name (struct frame *, Lisp_Object, | ||
| 344 | Lisp_Object); | ||
| 345 | |||
| 346 | extern void syms_of_androidfns (void); | ||
| 347 | |||
| 348 | /* Defined in androidfont.c. */ | ||
| 349 | |||
| 350 | extern struct font_driver androidfont_driver; | ||
| 351 | |||
| 352 | extern void init_androidfont (void); | ||
| 353 | extern void syms_of_androidfont (void); | ||
| 354 | |||
| 355 | extern void android_finalize_font_entity (struct font_entity *); | ||
| 356 | |||
| 357 | |||
| 358 | |||
| 359 | #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) | ||
| 360 | #define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) | ||
| 361 | #define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) | ||
| 362 | #define BLUE_FROM_ULONG(color) ((color) & 0xff) | ||
| 363 | |||
| 364 | |||
| 365 | |||
| 366 | #endif /* _ANDROID_TERM_H_ */ | ||
diff --git a/src/dired.c b/src/dired.c index ef729df5d2b..e7d4c75092a 100644 --- a/src/dired.c +++ b/src/dired.c | |||
| @@ -979,14 +979,15 @@ file_attributes (int fd, char const *name, | |||
| 979 | 979 | ||
| 980 | int err = EINVAL; | 980 | int err = EINVAL; |
| 981 | 981 | ||
| 982 | #if defined O_PATH && !defined HAVE_CYGWIN_O_PATH_BUG | 982 | #if defined O_PATH && !defined HAVE_CYGWIN_O_PATH_BUG \ |
| 983 | && !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 983 | int namefd = emacs_openat (fd, name, O_PATH | O_CLOEXEC | O_NOFOLLOW, 0); | 984 | int namefd = emacs_openat (fd, name, O_PATH | O_CLOEXEC | O_NOFOLLOW, 0); |
| 984 | if (namefd < 0) | 985 | if (namefd < 0) |
| 985 | err = errno; | 986 | err = errno; |
| 986 | else | 987 | else |
| 987 | { | 988 | { |
| 988 | record_unwind_protect_int (close_file_unwind, namefd); | 989 | record_unwind_protect_int (close_file_unwind, namefd); |
| 989 | if (fstat (namefd, &s) != 0) | 990 | if (sys_fstat (namefd, &s) != 0) |
| 990 | { | 991 | { |
| 991 | err = errno; | 992 | err = errno; |
| 992 | /* The Linux kernel before version 3.6 does not support | 993 | /* The Linux kernel before version 3.6 does not support |
diff --git a/src/dispextern.h b/src/dispextern.h index e6c4270bebd..e521dffc37c 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -53,8 +53,15 @@ typedef struct | |||
| 53 | unsigned short red, green, blue; | 53 | unsigned short red, green, blue; |
| 54 | } Emacs_Color; | 54 | } Emacs_Color; |
| 55 | 55 | ||
| 56 | #ifndef HAVE_ANDROID | ||
| 56 | /* Accommodate X's usage of None as a null resource ID. */ | 57 | /* Accommodate X's usage of None as a null resource ID. */ |
| 57 | #define No_Cursor (NULL) | 58 | #define No_Cursor (NULL) |
| 59 | #else | ||
| 60 | /* Android doesn't support cursors and also uses handles. */ | ||
| 61 | #define No_Cursor 0 | ||
| 62 | #endif | ||
| 63 | |||
| 64 | #ifndef HAVE_ANDROID | ||
| 58 | 65 | ||
| 59 | /* XRectangle-like struct used by non-X GUI code. */ | 66 | /* XRectangle-like struct used by non-X GUI code. */ |
| 60 | typedef struct | 67 | typedef struct |
| @@ -63,6 +70,12 @@ typedef struct | |||
| 63 | unsigned width, height; | 70 | unsigned width, height; |
| 64 | } Emacs_Rectangle; | 71 | } Emacs_Rectangle; |
| 65 | 72 | ||
| 73 | #else | ||
| 74 | |||
| 75 | typedef struct android_rectangle Emacs_Rectangle; | ||
| 76 | |||
| 77 | #endif | ||
| 78 | |||
| 66 | /* XGCValues-like struct used by non-X GUI code. */ | 79 | /* XGCValues-like struct used by non-X GUI code. */ |
| 67 | typedef struct | 80 | typedef struct |
| 68 | { | 81 | { |
| @@ -144,6 +157,13 @@ typedef Emacs_Pixmap Emacs_Pix_Container; | |||
| 144 | typedef Emacs_Pixmap Emacs_Pix_Context; | 157 | typedef Emacs_Pixmap Emacs_Pix_Context; |
| 145 | #endif | 158 | #endif |
| 146 | 159 | ||
| 160 | #ifdef HAVE_ANDROID | ||
| 161 | #include "androidgui.h" | ||
| 162 | typedef struct android_display_info Display_Info; | ||
| 163 | typedef Emacs_Pixmap Emacs_Pix_Container; | ||
| 164 | typedef Emacs_Pixmap Emacs_Pix_Context; | ||
| 165 | #endif | ||
| 166 | |||
| 147 | #ifdef HAVE_WINDOW_SYSTEM | 167 | #ifdef HAVE_WINDOW_SYSTEM |
| 148 | # include <time.h> | 168 | # include <time.h> |
| 149 | # include "fontset.h" | 169 | # include "fontset.h" |
| @@ -1401,6 +1421,8 @@ struct glyph_string | |||
| 1401 | /* The GC to use for drawing this glyph string. */ | 1421 | /* The GC to use for drawing this glyph string. */ |
| 1402 | #if defined (HAVE_X_WINDOWS) | 1422 | #if defined (HAVE_X_WINDOWS) |
| 1403 | GC gc; | 1423 | GC gc; |
| 1424 | #elif defined HAVE_ANDROID | ||
| 1425 | struct android_gc *gc; | ||
| 1404 | #endif | 1426 | #endif |
| 1405 | #if defined (HAVE_NTGUI) | 1427 | #if defined (HAVE_NTGUI) |
| 1406 | Emacs_GC *gc; | 1428 | Emacs_GC *gc; |
| @@ -1681,6 +1703,8 @@ struct face | |||
| 1681 | drawing the characters in this face. */ | 1703 | drawing the characters in this face. */ |
| 1682 | # ifdef HAVE_X_WINDOWS | 1704 | # ifdef HAVE_X_WINDOWS |
| 1683 | GC gc; | 1705 | GC gc; |
| 1706 | # elif defined HAVE_ANDROID | ||
| 1707 | struct android_gc *gc; | ||
| 1684 | # else | 1708 | # else |
| 1685 | Emacs_GC *gc; | 1709 | Emacs_GC *gc; |
| 1686 | # endif | 1710 | # endif |
| @@ -3502,9 +3526,11 @@ extern void gui_clear_window_mouse_face (struct window *); | |||
| 3502 | extern void cancel_mouse_face (struct frame *); | 3526 | extern void cancel_mouse_face (struct frame *); |
| 3503 | extern bool clear_mouse_face (Mouse_HLInfo *); | 3527 | extern bool clear_mouse_face (Mouse_HLInfo *); |
| 3504 | extern bool cursor_in_mouse_face_p (struct window *w); | 3528 | extern bool cursor_in_mouse_face_p (struct window *w); |
| 3529 | #ifndef HAVE_ANDROID | ||
| 3505 | extern void tty_draw_row_with_mouse_face (struct window *, struct glyph_row *, | 3530 | extern void tty_draw_row_with_mouse_face (struct window *, struct glyph_row *, |
| 3506 | int, int, enum draw_glyphs_face); | 3531 | int, int, enum draw_glyphs_face); |
| 3507 | extern void display_tty_menu_item (const char *, int, int, int, int, bool); | 3532 | extern void display_tty_menu_item (const char *, int, int, int, int, bool); |
| 3533 | #endif | ||
| 3508 | extern struct glyph *x_y_to_hpos_vpos (struct window *, int, int, int *, int *, | 3534 | extern struct glyph *x_y_to_hpos_vpos (struct window *, int, int, int *, int *, |
| 3509 | int *, int *, int *); | 3535 | int *, int *, int *); |
| 3510 | /* Flags passed to try_window. */ | 3536 | /* Flags passed to try_window. */ |
| @@ -3566,7 +3592,7 @@ void prepare_image_for_display (struct frame *, struct image *); | |||
| 3566 | ptrdiff_t lookup_image (struct frame *, Lisp_Object, int); | 3592 | ptrdiff_t lookup_image (struct frame *, Lisp_Object, int); |
| 3567 | 3593 | ||
| 3568 | #if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS \ | 3594 | #if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_NS \ |
| 3569 | || defined HAVE_HAIKU | 3595 | || defined HAVE_HAIKU || defined HAVE_ANDROID |
| 3570 | #define RGB_PIXEL_COLOR unsigned long | 3596 | #define RGB_PIXEL_COLOR unsigned long |
| 3571 | #endif | 3597 | #endif |
| 3572 | 3598 | ||
| @@ -3647,6 +3673,9 @@ void gamma_correct (struct frame *, COLORREF *); | |||
| 3647 | #ifdef HAVE_HAIKU | 3673 | #ifdef HAVE_HAIKU |
| 3648 | void gamma_correct (struct frame *, Emacs_Color *); | 3674 | void gamma_correct (struct frame *, Emacs_Color *); |
| 3649 | #endif | 3675 | #endif |
| 3676 | #ifdef HAVE_ANDROID | ||
| 3677 | extern void gamma_correct (struct frame *, Emacs_Color *); | ||
| 3678 | #endif | ||
| 3650 | 3679 | ||
| 3651 | #ifdef HAVE_WINDOW_SYSTEM | 3680 | #ifdef HAVE_WINDOW_SYSTEM |
| 3652 | 3681 | ||
diff --git a/src/dispnew.c b/src/dispnew.c index 5a9ba8909e3..ed10accac7b 100644 --- a/src/dispnew.c +++ b/src/dispnew.c | |||
| @@ -43,6 +43,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 43 | #include "xwidget.h" | 43 | #include "xwidget.h" |
| 44 | #include "pdumper.h" | 44 | #include "pdumper.h" |
| 45 | 45 | ||
| 46 | #ifdef HAVE_ANDROID | ||
| 47 | #include "android.h" | ||
| 48 | #endif | ||
| 49 | |||
| 46 | #ifdef HAVE_WINDOW_SYSTEM | 50 | #ifdef HAVE_WINDOW_SYSTEM |
| 47 | #include TERM_HEADER | 51 | #include TERM_HEADER |
| 48 | #endif /* HAVE_WINDOW_SYSTEM */ | 52 | #endif /* HAVE_WINDOW_SYSTEM */ |
| @@ -788,7 +792,7 @@ clear_current_matrices (register struct frame *f) | |||
| 788 | if (f->current_matrix) | 792 | if (f->current_matrix) |
| 789 | clear_glyph_matrix (f->current_matrix); | 793 | clear_glyph_matrix (f->current_matrix); |
| 790 | 794 | ||
| 791 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 795 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 792 | /* Clear the matrix of the menu bar window, if such a window exists. | 796 | /* Clear the matrix of the menu bar window, if such a window exists. |
| 793 | The menu bar window is currently used to display menus on X when | 797 | The menu bar window is currently used to display menus on X when |
| 794 | no toolkit support is compiled in. */ | 798 | no toolkit support is compiled in. */ |
| @@ -822,7 +826,7 @@ clear_desired_matrices (register struct frame *f) | |||
| 822 | if (f->desired_matrix) | 826 | if (f->desired_matrix) |
| 823 | clear_glyph_matrix (f->desired_matrix); | 827 | clear_glyph_matrix (f->desired_matrix); |
| 824 | 828 | ||
| 825 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 829 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 826 | if (WINDOWP (f->menu_bar_window)) | 830 | if (WINDOWP (f->menu_bar_window)) |
| 827 | clear_glyph_matrix (XWINDOW (f->menu_bar_window)->desired_matrix); | 831 | clear_glyph_matrix (XWINDOW (f->menu_bar_window)->desired_matrix); |
| 828 | #endif | 832 | #endif |
| @@ -1156,6 +1160,7 @@ prepare_desired_row (struct window *w, struct glyph_row *row, bool mode_line_p) | |||
| 1156 | } | 1160 | } |
| 1157 | } | 1161 | } |
| 1158 | 1162 | ||
| 1163 | #ifndef HAVE_ANDROID | ||
| 1159 | 1164 | ||
| 1160 | /* Return a hash code for glyph row ROW, which may | 1165 | /* Return a hash code for glyph row ROW, which may |
| 1161 | be from current or desired matrix of frame F. */ | 1166 | be from current or desired matrix of frame F. */ |
| @@ -1248,6 +1253,7 @@ line_draw_cost (struct frame *f, struct glyph_matrix *matrix, int vpos) | |||
| 1248 | return len; | 1253 | return len; |
| 1249 | } | 1254 | } |
| 1250 | 1255 | ||
| 1256 | #endif | ||
| 1251 | 1257 | ||
| 1252 | /* Return true if the glyph rows A and B have equal contents. | 1258 | /* Return true if the glyph rows A and B have equal contents. |
| 1253 | MOUSE_FACE_P means compare the mouse_face_p flags of A and B, too. */ | 1259 | MOUSE_FACE_P means compare the mouse_face_p flags of A and B, too. */ |
| @@ -2160,7 +2166,7 @@ adjust_frame_glyphs_for_window_redisplay (struct frame *f) | |||
| 2160 | /* Allocate/reallocate window matrices. */ | 2166 | /* Allocate/reallocate window matrices. */ |
| 2161 | allocate_matrices_for_window_redisplay (XWINDOW (FRAME_ROOT_WINDOW (f))); | 2167 | allocate_matrices_for_window_redisplay (XWINDOW (FRAME_ROOT_WINDOW (f))); |
| 2162 | 2168 | ||
| 2163 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 2169 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 2164 | /* Allocate/ reallocate matrices of the dummy window used to display | 2170 | /* Allocate/ reallocate matrices of the dummy window used to display |
| 2165 | the menu bar under X when no X toolkit support is available. */ | 2171 | the menu bar under X when no X toolkit support is available. */ |
| 2166 | { | 2172 | { |
| @@ -2296,7 +2302,7 @@ free_glyphs (struct frame *f) | |||
| 2296 | if (!NILP (f->root_window)) | 2302 | if (!NILP (f->root_window)) |
| 2297 | free_window_matrices (XWINDOW (f->root_window)); | 2303 | free_window_matrices (XWINDOW (f->root_window)); |
| 2298 | 2304 | ||
| 2299 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 2305 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 2300 | /* Free the dummy window for menu bars without X toolkit and its | 2306 | /* Free the dummy window for menu bars without X toolkit and its |
| 2301 | glyph matrices. */ | 2307 | glyph matrices. */ |
| 2302 | if (!NILP (f->menu_bar_window)) | 2308 | if (!NILP (f->menu_bar_window)) |
| @@ -3234,7 +3240,7 @@ update_frame (struct frame *f, bool force_p, bool inhibit_hairy_id_p) | |||
| 3234 | when pending input is detected. */ | 3240 | when pending input is detected. */ |
| 3235 | update_begin (f); | 3241 | update_begin (f); |
| 3236 | 3242 | ||
| 3237 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 3243 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 3238 | /* Update the menu bar on X frames that don't have toolkit | 3244 | /* Update the menu bar on X frames that don't have toolkit |
| 3239 | support. */ | 3245 | support. */ |
| 3240 | if (WINDOWP (f->menu_bar_window)) | 3246 | if (WINDOWP (f->menu_bar_window)) |
| @@ -5059,6 +5065,10 @@ update_frame_1 (struct frame *f, bool force_p, bool inhibit_id_p, | |||
| 5059 | static bool | 5065 | static bool |
| 5060 | scrolling (struct frame *frame) | 5066 | scrolling (struct frame *frame) |
| 5061 | { | 5067 | { |
| 5068 | /* In fact this code should never be reached at all under | ||
| 5069 | Android. */ | ||
| 5070 | |||
| 5071 | #ifndef HAVE_ANDROID | ||
| 5062 | int unchanged_at_top, unchanged_at_bottom; | 5072 | int unchanged_at_top, unchanged_at_bottom; |
| 5063 | int window_size; | 5073 | int window_size; |
| 5064 | int changed_lines; | 5074 | int changed_lines; |
| @@ -5149,6 +5159,7 @@ scrolling (struct frame *frame) | |||
| 5149 | free_at_end_vpos - unchanged_at_top); | 5159 | free_at_end_vpos - unchanged_at_top); |
| 5150 | 5160 | ||
| 5151 | SAFE_FREE (); | 5161 | SAFE_FREE (); |
| 5162 | #endif | ||
| 5152 | return false; | 5163 | return false; |
| 5153 | } | 5164 | } |
| 5154 | 5165 | ||
| @@ -5190,7 +5201,9 @@ count_match (struct glyph *str1, struct glyph *end1, struct glyph *str2, struct | |||
| 5190 | 5201 | ||
| 5191 | /* Char insertion/deletion cost vector, from term.c */ | 5202 | /* Char insertion/deletion cost vector, from term.c */ |
| 5192 | 5203 | ||
| 5204 | #ifndef HAVE_ANDROID | ||
| 5193 | #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_TOTAL_COLS ((f))]) | 5205 | #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_TOTAL_COLS ((f))]) |
| 5206 | #endif | ||
| 5194 | 5207 | ||
| 5195 | 5208 | ||
| 5196 | /* Perform a frame-based update on line VPOS in frame FRAME. */ | 5209 | /* Perform a frame-based update on line VPOS in frame FRAME. */ |
| @@ -5395,7 +5408,10 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) | |||
| 5395 | tem = (nlen - nsp) - (olen - osp); | 5408 | tem = (nlen - nsp) - (olen - osp); |
| 5396 | if (endmatch && tem | 5409 | if (endmatch && tem |
| 5397 | && (!FRAME_CHAR_INS_DEL_OK (f) | 5410 | && (!FRAME_CHAR_INS_DEL_OK (f) |
| 5398 | || endmatch <= char_ins_del_cost (f)[tem])) | 5411 | #ifndef HAVE_ANDROID |
| 5412 | || endmatch <= char_ins_del_cost (f)[tem] | ||
| 5413 | #endif | ||
| 5414 | )) | ||
| 5399 | endmatch = 0; | 5415 | endmatch = 0; |
| 5400 | 5416 | ||
| 5401 | /* nsp - osp is the distance to insert or delete. | 5417 | /* nsp - osp is the distance to insert or delete. |
| @@ -5405,7 +5421,10 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) | |||
| 5405 | 5421 | ||
| 5406 | if (nsp != osp | 5422 | if (nsp != osp |
| 5407 | && (!FRAME_CHAR_INS_DEL_OK (f) | 5423 | && (!FRAME_CHAR_INS_DEL_OK (f) |
| 5408 | || begmatch + endmatch <= char_ins_del_cost (f)[nsp - osp])) | 5424 | #ifndef HAVE_ANDROID |
| 5425 | || begmatch + endmatch <= char_ins_del_cost (f)[nsp - osp] | ||
| 5426 | #endif | ||
| 5427 | )) | ||
| 5409 | { | 5428 | { |
| 5410 | begmatch = 0; | 5429 | begmatch = 0; |
| 5411 | endmatch = 0; | 5430 | endmatch = 0; |
| @@ -6528,6 +6547,15 @@ init_display_interactive (void) | |||
| 6528 | } | 6547 | } |
| 6529 | #endif /* HAVE_X_WINDOWS */ | 6548 | #endif /* HAVE_X_WINDOWS */ |
| 6530 | 6549 | ||
| 6550 | #ifdef HAVE_ANDROID | ||
| 6551 | if (!inhibit_window_system && android_init_gui) | ||
| 6552 | { | ||
| 6553 | Vinitial_window_system = Qandroid; | ||
| 6554 | android_term_init (); | ||
| 6555 | return; | ||
| 6556 | } | ||
| 6557 | #endif | ||
| 6558 | |||
| 6531 | #ifdef HAVE_NTGUI | 6559 | #ifdef HAVE_NTGUI |
| 6532 | if (!inhibit_window_system) | 6560 | if (!inhibit_window_system) |
| 6533 | { | 6561 | { |
| @@ -6582,6 +6610,7 @@ init_display_interactive (void) | |||
| 6582 | exit (1); | 6610 | exit (1); |
| 6583 | } | 6611 | } |
| 6584 | 6612 | ||
| 6613 | #ifndef HAVE_ANDROID | ||
| 6585 | { | 6614 | { |
| 6586 | struct terminal *t; | 6615 | struct terminal *t; |
| 6587 | struct frame *f = XFRAME (selected_frame); | 6616 | struct frame *f = XFRAME (selected_frame); |
| @@ -6624,6 +6653,11 @@ init_display_interactive (void) | |||
| 6624 | : Qnil)); | 6653 | : Qnil)); |
| 6625 | Fmodify_frame_parameters (selected_frame, tty_arg); | 6654 | Fmodify_frame_parameters (selected_frame, tty_arg); |
| 6626 | } | 6655 | } |
| 6656 | #else | ||
| 6657 | fatal ("Could not establish a connection to the Android application.\n" | ||
| 6658 | "Emacs does not work on text terminals when built to run as" | ||
| 6659 | " part of an Android application package."); | ||
| 6660 | #endif | ||
| 6627 | 6661 | ||
| 6628 | { | 6662 | { |
| 6629 | struct frame *sf = SELECTED_FRAME (); | 6663 | struct frame *sf = SELECTED_FRAME (); |
diff --git a/src/editfns.c b/src/editfns.c index 8d56ef21d90..f061199705f 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -33,6 +33,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 33 | #include <sys/utsname.h> | 33 | #include <sys/utsname.h> |
| 34 | #endif | 34 | #endif |
| 35 | 35 | ||
| 36 | #ifdef HAVE_ANDROID | ||
| 37 | #include "android.h" | ||
| 38 | #endif | ||
| 39 | |||
| 36 | #include "lisp.h" | 40 | #include "lisp.h" |
| 37 | 41 | ||
| 38 | #include <float.h> | 42 | #include <float.h> |
| @@ -1264,7 +1268,11 @@ is in general a comma-separated list. */) | |||
| 1264 | if (!pw) | 1268 | if (!pw) |
| 1265 | return Qnil; | 1269 | return Qnil; |
| 1266 | 1270 | ||
| 1271 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 1272 | p = android_user_full_name (pw); | ||
| 1273 | #else | ||
| 1267 | p = USER_FULL_NAME; | 1274 | p = USER_FULL_NAME; |
| 1275 | #endif | ||
| 1268 | /* Chop off everything after the first comma, since 'pw_gecos' is a | 1276 | /* Chop off everything after the first comma, since 'pw_gecos' is a |
| 1269 | comma-separated list. */ | 1277 | comma-separated list. */ |
| 1270 | q = strchr (p, ','); | 1278 | q = strchr (p, ','); |
diff --git a/src/emacs.c b/src/emacs.c index d8a2863fd9c..b6686f88096 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -33,6 +33,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 33 | #include "lisp.h" | 33 | #include "lisp.h" |
| 34 | #include "sysstdio.h" | 34 | #include "sysstdio.h" |
| 35 | 35 | ||
| 36 | #ifdef HAVE_ANDROID | ||
| 37 | #include "androidterm.h" | ||
| 38 | #endif | ||
| 39 | |||
| 36 | #ifdef WINDOWSNT | 40 | #ifdef WINDOWSNT |
| 37 | #include <fcntl.h> | 41 | #include <fcntl.h> |
| 38 | #include <sys/socket.h> | 42 | #include <sys/socket.h> |
| @@ -137,6 +141,10 @@ extern char etext; | |||
| 137 | #include <sys/resource.h> | 141 | #include <sys/resource.h> |
| 138 | #endif | 142 | #endif |
| 139 | 143 | ||
| 144 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 145 | #include "android.h" | ||
| 146 | #endif | ||
| 147 | |||
| 140 | /* We don't guard this with HAVE_TREE_SITTER because treesit.o is | 148 | /* We don't guard this with HAVE_TREE_SITTER because treesit.o is |
| 141 | always compiled (to provide treesit-available-p). */ | 149 | always compiled (to provide treesit-available-p). */ |
| 142 | #include "treesit.h" | 150 | #include "treesit.h" |
| @@ -1123,7 +1131,7 @@ load_seccomp (const char *file) | |||
| 1123 | goto out; | 1131 | goto out; |
| 1124 | } | 1132 | } |
| 1125 | struct stat stat; | 1133 | struct stat stat; |
| 1126 | if (fstat (fd, &stat) != 0) | 1134 | if (sys_fstat (fd, &stat) != 0) |
| 1127 | { | 1135 | { |
| 1128 | emacs_perror ("fstat"); | 1136 | emacs_perror ("fstat"); |
| 1129 | goto out; | 1137 | goto out; |
| @@ -1225,12 +1233,18 @@ maybe_load_seccomp (int argc, char **argv) | |||
| 1225 | 1233 | ||
| 1226 | #endif /* SECCOMP_USABLE */ | 1234 | #endif /* SECCOMP_USABLE */ |
| 1227 | 1235 | ||
| 1236 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 1237 | int | ||
| 1238 | android_emacs_init (int argc, char **argv) | ||
| 1239 | #else | ||
| 1228 | int | 1240 | int |
| 1229 | main (int argc, char **argv) | 1241 | main (int argc, char **argv) |
| 1242 | #endif | ||
| 1230 | { | 1243 | { |
| 1231 | /* Variable near the bottom of the stack, and aligned appropriately | 1244 | /* Variable near the bottom of the stack, and aligned appropriately |
| 1232 | for pointers. */ | 1245 | for pointers. */ |
| 1233 | void *stack_bottom_variable; | 1246 | void *stack_bottom_variable; |
| 1247 | int old_argc; | ||
| 1234 | 1248 | ||
| 1235 | /* First, check whether we should apply a seccomp filter. This | 1249 | /* First, check whether we should apply a seccomp filter. This |
| 1236 | should come at the very beginning to allow the filter to protect | 1250 | should come at the very beginning to allow the filter to protect |
| @@ -1425,8 +1439,10 @@ main (int argc, char **argv) | |||
| 1425 | 1439 | ||
| 1426 | bool only_version = false; | 1440 | bool only_version = false; |
| 1427 | sort_args (argc, argv); | 1441 | sort_args (argc, argv); |
| 1428 | argc = 0; | 1442 | old_argc = argc, argc = 0; |
| 1429 | while (argv[argc]) argc++; | 1443 | while (argv[argc] |
| 1444 | /* Don't allow going past argv. */ | ||
| 1445 | && argc < old_argc) argc++; | ||
| 1430 | 1446 | ||
| 1431 | skip_args = 0; | 1447 | skip_args = 0; |
| 1432 | if (argmatch (argv, argc, "-version", "--version", 3, NULL, &skip_args)) | 1448 | if (argmatch (argv, argc, "-version", "--version", 3, NULL, &skip_args)) |
| @@ -2375,6 +2391,14 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 2375 | #endif | 2391 | #endif |
| 2376 | syms_of_fontset (); | 2392 | syms_of_fontset (); |
| 2377 | #endif /* HAVE_HAIKU */ | 2393 | #endif /* HAVE_HAIKU */ |
| 2394 | #ifdef HAVE_ANDROID | ||
| 2395 | syms_of_androidterm (); | ||
| 2396 | syms_of_androidfns (); | ||
| 2397 | syms_of_fontset (); | ||
| 2398 | #if !defined ANDROID_STUBIFY | ||
| 2399 | syms_of_androidfont (); | ||
| 2400 | #endif /* !ANDROID_STUBIFY */ | ||
| 2401 | #endif /* HAVE_ANDROID */ | ||
| 2378 | 2402 | ||
| 2379 | syms_of_gnutls (); | 2403 | syms_of_gnutls (); |
| 2380 | 2404 | ||
| @@ -2436,6 +2460,10 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 2436 | init_haiku_select (); | 2460 | init_haiku_select (); |
| 2437 | #endif | 2461 | #endif |
| 2438 | 2462 | ||
| 2463 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 2464 | init_androidfont (); | ||
| 2465 | #endif | ||
| 2466 | |||
| 2439 | init_charset (); | 2467 | init_charset (); |
| 2440 | 2468 | ||
| 2441 | /* This calls putenv and so must precede init_process_emacs. */ | 2469 | /* This calls putenv and so must precede init_process_emacs. */ |
| @@ -2950,7 +2978,7 @@ shut_down_emacs (int sig, Lisp_Object stuff) | |||
| 2950 | Vinhibit_redisplay = Qt; | 2978 | Vinhibit_redisplay = Qt; |
| 2951 | 2979 | ||
| 2952 | /* If we are controlling the terminal, reset terminal modes. */ | 2980 | /* If we are controlling the terminal, reset terminal modes. */ |
| 2953 | #ifndef DOS_NT | 2981 | #if !defined DOS_NT && !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) |
| 2954 | pid_t tpgrp = tcgetpgrp (STDIN_FILENO); | 2982 | pid_t tpgrp = tcgetpgrp (STDIN_FILENO); |
| 2955 | if (tpgrp != -1 && tpgrp == getpgrp ()) | 2983 | if (tpgrp != -1 && tpgrp == getpgrp ()) |
| 2956 | { | 2984 | { |
| @@ -3469,6 +3497,7 @@ Special values: | |||
| 3469 | `windows-nt' compiled as a native W32 application. | 3497 | `windows-nt' compiled as a native W32 application. |
| 3470 | `cygwin' compiled using the Cygwin library. | 3498 | `cygwin' compiled using the Cygwin library. |
| 3471 | `haiku' compiled for a Haiku system. | 3499 | `haiku' compiled for a Haiku system. |
| 3500 | `android' compiled for Android. | ||
| 3472 | Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix, | 3501 | Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix, |
| 3473 | hpux, usg-unix-v) indicates some sort of Unix system. */); | 3502 | hpux, usg-unix-v) indicates some sort of Unix system. */); |
| 3474 | Vsystem_type = intern_c_string (SYSTEM_TYPE); | 3503 | Vsystem_type = intern_c_string (SYSTEM_TYPE); |
diff --git a/src/epaths.in b/src/epaths.in index 2eccd0ac603..7ab1b4b3d86 100644 --- a/src/epaths.in +++ b/src/epaths.in | |||
| @@ -18,6 +18,7 @@ GNU General Public License for more details. | |||
| 18 | You should have received a copy of the GNU General Public License | 18 | You should have received a copy of the GNU General Public License |
| 19 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | 19 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ |
| 20 | 20 | ||
| 21 | #if !defined HAVE_ANDROID || defined ANDROID_STUBIFY | ||
| 21 | 22 | ||
| 22 | /* Together with PATH_SITELOADSEARCH, this gives the default value of | 23 | /* Together with PATH_SITELOADSEARCH, this gives the default value of |
| 23 | load-path, which is the search path for the Lisp function "load". | 24 | load-path, which is the search path for the Lisp function "load". |
| @@ -79,3 +80,24 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 79 | 80 | ||
| 80 | /* Where Emacs should look for the application default file. */ | 81 | /* Where Emacs should look for the application default file. */ |
| 81 | #define PATH_X_DEFAULTS "/usr/lib/X11/%L/%T/%N%C%S:/usr/lib/X11/%l/%T/%N%C%S:/usr/lib/X11/%T/%N%C%S:/usr/lib/X11/%L/%T/%N%S:/usr/lib/X11/%l/%T/%N%S:/usr/lib/X11/%T/%N%S" | 82 | #define PATH_X_DEFAULTS "/usr/lib/X11/%L/%T/%N%C%S:/usr/lib/X11/%l/%T/%N%C%S:/usr/lib/X11/%T/%N%C%S:/usr/lib/X11/%L/%T/%N%S:/usr/lib/X11/%l/%T/%N%S:/usr/lib/X11/%T/%N%S" |
| 83 | |||
| 84 | #else | ||
| 85 | |||
| 86 | /* Replace the defines above with links to files in the assets | ||
| 87 | pseudo-directory. Preserve the extra spaces, or epaths.in will not | ||
| 88 | be generated correctly. */ | ||
| 89 | |||
| 90 | # define PATH_EXEC (android_lib_dir) | ||
| 91 | # define PATH_LOADSEARCH "/assets/lisp/" | ||
| 92 | # define PATH_SITELOADSEARCH (android_site_load_path) | ||
| 93 | # define PATH_DUMPLOADSEARCH "/assets/lisp/" | ||
| 94 | # define PATH_DATA "/assets/etc/" | ||
| 95 | # define PATH_DOC "/assets/etc/" | ||
| 96 | # define PATH_INFO "/assets/info/" | ||
| 97 | # define PATH_GAME "" | ||
| 98 | # define PATH_BITMAPS "" | ||
| 99 | |||
| 100 | extern char *android_site_load_path; | ||
| 101 | extern char *android_lib_dir; | ||
| 102 | |||
| 103 | #endif | ||
diff --git a/src/fileio.c b/src/fileio.c index 66ce6b30887..1d22c51ebaa 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -56,6 +56,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 56 | #include "region-cache.h" | 56 | #include "region-cache.h" |
| 57 | #include "frame.h" | 57 | #include "frame.h" |
| 58 | 58 | ||
| 59 | #if defined HAVE_ANDROID | ||
| 60 | #include "android.h" | ||
| 61 | #endif | ||
| 62 | |||
| 59 | #ifdef HAVE_LINUX_FS_H | 63 | #ifdef HAVE_LINUX_FS_H |
| 60 | # include <sys/ioctl.h> | 64 | # include <sys/ioctl.h> |
| 61 | # include <linux/fs.h> | 65 | # include <linux/fs.h> |
| @@ -135,7 +139,6 @@ static dev_t timestamp_file_system; | |||
| 135 | static Lisp_Object Vwrite_region_annotation_buffers; | 139 | static Lisp_Object Vwrite_region_annotation_buffers; |
| 136 | 140 | ||
| 137 | static Lisp_Object emacs_readlinkat (int, char const *); | 141 | static Lisp_Object emacs_readlinkat (int, char const *); |
| 138 | static Lisp_Object file_name_directory (Lisp_Object); | ||
| 139 | static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, | 142 | static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, |
| 140 | Lisp_Object *, struct coding_system *); | 143 | Lisp_Object *, struct coding_system *); |
| 141 | static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, | 144 | static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, |
| @@ -160,6 +163,12 @@ file_access_p (char const *file, int amode) | |||
| 160 | } | 163 | } |
| 161 | #endif | 164 | #endif |
| 162 | 165 | ||
| 166 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 167 | /* FILE may be some kind of special Android file. */ | ||
| 168 | if (android_file_access_p (file, amode)) | ||
| 169 | return true; | ||
| 170 | #endif | ||
| 171 | |||
| 163 | if (faccessat (AT_FDCWD, file, amode, AT_EACCESS) == 0) | 172 | if (faccessat (AT_FDCWD, file, amode, AT_EACCESS) == 0) |
| 164 | return true; | 173 | return true; |
| 165 | 174 | ||
| @@ -370,7 +379,7 @@ Given a Unix syntax file name, returns a string ending in slash. */) | |||
| 370 | /* Return the directory component of FILENAME, or nil if FILENAME does | 379 | /* Return the directory component of FILENAME, or nil if FILENAME does |
| 371 | not contain a directory component. */ | 380 | not contain a directory component. */ |
| 372 | 381 | ||
| 373 | static Lisp_Object | 382 | Lisp_Object |
| 374 | file_name_directory (Lisp_Object filename) | 383 | file_name_directory (Lisp_Object filename) |
| 375 | { | 384 | { |
| 376 | char *beg = SSDATA (filename); | 385 | char *beg = SSDATA (filename); |
| @@ -2227,7 +2236,7 @@ permissions. */) | |||
| 2227 | 2236 | ||
| 2228 | record_unwind_protect_int (close_file_unwind, ifd); | 2237 | record_unwind_protect_int (close_file_unwind, ifd); |
| 2229 | 2238 | ||
| 2230 | if (fstat (ifd, &st) != 0) | 2239 | if (sys_fstat (ifd, &st) != 0) |
| 2231 | report_file_error ("Input file status", file); | 2240 | report_file_error ("Input file status", file); |
| 2232 | 2241 | ||
| 2233 | if (!NILP (preserve_permissions)) | 2242 | if (!NILP (preserve_permissions)) |
| @@ -2273,7 +2282,7 @@ permissions. */) | |||
| 2273 | if (already_exists) | 2282 | if (already_exists) |
| 2274 | { | 2283 | { |
| 2275 | struct stat out_st; | 2284 | struct stat out_st; |
| 2276 | if (fstat (ofd, &out_st) != 0) | 2285 | if (sys_fstat (ofd, &out_st) != 0) |
| 2277 | report_file_error ("Output file status", newname); | 2286 | report_file_error ("Output file status", newname); |
| 2278 | if (st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) | 2287 | if (st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) |
| 2279 | report_file_errno ("Input and output files are the same", | 2288 | report_file_errno ("Input and output files are the same", |
| @@ -3078,7 +3087,7 @@ file_directory_p (Lisp_Object file) | |||
| 3078 | errno = ENOTDIR; /* like the non-DOS_NT branch below does */ | 3087 | errno = ENOTDIR; /* like the non-DOS_NT branch below does */ |
| 3079 | return retval; | 3088 | return retval; |
| 3080 | #else | 3089 | #else |
| 3081 | # ifdef O_PATH | 3090 | # if defined O_PATH && !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) |
| 3082 | /* Use O_PATH if available, as it avoids races and EOVERFLOW issues. */ | 3091 | /* Use O_PATH if available, as it avoids races and EOVERFLOW issues. */ |
| 3083 | int fd = emacs_openat (AT_FDCWD, SSDATA (file), | 3092 | int fd = emacs_openat (AT_FDCWD, SSDATA (file), |
| 3084 | O_PATH | O_CLOEXEC | O_DIRECTORY, 0); | 3093 | O_PATH | O_CLOEXEC | O_DIRECTORY, 0); |
| @@ -4002,7 +4011,7 @@ by calling `format-decode', which see. */) | |||
| 4002 | XCAR (XCAR (window_markers))); | 4011 | XCAR (XCAR (window_markers))); |
| 4003 | } | 4012 | } |
| 4004 | 4013 | ||
| 4005 | if (fstat (fd, &st) != 0) | 4014 | if (sys_fstat (fd, &st) != 0) |
| 4006 | report_file_error ("Input file status", orig_filename); | 4015 | report_file_error ("Input file status", orig_filename); |
| 4007 | mtime = get_stat_mtime (&st); | 4016 | mtime = get_stat_mtime (&st); |
| 4008 | 4017 | ||
| @@ -5394,7 +5403,7 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename, | |||
| 5394 | modtime = invalid_timespec (); | 5403 | modtime = invalid_timespec (); |
| 5395 | if (visiting) | 5404 | if (visiting) |
| 5396 | { | 5405 | { |
| 5397 | if (fstat (desc, &st) == 0) | 5406 | if (sys_fstat (desc, &st) == 0) |
| 5398 | modtime = get_stat_mtime (&st); | 5407 | modtime = get_stat_mtime (&st); |
| 5399 | else | 5408 | else |
| 5400 | ok = 0, save_errno = errno; | 5409 | ok = 0, save_errno = errno; |
| @@ -5432,7 +5441,7 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename, | |||
| 5432 | if (desc1 >= 0) | 5441 | if (desc1 >= 0) |
| 5433 | { | 5442 | { |
| 5434 | struct stat st1; | 5443 | struct stat st1; |
| 5435 | if (fstat (desc1, &st1) == 0 | 5444 | if (sys_fstat (desc1, &st1) == 0 |
| 5436 | && st.st_dev == st1.st_dev && st.st_ino == st1.st_ino) | 5445 | && st.st_dev == st1.st_dev && st.st_ino == st1.st_ino) |
| 5437 | { | 5446 | { |
| 5438 | /* Use the heuristic if it appears to be valid. With neither | 5447 | /* Use the heuristic if it appears to be valid. With neither |
diff --git a/src/filelock.c b/src/filelock.c index a657cc4582c..e70c68501d1 100644 --- a/src/filelock.c +++ b/src/filelock.c | |||
| @@ -120,6 +120,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 120 | * Non-forced locks on non-MS-Windows systems that support neither | 120 | * Non-forced locks on non-MS-Windows systems that support neither |
| 121 | hard nor symbolic links. */ | 121 | hard nor symbolic links. */ |
| 122 | 122 | ||
| 123 | /* Boot time is not available on Android. */ | ||
| 124 | |||
| 125 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 126 | #undef BOOT_TIME | ||
| 127 | #endif | ||
| 128 | |||
| 123 | 129 | ||
| 124 | /* Return the time of the last system boot. */ | 130 | /* Return the time of the last system boot. */ |
| 125 | 131 | ||
| @@ -3519,6 +3519,10 @@ The data read from the system are decoded using `locale-coding-system'. */) | |||
| 3519 | (Lisp_Object item) | 3519 | (Lisp_Object item) |
| 3520 | { | 3520 | { |
| 3521 | char *str = NULL; | 3521 | char *str = NULL; |
| 3522 | |||
| 3523 | /* STR is apparently unused on Android. */ | ||
| 3524 | ((void) str); | ||
| 3525 | |||
| 3522 | #ifdef HAVE_LANGINFO_CODESET | 3526 | #ifdef HAVE_LANGINFO_CODESET |
| 3523 | if (EQ (item, Qcodeset)) | 3527 | if (EQ (item, Qcodeset)) |
| 3524 | { | 3528 | { |
diff --git a/src/font.c b/src/font.c index 6e720bc2856..4ea18f4ce76 100644 --- a/src/font.c +++ b/src/font.c | |||
| @@ -180,6 +180,22 @@ font_make_entity (void) | |||
| 180 | return font_entity; | 180 | return font_entity; |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | #ifdef HAVE_ANDROID | ||
| 184 | |||
| 185 | Lisp_Object | ||
| 186 | font_make_entity_android (int size) | ||
| 187 | { | ||
| 188 | Lisp_Object font_entity; | ||
| 189 | struct font_entity *entity | ||
| 190 | = ((struct font_entity *) | ||
| 191 | allocate_pseudovector (size, FONT_ENTITY_MAX, FONT_ENTITY_MAX, | ||
| 192 | PVEC_FONT)); | ||
| 193 | XSETFONT (font_entity, entity); | ||
| 194 | return font_entity; | ||
| 195 | } | ||
| 196 | |||
| 197 | #endif | ||
| 198 | |||
| 183 | /* Create a font-object whose structure size is SIZE. If ENTITY is | 199 | /* Create a font-object whose structure size is SIZE. If ENTITY is |
| 184 | not nil, copy properties from ENTITY to the font-object. If | 200 | not nil, copy properties from ENTITY to the font-object. If |
| 185 | PIXELSIZE is positive, set the `size' property to PIXELSIZE. */ | 201 | PIXELSIZE is positive, set the `size' property to PIXELSIZE. */ |
diff --git a/src/font.h b/src/font.h index d36c45a53c4..c1ab26b87cb 100644 --- a/src/font.h +++ b/src/font.h | |||
| @@ -823,6 +823,9 @@ extern Lisp_Object copy_font_spec (Lisp_Object); | |||
| 823 | extern Lisp_Object merge_font_spec (Lisp_Object, Lisp_Object); | 823 | extern Lisp_Object merge_font_spec (Lisp_Object, Lisp_Object); |
| 824 | 824 | ||
| 825 | extern Lisp_Object font_make_entity (void); | 825 | extern Lisp_Object font_make_entity (void); |
| 826 | #ifdef HAVE_ANDROID | ||
| 827 | extern Lisp_Object font_make_entity_android (int); | ||
| 828 | #endif | ||
| 826 | extern Lisp_Object font_make_object (int, Lisp_Object, int); | 829 | extern Lisp_Object font_make_object (int, Lisp_Object, int); |
| 827 | #if defined (HAVE_XFT) || defined (HAVE_FREETYPE) || defined (HAVE_NS) | 830 | #if defined (HAVE_XFT) || defined (HAVE_FREETYPE) || defined (HAVE_NS) |
| 828 | extern Lisp_Object font_build_object (int, Lisp_Object, Lisp_Object, double); | 831 | extern Lisp_Object font_build_object (int, Lisp_Object, Lisp_Object, double); |
diff --git a/src/frame.c b/src/frame.c index 7d902dabd4f..e843af257a4 100644 --- a/src/frame.c +++ b/src/frame.c | |||
| @@ -228,6 +228,7 @@ Value is: | |||
| 228 | `pc' for a direct-write MS-DOS frame, | 228 | `pc' for a direct-write MS-DOS frame, |
| 229 | `pgtk' for an Emacs frame running on pure GTK. | 229 | `pgtk' for an Emacs frame running on pure GTK. |
| 230 | `haiku' for an Emacs frame running in Haiku. | 230 | `haiku' for an Emacs frame running in Haiku. |
| 231 | `android' for an Emacs frame running in Android. | ||
| 231 | See also `frame-live-p'. */) | 232 | See also `frame-live-p'. */) |
| 232 | (Lisp_Object object) | 233 | (Lisp_Object object) |
| 233 | { | 234 | { |
| @@ -250,6 +251,8 @@ See also `frame-live-p'. */) | |||
| 250 | return Qpgtk; | 251 | return Qpgtk; |
| 251 | case output_haiku: | 252 | case output_haiku: |
| 252 | return Qhaiku; | 253 | return Qhaiku; |
| 254 | case output_android: | ||
| 255 | return Qandroid; | ||
| 253 | default: | 256 | default: |
| 254 | emacs_abort (); | 257 | emacs_abort (); |
| 255 | } | 258 | } |
| @@ -279,6 +282,7 @@ The value is a symbol: | |||
| 279 | `pc' for a direct-write MS-DOS frame. | 282 | `pc' for a direct-write MS-DOS frame. |
| 280 | `pgtk' for an Emacs frame using pure GTK facilities. | 283 | `pgtk' for an Emacs frame using pure GTK facilities. |
| 281 | `haiku' for an Emacs frame running in Haiku. | 284 | `haiku' for an Emacs frame running in Haiku. |
| 285 | `android' for an Emacs frame running in Android/ | ||
| 282 | 286 | ||
| 283 | FRAME defaults to the currently selected frame. | 287 | FRAME defaults to the currently selected frame. |
| 284 | 288 | ||
| @@ -1228,6 +1232,7 @@ make_initial_frame (void) | |||
| 1228 | return f; | 1232 | return f; |
| 1229 | } | 1233 | } |
| 1230 | 1234 | ||
| 1235 | #ifndef HAVE_ANDROID | ||
| 1231 | 1236 | ||
| 1232 | static struct frame * | 1237 | static struct frame * |
| 1233 | make_terminal_frame (struct terminal *terminal) | 1238 | make_terminal_frame (struct terminal *terminal) |
| @@ -1317,6 +1322,8 @@ get_future_frame_param (Lisp_Object parameter, | |||
| 1317 | return result; | 1322 | return result; |
| 1318 | } | 1323 | } |
| 1319 | 1324 | ||
| 1325 | #endif | ||
| 1326 | |||
| 1320 | DEFUN ("make-terminal-frame", Fmake_terminal_frame, Smake_terminal_frame, | 1327 | DEFUN ("make-terminal-frame", Fmake_terminal_frame, Smake_terminal_frame, |
| 1321 | 1, 1, 0, | 1328 | 1, 1, 0, |
| 1322 | doc: /* Create an additional terminal frame, possibly on another terminal. | 1329 | doc: /* Create an additional terminal frame, possibly on another terminal. |
| @@ -1336,6 +1343,10 @@ Note that changing the size of one terminal frame automatically | |||
| 1336 | affects all frames on the same terminal device. */) | 1343 | affects all frames on the same terminal device. */) |
| 1337 | (Lisp_Object parms) | 1344 | (Lisp_Object parms) |
| 1338 | { | 1345 | { |
| 1346 | #ifdef HAVE_ANDROID | ||
| 1347 | error ("Text terminals are not supported on this platform"); | ||
| 1348 | return Qnil; | ||
| 1349 | #else | ||
| 1339 | struct frame *f; | 1350 | struct frame *f; |
| 1340 | struct terminal *t = NULL; | 1351 | struct terminal *t = NULL; |
| 1341 | Lisp_Object frame; | 1352 | Lisp_Object frame; |
| @@ -1436,6 +1447,7 @@ affects all frames on the same terminal device. */) | |||
| 1436 | f->after_make_frame = true; | 1447 | f->after_make_frame = true; |
| 1437 | 1448 | ||
| 1438 | return frame; | 1449 | return frame; |
| 1450 | #endif | ||
| 1439 | } | 1451 | } |
| 1440 | 1452 | ||
| 1441 | 1453 | ||
| @@ -5303,16 +5315,23 @@ gui_display_get_resource (Display_Info *dpyinfo, Lisp_Object attribute, | |||
| 5303 | *nz++ = '.'; | 5315 | *nz++ = '.'; |
| 5304 | lispstpcpy (nz, attribute); | 5316 | lispstpcpy (nz, attribute); |
| 5305 | 5317 | ||
| 5306 | const char *value = | 5318 | #ifndef HAVE_ANDROID |
| 5307 | dpyinfo->terminal->get_string_resource_hook (&dpyinfo->rdb, | 5319 | const char *value |
| 5308 | name_key, | 5320 | = dpyinfo->terminal->get_string_resource_hook (&dpyinfo->rdb, |
| 5309 | class_key); | 5321 | name_key, |
| 5310 | SAFE_FREE(); | 5322 | class_key); |
| 5323 | |||
| 5324 | SAFE_FREE (); | ||
| 5311 | 5325 | ||
| 5312 | if (value && *value) | 5326 | if (value && *value) |
| 5313 | return build_string (value); | 5327 | return build_string (value); |
| 5314 | else | 5328 | else |
| 5315 | return Qnil; | 5329 | return Qnil; |
| 5330 | #else | ||
| 5331 | |||
| 5332 | SAFE_FREE (); | ||
| 5333 | return Qnil; | ||
| 5334 | #endif | ||
| 5316 | } | 5335 | } |
| 5317 | 5336 | ||
| 5318 | 5337 | ||
| @@ -6218,6 +6237,7 @@ syms_of_frame (void) | |||
| 6218 | DEFSYM (Qns, "ns"); | 6237 | DEFSYM (Qns, "ns"); |
| 6219 | DEFSYM (Qpgtk, "pgtk"); | 6238 | DEFSYM (Qpgtk, "pgtk"); |
| 6220 | DEFSYM (Qhaiku, "haiku"); | 6239 | DEFSYM (Qhaiku, "haiku"); |
| 6240 | DEFSYM (Qandroid, "android"); | ||
| 6221 | DEFSYM (Qvisible, "visible"); | 6241 | DEFSYM (Qvisible, "visible"); |
| 6222 | DEFSYM (Qbuffer_predicate, "buffer-predicate"); | 6242 | DEFSYM (Qbuffer_predicate, "buffer-predicate"); |
| 6223 | DEFSYM (Qbuffer_list, "buffer-list"); | 6243 | DEFSYM (Qbuffer_list, "buffer-list"); |
diff --git a/src/frame.h b/src/frame.h index dcd32036b86..e0b47d26d69 100644 --- a/src/frame.h +++ b/src/frame.h | |||
| @@ -181,7 +181,7 @@ struct frame | |||
| 181 | most recently buried buffer is first. For last-buffer. */ | 181 | most recently buried buffer is first. For last-buffer. */ |
| 182 | Lisp_Object buried_buffer_list; | 182 | Lisp_Object buried_buffer_list; |
| 183 | 183 | ||
| 184 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 184 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 185 | /* A dummy window used to display menu bars under X when no X | 185 | /* A dummy window used to display menu bars under X when no X |
| 186 | toolkit support is available. */ | 186 | toolkit support is available. */ |
| 187 | Lisp_Object menu_bar_window; | 187 | Lisp_Object menu_bar_window; |
| @@ -377,7 +377,7 @@ struct frame | |||
| 377 | /* The output method says how the contents of this frame are | 377 | /* The output method says how the contents of this frame are |
| 378 | displayed. It could be using termcap, or using an X window. | 378 | displayed. It could be using termcap, or using an X window. |
| 379 | This must be the same as the terminal->type. */ | 379 | This must be the same as the terminal->type. */ |
| 380 | ENUM_BF (output_method) output_method : 3; | 380 | ENUM_BF (output_method) output_method : 4; |
| 381 | 381 | ||
| 382 | #ifdef HAVE_WINDOW_SYSTEM | 382 | #ifdef HAVE_WINDOW_SYSTEM |
| 383 | /* True if this frame is a tooltip frame. */ | 383 | /* True if this frame is a tooltip frame. */ |
| @@ -586,12 +586,13 @@ struct frame | |||
| 586 | well. */ | 586 | well. */ |
| 587 | union output_data | 587 | union output_data |
| 588 | { | 588 | { |
| 589 | struct tty_output *tty; /* From termchar.h. */ | 589 | struct tty_output *tty; /* From termchar.h. */ |
| 590 | struct x_output *x; /* From xterm.h. */ | 590 | struct x_output *x; /* From xterm.h. */ |
| 591 | struct w32_output *w32; /* From w32term.h. */ | 591 | struct w32_output *w32; /* From w32term.h. */ |
| 592 | struct ns_output *ns; /* From nsterm.h. */ | 592 | struct ns_output *ns; /* From nsterm.h. */ |
| 593 | struct pgtk_output *pgtk; /* From pgtkterm.h. */ | 593 | struct pgtk_output *pgtk; /* From pgtkterm.h. */ |
| 594 | struct haiku_output *haiku; /* From haikuterm.h. */ | 594 | struct haiku_output *haiku; /* From haikuterm.h. */ |
| 595 | struct android_output *android; /* From androidterm.h. */ | ||
| 595 | } | 596 | } |
| 596 | output_data; | 597 | output_data; |
| 597 | 598 | ||
| @@ -713,7 +714,7 @@ fset_menu_bar_vector (struct frame *f, Lisp_Object val) | |||
| 713 | { | 714 | { |
| 714 | f->menu_bar_vector = val; | 715 | f->menu_bar_vector = val; |
| 715 | } | 716 | } |
| 716 | #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 717 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 717 | INLINE void | 718 | INLINE void |
| 718 | fset_menu_bar_window (struct frame *f, Lisp_Object val) | 719 | fset_menu_bar_window (struct frame *f, Lisp_Object val) |
| 719 | { | 720 | { |
| @@ -872,6 +873,11 @@ default_pixels_per_inch_y (void) | |||
| 872 | #else | 873 | #else |
| 873 | #define FRAME_HAIKU_P(f) ((f)->output_method == output_haiku) | 874 | #define FRAME_HAIKU_P(f) ((f)->output_method == output_haiku) |
| 874 | #endif | 875 | #endif |
| 876 | #ifndef HAVE_ANDROID | ||
| 877 | #define FRAME_ANDROID_P(f) false | ||
| 878 | #else | ||
| 879 | #define FRAME_ANDROID_P(f) ((f)->output_method == output_android) | ||
| 880 | #endif | ||
| 875 | 881 | ||
| 876 | /* FRAME_WINDOW_P tests whether the frame is a graphical window system | 882 | /* FRAME_WINDOW_P tests whether the frame is a graphical window system |
| 877 | frame. */ | 883 | frame. */ |
| @@ -890,6 +896,9 @@ default_pixels_per_inch_y (void) | |||
| 890 | #ifdef HAVE_HAIKU | 896 | #ifdef HAVE_HAIKU |
| 891 | #define FRAME_WINDOW_P(f) FRAME_HAIKU_P (f) | 897 | #define FRAME_WINDOW_P(f) FRAME_HAIKU_P (f) |
| 892 | #endif | 898 | #endif |
| 899 | #ifdef HAVE_ANDROID | ||
| 900 | #define FRAME_WINDOW_P(f) FRAME_ANDROID_P (f) | ||
| 901 | #endif | ||
| 893 | #ifndef FRAME_WINDOW_P | 902 | #ifndef FRAME_WINDOW_P |
| 894 | #define FRAME_WINDOW_P(f) ((void) (f), false) | 903 | #define FRAME_WINDOW_P(f) ((void) (f), false) |
| 895 | #endif | 904 | #endif |
| @@ -917,11 +926,17 @@ default_pixels_per_inch_y (void) | |||
| 917 | frame F. We need to define two versions because a TTY-only build | 926 | frame F. We need to define two versions because a TTY-only build |
| 918 | does not have FRAME_DISPLAY_INFO. */ | 927 | does not have FRAME_DISPLAY_INFO. */ |
| 919 | #ifdef HAVE_WINDOW_SYSTEM | 928 | #ifdef HAVE_WINDOW_SYSTEM |
| 929 | #ifndef HAVE_ANDROID | ||
| 920 | # define MOUSE_HL_INFO(F) \ | 930 | # define MOUSE_HL_INFO(F) \ |
| 921 | (FRAME_WINDOW_P(F) \ | 931 | (FRAME_WINDOW_P (F) \ |
| 922 | ? &FRAME_DISPLAY_INFO(F)->mouse_highlight \ | 932 | ? &FRAME_DISPLAY_INFO(F)->mouse_highlight \ |
| 923 | : &(F)->output_data.tty->display_info->mouse_highlight) | 933 | : &(F)->output_data.tty->display_info->mouse_highlight) |
| 924 | #else | 934 | #else |
| 935 | /* There is no "struct tty_output" on Android at all. */ | ||
| 936 | # define MOUSE_HL_INFO(F) \ | ||
| 937 | (&FRAME_DISPLAY_INFO(F)->mouse_highlight) | ||
| 938 | #endif | ||
| 939 | #else | ||
| 925 | # define MOUSE_HL_INFO(F) \ | 940 | # define MOUSE_HL_INFO(F) \ |
| 926 | (&(F)->output_data.tty->display_info->mouse_highlight) | 941 | (&(F)->output_data.tty->display_info->mouse_highlight) |
| 927 | #endif | 942 | #endif |
diff --git a/src/image.c b/src/image.c index b881e43e951..986dd7aada4 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -175,6 +175,28 @@ typedef struct haiku_bitmap_record Bitmap_Record; | |||
| 175 | 175 | ||
| 176 | #endif | 176 | #endif |
| 177 | 177 | ||
| 178 | #ifdef HAVE_ANDROID | ||
| 179 | #include "androidterm.h" | ||
| 180 | typedef struct android_bitmap_record Bitmap_Record; | ||
| 181 | |||
| 182 | /* TODO: implement images on Android. */ | ||
| 183 | #define GET_PIXEL(ximg, x, y) 0 | ||
| 184 | #define PUT_PIXEL(ximg, x, y, pixel) ((void) (pixel)) | ||
| 185 | #define NO_PIXMAP 0 | ||
| 186 | |||
| 187 | #define PIX_MASK_RETAIN 0 | ||
| 188 | #define PIX_MASK_DRAW 1 | ||
| 189 | |||
| 190 | #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) | ||
| 191 | #define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) | ||
| 192 | #define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) | ||
| 193 | #define BLUE_FROM_ULONG(color) ((color) & 0xff) | ||
| 194 | #define RED16_FROM_ULONG(color) (RED_FROM_ULONG (color) * 0x101) | ||
| 195 | #define GREEN16_FROM_ULONG(color) (GREEN_FROM_ULONG (color) * 0x101) | ||
| 196 | #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG (color) * 0x101) | ||
| 197 | |||
| 198 | #endif | ||
| 199 | |||
| 178 | static void image_disable_image (struct frame *, struct image *); | 200 | static void image_disable_image (struct frame *, struct image *); |
| 179 | static void image_edge_detection (struct frame *, struct image *, Lisp_Object, | 201 | static void image_edge_detection (struct frame *, struct image *, Lisp_Object, |
| 180 | Lisp_Object); | 202 | Lisp_Object); |
| @@ -831,6 +853,18 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file) | |||
| 831 | xfree (contents); | 853 | xfree (contents); |
| 832 | return id; | 854 | return id; |
| 833 | #endif | 855 | #endif |
| 856 | |||
| 857 | #ifdef HAVE_ANDROID | ||
| 858 | #ifdef ANDROID_STUBIFY | ||
| 859 | ((void) dpyinfo); | ||
| 860 | |||
| 861 | /* This function should never be called when building stubs. */ | ||
| 862 | emacs_abort (); | ||
| 863 | #else | ||
| 864 | /* you lose, not yet implemented TODO */ | ||
| 865 | return 0; | ||
| 866 | #endif | ||
| 867 | #endif | ||
| 834 | } | 868 | } |
| 835 | 869 | ||
| 836 | /* Free bitmap B. */ | 870 | /* Free bitmap B. */ |
| @@ -3338,6 +3372,16 @@ image_create_x_image_and_pixmap_1 (struct frame *f, int width, int height, int d | |||
| 3338 | Emacs_Pix_Container *pimg, | 3372 | Emacs_Pix_Container *pimg, |
| 3339 | Emacs_Pixmap *pixmap, Picture *picture) | 3373 | Emacs_Pixmap *pixmap, Picture *picture) |
| 3340 | { | 3374 | { |
| 3375 | #ifdef HAVE_ANDROID | ||
| 3376 | #ifdef ANDROID_STUBIFY | ||
| 3377 | /* This function should never be called when building stubs. */ | ||
| 3378 | emacs_abort (); | ||
| 3379 | #else | ||
| 3380 | /* you lose, not yet implemented TODO */ | ||
| 3381 | return false; | ||
| 3382 | #endif | ||
| 3383 | #endif | ||
| 3384 | |||
| 3341 | #ifdef USE_CAIRO | 3385 | #ifdef USE_CAIRO |
| 3342 | eassert (input_blocked_p ()); | 3386 | eassert (input_blocked_p ()); |
| 3343 | 3387 | ||
| @@ -3646,6 +3690,16 @@ image_unget_x_image_or_dc (struct image *img, bool mask_p, | |||
| 3646 | static Emacs_Pix_Container | 3690 | static Emacs_Pix_Container |
| 3647 | image_get_x_image (struct frame *f, struct image *img, bool mask_p) | 3691 | image_get_x_image (struct frame *f, struct image *img, bool mask_p) |
| 3648 | { | 3692 | { |
| 3693 | #ifdef HAVE_ANDROID | ||
| 3694 | #ifdef ANDROID_STUBIFY | ||
| 3695 | /* This function should never be called when building stubs. */ | ||
| 3696 | emacs_abort (); | ||
| 3697 | #else | ||
| 3698 | /* you lose, not yet implemented TODO */ | ||
| 3699 | return 0; | ||
| 3700 | #endif | ||
| 3701 | #endif | ||
| 3702 | |||
| 3649 | #if defined USE_CAIRO || defined (HAVE_HAIKU) | 3703 | #if defined USE_CAIRO || defined (HAVE_HAIKU) |
| 3650 | return !mask_p ? img->pixmap : img->mask; | 3704 | return !mask_p ? img->pixmap : img->mask; |
| 3651 | #elif defined HAVE_X_WINDOWS | 3705 | #elif defined HAVE_X_WINDOWS |
| @@ -3756,7 +3810,7 @@ slurp_file (int fd, ptrdiff_t *size) | |||
| 3756 | specpdl_ref count = SPECPDL_INDEX (); | 3810 | specpdl_ref count = SPECPDL_INDEX (); |
| 3757 | record_unwind_protect_ptr (fclose_unwind, fp); | 3811 | record_unwind_protect_ptr (fclose_unwind, fp); |
| 3758 | 3812 | ||
| 3759 | if (fstat (fileno (fp), &st) == 0 | 3813 | if (sys_fstat (fileno (fp), &st) == 0 |
| 3760 | && 0 <= st.st_size && st.st_size < min (PTRDIFF_MAX, SIZE_MAX)) | 3814 | && 0 <= st.st_size && st.st_size < min (PTRDIFF_MAX, SIZE_MAX)) |
| 3761 | { | 3815 | { |
| 3762 | /* Report an error if we read past the purported EOF. | 3816 | /* Report an error if we read past the purported EOF. |
| @@ -6074,7 +6128,8 @@ lookup_rgb_color (struct frame *f, int r, int g, int b) | |||
| 6074 | { | 6128 | { |
| 6075 | #ifdef HAVE_NTGUI | 6129 | #ifdef HAVE_NTGUI |
| 6076 | return PALETTERGB (r >> 8, g >> 8, b >> 8); | 6130 | return PALETTERGB (r >> 8, g >> 8, b >> 8); |
| 6077 | #elif defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU | 6131 | #elif defined USE_CAIRO || defined HAVE_NS || defined HAVE_HAIKU \ |
| 6132 | || defined HAVE_ANDROID | ||
| 6078 | return RGB_TO_ULONG (r >> 8, g >> 8, b >> 8); | 6133 | return RGB_TO_ULONG (r >> 8, g >> 8, b >> 8); |
| 6079 | #else | 6134 | #else |
| 6080 | xsignal1 (Qfile_error, | 6135 | xsignal1 (Qfile_error, |
| @@ -6147,7 +6202,8 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p) | |||
| 6147 | p = colors; | 6202 | p = colors; |
| 6148 | for (y = 0; y < img->height; ++y) | 6203 | for (y = 0; y < img->height; ++y) |
| 6149 | { | 6204 | { |
| 6150 | #if !defined USE_CAIRO && !defined HAVE_NS && !defined HAVE_HAIKU | 6205 | #if !defined USE_CAIRO && !defined HAVE_NS && !defined HAVE_HAIKU \ |
| 6206 | && !defined HAVE_ANDROID | ||
| 6151 | Emacs_Color *row = p; | 6207 | Emacs_Color *row = p; |
| 6152 | for (x = 0; x < img->width; ++x, ++p) | 6208 | for (x = 0; x < img->width; ++x, ++p) |
| 6153 | p->pixel = GET_PIXEL (ximg, x, y); | 6209 | p->pixel = GET_PIXEL (ximg, x, y); |
| @@ -6155,7 +6211,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p) | |||
| 6155 | { | 6211 | { |
| 6156 | FRAME_TERMINAL (f)->query_colors (f, row, img->width); | 6212 | FRAME_TERMINAL (f)->query_colors (f, row, img->width); |
| 6157 | } | 6213 | } |
| 6158 | #else /* USE_CAIRO || HAVE_NS || HAVE_HAIKU */ | 6214 | #else /* USE_CAIRO || HAVE_NS || HAVE_HAIKU || HAVE_ANDROID */ |
| 6159 | for (x = 0; x < img->width; ++x, ++p) | 6215 | for (x = 0; x < img->width; ++x, ++p) |
| 6160 | { | 6216 | { |
| 6161 | p->pixel = GET_PIXEL (ximg, x, y); | 6217 | p->pixel = GET_PIXEL (ximg, x, y); |
| @@ -6166,7 +6222,7 @@ image_to_emacs_colors (struct frame *f, struct image *img, bool rgb_p) | |||
| 6166 | p->blue = BLUE16_FROM_ULONG (p->pixel); | 6222 | p->blue = BLUE16_FROM_ULONG (p->pixel); |
| 6167 | } | 6223 | } |
| 6168 | } | 6224 | } |
| 6169 | #endif /* USE_CAIRO || HAVE_NS */ | 6225 | #endif /* USE_CAIRO || HAVE_NS || HAVE_ANDROID */ |
| 6170 | } | 6226 | } |
| 6171 | 6227 | ||
| 6172 | image_unget_x_image_or_dc (img, 0, ximg, prev); | 6228 | image_unget_x_image_or_dc (img, 0, ximg, prev); |
| @@ -6231,7 +6287,11 @@ image_from_emacs_colors (struct frame *f, struct image *img, Emacs_Color *colors | |||
| 6231 | Emacs_Pix_Container ximage; | 6287 | Emacs_Pix_Container ximage; |
| 6232 | Emacs_Color *p; | 6288 | Emacs_Color *p; |
| 6233 | 6289 | ||
| 6290 | #ifndef HAVE_ANDROID | ||
| 6234 | ximage = NULL; | 6291 | ximage = NULL; |
| 6292 | #else | ||
| 6293 | ximage = 0; | ||
| 6294 | #endif | ||
| 6235 | 6295 | ||
| 6236 | init_color_table (); | 6296 | init_color_table (); |
| 6237 | 6297 | ||
| @@ -6393,7 +6453,9 @@ image_edge_detection (struct frame *f, struct image *img, | |||
| 6393 | } | 6453 | } |
| 6394 | 6454 | ||
| 6395 | 6455 | ||
| 6396 | #if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_HAIKU | 6456 | #if defined HAVE_X_WINDOWS || defined USE_CAIRO || defined HAVE_HAIKU \ |
| 6457 | || defined HAVE_ANDROID | ||
| 6458 | |||
| 6397 | static void | 6459 | static void |
| 6398 | image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap, | 6460 | image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap, |
| 6399 | int x, int y, unsigned int width, unsigned int height, | 6461 | int x, int y, unsigned int width, unsigned int height, |
| @@ -6429,8 +6491,16 @@ image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap, | |||
| 6429 | XFreeGC (dpy, gc); | 6491 | XFreeGC (dpy, gc); |
| 6430 | #elif HAVE_HAIKU | 6492 | #elif HAVE_HAIKU |
| 6431 | be_draw_cross_on_pixmap (pixmap, x, y, width, height, color); | 6493 | be_draw_cross_on_pixmap (pixmap, x, y, width, height, color); |
| 6494 | #elif HAVE_ANDROID | ||
| 6495 | #ifdef ANDROID_STUBIFY | ||
| 6496 | /* This function should never be called when building stubs. */ | ||
| 6497 | emacs_abort (); | ||
| 6498 | #else | ||
| 6499 | /* you lose, not yet implemented TODO */ | ||
| 6500 | #endif | ||
| 6432 | #endif | 6501 | #endif |
| 6433 | } | 6502 | } |
| 6503 | |||
| 6434 | #endif /* HAVE_X_WINDOWS || USE_CAIRO || HAVE_HAIKU */ | 6504 | #endif /* HAVE_X_WINDOWS || USE_CAIRO || HAVE_HAIKU */ |
| 6435 | 6505 | ||
| 6436 | /* Transform image IMG on frame F so that it looks disabled. */ | 6506 | /* Transform image IMG on frame F so that it looks disabled. */ |
| @@ -6474,7 +6544,7 @@ image_disable_image (struct frame *f, struct image *img) | |||
| 6474 | #ifndef HAVE_NTGUI | 6544 | #ifndef HAVE_NTGUI |
| 6475 | #ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */ | 6545 | #ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */ |
| 6476 | 6546 | ||
| 6477 | #if !defined USE_CAIRO && !defined HAVE_HAIKU | 6547 | #if !defined USE_CAIRO && !defined HAVE_HAIKU && !defined HAVE_ANDROID |
| 6478 | #define CrossForeground(f) BLACK_PIX_DEFAULT (f) | 6548 | #define CrossForeground(f) BLACK_PIX_DEFAULT (f) |
| 6479 | #define MaskForeground(f) WHITE_PIX_DEFAULT (f) | 6549 | #define MaskForeground(f) WHITE_PIX_DEFAULT (f) |
| 6480 | #else /* USE_CAIRO || HAVE_HAIKU */ | 6550 | #else /* USE_CAIRO || HAVE_HAIKU */ |
| @@ -6482,7 +6552,7 @@ image_disable_image (struct frame *f, struct image *img) | |||
| 6482 | #define MaskForeground(f) PIX_MASK_DRAW | 6552 | #define MaskForeground(f) PIX_MASK_DRAW |
| 6483 | #endif /* USE_CAIRO || HAVE_HAIKU */ | 6553 | #endif /* USE_CAIRO || HAVE_HAIKU */ |
| 6484 | 6554 | ||
| 6485 | #if !defined USE_CAIRO && !defined HAVE_HAIKU | 6555 | #if !defined USE_CAIRO && !defined HAVE_HAIKU && !defined HAVE_ANDROID |
| 6486 | image_sync_to_pixmaps (f, img); | 6556 | image_sync_to_pixmaps (f, img); |
| 6487 | #endif /* !USE_CAIRO && !HAVE_HAIKU */ | 6557 | #endif /* !USE_CAIRO && !HAVE_HAIKU */ |
| 6488 | image_pixmap_draw_cross (f, img->pixmap, 0, 0, img->width, img->height, | 6558 | image_pixmap_draw_cross (f, img->pixmap, 0, 0, img->width, img->height, |
| @@ -9099,7 +9169,7 @@ gif_load (struct frame *f, struct image *img) | |||
| 9099 | `image-cache-size'. */ | 9169 | `image-cache-size'. */ |
| 9100 | struct stat st; | 9170 | struct stat st; |
| 9101 | FILE *fp = fopen (SSDATA (encoded_file), "rb"); | 9171 | FILE *fp = fopen (SSDATA (encoded_file), "rb"); |
| 9102 | if (fstat (fileno (fp), &st) == 0) | 9172 | if (sys_fstat (fileno (fp), &st) == 0) |
| 9103 | byte_size = st.st_size; | 9173 | byte_size = st.st_size; |
| 9104 | fclose (fp); | 9174 | fclose (fp); |
| 9105 | } | 9175 | } |
diff --git a/src/lisp.h b/src/lisp.h index be511a0eb9c..1f1d47f2a95 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -30,6 +30,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 30 | #include <inttypes.h> | 30 | #include <inttypes.h> |
| 31 | #include <limits.h> | 31 | #include <limits.h> |
| 32 | 32 | ||
| 33 | #ifdef HAVE_SYS_STAT_H | ||
| 34 | #include <sys/stat.h> | ||
| 35 | #endif | ||
| 36 | |||
| 33 | #include <attribute.h> | 37 | #include <attribute.h> |
| 34 | #include <intprops.h> | 38 | #include <intprops.h> |
| 35 | #include <verify.h> | 39 | #include <verify.h> |
| @@ -4726,6 +4730,7 @@ extern void syms_of_marker (void); | |||
| 4726 | 4730 | ||
| 4727 | /* Defined in fileio.c. */ | 4731 | /* Defined in fileio.c. */ |
| 4728 | 4732 | ||
| 4733 | extern Lisp_Object file_name_directory (Lisp_Object); | ||
| 4729 | extern char *splice_dir_file (char *, char const *, char const *) | 4734 | extern char *splice_dir_file (char *, char const *, char const *) |
| 4730 | ATTRIBUTE_RETURNS_NONNULL; | 4735 | ATTRIBUTE_RETURNS_NONNULL; |
| 4731 | extern bool file_name_absolute_p (const char *); | 4736 | extern bool file_name_absolute_p (const char *); |
| @@ -5063,7 +5068,12 @@ extern void init_random (void); | |||
| 5063 | extern void emacs_backtrace (int); | 5068 | extern void emacs_backtrace (int); |
| 5064 | extern AVOID emacs_abort (void) NO_INLINE; | 5069 | extern AVOID emacs_abort (void) NO_INLINE; |
| 5065 | extern int emacs_fstatat (int, char const *, void *, int); | 5070 | extern int emacs_fstatat (int, char const *, void *, int); |
| 5071 | #ifdef HAVE_SYS_STAT_H | ||
| 5072 | extern int sys_fstat (int, struct stat *); | ||
| 5073 | #endif | ||
| 5074 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 5066 | extern int emacs_openat (int, char const *, int, int); | 5075 | extern int emacs_openat (int, char const *, int, int); |
| 5076 | #endif | ||
| 5067 | extern int emacs_open (const char *, int, int); | 5077 | extern int emacs_open (const char *, int, int); |
| 5068 | extern int emacs_open_noquit (const char *, int, int); | 5078 | extern int emacs_open_noquit (const char *, int, int); |
| 5069 | extern int emacs_pipe (int[2]); | 5079 | extern int emacs_pipe (int[2]); |
| @@ -5101,7 +5111,9 @@ extern Lisp_Object directory_files_internal (Lisp_Object, Lisp_Object, | |||
| 5101 | bool, Lisp_Object, Lisp_Object); | 5111 | bool, Lisp_Object, Lisp_Object); |
| 5102 | 5112 | ||
| 5103 | /* Defined in term.c. */ | 5113 | /* Defined in term.c. */ |
| 5114 | #ifndef HAVE_ANDROID | ||
| 5104 | extern int *char_ins_del_vector; | 5115 | extern int *char_ins_del_vector; |
| 5116 | #endif | ||
| 5105 | extern void syms_of_term (void); | 5117 | extern void syms_of_term (void); |
| 5106 | extern AVOID fatal (const char *msgid, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); | 5118 | extern AVOID fatal (const char *msgid, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); |
| 5107 | 5119 | ||
diff --git a/src/lread.c b/src/lread.c index d838a18de5a..eb029f01623 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -1047,7 +1047,7 @@ safe_to_load_version (Lisp_Object file, int fd) | |||
| 1047 | 1047 | ||
| 1048 | /* If the file is not regular, then we cannot safely seek it. | 1048 | /* If the file is not regular, then we cannot safely seek it. |
| 1049 | Assume that it is not safe to load as a compiled file. */ | 1049 | Assume that it is not safe to load as a compiled file. */ |
| 1050 | if (fstat (fd, &st) == 0 && !S_ISREG (st.st_mode)) | 1050 | if (sys_fstat (fd, &st) == 0 && !S_ISREG (st.st_mode)) |
| 1051 | return 0; | 1051 | return 0; |
| 1052 | 1052 | ||
| 1053 | /* Read the first few bytes from the file, and look for a line | 1053 | /* Read the first few bytes from the file, and look for a line |
| @@ -1676,7 +1676,7 @@ maybe_swap_for_eln1 (Lisp_Object src_name, Lisp_Object eln_name, | |||
| 1676 | 1676 | ||
| 1677 | if (eln_fd > 0) | 1677 | if (eln_fd > 0) |
| 1678 | { | 1678 | { |
| 1679 | if (fstat (eln_fd, &eln_st) || S_ISDIR (eln_st.st_mode)) | 1679 | if (sys_fstat (eln_fd, &eln_st) || S_ISDIR (eln_st.st_mode)) |
| 1680 | emacs_close (eln_fd); | 1680 | emacs_close (eln_fd); |
| 1681 | else | 1681 | else |
| 1682 | { | 1682 | { |
| @@ -1998,7 +1998,7 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, | |||
| 1998 | } | 1998 | } |
| 1999 | else | 1999 | else |
| 2000 | { | 2000 | { |
| 2001 | int err = (fstat (fd, &st) != 0 ? errno | 2001 | int err = (sys_fstat (fd, &st) != 0 ? errno |
| 2002 | : S_ISDIR (st.st_mode) ? EISDIR : 0); | 2002 | : S_ISDIR (st.st_mode) ? EISDIR : 0); |
| 2003 | if (err) | 2003 | if (err) |
| 2004 | { | 2004 | { |
diff --git a/src/pdumper.c b/src/pdumper.c index e1c55d07ac3..87c652da52f 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -5620,7 +5620,7 @@ pdumper_load (const char *dump_filename, char *argv0) | |||
| 5620 | } | 5620 | } |
| 5621 | 5621 | ||
| 5622 | err = PDUMPER_LOAD_FILE_NOT_FOUND; | 5622 | err = PDUMPER_LOAD_FILE_NOT_FOUND; |
| 5623 | if (fstat (dump_fd, &stat) < 0) | 5623 | if (sys_fstat (dump_fd, &stat) < 0) |
| 5624 | goto out; | 5624 | goto out; |
| 5625 | 5625 | ||
| 5626 | err = PDUMPER_LOAD_BAD_FILE_TYPE; | 5626 | err = PDUMPER_LOAD_BAD_FILE_TYPE; |
diff --git a/src/process.c b/src/process.c index 5144c5d6c92..de1b07a81cc 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -119,6 +119,10 @@ static struct rlimit nofile_limit; | |||
| 119 | #include "gnutls.h" | 119 | #include "gnutls.h" |
| 120 | #endif | 120 | #endif |
| 121 | 121 | ||
| 122 | #ifdef HAVE_ANDROID | ||
| 123 | #include "android.h" | ||
| 124 | #endif | ||
| 125 | |||
| 122 | #ifdef HAVE_WINDOW_SYSTEM | 126 | #ifdef HAVE_WINDOW_SYSTEM |
| 123 | #include TERM_HEADER | 127 | #include TERM_HEADER |
| 124 | #endif /* HAVE_WINDOW_SYSTEM */ | 128 | #endif /* HAVE_WINDOW_SYSTEM */ |
| @@ -5679,7 +5683,17 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5679 | timeout = short_timeout; | 5683 | timeout = short_timeout; |
| 5680 | #endif | 5684 | #endif |
| 5681 | 5685 | ||
| 5682 | /* Non-macOS HAVE_GLIB builds call thread_select in xgselect.c. */ | 5686 | /* Android doesn't support threads and requires using a |
| 5687 | replacement for pselect in android.c to poll for | ||
| 5688 | events. */ | ||
| 5689 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 5690 | nfds = android_select (max_desc + 1, | ||
| 5691 | &Available, (check_write ? &Writeok : 0), | ||
| 5692 | NULL, &timeout, NULL); | ||
| 5693 | #else | ||
| 5694 | |||
| 5695 | /* Non-macOS HAVE_GLIB builds call thread_select in | ||
| 5696 | xgselect.c. */ | ||
| 5683 | #if defined HAVE_GLIB && !defined HAVE_NS | 5697 | #if defined HAVE_GLIB && !defined HAVE_NS |
| 5684 | nfds = xg_select (max_desc + 1, | 5698 | nfds = xg_select (max_desc + 1, |
| 5685 | &Available, (check_write ? &Writeok : 0), | 5699 | &Available, (check_write ? &Writeok : 0), |
| @@ -5695,6 +5709,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5695 | (check_write ? &Writeok : 0), | 5709 | (check_write ? &Writeok : 0), |
| 5696 | NULL, &timeout, NULL); | 5710 | NULL, &timeout, NULL); |
| 5697 | #endif /* !HAVE_GLIB */ | 5711 | #endif /* !HAVE_GLIB */ |
| 5712 | #endif /* HAVE_ANDROID && !ANDROID_STUBIFY */ | ||
| 5698 | 5713 | ||
| 5699 | #ifdef HAVE_GNUTLS | 5714 | #ifdef HAVE_GNUTLS |
| 5700 | /* Merge tls_available into Available. */ | 5715 | /* Merge tls_available into Available. */ |
diff --git a/src/scroll.c b/src/scroll.c index c643730965d..6d4e0d062b9 100644 --- a/src/scroll.c +++ b/src/scroll.c | |||
| @@ -21,6 +21,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 21 | 21 | ||
| 22 | #include <config.h> | 22 | #include <config.h> |
| 23 | 23 | ||
| 24 | /* The entire file is defined out under Android, where there is no | ||
| 25 | text terminal support of any kind. */ | ||
| 26 | |||
| 27 | #ifndef HAVE_ANDROID | ||
| 28 | |||
| 24 | #include "lisp.h" | 29 | #include "lisp.h" |
| 25 | #include "termchar.h" | 30 | #include "termchar.h" |
| 26 | #include "dispextern.h" | 31 | #include "dispextern.h" |
| @@ -984,3 +989,5 @@ do_line_insertion_deletion_costs (struct frame *frame, | |||
| 984 | FRAME_DELETE_COST (frame), FRAME_DELETEN_COST (frame), | 989 | FRAME_DELETE_COST (frame), FRAME_DELETEN_COST (frame), |
| 985 | coefficient); | 990 | coefficient); |
| 986 | } | 991 | } |
| 992 | |||
| 993 | #endif | ||
diff --git a/src/sysdep.c b/src/sysdep.c index 8402ffe308c..808c4af85f3 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -134,6 +134,10 @@ int _cdecl _spawnlp (int, const char *, const char *, ...); | |||
| 134 | # include <sys/socket.h> | 134 | # include <sys/socket.h> |
| 135 | #endif | 135 | #endif |
| 136 | 136 | ||
| 137 | #ifdef HAVE_ANDROID | ||
| 138 | #include "android.h" | ||
| 139 | #endif | ||
| 140 | |||
| 137 | /* Declare here, including term.h is problematic on some systems. */ | 141 | /* Declare here, including term.h is problematic on some systems. */ |
| 138 | extern void tputs (const char *, int, int (*)(int)); | 142 | extern void tputs (const char *, int, int (*)(int)); |
| 139 | 143 | ||
| @@ -790,6 +794,7 @@ init_sigio (int fd) | |||
| 790 | #endif | 794 | #endif |
| 791 | } | 795 | } |
| 792 | 796 | ||
| 797 | #ifndef HAVE_ANDROID | ||
| 793 | #ifndef DOS_NT | 798 | #ifndef DOS_NT |
| 794 | #ifdef F_SETOWN | 799 | #ifdef F_SETOWN |
| 795 | static void | 800 | static void |
| @@ -801,6 +806,7 @@ reset_sigio (int fd) | |||
| 801 | } | 806 | } |
| 802 | #endif /* F_SETOWN */ | 807 | #endif /* F_SETOWN */ |
| 803 | #endif | 808 | #endif |
| 809 | #endif | ||
| 804 | 810 | ||
| 805 | void | 811 | void |
| 806 | request_sigio (void) | 812 | request_sigio (void) |
| @@ -972,6 +978,8 @@ narrow_foreground_group (int fd) | |||
| 972 | tcsetpgrp_without_stopping (fd, getpid ()); | 978 | tcsetpgrp_without_stopping (fd, getpid ()); |
| 973 | } | 979 | } |
| 974 | 980 | ||
| 981 | #ifndef HAVE_ANDROID | ||
| 982 | |||
| 975 | /* Set the tty to our original foreground group. */ | 983 | /* Set the tty to our original foreground group. */ |
| 976 | static void | 984 | static void |
| 977 | widen_foreground_group (int fd) | 985 | widen_foreground_group (int fd) |
| @@ -979,6 +987,9 @@ widen_foreground_group (int fd) | |||
| 979 | if (inherited_pgroup && setpgid (0, inherited_pgroup) == 0) | 987 | if (inherited_pgroup && setpgid (0, inherited_pgroup) == 0) |
| 980 | tcsetpgrp_without_stopping (fd, inherited_pgroup); | 988 | tcsetpgrp_without_stopping (fd, inherited_pgroup); |
| 981 | } | 989 | } |
| 990 | |||
| 991 | #endif | ||
| 992 | |||
| 982 | 993 | ||
| 983 | /* Getting and setting emacs_tty structures. */ | 994 | /* Getting and setting emacs_tty structures. */ |
| 984 | 995 | ||
| @@ -1496,6 +1507,8 @@ reset_sys_modes (struct tty_display_info *tty_out) | |||
| 1496 | fflush (stdout); | 1507 | fflush (stdout); |
| 1497 | return; | 1508 | return; |
| 1498 | } | 1509 | } |
| 1510 | |||
| 1511 | #ifndef HAVE_ANDROID | ||
| 1499 | if (!tty_out->term_initted) | 1512 | if (!tty_out->term_initted) |
| 1500 | return; | 1513 | return; |
| 1501 | 1514 | ||
| @@ -1552,6 +1565,7 @@ reset_sys_modes (struct tty_display_info *tty_out) | |||
| 1552 | #endif | 1565 | #endif |
| 1553 | 1566 | ||
| 1554 | widen_foreground_group (fileno (tty_out->input)); | 1567 | widen_foreground_group (fileno (tty_out->input)); |
| 1568 | #endif | ||
| 1555 | } | 1569 | } |
| 1556 | 1570 | ||
| 1557 | #ifdef HAVE_PTYS | 1571 | #ifdef HAVE_PTYS |
| @@ -1802,7 +1816,11 @@ handle_arith_signal (int sig) | |||
| 1802 | xsignal0 (Qarith_error); | 1816 | xsignal0 (Qarith_error); |
| 1803 | } | 1817 | } |
| 1804 | 1818 | ||
| 1805 | #if defined HAVE_STACK_OVERFLOW_HANDLING && !defined WINDOWSNT | 1819 | /* This does not work on Android and interferes with the system |
| 1820 | tombstone generation. */ | ||
| 1821 | |||
| 1822 | #if defined HAVE_STACK_OVERFLOW_HANDLING && !defined WINDOWSNT \ | ||
| 1823 | && (!defined HAVE_ANDROID || defined ANDROID_STUBIFY) | ||
| 1806 | 1824 | ||
| 1807 | /* Alternate stack used by SIGSEGV handler below. */ | 1825 | /* Alternate stack used by SIGSEGV handler below. */ |
| 1808 | 1826 | ||
| @@ -1914,12 +1932,16 @@ init_sigsegv (void) | |||
| 1914 | 1932 | ||
| 1915 | #else /* not HAVE_STACK_OVERFLOW_HANDLING or WINDOWSNT */ | 1933 | #else /* not HAVE_STACK_OVERFLOW_HANDLING or WINDOWSNT */ |
| 1916 | 1934 | ||
| 1935 | #if !defined HAVE_ANDROID || defined ANDROID_STUBIFY | ||
| 1936 | |||
| 1917 | static bool | 1937 | static bool |
| 1918 | init_sigsegv (void) | 1938 | init_sigsegv (void) |
| 1919 | { | 1939 | { |
| 1920 | return 0; | 1940 | return 0; |
| 1921 | } | 1941 | } |
| 1922 | 1942 | ||
| 1943 | #endif | ||
| 1944 | |||
| 1923 | #endif /* HAVE_STACK_OVERFLOW_HANDLING && !WINDOWSNT */ | 1945 | #endif /* HAVE_STACK_OVERFLOW_HANDLING && !WINDOWSNT */ |
| 1924 | 1946 | ||
| 1925 | static void | 1947 | static void |
| @@ -2020,12 +2042,17 @@ init_signals (void) | |||
| 2020 | sigaction (SIGFPE, &action, 0); | 2042 | sigaction (SIGFPE, &action, 0); |
| 2021 | } | 2043 | } |
| 2022 | 2044 | ||
| 2045 | /* SIGUSR1 and SIGUSR2 are used internally by the android_select | ||
| 2046 | function. */ | ||
| 2047 | #if !defined HAVE_ANDROID | ||
| 2023 | #ifdef SIGUSR1 | 2048 | #ifdef SIGUSR1 |
| 2024 | add_user_signal (SIGUSR1, "sigusr1"); | 2049 | add_user_signal (SIGUSR1, "sigusr1"); |
| 2025 | #endif | 2050 | #endif |
| 2026 | #ifdef SIGUSR2 | 2051 | #ifdef SIGUSR2 |
| 2027 | add_user_signal (SIGUSR2, "sigusr2"); | 2052 | add_user_signal (SIGUSR2, "sigusr2"); |
| 2028 | #endif | 2053 | #endif |
| 2054 | #endif | ||
| 2055 | |||
| 2029 | sigaction (SIGABRT, &thread_fatal_action, 0); | 2056 | sigaction (SIGABRT, &thread_fatal_action, 0); |
| 2030 | #ifdef SIGPRE | 2057 | #ifdef SIGPRE |
| 2031 | sigaction (SIGPRE, &thread_fatal_action, 0); | 2058 | sigaction (SIGPRE, &thread_fatal_action, 0); |
| @@ -2051,8 +2078,10 @@ init_signals (void) | |||
| 2051 | #ifdef SIGBUS | 2078 | #ifdef SIGBUS |
| 2052 | sigaction (SIGBUS, &thread_fatal_action, 0); | 2079 | sigaction (SIGBUS, &thread_fatal_action, 0); |
| 2053 | #endif | 2080 | #endif |
| 2081 | #if !defined HAVE_ANDROID || defined ANDROID_STUBIFY | ||
| 2054 | if (!init_sigsegv ()) | 2082 | if (!init_sigsegv ()) |
| 2055 | sigaction (SIGSEGV, &thread_fatal_action, 0); | 2083 | sigaction (SIGSEGV, &thread_fatal_action, 0); |
| 2084 | #endif | ||
| 2056 | #ifdef SIGSYS | 2085 | #ifdef SIGSYS |
| 2057 | sigaction (SIGSYS, &thread_fatal_action, 0); | 2086 | sigaction (SIGSYS, &thread_fatal_action, 0); |
| 2058 | #endif | 2087 | #endif |
| @@ -2328,11 +2357,20 @@ int | |||
| 2328 | emacs_fstatat (int dirfd, char const *filename, void *st, int flags) | 2357 | emacs_fstatat (int dirfd, char const *filename, void *st, int flags) |
| 2329 | { | 2358 | { |
| 2330 | int r; | 2359 | int r; |
| 2331 | while ((r = fstatat (dirfd, filename, st, flags)) != 0 && errno == EINTR) | 2360 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) |
| 2361 | while ((r = fstatat (dirfd, filename, st, flags)) != 0 | ||
| 2362 | && errno == EINTR) | ||
| 2363 | maybe_quit (); | ||
| 2364 | #else | ||
| 2365 | while ((r = android_fstatat (dirfd, filename, st, flags)) != 0 | ||
| 2366 | && errno == EINTR) | ||
| 2332 | maybe_quit (); | 2367 | maybe_quit (); |
| 2368 | #endif | ||
| 2333 | return r; | 2369 | return r; |
| 2334 | } | 2370 | } |
| 2335 | 2371 | ||
| 2372 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2373 | |||
| 2336 | static int | 2374 | static int |
| 2337 | sys_openat (int dirfd, char const *file, int oflags, int mode) | 2375 | sys_openat (int dirfd, char const *file, int oflags, int mode) |
| 2338 | { | 2376 | { |
| @@ -2347,6 +2385,18 @@ sys_openat (int dirfd, char const *file, int oflags, int mode) | |||
| 2347 | #endif | 2385 | #endif |
| 2348 | } | 2386 | } |
| 2349 | 2387 | ||
| 2388 | #endif | ||
| 2389 | |||
| 2390 | int | ||
| 2391 | sys_fstat (int fd, struct stat *statb) | ||
| 2392 | { | ||
| 2393 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2394 | return fstat (fd, statb); | ||
| 2395 | #else | ||
| 2396 | return android_fstat (fd, statb); | ||
| 2397 | #endif | ||
| 2398 | } | ||
| 2399 | |||
| 2350 | /* Assuming the directory DIRFD, open FILE for Emacs use, | 2400 | /* Assuming the directory DIRFD, open FILE for Emacs use, |
| 2351 | using open flags OFLAGS and mode MODE. | 2401 | using open flags OFLAGS and mode MODE. |
| 2352 | Use binary I/O on systems that care about text vs binary I/O. | 2402 | Use binary I/O on systems that care about text vs binary I/O. |
| @@ -2355,6 +2405,8 @@ sys_openat (int dirfd, char const *file, int oflags, int mode) | |||
| 2355 | Do not fail merely because the open was interrupted by a signal. | 2405 | Do not fail merely because the open was interrupted by a signal. |
| 2356 | Allow the user to quit. */ | 2406 | Allow the user to quit. */ |
| 2357 | 2407 | ||
| 2408 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2409 | |||
| 2358 | int | 2410 | int |
| 2359 | emacs_openat (int dirfd, char const *file, int oflags, int mode) | 2411 | emacs_openat (int dirfd, char const *file, int oflags, int mode) |
| 2360 | { | 2412 | { |
| @@ -2367,10 +2419,23 @@ emacs_openat (int dirfd, char const *file, int oflags, int mode) | |||
| 2367 | return fd; | 2419 | return fd; |
| 2368 | } | 2420 | } |
| 2369 | 2421 | ||
| 2422 | #endif | ||
| 2423 | |||
| 2370 | int | 2424 | int |
| 2371 | emacs_open (char const *file, int oflags, int mode) | 2425 | emacs_open (char const *file, int oflags, int mode) |
| 2372 | { | 2426 | { |
| 2427 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 2428 | int fd; | ||
| 2429 | #endif | ||
| 2430 | |||
| 2431 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2373 | return emacs_openat (AT_FDCWD, file, oflags, mode); | 2432 | return emacs_openat (AT_FDCWD, file, oflags, mode); |
| 2433 | #else | ||
| 2434 | while ((fd = android_open (file, oflags, mode)) < 0 && errno == EINTR) | ||
| 2435 | maybe_quit (); | ||
| 2436 | |||
| 2437 | return fd; | ||
| 2438 | #endif | ||
| 2374 | } | 2439 | } |
| 2375 | 2440 | ||
| 2376 | /* Same as above, but doesn't allow the user to quit. */ | 2441 | /* Same as above, but doesn't allow the user to quit. */ |
| @@ -2382,9 +2447,15 @@ emacs_open_noquit (char const *file, int oflags, int mode) | |||
| 2382 | if (! (oflags & O_TEXT)) | 2447 | if (! (oflags & O_TEXT)) |
| 2383 | oflags |= O_BINARY; | 2448 | oflags |= O_BINARY; |
| 2384 | oflags |= O_CLOEXEC; | 2449 | oflags |= O_CLOEXEC; |
| 2450 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2385 | do | 2451 | do |
| 2386 | fd = open (file, oflags, mode); | 2452 | fd = open (file, oflags, mode); |
| 2387 | while (fd < 0 && errno == EINTR); | 2453 | while (fd < 0 && errno == EINTR); |
| 2454 | #else | ||
| 2455 | do | ||
| 2456 | fd = android_open (file, oflags, mode); | ||
| 2457 | while (fd < 0 && errno == EINTR); | ||
| 2458 | #endif | ||
| 2388 | return fd; | 2459 | return fd; |
| 2389 | } | 2460 | } |
| 2390 | 2461 | ||
| @@ -2434,6 +2505,8 @@ emacs_pipe (int fd[2]) | |||
| 2434 | For the background behind this mess, please see Austin Group defect 529 | 2505 | For the background behind this mess, please see Austin Group defect 529 |
| 2435 | <https://austingroupbugs.net/view.php?id=529>. */ | 2506 | <https://austingroupbugs.net/view.php?id=529>. */ |
| 2436 | 2507 | ||
| 2508 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) | ||
| 2509 | |||
| 2437 | #ifndef POSIX_CLOSE_RESTART | 2510 | #ifndef POSIX_CLOSE_RESTART |
| 2438 | # define POSIX_CLOSE_RESTART 1 | 2511 | # define POSIX_CLOSE_RESTART 1 |
| 2439 | static int | 2512 | static int |
| @@ -2460,6 +2533,8 @@ posix_close (int fd, int flag) | |||
| 2460 | } | 2533 | } |
| 2461 | #endif | 2534 | #endif |
| 2462 | 2535 | ||
| 2536 | #endif | ||
| 2537 | |||
| 2463 | /* Close FD, retrying if interrupted. If successful, return 0; | 2538 | /* Close FD, retrying if interrupted. If successful, return 0; |
| 2464 | otherwise, return -1 and set errno to a non-EINTR value. Consider | 2539 | otherwise, return -1 and set errno to a non-EINTR value. Consider |
| 2465 | an EINPROGRESS error to be successful, as that's merely a signal | 2540 | an EINPROGRESS error to be successful, as that's merely a signal |
| @@ -2472,9 +2547,17 @@ posix_close (int fd, int flag) | |||
| 2472 | int | 2547 | int |
| 2473 | emacs_close (int fd) | 2548 | emacs_close (int fd) |
| 2474 | { | 2549 | { |
| 2550 | int r; | ||
| 2551 | |||
| 2475 | while (1) | 2552 | while (1) |
| 2476 | { | 2553 | { |
| 2477 | int r = posix_close (fd, POSIX_CLOSE_RESTART); | 2554 | #if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) |
| 2555 | r = posix_close (fd, POSIX_CLOSE_RESTART); | ||
| 2556 | #else | ||
| 2557 | r = android_close (fd) == 0 || errno == EINTR ? 0 : -1; | ||
| 2558 | #define POSIX_CLOSE_RESTART 1 | ||
| 2559 | #endif | ||
| 2560 | |||
| 2478 | if (r == 0) | 2561 | if (r == 0) |
| 2479 | return r; | 2562 | return r; |
| 2480 | if (!POSIX_CLOSE_RESTART || errno != EINTR) | 2563 | if (!POSIX_CLOSE_RESTART || errno != EINTR) |
| @@ -2729,6 +2812,15 @@ errwrite (void const *buf, ptrdiff_t nbuf) | |||
| 2729 | void | 2812 | void |
| 2730 | close_output_streams (void) | 2813 | close_output_streams (void) |
| 2731 | { | 2814 | { |
| 2815 | /* Android comes with some kind of ``file descriptor sanitizer'' | ||
| 2816 | that aborts when stdout or stderr is closed. */ | ||
| 2817 | |||
| 2818 | #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY | ||
| 2819 | fflush (stderr); | ||
| 2820 | fflush (stdout); | ||
| 2821 | return; | ||
| 2822 | #endif | ||
| 2823 | |||
| 2732 | if (close_stream (stdout) != 0) | 2824 | if (close_stream (stdout) != 0) |
| 2733 | { | 2825 | { |
| 2734 | emacs_perror ("Write error to standard output"); | 2826 | emacs_perror ("Write error to standard output"); |
diff --git a/src/term.c b/src/term.c index f8104e0304e..05c54accdee 100644 --- a/src/term.c +++ b/src/term.c | |||
| @@ -62,6 +62,8 @@ static int been_here = -1; | |||
| 62 | #include "w32term.h" | 62 | #include "w32term.h" |
| 63 | #endif | 63 | #endif |
| 64 | 64 | ||
| 65 | #ifndef HAVE_ANDROID | ||
| 66 | |||
| 65 | static void tty_set_scroll_region (struct frame *f, int start, int stop); | 67 | static void tty_set_scroll_region (struct frame *f, int start, int stop); |
| 66 | static void turn_on_face (struct frame *, int face_id); | 68 | static void turn_on_face (struct frame *, int face_id); |
| 67 | static void turn_off_face (struct frame *, int face_id); | 69 | static void turn_off_face (struct frame *, int face_id); |
| @@ -73,11 +75,15 @@ static void clear_tty_hooks (struct terminal *terminal); | |||
| 73 | static void set_tty_hooks (struct terminal *terminal); | 75 | static void set_tty_hooks (struct terminal *terminal); |
| 74 | static void dissociate_if_controlling_tty (int fd); | 76 | static void dissociate_if_controlling_tty (int fd); |
| 75 | static void delete_tty (struct terminal *); | 77 | static void delete_tty (struct terminal *); |
| 78 | |||
| 79 | #endif | ||
| 80 | |||
| 76 | static AVOID maybe_fatal (bool, struct terminal *, const char *, const char *, | 81 | static AVOID maybe_fatal (bool, struct terminal *, const char *, const char *, |
| 77 | ...) | 82 | ...) |
| 78 | ATTRIBUTE_FORMAT_PRINTF (3, 5) ATTRIBUTE_FORMAT_PRINTF (4, 5); | 83 | ATTRIBUTE_FORMAT_PRINTF (3, 5) ATTRIBUTE_FORMAT_PRINTF (4, 5); |
| 79 | static AVOID vfatal (const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0); | 84 | static AVOID vfatal (const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0); |
| 80 | 85 | ||
| 86 | #ifndef HAVE_ANDROID | ||
| 81 | 87 | ||
| 82 | #define OUTPUT(tty, a) \ | 88 | #define OUTPUT(tty, a) \ |
| 83 | emacs_tputs ((tty), a, \ | 89 | emacs_tputs ((tty), a, \ |
| @@ -95,6 +101,8 @@ static AVOID vfatal (const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0); | |||
| 95 | 101 | ||
| 96 | #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0) | 102 | #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } while (0) |
| 97 | 103 | ||
| 104 | #endif | ||
| 105 | |||
| 98 | /* Display space properties. */ | 106 | /* Display space properties. */ |
| 99 | 107 | ||
| 100 | /* Chain of all tty device parameters. */ | 108 | /* Chain of all tty device parameters. */ |
| @@ -117,10 +125,14 @@ enum no_color_bit | |||
| 117 | 125 | ||
| 118 | /* internal state */ | 126 | /* internal state */ |
| 119 | 127 | ||
| 128 | #ifndef HAVE_ANDROID | ||
| 129 | |||
| 120 | /* The largest frame width in any call to calculate_costs. */ | 130 | /* The largest frame width in any call to calculate_costs. */ |
| 121 | 131 | ||
| 122 | static int max_frame_cols; | 132 | static int max_frame_cols; |
| 123 | 133 | ||
| 134 | #endif | ||
| 135 | |||
| 124 | 136 | ||
| 125 | 137 | ||
| 126 | #ifdef HAVE_GPM | 138 | #ifdef HAVE_GPM |
| @@ -133,6 +145,8 @@ struct tty_display_info *gpm_tty = NULL; | |||
| 133 | static int last_mouse_x, last_mouse_y; | 145 | static int last_mouse_x, last_mouse_y; |
| 134 | #endif /* HAVE_GPM */ | 146 | #endif /* HAVE_GPM */ |
| 135 | 147 | ||
| 148 | #ifndef HAVE_ANDROID | ||
| 149 | |||
| 136 | /* Ring the bell on a tty. */ | 150 | /* Ring the bell on a tty. */ |
| 137 | 151 | ||
| 138 | static void | 152 | static void |
| @@ -718,7 +732,20 @@ encode_terminal_code (struct glyph *src, int src_len, | |||
| 718 | return (encode_terminal_dst); | 732 | return (encode_terminal_dst); |
| 719 | } | 733 | } |
| 720 | 734 | ||
| 735 | #else /* !HAVE_ANDROID */ | ||
| 736 | |||
| 737 | unsigned char * | ||
| 738 | encode_terminal_code (struct glyph *src, int src_len, | ||
| 739 | struct coding_system *coding) | ||
| 740 | { | ||
| 741 | /* Text terminals are simply not supported on Android. */ | ||
| 742 | coding->produced = 0; | ||
| 743 | return NULL; | ||
| 744 | } | ||
| 745 | |||
| 746 | #endif /* HAVE_ANDROID */ | ||
| 721 | 747 | ||
| 748 | #ifndef HAVE_ANDROID | ||
| 722 | 749 | ||
| 723 | /* An implementation of write_glyphs for termcap frames. */ | 750 | /* An implementation of write_glyphs for termcap frames. */ |
| 724 | 751 | ||
| @@ -1046,8 +1073,10 @@ int | |||
| 1046 | string_cost (const char *str) | 1073 | string_cost (const char *str) |
| 1047 | { | 1074 | { |
| 1048 | cost = 0; | 1075 | cost = 0; |
| 1076 | #ifndef HAVE_ANDROID | ||
| 1049 | if (str) | 1077 | if (str) |
| 1050 | tputs (str, 0, evalcost); | 1078 | tputs (str, 0, evalcost); |
| 1079 | #endif | ||
| 1051 | return cost; | 1080 | return cost; |
| 1052 | } | 1081 | } |
| 1053 | 1082 | ||
| @@ -1058,8 +1087,10 @@ static int | |||
| 1058 | string_cost_one_line (const char *str) | 1087 | string_cost_one_line (const char *str) |
| 1059 | { | 1088 | { |
| 1060 | cost = 0; | 1089 | cost = 0; |
| 1090 | #ifndef HAVE_ANDROID | ||
| 1061 | if (str) | 1091 | if (str) |
| 1062 | tputs (str, 1, evalcost); | 1092 | tputs (str, 1, evalcost); |
| 1093 | #endif | ||
| 1063 | return cost; | 1094 | return cost; |
| 1064 | } | 1095 | } |
| 1065 | 1096 | ||
| @@ -1070,11 +1101,13 @@ int | |||
| 1070 | per_line_cost (const char *str) | 1101 | per_line_cost (const char *str) |
| 1071 | { | 1102 | { |
| 1072 | cost = 0; | 1103 | cost = 0; |
| 1104 | #ifndef HAVE_ANDROID | ||
| 1073 | if (str) | 1105 | if (str) |
| 1074 | tputs (str, 0, evalcost); | 1106 | tputs (str, 0, evalcost); |
| 1075 | cost = - cost; | 1107 | cost = - cost; |
| 1076 | if (str) | 1108 | if (str) |
| 1077 | tputs (str, 10, evalcost); | 1109 | tputs (str, 10, evalcost); |
| 1110 | #endif | ||
| 1078 | return cost; | 1111 | return cost; |
| 1079 | } | 1112 | } |
| 1080 | 1113 | ||
| @@ -1147,11 +1180,14 @@ calculate_ins_del_char_costs (struct frame *f) | |||
| 1147 | *p++ = (ins_startup_cost += ins_cost_per_char); | 1180 | *p++ = (ins_startup_cost += ins_cost_per_char); |
| 1148 | } | 1181 | } |
| 1149 | 1182 | ||
| 1183 | #endif | ||
| 1184 | |||
| 1150 | void | 1185 | void |
| 1151 | calculate_costs (struct frame *frame) | 1186 | calculate_costs (struct frame *frame) |
| 1152 | { | 1187 | { |
| 1153 | FRAME_COST_BAUD_RATE (frame) = baud_rate; | 1188 | FRAME_COST_BAUD_RATE (frame) = baud_rate; |
| 1154 | 1189 | ||
| 1190 | #ifndef HAVE_ANDROID | ||
| 1155 | if (FRAME_TERMCAP_P (frame)) | 1191 | if (FRAME_TERMCAP_P (frame)) |
| 1156 | { | 1192 | { |
| 1157 | struct tty_display_info *tty = FRAME_TTY (frame); | 1193 | struct tty_display_info *tty = FRAME_TTY (frame); |
| @@ -1206,13 +1242,15 @@ calculate_costs (struct frame *frame) | |||
| 1206 | 1242 | ||
| 1207 | cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */ | 1243 | cmcostinit (FRAME_TTY (frame)); /* set up cursor motion costs */ |
| 1208 | } | 1244 | } |
| 1245 | #endif | ||
| 1209 | } | 1246 | } |
| 1210 | 1247 | ||
| 1211 | struct fkey_table { | 1248 | struct fkey_table |
| 1249 | { | ||
| 1212 | const char *cap, *name; | 1250 | const char *cap, *name; |
| 1213 | }; | 1251 | }; |
| 1214 | 1252 | ||
| 1215 | #ifndef DOS_NT | 1253 | #if !defined DOS_NT && !defined HAVE_ANDROID |
| 1216 | /* Termcap capability names that correspond directly to X keysyms. | 1254 | /* Termcap capability names that correspond directly to X keysyms. |
| 1217 | Some of these (marked "terminfo") aren't supplied by old-style | 1255 | Some of these (marked "terminfo") aren't supplied by old-style |
| 1218 | (Berkeley) termcap entries. They're listed in X keysym order; | 1256 | (Berkeley) termcap entries. They're listed in X keysym order; |
| @@ -1443,6 +1481,9 @@ term_get_fkeys_1 (void) | |||
| 1443 | #endif /* not DOS_NT */ | 1481 | #endif /* not DOS_NT */ |
| 1444 | 1482 | ||
| 1445 | 1483 | ||
| 1484 | |||
| 1485 | #ifndef HAVE_ANDROID | ||
| 1486 | |||
| 1446 | /*********************************************************************** | 1487 | /*********************************************************************** |
| 1447 | Character Display Information | 1488 | Character Display Information |
| 1448 | ***********************************************************************/ | 1489 | ***********************************************************************/ |
| @@ -1519,14 +1560,17 @@ append_glyph (struct it *it) | |||
| 1519 | } | 1560 | } |
| 1520 | } | 1561 | } |
| 1521 | 1562 | ||
| 1563 | #endif | ||
| 1564 | |||
| 1522 | /* For external use. */ | 1565 | /* For external use. */ |
| 1523 | void | 1566 | void |
| 1524 | tty_append_glyph (struct it *it) | 1567 | tty_append_glyph (struct it *it) |
| 1525 | { | 1568 | { |
| 1569 | #ifndef HAVE_ANDROID | ||
| 1526 | append_glyph (it); | 1570 | append_glyph (it); |
| 1571 | #endif | ||
| 1527 | } | 1572 | } |
| 1528 | 1573 | ||
| 1529 | |||
| 1530 | /* Produce glyphs for the display element described by IT. *IT | 1574 | /* Produce glyphs for the display element described by IT. *IT |
| 1531 | specifies what we want to produce a glyph for (character, image, ...), | 1575 | specifies what we want to produce a glyph for (character, image, ...), |
| 1532 | and where in the glyph matrix we currently are (glyph row and hpos). | 1576 | and where in the glyph matrix we currently are (glyph row and hpos). |
| @@ -1549,6 +1593,7 @@ tty_append_glyph (struct it *it) | |||
| 1549 | void | 1593 | void |
| 1550 | produce_glyphs (struct it *it) | 1594 | produce_glyphs (struct it *it) |
| 1551 | { | 1595 | { |
| 1596 | #ifndef HAVE_ANDROID | ||
| 1552 | /* If a hook is installed, let it do the work. */ | 1597 | /* If a hook is installed, let it do the work. */ |
| 1553 | 1598 | ||
| 1554 | /* Nothing but characters are supported on terminal frames. */ | 1599 | /* Nothing but characters are supported on terminal frames. */ |
| @@ -1661,8 +1706,11 @@ produce_glyphs (struct it *it) | |||
| 1661 | it->current_x += it->pixel_width; | 1706 | it->current_x += it->pixel_width; |
| 1662 | it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0; | 1707 | it->ascent = it->max_ascent = it->phys_ascent = it->max_phys_ascent = 0; |
| 1663 | it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1; | 1708 | it->descent = it->max_descent = it->phys_descent = it->max_phys_descent = 1; |
| 1709 | #endif | ||
| 1664 | } | 1710 | } |
| 1665 | 1711 | ||
| 1712 | #ifndef HAVE_ANDROID | ||
| 1713 | |||
| 1666 | /* Append glyphs to IT's glyph_row for the composition IT->cmp_id. | 1714 | /* Append glyphs to IT's glyph_row for the composition IT->cmp_id. |
| 1667 | Called from produce_composite_glyph for terminal frames if | 1715 | Called from produce_composite_glyph for terminal frames if |
| 1668 | IT->glyph_row != NULL. IT->face_id contains the character's | 1716 | IT->glyph_row != NULL. IT->face_id contains the character's |
| @@ -2020,6 +2068,7 @@ turn_off_face (struct frame *f, int face_id) | |||
| 2020 | OUTPUT1_IF (tty, tty->TS_orig_pair); | 2068 | OUTPUT1_IF (tty, tty->TS_orig_pair); |
| 2021 | } | 2069 | } |
| 2022 | 2070 | ||
| 2071 | #endif /* !HAVE_ANDROID */ | ||
| 2023 | 2072 | ||
| 2024 | /* Return true if the terminal on frame F supports all of the | 2073 | /* Return true if the terminal on frame F supports all of the |
| 2025 | capabilities in CAPS simultaneously. */ | 2074 | capabilities in CAPS simultaneously. */ |
| @@ -2027,8 +2076,9 @@ turn_off_face (struct frame *f, int face_id) | |||
| 2027 | bool | 2076 | bool |
| 2028 | tty_capable_p (struct tty_display_info *tty, unsigned int caps) | 2077 | tty_capable_p (struct tty_display_info *tty, unsigned int caps) |
| 2029 | { | 2078 | { |
| 2079 | #ifndef HAVE_ANDROID | ||
| 2030 | #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \ | 2080 | #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \ |
| 2031 | if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \ | 2081 | if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P (tty, NC_bit))) \ |
| 2032 | return 0; | 2082 | return 0; |
| 2033 | 2083 | ||
| 2034 | TTY_CAPABLE_P_TRY (tty, | 2084 | TTY_CAPABLE_P_TRY (tty, |
| @@ -2048,6 +2098,9 @@ tty_capable_p (struct tty_display_info *tty, unsigned int caps) | |||
| 2048 | 2098 | ||
| 2049 | /* We can do it! */ | 2099 | /* We can do it! */ |
| 2050 | return 1; | 2100 | return 1; |
| 2101 | #else | ||
| 2102 | return false; | ||
| 2103 | #endif | ||
| 2051 | } | 2104 | } |
| 2052 | 2105 | ||
| 2053 | /* Return non-zero if the terminal is capable to display colors. */ | 2106 | /* Return non-zero if the terminal is capable to display colors. */ |
| @@ -2081,7 +2134,7 @@ TERMINAL does not refer to a text terminal. */) | |||
| 2081 | return make_fixnum (t ? t->display_info.tty->TN_max_colors : 0); | 2134 | return make_fixnum (t ? t->display_info.tty->TN_max_colors : 0); |
| 2082 | } | 2135 | } |
| 2083 | 2136 | ||
| 2084 | #ifndef DOS_NT | 2137 | #if !defined DOS_NT && !defined HAVE_ANDROID |
| 2085 | 2138 | ||
| 2086 | /* Declare here rather than in the function, as in the rest of Emacs, | 2139 | /* Declare here rather than in the function, as in the rest of Emacs, |
| 2087 | to work around an HPUX compiler bug (?). See | 2140 | to work around an HPUX compiler bug (?). See |
| @@ -2186,7 +2239,7 @@ set_tty_color_mode (struct tty_display_info *tty, struct frame *f) | |||
| 2186 | } | 2239 | } |
| 2187 | } | 2240 | } |
| 2188 | 2241 | ||
| 2189 | #endif /* !DOS_NT */ | 2242 | #endif /* !DOS_NT && !HAVE_ANDROID */ |
| 2190 | 2243 | ||
| 2191 | char * | 2244 | char * |
| 2192 | tty_type_name (Lisp_Object terminal) | 2245 | tty_type_name (Lisp_Object terminal) |
| @@ -2278,6 +2331,7 @@ suspended. | |||
| 2278 | A suspended tty may be resumed by calling `resume-tty' on it. */) | 2331 | A suspended tty may be resumed by calling `resume-tty' on it. */) |
| 2279 | (Lisp_Object tty) | 2332 | (Lisp_Object tty) |
| 2280 | { | 2333 | { |
| 2334 | #ifndef HAVE_ANDROID | ||
| 2281 | struct terminal *t = decode_tty_terminal (tty); | 2335 | struct terminal *t = decode_tty_terminal (tty); |
| 2282 | FILE *f; | 2336 | FILE *f; |
| 2283 | 2337 | ||
| @@ -2314,6 +2368,10 @@ A suspended tty may be resumed by calling `resume-tty' on it. */) | |||
| 2314 | 2368 | ||
| 2315 | /* Clear display hooks to prevent further output. */ | 2369 | /* Clear display hooks to prevent further output. */ |
| 2316 | clear_tty_hooks (t); | 2370 | clear_tty_hooks (t); |
| 2371 | #else | ||
| 2372 | /* This will always signal on Android. */ | ||
| 2373 | decode_tty_terminal (tty); | ||
| 2374 | #endif | ||
| 2317 | 2375 | ||
| 2318 | return Qnil; | 2376 | return Qnil; |
| 2319 | } | 2377 | } |
| @@ -2337,9 +2395,12 @@ TTY may be a terminal object, a frame, or nil (meaning the selected | |||
| 2337 | frame's terminal). */) | 2395 | frame's terminal). */) |
| 2338 | (Lisp_Object tty) | 2396 | (Lisp_Object tty) |
| 2339 | { | 2397 | { |
| 2340 | struct terminal *t = decode_tty_terminal (tty); | 2398 | #ifndef HAVE_ANDROID |
| 2399 | struct terminal *t; | ||
| 2341 | int fd; | 2400 | int fd; |
| 2342 | 2401 | ||
| 2402 | t = decode_tty_terminal (tty); | ||
| 2403 | |||
| 2343 | if (!t) | 2404 | if (!t) |
| 2344 | error ("Attempt to resume a non-text terminal device"); | 2405 | error ("Attempt to resume a non-text terminal device"); |
| 2345 | 2406 | ||
| @@ -2396,10 +2457,15 @@ frame's terminal). */) | |||
| 2396 | } | 2457 | } |
| 2397 | 2458 | ||
| 2398 | set_tty_hooks (t); | 2459 | set_tty_hooks (t); |
| 2460 | #else | ||
| 2461 | decode_tty_terminal (tty); | ||
| 2462 | #endif | ||
| 2399 | 2463 | ||
| 2400 | return Qnil; | 2464 | return Qnil; |
| 2401 | } | 2465 | } |
| 2402 | 2466 | ||
| 2467 | #ifndef HAVE_ANDROID | ||
| 2468 | |||
| 2403 | DEFUN ("tty--set-output-buffer-size", Ftty__set_output_buffer_size, | 2469 | DEFUN ("tty--set-output-buffer-size", Ftty__set_output_buffer_size, |
| 2404 | Stty__set_output_buffer_size, 1, 2, 0, doc: | 2470 | Stty__set_output_buffer_size, 1, 2, 0, doc: |
| 2405 | /* Set the output buffer size for a TTY. | 2471 | /* Set the output buffer size for a TTY. |
| @@ -2438,12 +2504,14 @@ A value of zero means TTY uses the system's default value. */) | |||
| 2438 | error ("Not a tty terminal"); | 2504 | error ("Not a tty terminal"); |
| 2439 | } | 2505 | } |
| 2440 | 2506 | ||
| 2507 | #endif | ||
| 2508 | |||
| 2441 | 2509 | ||
| 2442 | /*********************************************************************** | 2510 | /*********************************************************************** |
| 2443 | Mouse | 2511 | Mouse |
| 2444 | ***********************************************************************/ | 2512 | ***********************************************************************/ |
| 2445 | 2513 | ||
| 2446 | #ifndef DOS_NT | 2514 | #if !defined DOS_NT && !defined HAVE_ANDROID |
| 2447 | 2515 | ||
| 2448 | /* Implementation of draw_row_with_mouse_face for TTY/GPM and macOS. */ | 2516 | /* Implementation of draw_row_with_mouse_face for TTY/GPM and macOS. */ |
| 2449 | void | 2517 | void |
| @@ -2713,7 +2781,7 @@ DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop, | |||
| 2713 | Menus | 2781 | Menus |
| 2714 | ***********************************************************************/ | 2782 | ***********************************************************************/ |
| 2715 | 2783 | ||
| 2716 | #if !defined (MSDOS) | 2784 | #if !defined (MSDOS) && !defined HAVE_ANDROID |
| 2717 | 2785 | ||
| 2718 | /* TTY menu implementation and main ideas are borrowed from msdos.c. | 2786 | /* TTY menu implementation and main ideas are borrowed from msdos.c. |
| 2719 | 2787 | ||
| @@ -3813,10 +3881,12 @@ tty_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 3813 | return SAFE_FREE_UNBIND_TO (specpdl_count, entry); | 3881 | return SAFE_FREE_UNBIND_TO (specpdl_count, entry); |
| 3814 | } | 3882 | } |
| 3815 | 3883 | ||
| 3816 | #endif /* !MSDOS */ | 3884 | #endif /* !MSDOS && !defined HAVE_ANDROID */ |
| 3817 | 3885 | ||
| 3818 | 3886 | ||
| 3819 | #ifndef MSDOS | 3887 | |
| 3888 | #if !defined MSDOS && !defined HAVE_ANDROID | ||
| 3889 | |||
| 3820 | /*********************************************************************** | 3890 | /*********************************************************************** |
| 3821 | Initialization | 3891 | Initialization |
| 3822 | ***********************************************************************/ | 3892 | ***********************************************************************/ |
| @@ -3846,7 +3916,7 @@ tty_free_frame_resources (struct frame *f) | |||
| 3846 | xfree (f->output_data.tty); | 3916 | xfree (f->output_data.tty); |
| 3847 | } | 3917 | } |
| 3848 | 3918 | ||
| 3849 | #else /* MSDOS */ | 3919 | #elif defined MSDOS |
| 3850 | 3920 | ||
| 3851 | /* Delete frame F's face cache. */ | 3921 | /* Delete frame F's face cache. */ |
| 3852 | 3922 | ||
| @@ -3856,8 +3926,13 @@ tty_free_frame_resources (struct frame *f) | |||
| 3856 | eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)); | 3926 | eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)); |
| 3857 | free_frame_faces (f); | 3927 | free_frame_faces (f); |
| 3858 | } | 3928 | } |
| 3859 | #endif /* MSDOS */ | 3929 | |
| 3930 | #endif | ||
| 3931 | |||
| 3860 | 3932 | ||
| 3933 | |||
| 3934 | #ifndef HAVE_ANDROID | ||
| 3935 | |||
| 3861 | /* Reset the hooks in TERMINAL. */ | 3936 | /* Reset the hooks in TERMINAL. */ |
| 3862 | 3937 | ||
| 3863 | static void | 3938 | static void |
| @@ -3952,6 +4027,8 @@ dissociate_if_controlling_tty (int fd) | |||
| 3952 | } | 4027 | } |
| 3953 | } | 4028 | } |
| 3954 | 4029 | ||
| 4030 | #endif /* !HAVE_ANDROID */ | ||
| 4031 | |||
| 3955 | /* Create a termcap display on the tty device with the given name and | 4032 | /* Create a termcap display on the tty device with the given name and |
| 3956 | type. | 4033 | type. |
| 3957 | 4034 | ||
| @@ -3961,11 +4038,23 @@ dissociate_if_controlling_tty (int fd) | |||
| 3961 | 4038 | ||
| 3962 | TERMINAL_TYPE is the termcap type of the device, e.g. "vt100". | 4039 | TERMINAL_TYPE is the termcap type of the device, e.g. "vt100". |
| 3963 | 4040 | ||
| 3964 | If MUST_SUCCEED is true, then all errors are fatal. */ | 4041 | If MUST_SUCCEED is true, then all errors are fatal. This function |
| 4042 | always signals on Android, where text terminals are prohibited by | ||
| 4043 | system policy (and the required libraries are usually not | ||
| 4044 | available.) */ | ||
| 4045 | |||
| 4046 | #ifdef HAVE_ANDROID | ||
| 4047 | _Noreturn | ||
| 4048 | #endif | ||
| 3965 | 4049 | ||
| 3966 | struct terminal * | 4050 | struct terminal * |
| 3967 | init_tty (const char *name, const char *terminal_type, bool must_succeed) | 4051 | init_tty (const char *name, const char *terminal_type, bool must_succeed) |
| 3968 | { | 4052 | { |
| 4053 | #ifdef HAVE_ANDROID | ||
| 4054 | maybe_fatal (must_succeed, 0, "Text terminals are not supported" | ||
| 4055 | " under Android", "Text terminals are not supported" | ||
| 4056 | " under Android"); | ||
| 4057 | #else | ||
| 3969 | struct tty_display_info *tty = NULL; | 4058 | struct tty_display_info *tty = NULL; |
| 3970 | struct terminal *terminal = NULL; | 4059 | struct terminal *terminal = NULL; |
| 3971 | #ifndef DOS_NT | 4060 | #ifndef DOS_NT |
| @@ -4447,6 +4536,7 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\ | |||
| 4447 | init_sys_modes (tty); | 4536 | init_sys_modes (tty); |
| 4448 | 4537 | ||
| 4449 | return terminal; | 4538 | return terminal; |
| 4539 | #endif /* !HAVE_ANDROID */ | ||
| 4450 | } | 4540 | } |
| 4451 | 4541 | ||
| 4452 | 4542 | ||
| @@ -4471,8 +4561,13 @@ maybe_fatal (bool must_succeed, struct terminal *terminal, | |||
| 4471 | { | 4561 | { |
| 4472 | va_list ap; | 4562 | va_list ap; |
| 4473 | va_start (ap, str2); | 4563 | va_start (ap, str2); |
| 4564 | |||
| 4565 | #ifndef HAVE_ANDROID | ||
| 4474 | if (terminal) | 4566 | if (terminal) |
| 4475 | delete_tty (terminal); | 4567 | delete_tty (terminal); |
| 4568 | #else | ||
| 4569 | eassert (terminal == NULL); | ||
| 4570 | #endif | ||
| 4476 | 4571 | ||
| 4477 | if (must_succeed) | 4572 | if (must_succeed) |
| 4478 | vfatal (str2, ap); | 4573 | vfatal (str2, ap); |
| @@ -4490,6 +4585,8 @@ fatal (const char *str, ...) | |||
| 4490 | 4585 | ||
| 4491 | 4586 | ||
| 4492 | 4587 | ||
| 4588 | #ifndef HAVE_ANDROID | ||
| 4589 | |||
| 4493 | /* Delete the given tty terminal, closing all frames on it. */ | 4590 | /* Delete the given tty terminal, closing all frames on it. */ |
| 4494 | 4591 | ||
| 4495 | static void | 4592 | static void |
| @@ -4547,6 +4644,8 @@ delete_tty (struct terminal *terminal) | |||
| 4547 | xfree (tty); | 4644 | xfree (tty); |
| 4548 | } | 4645 | } |
| 4549 | 4646 | ||
| 4647 | #endif | ||
| 4648 | |||
| 4550 | void | 4649 | void |
| 4551 | syms_of_term (void) | 4650 | syms_of_term (void) |
| 4552 | { | 4651 | { |
| @@ -4594,21 +4693,25 @@ trigger redisplay. */); | |||
| 4594 | defsubr (&Stty_top_frame); | 4693 | defsubr (&Stty_top_frame); |
| 4595 | defsubr (&Ssuspend_tty); | 4694 | defsubr (&Ssuspend_tty); |
| 4596 | defsubr (&Sresume_tty); | 4695 | defsubr (&Sresume_tty); |
| 4696 | #ifndef HAVE_ANDROID | ||
| 4597 | defsubr (&Stty__set_output_buffer_size); | 4697 | defsubr (&Stty__set_output_buffer_size); |
| 4598 | defsubr (&Stty__output_buffer_size); | 4698 | defsubr (&Stty__output_buffer_size); |
| 4699 | #endif /* !HAVE_ANDROID */ | ||
| 4599 | #ifdef HAVE_GPM | 4700 | #ifdef HAVE_GPM |
| 4600 | defsubr (&Sgpm_mouse_start); | 4701 | defsubr (&Sgpm_mouse_start); |
| 4601 | defsubr (&Sgpm_mouse_stop); | 4702 | defsubr (&Sgpm_mouse_stop); |
| 4602 | #endif /* HAVE_GPM */ | 4703 | #endif /* HAVE_GPM */ |
| 4603 | 4704 | ||
| 4604 | #ifndef DOS_NT | 4705 | #if !defined DOS_NT && !defined HAVE_ANDROID |
| 4605 | default_orig_pair = NULL; | 4706 | default_orig_pair = NULL; |
| 4606 | default_set_foreground = NULL; | 4707 | default_set_foreground = NULL; |
| 4607 | default_set_background = NULL; | 4708 | default_set_background = NULL; |
| 4608 | #endif /* !DOS_NT */ | 4709 | #endif /* !DOS_NT && !HAVE_ANDROID */ |
| 4609 | 4710 | ||
| 4711 | #ifndef HAVE_ANDROID | ||
| 4610 | encode_terminal_src = NULL; | 4712 | encode_terminal_src = NULL; |
| 4611 | encode_terminal_dst = NULL; | 4713 | encode_terminal_dst = NULL; |
| 4714 | #endif | ||
| 4612 | 4715 | ||
| 4613 | DEFSYM (Qtty_mode_set_strings, "tty-mode-set-strings"); | 4716 | DEFSYM (Qtty_mode_set_strings, "tty-mode-set-strings"); |
| 4614 | DEFSYM (Qtty_mode_reset_strings, "tty-mode-reset-strings"); | 4717 | DEFSYM (Qtty_mode_reset_strings, "tty-mode-reset-strings"); |
diff --git a/src/termhooks.h b/src/termhooks.h index c5f1e286e92..ea2a1cc3301 100644 --- a/src/termhooks.h +++ b/src/termhooks.h | |||
| @@ -63,7 +63,8 @@ enum output_method | |||
| 63 | output_w32, | 63 | output_w32, |
| 64 | output_ns, | 64 | output_ns, |
| 65 | output_pgtk, | 65 | output_pgtk, |
| 66 | output_haiku | 66 | output_haiku, |
| 67 | output_android, | ||
| 67 | }; | 68 | }; |
| 68 | 69 | ||
| 69 | /* Input queue declarations and hooks. */ | 70 | /* Input queue declarations and hooks. */ |
| @@ -516,12 +517,13 @@ struct terminal | |||
| 516 | /* Device-type dependent data shared amongst all frames on this terminal. */ | 517 | /* Device-type dependent data shared amongst all frames on this terminal. */ |
| 517 | union display_info | 518 | union display_info |
| 518 | { | 519 | { |
| 519 | struct tty_display_info *tty; /* termchar.h */ | 520 | struct tty_display_info *tty; /* termchar.h */ |
| 520 | struct x_display_info *x; /* xterm.h */ | 521 | struct x_display_info *x; /* xterm.h */ |
| 521 | struct w32_display_info *w32; /* w32term.h */ | 522 | struct w32_display_info *w32; /* w32term.h */ |
| 522 | struct ns_display_info *ns; /* nsterm.h */ | 523 | struct ns_display_info *ns; /* nsterm.h */ |
| 523 | struct pgtk_display_info *pgtk; /* pgtkterm.h */ | 524 | struct pgtk_display_info *pgtk; /* pgtkterm.h */ |
| 524 | struct haiku_display_info *haiku; /* haikuterm.h */ | 525 | struct haiku_display_info *haiku; /* haikuterm.h */ |
| 526 | struct android_display_info *android; /* androidterm.h */ | ||
| 525 | } display_info; | 527 | } display_info; |
| 526 | 528 | ||
| 527 | 529 | ||
| @@ -595,7 +597,8 @@ struct terminal | |||
| 595 | BGCOLOR. */ | 597 | BGCOLOR. */ |
| 596 | void (*query_frame_background_color) (struct frame *f, Emacs_Color *bgcolor); | 598 | void (*query_frame_background_color) (struct frame *f, Emacs_Color *bgcolor); |
| 597 | 599 | ||
| 598 | #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI) || defined (HAVE_PGTK) | 600 | #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI) || defined (HAVE_PGTK) \ |
| 601 | || defined (HAVE_ANDROID) | ||
| 599 | /* On frame F, translate pixel colors to RGB values for the NCOLORS | 602 | /* On frame F, translate pixel colors to RGB values for the NCOLORS |
| 600 | colors in COLORS. Use cached information, if available. */ | 603 | colors in COLORS. Use cached information, if available. */ |
| 601 | 604 | ||
| @@ -930,6 +933,9 @@ extern struct terminal *terminal_list; | |||
| 930 | #elif defined (HAVE_HAIKU) | 933 | #elif defined (HAVE_HAIKU) |
| 931 | #define TERMINAL_FONT_CACHE(t) \ | 934 | #define TERMINAL_FONT_CACHE(t) \ |
| 932 | (t->type == output_haiku ? t->display_info.haiku->name_list_element : Qnil) | 935 | (t->type == output_haiku ? t->display_info.haiku->name_list_element : Qnil) |
| 936 | #elif defined (HAVE_ANDROID) | ||
| 937 | #define TERMINAL_FONT_CACHE(t) \ | ||
| 938 | (t->type == output_android ? t->display_info.android->name_list_element : Qnil) | ||
| 933 | #endif | 939 | #endif |
| 934 | 940 | ||
| 935 | extern struct terminal *decode_live_terminal (Lisp_Object); | 941 | extern struct terminal *decode_live_terminal (Lisp_Object); |
diff --git a/src/terminal.c b/src/terminal.c index d366e9d2438..a0fe0fe5d3d 100644 --- a/src/terminal.c +++ b/src/terminal.c | |||
| @@ -451,6 +451,8 @@ return values. */) | |||
| 451 | return Qpgtk; | 451 | return Qpgtk; |
| 452 | case output_haiku: | 452 | case output_haiku: |
| 453 | return Qhaiku; | 453 | return Qhaiku; |
| 454 | case output_android: | ||
| 455 | return Qandroid; | ||
| 454 | default: | 456 | default: |
| 455 | emacs_abort (); | 457 | emacs_abort (); |
| 456 | } | 458 | } |
diff --git a/src/verbose.mk.in b/src/verbose.mk.in index 4ec7788442d..8d89c88c27a 100644 --- a/src/verbose.mk.in +++ b/src/verbose.mk.in | |||
| @@ -32,6 +32,10 @@ AM_V_GEN = | |||
| 32 | AM_V_GLOBALS = | 32 | AM_V_GLOBALS = |
| 33 | AM_V_NO_PD = | 33 | AM_V_NO_PD = |
| 34 | AM_V_RC = | 34 | AM_V_RC = |
| 35 | AM_V_JAVAC = | ||
| 36 | AM_V_DX = | ||
| 37 | AM_V_AAPT = | ||
| 38 | AM_V_ZIPALIGN = | ||
| 35 | else | 39 | else |
| 36 | 40 | ||
| 37 | # Whether $(info ...) works. This is to work around a bug in GNU Make | 41 | # Whether $(info ...) works. This is to work around a bug in GNU Make |
| @@ -76,4 +80,8 @@ AM_V_GEN = @$(info $ GEN $@) | |||
| 76 | AM_V_GLOBALS = @$(info $ GEN globals.h) | 80 | AM_V_GLOBALS = @$(info $ GEN globals.h) |
| 77 | AM_V_NO_PD = --no-print-directory | 81 | AM_V_NO_PD = --no-print-directory |
| 78 | AM_V_RC = @$(info $ RC $@) | 82 | AM_V_RC = @$(info $ RC $@) |
| 83 | |||
| 84 | # These are used for the Android port. | ||
| 85 | AM_V_JAVAC = @$(info $ JAVAC $@) | ||
| 86 | AM_V_DX = @$(info $ DX $@) | ||
| 79 | endif | 87 | endif |
diff --git a/src/xdisp.c b/src/xdisp.c index e8df230ef89..cc4c60f02da 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -16415,7 +16415,7 @@ redisplay_internal (void) | |||
| 16415 | display area, displaying a different frame means redisplay | 16415 | display area, displaying a different frame means redisplay |
| 16416 | the whole thing. */ | 16416 | the whole thing. */ |
| 16417 | SET_FRAME_GARBAGED (sf); | 16417 | SET_FRAME_GARBAGED (sf); |
| 16418 | #ifndef DOS_NT | 16418 | #if !defined DOS_NT && !defined HAVE_ANDROID |
| 16419 | set_tty_color_mode (FRAME_TTY (sf), sf); | 16419 | set_tty_color_mode (FRAME_TTY (sf), sf); |
| 16420 | #endif | 16420 | #endif |
| 16421 | FRAME_TTY (sf)->previous_frame = sf; | 16421 | FRAME_TTY (sf)->previous_frame = sf; |
| @@ -26320,7 +26320,7 @@ display_menu_bar (struct window *w) | |||
| 26320 | init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID); | 26320 | init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID); |
| 26321 | it.first_visible_x = 0; | 26321 | it.first_visible_x = 0; |
| 26322 | it.last_visible_x = FRAME_PIXEL_WIDTH (f); | 26322 | it.last_visible_x = FRAME_PIXEL_WIDTH (f); |
| 26323 | #elif defined (HAVE_X_WINDOWS) /* X without toolkit. */ | 26323 | #elif defined (HAVE_X_WINDOWS) || defined (HAVE_ANDROID) |
| 26324 | struct window *menu_window = NULL; | 26324 | struct window *menu_window = NULL; |
| 26325 | struct face *face = FACE_FROM_ID (f, MENU_FACE_ID); | 26325 | struct face *face = FACE_FROM_ID (f, MENU_FACE_ID); |
| 26326 | 26326 | ||
| @@ -26390,7 +26390,11 @@ display_menu_bar (struct window *w) | |||
| 26390 | it.glyph_row->truncated_on_left_p = false; | 26390 | it.glyph_row->truncated_on_left_p = false; |
| 26391 | it.glyph_row->truncated_on_right_p = false; | 26391 | it.glyph_row->truncated_on_right_p = false; |
| 26392 | 26392 | ||
| 26393 | #if defined (HAVE_X_WINDOWS) && !defined (USE_X_TOOLKIT) && !defined (USE_GTK) | 26393 | /* This will break the moment someone tries to add another window |
| 26394 | system that uses the no toolkit menu bar. Oh well. At least | ||
| 26395 | there will be an error, meaning he will correct the ifdef inside | ||
| 26396 | which `face' is defined. */ | ||
| 26397 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR | ||
| 26394 | /* Make a 3D menu bar have a shadow at its right end. */ | 26398 | /* Make a 3D menu bar have a shadow at its right end. */ |
| 26395 | extend_face_to_end_of_line (&it); | 26399 | extend_face_to_end_of_line (&it); |
| 26396 | if (face->box != FACE_NO_BOX) | 26400 | if (face->box != FACE_NO_BOX) |
| @@ -26431,6 +26435,11 @@ display_menu_bar (struct window *w) | |||
| 26431 | #endif | 26435 | #endif |
| 26432 | } | 26436 | } |
| 26433 | 26437 | ||
| 26438 | /* This code is never used on Android where there are only GUI and | ||
| 26439 | initial frames. */ | ||
| 26440 | |||
| 26441 | #ifndef HAVE_ANDROID | ||
| 26442 | |||
| 26434 | /* Deep copy of a glyph row, including the glyphs. */ | 26443 | /* Deep copy of a glyph row, including the glyphs. */ |
| 26435 | static void | 26444 | static void |
| 26436 | deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from) | 26445 | deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from) |
| @@ -26551,6 +26560,9 @@ display_tty_menu_item (const char *item_text, int width, int face_id, | |||
| 26551 | row->full_width_p = saved_width; | 26560 | row->full_width_p = saved_width; |
| 26552 | row->reversed_p = saved_reversed; | 26561 | row->reversed_p = saved_reversed; |
| 26553 | } | 26562 | } |
| 26563 | |||
| 26564 | #endif | ||
| 26565 | |||
| 26554 | 26566 | ||
| 26555 | /*********************************************************************** | 26567 | /*********************************************************************** |
| 26556 | Mode Line | 26568 | Mode Line |
| @@ -33432,7 +33444,9 @@ draw_row_with_mouse_face (struct window *w, int start_x, struct glyph_row *row, | |||
| 33432 | } | 33444 | } |
| 33433 | #endif | 33445 | #endif |
| 33434 | 33446 | ||
| 33447 | #ifndef HAVE_ANDROID | ||
| 33435 | tty_draw_row_with_mouse_face (w, row, start_hpos, end_hpos, draw); | 33448 | tty_draw_row_with_mouse_face (w, row, start_hpos, end_hpos, draw); |
| 33449 | #endif | ||
| 33436 | } | 33450 | } |
| 33437 | 33451 | ||
| 33438 | /* Display the active region described by mouse_face_* according to DRAW. */ | 33452 | /* Display the active region described by mouse_face_* according to DRAW. */ |
| @@ -36104,14 +36118,10 @@ expose_frame (struct frame *f, int x, int y, int w, int h) | |||
| 36104 | |= expose_window (XWINDOW (f->tool_bar_window), &r); | 36118 | |= expose_window (XWINDOW (f->tool_bar_window), &r); |
| 36105 | #endif | 36119 | #endif |
| 36106 | 36120 | ||
| 36107 | #ifdef HAVE_X_WINDOWS | 36121 | #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR |
| 36108 | #ifndef MSDOS | ||
| 36109 | #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | ||
| 36110 | if (WINDOWP (f->menu_bar_window)) | 36122 | if (WINDOWP (f->menu_bar_window)) |
| 36111 | mouse_face_overwritten_p | 36123 | mouse_face_overwritten_p |
| 36112 | |= expose_window (XWINDOW (f->menu_bar_window), &r); | 36124 | |= expose_window (XWINDOW (f->menu_bar_window), &r); |
| 36113 | #endif /* not USE_X_TOOLKIT and not USE_GTK */ | ||
| 36114 | #endif | ||
| 36115 | #endif | 36125 | #endif |
| 36116 | 36126 | ||
| 36117 | /* Some window managers support a focus-follows-mouse style with | 36127 | /* Some window managers support a focus-follows-mouse style with |
diff --git a/src/xfaces.c b/src/xfaces.c index 663386dc25b..0f85a753393 100644 --- a/src/xfaces.c +++ b/src/xfaces.c | |||
| @@ -254,6 +254,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 254 | #ifdef HAVE_HAIKU | 254 | #ifdef HAVE_HAIKU |
| 255 | #define GCGraphicsExposures 0 | 255 | #define GCGraphicsExposures 0 |
| 256 | #endif /* HAVE_HAIKU */ | 256 | #endif /* HAVE_HAIKU */ |
| 257 | |||
| 258 | #ifdef HAVE_ANDROID | ||
| 259 | #define GCGraphicsExposures 0 | ||
| 260 | #endif /* HAVE_ANDROID */ | ||
| 257 | #endif /* HAVE_WINDOW_SYSTEM */ | 261 | #endif /* HAVE_WINDOW_SYSTEM */ |
| 258 | 262 | ||
| 259 | #include "buffer.h" | 263 | #include "buffer.h" |
| @@ -607,6 +611,39 @@ x_free_gc (struct frame *f, Emacs_GC *gc) | |||
| 607 | } | 611 | } |
| 608 | #endif /* HAVE_NS */ | 612 | #endif /* HAVE_NS */ |
| 609 | 613 | ||
| 614 | #ifdef HAVE_ANDROID | ||
| 615 | |||
| 616 | /* Android real GCs. */ | ||
| 617 | |||
| 618 | static struct android_gc * | ||
| 619 | x_create_gc (struct frame *f, unsigned long value_mask, | ||
| 620 | Emacs_GC *xgcv) | ||
| 621 | { | ||
| 622 | struct android_gc_values gcv; | ||
| 623 | unsigned long mask; | ||
| 624 | |||
| 625 | gcv.foreground = xgcv->foreground; | ||
| 626 | gcv.background = xgcv->background; | ||
| 627 | |||
| 628 | mask = 0; | ||
| 629 | |||
| 630 | if (value_mask & GCForeground) | ||
| 631 | mask |= ANDROID_GC_FOREGROUND; | ||
| 632 | |||
| 633 | if (value_mask & GCBackground) | ||
| 634 | mask |= ANDROID_GC_BACKGROUND; | ||
| 635 | |||
| 636 | return android_create_gc (mask, &gcv); | ||
| 637 | } | ||
| 638 | |||
| 639 | static void | ||
| 640 | x_free_gc (struct frame *f, struct android_gc *gc) | ||
| 641 | { | ||
| 642 | android_free_gc (gc); | ||
| 643 | } | ||
| 644 | |||
| 645 | #endif | ||
| 646 | |||
| 610 | /*********************************************************************** | 647 | /*********************************************************************** |
| 611 | Frames and faces | 648 | Frames and faces |
| 612 | ***********************************************************************/ | 649 | ***********************************************************************/ |
| @@ -6951,19 +6988,21 @@ where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */) | |||
| 6951 | int num; | 6988 | int num; |
| 6952 | 6989 | ||
| 6953 | while (fgets (buf, sizeof (buf), fp) != NULL) | 6990 | while (fgets (buf, sizeof (buf), fp) != NULL) |
| 6954 | if (sscanf (buf, "%d %d %d %n", &red, &green, &blue, &num) == 3) | 6991 | { |
| 6955 | { | 6992 | if (sscanf (buf, "%d %d %d %n", &red, &green, &blue, &num) == 3) |
| 6993 | { | ||
| 6956 | #ifdef HAVE_NTGUI | 6994 | #ifdef HAVE_NTGUI |
| 6957 | int color = RGB (red, green, blue); | 6995 | int color = RGB (red, green, blue); |
| 6958 | #else | 6996 | #else |
| 6959 | int color = (red << 16) | (green << 8) | blue; | 6997 | int color = (red << 16) | (green << 8) | blue; |
| 6960 | #endif | 6998 | #endif |
| 6961 | char *name = buf + num; | 6999 | char *name = buf + num; |
| 6962 | ptrdiff_t len = strlen (name); | 7000 | ptrdiff_t len = strlen (name); |
| 6963 | len -= 0 < len && name[len - 1] == '\n'; | 7001 | len -= 0 < len && name[len - 1] == '\n'; |
| 6964 | cmap = Fcons (Fcons (make_string (name, len), make_fixnum (color)), | 7002 | cmap = Fcons (Fcons (make_string (name, len), make_fixnum (color)), |
| 6965 | cmap); | 7003 | cmap); |
| 6966 | } | 7004 | } |
| 7005 | } | ||
| 6967 | fclose (fp); | 7006 | fclose (fp); |
| 6968 | } | 7007 | } |
| 6969 | unblock_input (); | 7008 | unblock_input (); |