aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2022-12-31 18:04:18 +0800
committerPo Lu2022-12-31 18:04:18 +0800
commitcfbc8a5dbcd362b69b37b4e6832ae4a31834364c (patch)
treece003d03c4ae98f4e1d02186d78e5ae6e0d36e55
parent785095c416f9bae43d2947849282b814e2c7942e (diff)
downloademacs-cfbc8a5dbcd362b69b37b4e6832ae4a31834364c.tar.gz
emacs-cfbc8a5dbcd362b69b37b4e6832ae4a31834364c.zip
Bring up the Android operating system and its window system
* .dir-locals.el (c-mode): Add ANDROID_EXPORT noise macro. * .gitignore: Add new files to ignore. * Makefile.in: Adjust for Android. * admin/merge-gnulib: Add new warning. * configure.ac: Detect Android. Run cross-configuration for Android when appropriate. * etc/DEBUG: Document how to debug Emacs on Android. * java/AndroidManifest.xml: * java/Makefile.in: * java/README: * java/debug.sh: * java/org/gnu/emacs/EmacsActivity.java (EmacsActivity): * java/org/gnu/emacs/EmacsApplication.java (EmacsApplication): * java/org/gnu/emacs/EmacsCopyArea.java (EmacsCopyArea): * java/org/gnu/emacs/EmacsDrawLine.java (EmacsDrawLine): * java/org/gnu/emacs/EmacsDrawPoint.java (EmacsDrawPoint): * java/org/gnu/emacs/EmacsDrawRectangle.java (EmacsDrawRectangle): * java/org/gnu/emacs/EmacsDrawable.java (EmacsDrawable): * java/org/gnu/emacs/EmacsFillPolygon.java (EmacsFillPolygon): * java/org/gnu/emacs/EmacsFillRectangle.java (EmacsFillRectangle): * java/org/gnu/emacs/EmacsFontDriver.java (EmacsFontDriver): * java/org/gnu/emacs/EmacsGC.java (EmacsGC): * java/org/gnu/emacs/EmacsHandleObject.java (EmacsHandleObject): * java/org/gnu/emacs/EmacsNative.java (EmacsNative): * java/org/gnu/emacs/EmacsPaintQueue.java (EmacsPaintQueue): * java/org/gnu/emacs/EmacsPaintReq.java (EmacsPaintReq): * java/org/gnu/emacs/EmacsPixmap.java (EmacsPixmap): * java/org/gnu/emacs/EmacsSdk7FontDriver.java (EmacsSdk7FontDriver): * java/org/gnu/emacs/EmacsService.java (class Holder<T>) (EmacsService): * java/org/gnu/emacs/EmacsSurfaceView.java (EmacsSurfaceView): * java/org/gnu/emacs/EmacsThread.java (EmacsThread): * java/org/gnu/emacs/EmacsView.java (EmacsView): * java/org/gnu/emacs/EmacsWindow.java (EmacsWindow): New files and classes. * lib-src/Makefile.in (srcdir): * lib/Makefile.in (VPATH): (HAVE_NATIVE_COMP): (libgnu_a_SOURCES): (DEPFLAGS): Configure correctly for cross-compiling. * lib/faccessat.c: * lib/fpending.c (__fpending): * lib/open.c: * lib/unistd.c (_GL_UNISTD_INLINE): Temporary adjustments to gnulib. * lisp/frame.el (display-graphic-p): (display-screens): (display-pixel-height): (display-pixel-width): (display-mm-height): (display-mm-width): (display-backing-store): (display-save-under): (display-planes): (display-color-cells): (display-visual-class): Adjust for new window system `android'. * lisp/image/wallpaper.el (x-open-connection): Add declaration. * lisp/loadup.el (featurep): Load up files for Android. * lisp/net/eww.el (eww-form-submit, eww-form-file) (eww-form-checkbox, eww-form-select): Adjust faces for android. * lisp/term/android-win.el: New file. * src/Makefile.in: Add new targets emacs.so and android-emacs, then adjust for cross compilation. * src/alloc.c (cleanup_vector): Clean up Android font entities as well. (garbage_collect): Mark androidterm. * src/android-emacs.c (main): * src/android.c (ANDROID_THROW, enum android_fd_table_entry_flags) (struct android_emacs_service, struct android_emacs_pixmap) (struct android_graphics_point, struct android_event_container) (struct android_event_queue, android_run_select_thread) (android_handle_sigusr1, android_init_events, android_pending) (android_next_event, android_write_event, android_select) (android_run_debug_thread, android_user_full_name) (android_get_asset_name, android_fstat, android_fstatat) (android_file_access_p, android_hack_asset_fd, android_open) (android_close, JNICALL, android_init_emacs_service) (android_init_emacs_pixmap, android_init_graphics_point) (MAX_HANDLE, struct android_handle_entry, android_alloc_id) (android_destroy_handle, android_resolve_handle) (android_resolve_handle2, android_change_window_attributes) (android_create_window, android_set_window_background) (android_destroy_window, android_init_android_rect_class) (android_init_emacs_gc_class, android_create_gc, android_free_gc) (android_change_gc, android_set_clip_rectangles) (android_reparent_window, android_lookup_method) (android_clear_window, android_map_window, android_unmap_window) (android_resize_window, android_move_window, android_swap_buffers) (android_get_gc_values, android_set_foreground) (android_fill_rectangle, android_create_pixmap_from_bitmap_data) (android_set_clip_mask, android_set_fill_style, android_copy_area) (android_free_pixmap, android_set_background, android_fill_polygon) (android_draw_rectangle, android_draw_point, android_draw_line) (android_create_pixmap, android_set_ts_origin, android_clear_area): * src/android.h (ANDROID_EXPORT): * src/androidfns.c (android_display_info_for_name) (check_android_display_info, check_x_display_info, gamma_correct) (android_defined_color, android_decode_color) (android_implicitly_set_name, android_explicitly_set_name) (android_set_tool_bar_lines, android_change_tool_bar_height) (android_set_tab_bar_lines, android_change_tab_bar_height) (android_set_scroll_bar_default_height) (android_set_scroll_bar_default_width, android_icon_verify) (android_icon, android_make_gc, android_free_gcs) (unwind_create_frame, do_unwind_create_frame) (android_default_font_parameter, android_create_frame_window) (Fx_create_frame, Fxw_color_defined_p, Fxw_color_values) (Fxw_display_color_p, Fx_display_grayscale_p) (Fx_display_pixel_width, Fx_display_pixel_height) (Fx_display_planes, Fx_display_color_cells, Fx_display_screens) (Fx_display_mm_width, Fx_display_mm_height) (Fx_display_backing_store, Fx_display_visual_class) (Fx_display_monitor_attributes_list, Fx_frame_geometry) (Fx_frame_list_z_order, Fx_frame_restack) (Fx_mouse_absolute_pixel_position) (Fx_set_mouse_absolute_pixel_position, Fandroid_get_connection) (Fx_display_list, Fx_show_tip, Fx_hide_tip) (android_set_background_color, android_set_border_color) (android_set_cursor_color, android_set_cursor_type) (android_set_foreground_color) (android_set_child_frame_border_width) (android_set_internal_border_width, android_set_menu_bar_lines) (android_set_mouse_color, android_set_title, android_set_alpha) (android_frame_parm_handlers, syms_of_androidfns): * src/androidfont.c (struct android_emacs_font_driver) (struct android_emacs_font_spec, struct android_emacs_font_metrics) (struct android_emacs_font_object, struct android_integer) (struct androidfont_info, struct androidfont_entity) (android_init_font_driver, android_init_font_spec) (android_init_font_metrics, android_init_integer) (android_init_font_object, androidfont_get_cache) (androidfont_from_lisp, androidfont_from_java, androidfont_list) (androidfont_match, androidfont_draw, androidfont_open_font) (androidfont_close_font, androidfont_has_char) (androidfont_encode_char, androidfont_text_extents) (androidfont_list_family, androidfont_driver) (syms_of_androidfont_for_pdumper, syms_of_androidfont) (init_androidfont, android_finalize_font_entity): * src/androidgui.h (_ANDROID_GUI_H_, struct android_rectangle) (struct android_point, enum android_gc_function) (enum android_gc_value_mask, enum android_fill_style) (enum android_window_value_mask) (struct android_set_window_attributes, struct android_gc_values) (struct android_gc, enum android_swap_action, enum android_shape) (enum android_coord_mode, struct android_swap_info) (NativeRectangle, struct android_any_event) (struct android_key_event, struct android_configure_event) (union android_event): * src/androidterm.c (android_window_to_frame, android_clear_frame) (android_ring_bell, android_toggle_invisible_pointer) (android_update_begin, android_update_end, show_back_buffer) (android_flush_dirty_back_buffer_on, handle_one_android_event) (android_read_socket, android_frame_up_to_date) (android_buffer_flipping_unblocked_hook) (android_query_frame_background_color, android_parse_color) (android_alloc_nearest_color, android_query_colors) (android_mouse_position, android_get_focus_frame) (android_focus_frame, android_frame_rehighlight) (android_frame_raise_lower, android_make_frame_visible) (android_make_frame_invisible) (android_make_frame_visible_invisible, android_fullscreen_hook) (android_iconify_frame, android_set_window_size_1) (android_set_window_size, android_set_offset, android_set_alpha) (android_new_font, android_bitmap_icon, android_free_pixmap_hook) (android_free_frame_resources, android_delete_frame) (android_delete_terminal, android_scroll_run) (android_after_update_window_line, android_flip_and_flush) (android_clear_rectangle, android_reset_clip_rectangles) (android_clip_to_row, android_draw_fringe_bitmap) (android_set_cursor_gc, android_set_mouse_face_gc) (android_set_mode_line_face_gc, android_set_glyph_string_gc) (android_set_glyph_string_clipping) (android_set_glyph_string_clipping_exactly) (android_compute_glyph_string_overhangs) (android_clear_glyph_string_rect) (android_draw_glyph_string_background, android_fill_triangle) (android_make_point, android_inside_rect_p, android_clear_point) (android_draw_relief_rect, android_draw_box_rect) (HIGHLIGHT_COLOR_DARK_BOOST_LIMIT, android_setup_relief_color) (android_setup_relief_colors, android_draw_glyph_string_box) (android_draw_glyph_string_bg_rect, android_draw_image_relief) (android_draw_image_foreground, android_draw_image_foreground_1) (android_draw_image_glyph_string) (android_draw_stretch_glyph_string, android_draw_underwave) (android_draw_glyph_string_foreground) (android_draw_composite_glyph_string_foreground) (android_draw_glyphless_glyph_string_foreground) (android_draw_glyph_string, android_define_frame_cursor) (android_clear_frame_area, android_clear_under_internal_border) (android_draw_hollow_cursor, android_draw_bar_cursor) (android_draw_window_cursor, android_draw_vertical_window_border) (android_draw_window_divider, android_redisplay_interface) (frame_set_mouse_pixel_position, get_keysym_name) (android_create_terminal, android_term_init, syms_of_androidterm) (mark_androidterm): * src/androidterm.h (_ANDROID_TERM_H_, struct android_display_info) (struct android_output, FRAME_ANDROID_OUTPUT, XSCROLL_BAR): New files. * src/dired.c (file_attributes): Do not use openat on Android. * src/dispextern.h (No_Cursor): Define appropriately on Android. (struct glyph_string, struct face): Make gc field of type struct android_gc on Android. * src/dispnew.c (clear_current_matrices, clear_desired_matrices) (adjust_frame_glyphs_for_window_redisplay, free_glyphs) (update_frame, scrolling, char_ins_del_cost, update_frame_line) (init_display_interactive): Disable text terminal support completely on Android. Fix non-toolkit menus for non-X systems. * src/editfns.c (Fuser_full_name): Call android_user_full_name. * src/emacs.c (android_emacs_init): Make main this on Android. Prohibit argv sorting from exceeding end of argv. * src/epaths.in: Add path definitions for Android. * src/fileio.c (file_access_p): Call android_file_access_p. (file_name_directory): Avoid using openat on Android. (Fcopy_file): Adjust to call sys_fstat instead. (file_directory_p): (Finsert_file_contents): (write_region): Likewise. * src/filelock.c: * src/fns.c (Flocale_info): Pacify warning on Android. * src/font.c (font_make_entity_android): New function. * src/font.h: * src/frame.c (Fframep): (Fwindow_system): Handle new window system `android'. Update doc strings. (Fmake_terminal_frame): Disable on Android. (gui_display_get_resource): Disable get_string_resource_hook on Android. (syms_of_frame): New defsym `android'. * src/frame.h (GCALIGNED_STRUCT): Add new output data for Android. (ENUM_BF): Expand enumerator size. (FRAME_ANDROID_P, FRAME_WINDOW_P, MOUSE_HL_INFO): Add definitions for Android. * src/image.c (GET_PIXEL): (image_create_bitmap_from_file): (image_create_x_image_and_pixmap_1): (image_get_x_image): (slurp_file): (lookup_rgb_color): (image_to_emacs_colors): (image_from_emacs_colors): (image_pixmap_draw_cross): (image_disable_image): (MaskForeground): (gif_load): Add stubs for Android. * src/lisp.h: * src/lread.c (safe_to_load_version, maybe_swap_for_eln1, openp): * src/pdumper.c (pdumper_load): Call sys_fstat instead of fstat. * src/process.c (wait_reading_process_output): Use android_select instead of pselect. * src/scroll.c: Disable on Android. * src/sysdep.c (widen_foreground_group, reset_sys_modes) (init_signals, emacs_fstatat, sys_fstat): New function. (emacs_open, emacs_open_noquit, emacs_close): Implement differently on Android. (close_output_streams): Disable what is not required on Android. * src/term.c (OUTPUT1_IF, encode_terminal_code, string_cost) (string_cost_one_line, per_line_cost, calculate_costs) (struct fkey_table, tty_append_glyph, produce_glyphs) (tty_capable_p, Fsuspend_tty, Fresume_tty, device, init_tty) (maybe_fatal, syms_of_term): Disable text terminal support on Android. * src/termhooks.h (enum output_method): Add android output method. (GCALIGNED_STRUCT, TERMINAL_FONT_CACHE): Define for Android. * src/terminal.c (Fterminal_live_p): Implement for Android. * src/verbose.mk.in (AM_V_GLOBALS): Add JAVAC and DX. * src/xdisp.c (redisplay_internal): Disable text terminals on Android. (display_menu_bar): (display_tty_menu_item): (draw_row_with_mouse_face): (expose_frame): Make the non toolkit menu bar work on Android. * src/xfaces.c (GCGraphicsExposures): (x_create_gc): (x_free_gc): (Fx_load_color_file): Define for Android. * xcompile/Makefile.in (top_srcdir): (top_builddir): * xcompile/README: * xcompile/langinfo.h (nl_langinfo): New files.
-rw-r--r--.dir-locals.el2
-rw-r--r--.gitignore17
-rw-r--r--Makefile.in68
-rwxr-xr-xadmin/merge-gnulib2
-rw-r--r--configure.ac526
-rw-r--r--etc/DEBUG24
-rw-r--r--java/AndroidManifest.xml54
-rw-r--r--java/Makefile.in150
-rw-r--r--java/README6
-rwxr-xr-xjava/debug.sh242
-rw-r--r--java/emacs.keystorebin0 -> 2776 bytes
-rw-r--r--java/org/gnu/emacs/EmacsActivity.java146
-rw-r--r--java/org/gnu/emacs/EmacsApplication.java27
-rw-r--r--java/org/gnu/emacs/EmacsCopyArea.java131
-rw-r--r--java/org/gnu/emacs/EmacsDrawLine.java137
-rw-r--r--java/org/gnu/emacs/EmacsDrawPoint.java30
-rw-r--r--java/org/gnu/emacs/EmacsDrawRectangle.java127
-rw-r--r--java/org/gnu/emacs/EmacsDrawable.java33
-rw-r--r--java/org/gnu/emacs/EmacsFillPolygon.java150
-rw-r--r--java/org/gnu/emacs/EmacsFillRectangle.java129
-rw-r--r--java/org/gnu/emacs/EmacsFontDriver.java150
-rw-r--r--java/org/gnu/emacs/EmacsGC.java116
-rw-r--r--java/org/gnu/emacs/EmacsHandleObject.java62
-rw-r--r--java/org/gnu/emacs/EmacsNative.java72
-rw-r--r--java/org/gnu/emacs/EmacsPaintQueue.java138
-rw-r--r--java/org/gnu/emacs/EmacsPaintReq.java33
-rw-r--r--java/org/gnu/emacs/EmacsPixmap.java102
-rw-r--r--java/org/gnu/emacs/EmacsSdk7FontDriver.java460
-rw-r--r--java/org/gnu/emacs/EmacsService.java384
-rw-r--r--java/org/gnu/emacs/EmacsSurfaceView.java83
-rw-r--r--java/org/gnu/emacs/EmacsThread.java44
-rw-r--r--java/org/gnu/emacs/EmacsView.java211
-rw-r--r--java/org/gnu/emacs/EmacsWindow.java336
-rw-r--r--lib-src/Makefile.in8
-rw-r--r--lib/Makefile.in137
-rw-r--r--lib/faccessat.c4
-rw-r--r--lib/fpending.c6
-rw-r--r--lib/open.c4
-rw-r--r--lib/unistd.c2
-rw-r--r--lisp/frame.el23
-rw-r--r--lisp/image/wallpaper.el2
-rw-r--r--lisp/loadup.el5
-rw-r--r--lisp/net/eww.el8
-rw-r--r--lisp/term/android-win.el62
-rw-r--r--src/Makefile.in52
-rw-r--r--src/alloc.c12
-rw-r--r--src/android-emacs.c30
-rw-r--r--src/android.c2335
-rw-r--r--src/android.h70
-rw-r--r--src/androidfns.c1779
-rw-r--r--src/androidfont.c955
-rw-r--r--src/androidgui.h315
-rw-r--r--src/androidterm.c3161
-rw-r--r--src/androidterm.h366
-rw-r--r--src/dired.c5
-rw-r--r--src/dispextern.h31
-rw-r--r--src/dispnew.c48
-rw-r--r--src/editfns.c8
-rw-r--r--src/emacs.c37
-rw-r--r--src/epaths.in22
-rw-r--r--src/fileio.c25
-rw-r--r--src/filelock.c6
-rw-r--r--src/fns.c4
-rw-r--r--src/font.c16
-rw-r--r--src/font.h3
-rw-r--r--src/frame.c30
-rw-r--r--src/frame.h35
-rw-r--r--src/image.c88
-rw-r--r--src/lisp.h12
-rw-r--r--src/lread.c6
-rw-r--r--src/pdumper.c2
-rw-r--r--src/process.c17
-rw-r--r--src/scroll.c7
-rw-r--r--src/sysdep.c98
-rw-r--r--src/term.c135
-rw-r--r--src/termhooks.h22
-rw-r--r--src/terminal.c2
-rw-r--r--src/verbose.mk.in8
-rw-r--r--src/xdisp.c26
-rw-r--r--src/xfaces.c59
-rw-r--r--xcompile/Makefile.in209
-rw-r--r--xcompile/README7
-rw-r--r--xcompile/langinfo.h20
83 files changed, 14298 insertions, 218 deletions
diff --git a/.dir-locals.el b/.dir-locals.el
index fc89dff87f2..d8eece92245 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -12,7 +12,7 @@
12 (c-mode . ((c-file-style . "GNU") 12 (c-mode . ((c-file-style . "GNU")
13 (c-noise-macro-names . ("INLINE" "NO_INLINE" "ATTRIBUTE_NO_SANITIZE_UNDEFINED" 13 (c-noise-macro-names . ("INLINE" "NO_INLINE" "ATTRIBUTE_NO_SANITIZE_UNDEFINED"
14 "UNINIT" "CALLBACK" "ALIGN_STACK" "ATTRIBUTE_MALLOC" 14 "UNINIT" "CALLBACK" "ALIGN_STACK" "ATTRIBUTE_MALLOC"
15 "ATTRIBUTE_DEALLOC_FREE")) 15 "ATTRIBUTE_DEALLOC_FREE" "ANDROID_EXPORT"))
16 (electric-quote-comment . nil) 16 (electric-quote-comment . nil)
17 (electric-quote-string . nil) 17 (electric-quote-string . nil)
18 (indent-tabs-mode . t) 18 (indent-tabs-mode . t)
diff --git a/.gitignore b/.gitignore
index af0ba0eb410..b5cc3191253 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,6 +52,15 @@ src/config.h
52src/epaths.h 52src/epaths.h
53src/emacs-module.h 53src/emacs-module.h
54 54
55# Built by recursive call to `configure'.
56*.android
57
58# Built by `java'.
59java/install_temp/*
60java/*.apk*
61java/*.dex
62java/org/gnu/emacs/*.class
63
55# C-level sources built by 'make'. 64# C-level sources built by 'make'.
56lib/alloca.h 65lib/alloca.h
57lib/assert.h 66lib/assert.h
@@ -81,6 +90,14 @@ src/globals.h
81src/lisp.mk 90src/lisp.mk
82src/verbose.mk 91src/verbose.mk
83 92
93# Stuff built during cross compilation
94xcompile/lib/*
95xcompile/src/*
96xcompile/lib-src/*
97xcompile/sys/*
98xcompile/config.status
99xcompile/*.bak
100
84# Lisp-level sources built by 'make'. 101# Lisp-level sources built by 'make'.
85*cus-load.el 102*cus-load.el
86*loaddefs.el 103*loaddefs.el
diff --git a/Makefile.in b/Makefile.in
index 93609a4e166..d8c5ba555d3 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -106,15 +106,15 @@ top_builddir = @top_builddir@
106 106
107FIND_DELETE = @FIND_DELETE@ 107FIND_DELETE = @FIND_DELETE@
108 108
109HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@
110
111USE_STARTUP_NOTIFICATION = @USE_STARTUP_NOTIFICATION@ 109USE_STARTUP_NOTIFICATION = @USE_STARTUP_NOTIFICATION@
112 110
111HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@
113HAVE_BE_APP = @HAVE_BE_APP@ 112HAVE_BE_APP = @HAVE_BE_APP@
114
115HAVE_PGTK = @HAVE_PGTK@ 113HAVE_PGTK = @HAVE_PGTK@
116HAVE_GSETTINGS = @HAVE_GSETTINGS@ 114HAVE_GSETTINGS = @HAVE_GSETTINGS@
117 115
116ANDROID = @ANDROID@
117
118# ==================== Where To Install Things ==================== 118# ==================== Where To Install Things ====================
119 119
120# Location to install Emacs.app under GNUstep / macOS. 120# Location to install Emacs.app under GNUstep / macOS.
@@ -339,6 +339,10 @@ EMACS_PDMP = `./src/emacs${EXEEXT} --fingerprint`.pdmp
339# Subdirectories to make recursively. 339# Subdirectories to make recursively.
340SUBDIR = $(NTDIR) lib lib-src src lisp 340SUBDIR = $(NTDIR) lib lib-src src lisp
341 341
342ifeq ($(ANDROID),yes)
343SUBDIR := $(SUBDIR) java
344endif
345
342# The subdir makefiles created by config.status. 346# The subdir makefiles created by config.status.
343SUBDIR_MAKEFILES_IN = @SUBDIR_MAKEFILES_IN@ 347SUBDIR_MAKEFILES_IN = @SUBDIR_MAKEFILES_IN@
344SUBDIR_MAKEFILES = $(patsubst ${srcdir}/%,%,${SUBDIR_MAKEFILES_IN:.in=}) 348SUBDIR_MAKEFILES = $(patsubst ${srcdir}/%,%,${SUBDIR_MAKEFILES_IN:.in=})
@@ -467,20 +471,20 @@ epaths-force:
467 esac; \ 471 esac; \
468 done 472 done
469 @(gamedir='${gamedir}'; \ 473 @(gamedir='${gamedir}'; \
470 sed < ${srcdir}/src/epaths.in > epaths.h.$$$$ \ 474 sed < ${srcdir}/src/epaths.in > epaths.h.$$$$ \
471 -e 's;\(#.*PATH_LOADSEARCH\).*$$;\1 "${standardlisppath}";' \ 475 -e 's;\(#define.*PATH_LOADSEARCH\).*$$;\1 "${standardlisppath}";' \
472 -e 's;\(#.*PATH_REL_LOADSEARCH\).*$$;\1 "${lispdirrel}";' \ 476 -e 's;\(#define.*PATH_REL_LOADSEARCH\).*$$;\1 "${lispdirrel}";' \
473 -e 's;\(#.*PATH_SITELOADSEARCH\).*$$;\1 "${locallisppath}";' \ 477 -e 's;\(#define.*PATH_SITELOADSEARCH\).*$$;\1 "${locallisppath}";' \
474 -e 's;\(#.*PATH_DUMPLOADSEARCH\).*$$;\1 "${buildlisppath}";' \ 478 -e 's;\(#define.*PATH_DUMPLOADSEARCH\).*$$;\1 "${buildlisppath}";' \
475 -e '/^#define PATH_[^ ]*SEARCH /s/\([":]\):*/\1/g' \ 479 -e '/^#define PATH_[^ ]*SEARCH /s/\([":]\):*/\1/g' \
476 -e '/^#define PATH_[^ ]*SEARCH /s/:"/"/' \ 480 -e '/^#define PATH_[^ ]*SEARCH /s/:"/"/' \
477 -e 's;\(#.*PATH_EXEC\).*$$;\1 "${archlibdir}";' \ 481 -e 's;\(#define.*PATH_EXEC\).*$$;\1 "${archlibdir}";' \
478 -e 's;\(#.*PATH_INFO\).*$$;\1 "${infodir}";' \ 482 -e 's;\(#define.*PATH_INFO\).*$$;\1 "${infodir}";' \
479 -e 's;\(#.*PATH_DATA\).*$$;\1 "${etcdir}";' \ 483 -e 's;\(#define.*PATH_DATA\).*$$;\1 "${etcdir}";' \
480 -e 's;\(#.*PATH_BITMAPS\).*$$;\1 "${bitmapdir}";' \ 484 -e 's;\(#define.*PATH_BITMAPS\).*$$;\1 "${bitmapdir}";' \
481 -e 's;\(#.*PATH_X_DEFAULTS\).*$$;\1 "${x_default_search_path}";' \ 485 -e 's;\(#define.*PATH_X_DEFAULTS\).*$$;\1 "${x_default_search_path}";' \
482 -e 's;\(#.*PATH_GAME\).*$$;\1 $(PATH_GAME);' \ 486 -e 's;\(#define.*PATH_GAME\).*$$;\1 $(PATH_GAME);' \
483 -e 's;\(#.*PATH_DOC\).*$$;\1 "${etcdocdir}";') && \ 487 -e 's;\(#define.*PATH_DOC\).*$$;\1 "${etcdocdir}";') && \
484 ${srcdir}/build-aux/move-if-change epaths.h.$$$$ src/epaths.h 488 ${srcdir}/build-aux/move-if-change epaths.h.$$$$ src/epaths.h
485 489
486# The w32 build needs a slightly different editing, and it uses 490# The w32 build needs a slightly different editing, and it uses
@@ -532,6 +536,12 @@ lisp: src
532lib lib-src lisp nt: Makefile 536lib lib-src lisp nt: Makefile
533 $(MAKE) -C $@ all 537 $(MAKE) -C $@ all
534 538
539java: lisp
540 $(MAKE) -C $@ all
541
542xcompile: src
543 $(MAKE) -C $@ all
544
535trampolines: src lisp 545trampolines: src lisp
536ifeq ($(HAVE_NATIVE_COMP),yes) 546ifeq ($(HAVE_NATIVE_COMP),yes)
537 $(MAKE) -C lisp trampolines 547 $(MAKE) -C lisp trampolines
@@ -561,20 +571,38 @@ blessmail: Makefile src
561# then attempts to build that file. This forces 'Makefile', 'lib/Makefile', 571# then attempts to build that file. This forces 'Makefile', 'lib/Makefile',
562# etc. to be built without running into similar recursion problems. 572# etc. to be built without running into similar recursion problems.
563MAKEFILE_NAME = Makefile 573MAKEFILE_NAME = Makefile
574ifeq ($(ANDROID),)
564$(MAKEFILE_NAME): config.status $(srcdir)/configure \ 575$(MAKEFILE_NAME): config.status $(srcdir)/configure \
565 $(srcdir)/lib/gnulib.mk.in \ 576 $(srcdir)/lib/gnulib.mk.in \
566 $(srcdir)/Makefile.in $(SUBDIR_MAKEFILES_IN) $(CONFIG_STATUS_FILES_IN) 577 $(srcdir)/Makefile.in $(SUBDIR_MAKEFILES_IN) $(CONFIG_STATUS_FILES_IN)
567 MAKE='$(MAKE)' ./config.status 578 MAKE='$(MAKE)' ./config.status
579else
580# Note that calling config.status is insufficient on Android due to
581# the recursive calls to configure.
582
583$(MAKEFILE_NAME): $(srcdir)/configure \
584 $(srcdir)/lib/gnulib.mk.in \
585 $(srcdir)/Makefile.in $(SUBDIR_MAKEFILES_IN) $(CONFIG_STATUS_FILES_IN)
586 $(CFG) $(srcdir)/configure $(CONFIGURE_FLAGS);
587endif
568 588
569# Don't erase these files if make is interrupted while refreshing them. 589# Don't erase these files if make is interrupted while refreshing them.
570.PRECIOUS: Makefile config.status 590.PRECIOUS: Makefile config.status
571 591
592# Note that calling config.status --recheck is insufficient on Android
593# due to the recursive calls to configure.
594
595ifneq ($(ANDROID),)
572config.status: ${srcdir}/configure 596config.status: ${srcdir}/configure
573 if [ -x ./config.status ]; then \ 597 $(CFG) $(srcdir)/configure $(CONFIGURE_FLAGS)
598else
599config.status: ${srcdir}/configure
600 if [ -x ./config.status ]; then \
574 $(CFG) ./config.status --recheck; \ 601 $(CFG) ./config.status --recheck; \
575 else \ 602 else \
576 $(CFG) $(srcdir)/configure $(CONFIGURE_FLAGS); \ 603 $(CFG) $(srcdir)/configure $(CONFIGURE_FLAGS); \
577 fi 604 fi
605endif
578 606
579$(srcdir)/configure: $(srcdir)/configure.ac $(srcdir)/m4/*.m4 607$(srcdir)/configure: $(srcdir)/configure.ac $(srcdir)/m4/*.m4
580 cd $(srcdir) && ./autogen.sh autoconf 608 cd $(srcdir) && ./autogen.sh autoconf
@@ -999,7 +1027,7 @@ mostlyclean: $(mostlyclean_dirs:=_mostlyclean)
999### with them. 1027### with them.
1000### 1028###
1001### Delete '.dvi' files here if they are not part of the distribution. 1029### Delete '.dvi' files here if they are not part of the distribution.
1002clean_dirs = $(mostlyclean_dirs) nextstep admin/charsets admin/unidata 1030clean_dirs = $(mostlyclean_dirs) java nextstep admin/charsets admin/unidata
1003 1031
1004$(foreach dir,$(clean_dirs),$(eval $(call submake_template,$(dir),clean))) 1032$(foreach dir,$(clean_dirs),$(eval $(call submake_template,$(dir),clean)))
1005 1033
diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index 99f834b0ae3..f5d3e69e79b 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -134,3 +134,5 @@ cp -- "$gnulib_srcdir"/lib/af_alg.h \
134 "$src"lib && 134 "$src"lib &&
135{ test -z "$src" || cd "$src"; } && 135{ test -z "$src" || cd "$src"; } &&
136./autogen.sh 136./autogen.sh
137
138echo "Please update the block of vpath statements in lib/Makefile.in"
diff --git a/configure.ac b/configure.ac
index 6e9b11986c7..ad2d306c649 100644
--- a/configure.ac
+++ b/configure.ac
@@ -26,6 +26,16 @@ dnl Note this is parsed by (at least) make-dist and lisp/cedet/ede/emacs.el.
26AC_INIT([GNU Emacs], [30.0.50], [bug-gnu-emacs@gnu.org], [], 26AC_INIT([GNU Emacs], [30.0.50], [bug-gnu-emacs@gnu.org], [],
27 [https://www.gnu.org/software/emacs/]) 27 [https://www.gnu.org/software/emacs/])
28 28
29if test "$XCONFIGURE" = "android"; then
30 # configure is being called recursively to configure Emacs for
31 # Android!
32 AC_MSG_NOTICE([called to recursively configure Emacs \
33for Android.])
34 # Set CC to ANDROID_CC, and CXX to ANDROID_CXX.
35 CC=$ANDROID_CC
36 CXX=$ANDROID_CXX
37fi
38
29dnl Set emacs_config_options to the options of 'configure', quoted for the shell, 39dnl Set emacs_config_options to the options of 'configure', quoted for the shell,
30dnl and then quoted again for a C string. Separate options with spaces. 40dnl and then quoted again for a C string. Separate options with spaces.
31dnl Add some environment variables, if they were passed via the environment 41dnl Add some environment variables, if they were passed via the environment
@@ -126,7 +136,25 @@ MAKE=$ac_cv_path_MAKE
126export MAKE 136export MAKE
127 137
128dnl Canonicalize the configuration name. 138dnl Canonicalize the configuration name.
139if test "$XCONFIGURE" = "android"; then
140 dnl Set host to whatever Android system Emacs is being configured
141 dnl for. Determine this by looking at the output of ANDROID_CC.
142
143 AC_MSG_CHECKING([the cross-compiler's target])
144 cc_target=`${CC} -v 2>&1 | sed -n 's/Target: //p'`
145 case "$cc_target" in
146 *android*) host_alias=$cc_target
147 ;;
148 *) AC_MSG_ERROR([The cross compiler does not compile for Android.
149Please verify that you specified the correct compiler in the ANDROID_CC
150and ANDROID_CXX variables when you ran configure.])
151 ;;
152 esac
153 AC_MSG_RESULT([$host_alias])
154fi
155
129AC_CANONICAL_HOST 156AC_CANONICAL_HOST
157AC_CANONICAL_BUILD
130 158
131case $host in 159case $host in
132 *-mingw*) 160 *-mingw*)
@@ -207,6 +235,13 @@ AC_ARG_WITH([all],
207 [with_features=$withval], 235 [with_features=$withval],
208 [with_features=yes]) 236 [with_features=yes])
209 237
238dnl ARCH_INDEPENDENT_CONFIG_FILES(FILE...)
239dnl Like AC_CONFIG_FILES(FILE). However, do not generate this
240dnl if configure is being called recursively in preparation
241dnl for cross-compilation.
242AC_DEFUN([ARCH_INDEPENDENT_CONFIG_FILES], [
243 AS_IF([test "$XCONFIGURE" != "android"], [AC_CONFIG_FILES([$1])])])
244
210dnl OPTION_DEFAULT_OFF(NAME, HELP-STRING) 245dnl OPTION_DEFAULT_OFF(NAME, HELP-STRING)
211dnl Create a new --with option that defaults to being disabled. 246dnl Create a new --with option that defaults to being disabled.
212dnl NAME is the base name of the option. The shell variable with_NAME 247dnl NAME is the base name of the option. The shell variable with_NAME
@@ -498,6 +533,7 @@ OPTION_DEFAULT_ON([threads],[don't compile with elisp threading support])
498OPTION_DEFAULT_OFF([cygwin32-native-compilation],[use native compilation on 32-bit Cygwin]) 533OPTION_DEFAULT_OFF([cygwin32-native-compilation],[use native compilation on 32-bit Cygwin])
499OPTION_DEFAULT_ON([xinput2],[don't use version 2 of the X Input Extension for input]) 534OPTION_DEFAULT_ON([xinput2],[don't use version 2 of the X Input Extension for input])
500OPTION_DEFAULT_OFF([small-ja-dic],[generate a smaller-size Japanese dictionary]) 535OPTION_DEFAULT_OFF([small-ja-dic],[generate a smaller-size Japanese dictionary])
536OPTION_DEFAULT_OFF([android],[cross-compile Android application package])
501 537
502AC_ARG_WITH([file-notification],[AS_HELP_STRING([--with-file-notification=LIB], 538AC_ARG_WITH([file-notification],[AS_HELP_STRING([--with-file-notification=LIB],
503 [use a file notification library (LIB one of: yes, inotify, kqueue, gfile, w32, no)])], 539 [use a file notification library (LIB one of: yes, inotify, kqueue, gfile, w32, no)])],
@@ -682,6 +718,237 @@ AC_ARG_ENABLE([build-details],
682 [test "$enableval" = no && BUILD_DETAILS=--no-build-details]) 718 [test "$enableval" = no && BUILD_DETAILS=--no-build-details])
683AC_SUBST([BUILD_DETAILS]) 719AC_SUBST([BUILD_DETAILS])
684 720
721# Start Android configuration. This is done in three steps:
722
723# First, the SDK tools needed to build the Android package on the host
724# are found.
725
726# Then, configure is called inside itself with the NDK C and C++
727# compilers, and the Makefiles generated, along with config.h, are
728# renamed to end with .android.
729
730# Finally, configure continues to configure the Emacs binary that will
731# run on the host.
732
733ANDROID=
734JAVAC=
735AAPT=
736JARSIGNER=
737ZIPALIGN=
738DX=
739ANDROID_JAR=
740ANDROID_ABI=
741
742# This is a list of Makefiles that have alternative versions for
743# Android.
744android_makefiles="lib/Makefile lib/gnulib.mk lib-src/Makefile src/Makefile"
745
746AC_ARG_VAR([JAVAC], [Java compiler path. Used for Android.])
747AC_ARG_VAR([JARSIGNER], [Java package signer path. Used for Android.])
748AC_ARG_VAR([SDK_BULD_TOOLS], [Path to the Android SDK build tools.])
749
750if test "$with_android" = "yes"; then
751 AC_MSG_ERROR([Please specify the path to the Android.jar file, like so:
752
753 ./configure --with-android=/path/to/android.jar
754
755along with the path to the SDK build-tools (this is the directory with
756tools such as aapt, dx, and aidl):
757
758 SDK_BUILD_TOOLS=/path/to/sdk-build-tools
759
760The cross-compiler should then be specified:
761
762 ANDROID_CC=/path/to/armv7a-linux-androideabi19-clang
763 ANDROID_CXX=/path/to/armv7a-linux-androideabi19-clang++])
764elif test "$with_android" = "no" || test "$with_android" = ""; then
765 ANDROID=no
766else
767 AC_CHECK_PROGS([JAVAC], [javac])
768 if test "$JAVAC" = ""; then
769 AC_MSG_ERROR([The Java compiler required to build Emacs was not found.
770Please make sure `javac' can be found on your path, or alternatively specify
771the path to your Java compiler before configuring Emacs, like so:
772
773 JAVAC=/opt/jdk/bin/javac ./configure --with-android])
774 fi
775 AC_CHECK_PROGS([JARSIGNER], [jarsigner])
776 if test "$JARSIGNER" = ""; then
777 AC_MSG_ERROR([The Java package signing utility was not found.
778Please make sure `jarsigner' can be found on your path, or alternatively
779specify its location before configuring Emacs, like so:
780
781 JARSIGNER=/opt/jdk/bin/jarsigner ./configure --with-android])
782 fi
783
784 AC_CACHE_CHECK([whether or not the Java compiler works],
785 [emacs_cv_working_javac],
786 AS_IF([rm -f conftest.class
787cat << EOF > conftest.java
788
789import android.app.Activity;
790import android.os.Bundle;
791
792class conftest extends Activity
793{
794 @Override
795 public void
796 onCreate (Bundle savedInstanceState)
797 {
798 super.onCreate (savedInstanceState);
799 }
800}
801
802EOF
803("$JAVAC" -classpath "$with_android" -target 1.7 -source 1.7 conftest.java \
804 -d . >&AS_MESSAGE_LOG_FD 2>&1) && test -s conftest.class && rm -f conftest.class],
805 [emacs_cv_working_javac=yes],
806 [emacs_cv_working_javac=no]))
807
808 if test "$emacs_cv_working_javac" = "no"; then
809 AC_MSG_ERROR([The Java compiler does not work, or you did not specify
810a valid path to android.jar. See config.log for more details.])
811 fi
812
813 ANDROID_JAR="$with_android"
814
815 AC_PATH_PROGS([AAPT], [aapt], [], "${SDK_BUILD_TOOLS}:$PATH")
816 if test "$AAPT" = ""; then
817 AC_MSG_ERROR([The Android asset packaging tool was not found.
818Please verify that the path to the SDK build tools you specified is correct])
819 fi
820
821 AC_PATH_PROGS([DX], [dx d8], [], "${SDK_BUILD_TOOLS}:$PATH")
822 if test "DX" = ""; then
823 AC_MSG_ERROR([The Android dexer was not found.
824Please verify that the path to the SDK build tools you specified is correct])
825 fi
826
827 AC_PATH_PROGS([ZIPALIGN], [zipalign], [], "${SDK_BUILD_TOOLS}:$PATH")
828 if test "ZIPALIGN" = ""; then
829 AC_MSG_ERROR([The Android ZIP archive alignment utility was not found.
830Please verify that the path to the SDK build tools you specified is correct]);
831 fi
832
833 dnl Now configure Emacs to generate binaries for Android. After the
834 dnl configuration completes, move the generated Makefiles.
835
836 if test "$ANDROID_CC" = "" || test "$ANDROID_CXX" = ""; then
837 AC_MSG_ERROR([Please specify the path to the Android cross-compiler
838for your machine. For example:
839
840 ANDROID_CC=/path/to/armv7a-linux-androideabi19-clang \\
841 ANDROID_CXX=/path/to/armv7a-linux-androideabi19-clang++ \\
842 ./configure --with-android])
843 fi
844
845 dnl Obtain the cross compiler's target to find out where binaries go
846 dnl in the resulting package.
847
848 AC_MSG_CHECKING([for the kind of Android system Emacs is being built for])
849 cc_target=`${ANDROID_CC} -v 2>&1 | sed -n 's/Target: //p'`
850 case "$cc_target" in
851 *i[3-6]86*) android_abi=x86
852 ;;
853 *x86_64*) android_abi=x86_64
854 ;;
855 *aarch64*) android_abi=arm64-v8a
856 ;;
857 *arm*v7a*) android_abi=armeabi-v7a
858 ;;
859 *mips*) android_abi=mips
860 ;;
861 *arm*) android_abi=armeabi
862 ;;
863 *) AC_MSG_ERROR([configure could not determine the type of Android \
864binary Emacs is being configured for. Please port this configure script \
865to your Android system, or verify that you specified the correct compiler \
866in the ANDROID_CC and ANDROID_CXX variables when you ran configure.])
867 ;;
868 esac
869 AC_MSG_RESULT([$android_abi])
870
871 ANDROID_ABI=$android_abi
872
873 # Save confdefs.h and config.log for now.
874 mv -f confdefs.h _confdefs.h
875 mv -f config.log _config.log
876
877 AS_IF([XCONFIGURE=android ANDROID_CC="$ANDROID_CC" \
878 ANDROID_CXX="$ANDROID_CXX" $0], [], [AC_MSG_ERROR([Failed to cross-\
879configure Emacs for android.])])
880
881 # Now set ANDROID to yes.
882 ANDROID=yes
883
884 for makefile in $android_makefiles; do
885 AC_MSG_NOTICE([Generating $makefile.android])
886 mv -f "$makefile" "$makefile.android"
887 done
888
889 AC_MSG_NOTICE([Generating src/config.h.android])
890 mv -f src/config.h src/config.h.android
891
892 # Move confdefs.h back now that the recursive call to configure is
893 # complete.
894 mv -f _confdefs.h confdefs.h
895
896 # Move the Android config.log to config.log.android. */
897 mv -f config.log config.log.android
898
899 # And _config.log back.
900 mv -f _config.log config.log
901fi
902
903AC_SUBST([ANDROID])
904AC_SUBST([JAVAC])
905AC_SUBST([AAPT])
906AC_SUBST([DX])
907AC_SUBST([ZIPALIGN])
908AC_SUBST([ANDROID_JAR])
909AC_SUBST([ANDROID_ABI])
910
911if test "$XCONFIGURE" = "android"; then
912 ANDROID=yes
913
914 # Enable cross compiling.
915 cross_compiling=yes
916fi
917
918AC_SUBST([XCONFIGURE])
919
920if test "$ANDROID" = "yes"; then
921 # When --with-android is specified, all build options must be
922 # disabled, both within the recursive invocation of configure and
923 # outside.
924 with_xpm=no
925 with_jpeg=no
926 with_tiff=no
927 with_gif=no
928 with_png=no
929 with_rsvg=no
930 with_webp=no
931 with_sqlite3=no
932 with_lcms2=no
933 with_libsystemd=no
934 with_cairo=no
935 with_xml2=no
936 with_imagemagick=no
937 with_json=no
938 with_tree_sitter=no
939 with_xft=no
940 with_harfbuzz=no
941 with_libotf=no
942 with_gpm=no
943 with_dbus=no
944 with_gsettings=no
945 with_selinx=no
946 with_gnutls=no
947 with_zlib=no
948 with_modules=no
949 with_threads=no
950fi
951
685dnl This used to use changequote, but, apart from 'changequote is evil' 952dnl This used to use changequote, but, apart from 'changequote is evil'
686dnl per the autoconf manual, we can speed up autoconf somewhat by quoting 953dnl per the autoconf manual, we can speed up autoconf somewhat by quoting
687dnl the great gob of text. Thus it's not processed for possible expansion. 954dnl the great gob of text. Thus it's not processed for possible expansion.
@@ -705,6 +972,11 @@ dnl quotation begins
705opsys='' unported=no 972opsys='' unported=no
706case "${canonical}" in 973case "${canonical}" in
707 974
975 ## Android
976 *linux-android* )
977 opsys=android
978 ;;
979
708 ## GNU/Linux and similar ports 980 ## GNU/Linux and similar ports
709 *-*-linux* ) 981 *-*-linux* )
710 opsys=gnu-linux 982 opsys=gnu-linux
@@ -871,6 +1143,7 @@ AC_DEFUN([_AC_PROG_CC_C89], [$2])
871 1143
872dnl Sets GCC=yes if using gcc. 1144dnl Sets GCC=yes if using gcc.
873AC_PROG_CC([gcc cc cl clang "$XCRUN gcc" "$XCRUN clang"]) 1145AC_PROG_CC([gcc cc cl clang "$XCRUN gcc" "$XCRUN clang"])
1146
874if test -n "$XCRUN"; then 1147if test -n "$XCRUN"; then
875 AC_CHECK_PROGS([AR], [ar "$XCRUN ar"]) 1148 AC_CHECK_PROGS([AR], [ar "$XCRUN ar"])
876 test -n "$AR" && export AR 1149 test -n "$AR" && export AR
@@ -1123,6 +1396,12 @@ AS_IF([test $gl_gcc_warnings = no],
1123 nw="$nw -Wsuggest-attribute=format" 1396 nw="$nw -Wsuggest-attribute=format"
1124 fi 1397 fi
1125 1398
1399 # If Emacs is being built for Android and many functions are
1400 # currently stubbed out for operation on the build machine, disable
1401 # -Wsuggest-attribute=noreturn.
1402
1403 nw="$nw -Wsuggest-attribute=noreturn"
1404
1126 gl_MANYWARN_ALL_GCC([ws]) 1405 gl_MANYWARN_ALL_GCC([ws])
1127 gl_MANYWARN_COMPLEMENT([ws], [$ws], [$nw]) 1406 gl_MANYWARN_COMPLEMENT([ws], [$ws], [$nw])
1128 for w in $ws; do 1407 for w in $ws; do
@@ -1143,6 +1422,8 @@ AS_IF([test $gl_gcc_warnings = no],
1143 gl_WARN_ADD([-Wno-null-pointer-arithmetic]) 1422 gl_WARN_ADD([-Wno-null-pointer-arithmetic])
1144 gl_WARN_ADD([-Wno-implicit-const-int-float-conversion]) 1423 gl_WARN_ADD([-Wno-implicit-const-int-float-conversion])
1145 gl_WARN_ADD([-Wno-int-in-bool-context]) 1424 gl_WARN_ADD([-Wno-int-in-bool-context])
1425 gl_WARN_ADD([-Wno-shift-overflow])
1426 gl_WARN_ADD([-Wno-bitwise-instead-of-logical])
1146 fi 1427 fi
1147 1428
1148 # This causes too much noise in the MinGW build 1429 # This causes too much noise in the MinGW build
@@ -1265,7 +1546,7 @@ else
1265 AM_DEFAULT_VERBOSITY=0 1546 AM_DEFAULT_VERBOSITY=0
1266fi 1547fi
1267AC_SUBST([AM_DEFAULT_VERBOSITY]) 1548AC_SUBST([AM_DEFAULT_VERBOSITY])
1268AC_CONFIG_FILES([src/verbose.mk]) 1549ARCH_INDEPENDENT_CONFIG_FILES([src/verbose.mk])
1269 1550
1270dnl Some other nice autoconf tests. 1551dnl Some other nice autoconf tests.
1271AC_PROG_INSTALL 1552AC_PROG_INSTALL
@@ -1762,7 +2043,10 @@ AC_SUBST([SYSTEM_TYPE])
1762pre_PKG_CONFIG_CFLAGS=$CFLAGS 2043pre_PKG_CONFIG_CFLAGS=$CFLAGS
1763pre_PKG_CONFIG_LIBS=$LIBS 2044pre_PKG_CONFIG_LIBS=$LIBS
1764 2045
1765PKG_PROG_PKG_CONFIG([0.9.0]) 2046dnl pkg-config does not work when cross-compiling for Android.
2047if test "${ANDROID}" != "yes"; then
2048 PKG_PROG_PKG_CONFIG([0.9.0])
2049fi
1766 2050
1767dnl EMACS_CHECK_MODULES([GSTUFF], [gtk+-2.0 >= 1.3 glib = 1.3.4]) 2051dnl EMACS_CHECK_MODULES([GSTUFF], [gtk+-2.0 >= 1.3 glib = 1.3.4])
1768dnl acts like PKG_CHECK_MODULES([GSTUFF], [gtk+-2.0 >= 1.3 glib = 1.3.4], 2052dnl acts like PKG_CHECK_MODULES([GSTUFF], [gtk+-2.0 >= 1.3 glib = 1.3.4],
@@ -1945,14 +2229,49 @@ AC_SUBST([AUTO_DEPEND])
1945 2229
1946window_system=none 2230window_system=none
1947 2231
2232ANDROID_OBJ=
2233ANDROID_LIBS=
2234ANDROID_CFLAGS=
2235CM_OBJ="cm.o"
2236
2237if test "${ANDROID}" = "yes"; then
2238 window_system=android
2239 no_x=yes
2240 ANDROID_OBJ="androidterm.o androidfns.o androidfont.o android.o"
2241 ANDROID_LIBS=
2242 CM_OBJ=
2243
2244 AC_DEFINE([HAVE_ANDROID], [1], [Define to 1 if Emacs is being built
2245with Android support])
2246
2247 if test "${XCONFIGURE}" != "android"; then
2248 AC_DEFINE([ANDROID_STUBIFY], [1], [Define to 1 if Emacs is being built
2249for Android, but all API calls need to be stubbed out])
2250 else
2251 # Emacs will be built as a shared library, and a wrapper around it
2252 # will also be built for the benefit of applications. This
2253 # requires Emacs be built as a position independent executable.
2254 ANDROID_CFLAGS="-fPIC -fvisibility=hidden"
2255
2256 # Link with libraries required for Android support.
2257 ANDROID_LIBS="-landroid -llog"
2258 fi
2259fi
2260
2261AC_SUBST(ANDROID)
2262AC_SUBST(ANDROID_OBJ)
2263AC_SUBST(ANDROID_LIBS)
2264AC_SUBST(ANDROID_CFLAGS)
2265
1948if test "${with_pgtk}" = "yes"; then 2266if test "${with_pgtk}" = "yes"; then
1949 window_system=pgtk 2267 window_system=pgtk
1950fi 2268fi
1951 2269
1952 2270if test "${ANDROID}" != "yes"; then
1953AC_PATH_X 2271 AC_PATH_X
1954if test "$no_x" != yes && test "${with_pgtk}" != "yes"; then 2272 if test "$no_x" != yes && test "${with_pgtk}" != "yes"; then
1955 window_system=x11 2273 window_system=x11
2274 fi
1956fi 2275fi
1957 2276
1958LD_SWITCH_X_SITE_RPATH= 2277LD_SWITCH_X_SITE_RPATH=
@@ -2276,7 +2595,6 @@ NTDIR=
2276LIBS_ECLIENT= 2595LIBS_ECLIENT=
2277LIB_WSOCK32= 2596LIB_WSOCK32=
2278NTLIB= 2597NTLIB=
2279CM_OBJ="cm.o"
2280XARGS_LIMIT= 2598XARGS_LIMIT=
2281if test "${HAVE_W32}" = "yes"; then 2599if test "${HAVE_W32}" = "yes"; then
2282 AC_DEFINE([HAVE_NTGUI], [1], [Define to use native MS Windows GUI.]) 2600 AC_DEFINE([HAVE_NTGUI], [1], [Define to use native MS Windows GUI.])
@@ -2439,7 +2757,11 @@ dnl use the toolkit if we have gtk, or X11R5 or newer.
2439 haiku ) 2757 haiku )
2440 term_header=haikuterm.h 2758 term_header=haikuterm.h
2441 ;; 2759 ;;
2760 android )
2761 term_header=androidterm.h
2762 ;;
2442esac 2763esac
2764
2443AC_SUBST([HAVE_PGTK]) 2765AC_SUBST([HAVE_PGTK])
2444 2766
2445if test "$window_system" = none && test "X$with_x" != "Xno"; then 2767if test "$window_system" = none && test "X$with_x" != "Xno"; then
@@ -2773,7 +3095,6 @@ fail;
2773 fi 3095 fi
2774fi 3096fi
2775 3097
2776
2777### Use -lrsvg-2 if available, unless '--with-rsvg=no' is specified. 3098### Use -lrsvg-2 if available, unless '--with-rsvg=no' is specified.
2778HAVE_RSVG=no 3099HAVE_RSVG=no
2779if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" \ 3100if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" \
@@ -4202,7 +4523,7 @@ AC_SUBST([HAVE_MODULES])
4202AC_SUBST([MODULES_SUFFIX]) 4523AC_SUBST([MODULES_SUFFIX])
4203AC_SUBST([MODULES_SECONDARY_SUFFIX]) 4524AC_SUBST([MODULES_SECONDARY_SUFFIX])
4204 4525
4205AC_CONFIG_FILES([src/emacs-module.h]) 4526ARCH_INDEPENDENT_CONFIG_FILES([src/emacs-module.h])
4206AC_SUBST_FILE([module_env_snippet_25]) 4527AC_SUBST_FILE([module_env_snippet_25])
4207AC_SUBST_FILE([module_env_snippet_26]) 4528AC_SUBST_FILE([module_env_snippet_26])
4208AC_SUBST_FILE([module_env_snippet_27]) 4529AC_SUBST_FILE([module_env_snippet_27])
@@ -5003,6 +5324,40 @@ getpwent endpwent getgrent endgrent \
5003renameat2 \ 5324renameat2 \
5004cfmakeraw cfsetspeed __executable_start log2 pthread_setname_np \ 5325cfmakeraw cfsetspeed __executable_start log2 pthread_setname_np \
5005pthread_set_name_np]) 5326pthread_set_name_np])
5327
5328if test "$ac_cv_func_cfmakeraw" != "yes"; then
5329 # On some systems (Android), cfmakeraw is inline, so AC_CHECK_FUNCS
5330 # cannot find it. Check if some code including termios.h and using
5331 # cfmakeraw builds.
5332 AC_CACHE_CHECK([whether cfmakeraw is inline],
5333 [emacs_cv_func_cfmakeraw_inline],
5334 [AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
5335 [[#include <termios.h>]],
5336 [[&cfmakeraw;]])],
5337 [emacs_cv_func_cfmakeraw_inline=yes],
5338 [emacs_cv_func_cfmakeraw_inline=no])])
5339
5340 if test "$emacs_cv_func_cfmakeraw_inline" = "yes"; then
5341 # Define HAVE_CFMAKERAW again.
5342 AC_DEFINE([HAVE_CFMAKERAW], [1])
5343 fi
5344fi
5345
5346if test "$ac_cv_func_cfsetspeed" != "yes"; then
5347 AC_CACHE_CHECK([whether cfsetspeed is inline],
5348 [emacs_cv_func_cfsetspeed_inline],
5349 [AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
5350 [[#include <termios.h>]],
5351 [[&cfsetspeed;]])],
5352 [emacs_cv_func_cfsetspeed_inline=yes],
5353 [emacs_cv_func_cfsetspeed_inline=no])])
5354
5355 if test "$emacs_cv_func_cfsetspeed_inline" = "yes"; then
5356 # Define HAVE_CFSETSPEED again.
5357 AC_DEFINE([HAVE_CFSETSPEED], [1])
5358 fi
5359fi
5360
5006LIBS=$OLD_LIBS 5361LIBS=$OLD_LIBS
5007 5362
5008if test "$ac_cv_func_pthread_setname_np" = "yes"; then 5363if test "$ac_cv_func_pthread_setname_np" = "yes"; then
@@ -5108,7 +5463,7 @@ AC_DEFUN([tputs_link_source], [
5108# than to expect to find it in ncurses. 5463# than to expect to find it in ncurses.
5109# Also we need tputs and friends to be able to build at all. 5464# Also we need tputs and friends to be able to build at all.
5110AC_CACHE_CHECK([for library containing tputs], [emacs_cv_tputs_lib], 5465AC_CACHE_CHECK([for library containing tputs], [emacs_cv_tputs_lib],
5111[if test "${opsys}" = "mingw32"; then 5466[if test "${opsys}" = "mingw32" || test "$opsys" = "android"; then
5112 emacs_cv_tputs_lib='none required' 5467 emacs_cv_tputs_lib='none required'
5113else 5468else
5114 # curses precedes termcap because of AIX (Bug#9736#35) and OpenIndiana. 5469 # curses precedes termcap because of AIX (Bug#9736#35) and OpenIndiana.
@@ -5175,7 +5530,7 @@ fail;
5175 fi 5530 fi
5176 ;; 5531 ;;
5177 5532
5178 mingw32) 5533 mingw32 | android)
5179 TERMINFO=no 5534 TERMINFO=no
5180 LIBS_TERMCAP= 5535 LIBS_TERMCAP=
5181 ;; 5536 ;;
@@ -5729,7 +6084,7 @@ case $opsys in
5729 AC_DEFINE([FIRST_PTY_LETTER], ['p']) 6084 AC_DEFINE([FIRST_PTY_LETTER], ['p'])
5730 ;; 6085 ;;
5731 6086
5732 gnu-linux | gnu-kfreebsd | dragonfly | freebsd | openbsd | netbsd | darwin | nacl ) 6087 gnu-linux | gnu-kfreebsd | dragonfly | freebsd | openbsd | netbsd | darwin | nacl | android )
5733 dnl if HAVE_GRANTPT 6088 dnl if HAVE_GRANTPT
5734 if test "x$ac_cv_func_grantpt" = xyes; then 6089 if test "x$ac_cv_func_grantpt" = xyes; then
5735 AC_DEFINE([UNIX98_PTYS], [1], [Define if the system has Unix98 PTYs.]) 6090 AC_DEFINE([UNIX98_PTYS], [1], [Define if the system has Unix98 PTYs.])
@@ -6656,6 +7011,7 @@ AC_DEFINE_UNQUOTED([EMACS_CONFIG_FEATURES], ["${emacs_config_features}"],
6656 [Summary of some of the main features enabled by configure.]) 7011 [Summary of some of the main features enabled by configure.])
6657 7012
6658AS_ECHO([" Does Emacs use -lXaw3d? ${HAVE_XAW3D} 7013AS_ECHO([" Does Emacs use -lXaw3d? ${HAVE_XAW3D}
7014 Does Emacs use Android? ${ANDROID}
6659 Does Emacs use -lXpm? ${HAVE_XPM} 7015 Does Emacs use -lXpm? ${HAVE_XPM}
6660 Does Emacs use -ljpeg? ${HAVE_JPEG} 7016 Does Emacs use -ljpeg? ${HAVE_JPEG}
6661 Does Emacs use -ltiff? ${HAVE_TIFF} 7017 Does Emacs use -ltiff? ${HAVE_TIFF}
@@ -6759,12 +7115,15 @@ fi
6759AC_CONFIG_FILES([Makefile lib/gnulib.mk]) 7115AC_CONFIG_FILES([Makefile lib/gnulib.mk])
6760 7116
6761dnl config.status treats $srcdir specially, so I think this is ok... 7117dnl config.status treats $srcdir specially, so I think this is ok...
6762AC_CONFIG_FILES([$srcdir/doc/man/emacs.1]) 7118ARCH_INDEPENDENT_CONFIG_FILES([$srcdir/doc/man/emacs.1])
6763 7119
6764m4_define([subdir_makefiles], 7120AC_CONFIG_FILES([lib/Makefile lib-src/Makefile oldXMenu/Makefile src/Makefile
6765 [lib/Makefile lib-src/Makefile oldXMenu/Makefile doc/emacs/Makefile doc/misc/Makefile doc/lispintro/Makefile doc/lispref/Makefile src/Makefile lwlib/Makefile lisp/Makefile leim/Makefile nextstep/Makefile nt/Makefile]) 7121 lwlib/Makefile nextstep/Makefile nt/Makefile])
6766SUBDIR_MAKEFILES="subdir_makefiles" 7122ARCH_INDEPENDENT_CONFIG_FILES([doc/emacs/Makefile doc/misc/Makefile
6767AC_CONFIG_FILES(subdir_makefiles) 7123 doc/lispintro/Makefile doc/lispref/Makefile
7124 lisp/Makefile leim/Makefile])
7125
7126SUBDIR_MAKEFILES="lib/Makefile lib-src/Makefile oldXMenu/Makefile src/Makefile lwlib/Makefile nextstep/Makefile nt/Makefile doc/emacs/Makefile doc/misc/Makefile doc/lispintro/Makefile doc/lispref/Makefile lisp/Makefile leim/Makefile"
6768 7127
6769dnl The test/ directory is missing if './make-dist --no-tests' was used. 7128dnl The test/ directory is missing if './make-dist --no-tests' was used.
6770opt_makefile=test/Makefile 7129opt_makefile=test/Makefile
@@ -6772,24 +7131,31 @@ if test -f "$srcdir/$opt_makefile.in"; then
6772 SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES $opt_makefile" 7131 SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES $opt_makefile"
6773 dnl Again, it's best not to use a variable. Though you can add 7132 dnl Again, it's best not to use a variable. Though you can add
6774 dnl ", [], [opt_makefile='$opt_makefile']" and it should work. 7133 dnl ", [], [opt_makefile='$opt_makefile']" and it should work.
6775 AC_CONFIG_FILES([test/Makefile]) 7134 ARCH_INDEPENDENT_CONFIG_FILES([test/Makefile])
6776 AC_CONFIG_FILES([test/manual/noverlay/Makefile]) 7135 ARCH_INDEPENDENT_CONFIG_FILES([test/manual/noverlay/Makefile])
6777fi 7136fi
6778opt_makefile=test/infra/Makefile 7137opt_makefile=test/infra/Makefile
6779if test -f "$srcdir/$opt_makefile.in"; then 7138if test -f "$srcdir/$opt_makefile.in"; then
6780 SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES $opt_makefile" 7139 SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES $opt_makefile"
6781 dnl Again, it's best not to use a variable. Though you can add 7140 dnl Again, it's best not to use a variable. Though you can add
6782 dnl ", [], [opt_makefile='$opt_makefile']" and it should work. 7141 dnl ", [], [opt_makefile='$opt_makefile']" and it should work.
6783 AC_CONFIG_FILES([test/infra/Makefile]) 7142 ARCH_INDEPENDENT_CONFIG_FILES([test/infra/Makefile])
7143fi
7144
7145if test "$ANDROID" = "yes"; then
7146 SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES java/Makefile"
6784fi 7147fi
6785 7148
7149if test "$XCOMPILE" = "yes"; then
7150 SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES xcompile/Makefile"
7151fi
6786 7152
6787dnl The admin/ directory used to be excluded from tarfiles. 7153dnl The admin/ directory used to be excluded from tarfiles.
6788if test -d $srcdir/admin; then 7154if test -d $srcdir/admin; then
6789 SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES admin/charsets/Makefile admin/unidata/Makefile admin/grammars/Makefile" 7155 SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES admin/charsets/Makefile admin/unidata/Makefile admin/grammars/Makefile"
6790 AC_CONFIG_FILES([admin/charsets/Makefile]) 7156 ARCH_INDEPENDENT_CONFIG_FILES([admin/charsets/Makefile])
6791 AC_CONFIG_FILES([admin/unidata/Makefile]) 7157 ARCH_INDEPENDENT_CONFIG_FILES([admin/unidata/Makefile])
6792 AC_CONFIG_FILES([admin/grammars/Makefile]) 7158 ARCH_INDEPENDENT_CONFIG_FILES([admin/grammars/Makefile])
6793fi dnl -d admin 7159fi dnl -d admin
6794 7160
6795 7161
@@ -6800,65 +7166,75 @@ AC_SUBST([SUBDIR_MAKEFILES_IN])
6800SMALL_JA_DIC=$with_small_ja_dic 7166SMALL_JA_DIC=$with_small_ja_dic
6801AC_SUBST([SMALL_JA_DIC]) 7167AC_SUBST([SMALL_JA_DIC])
6802 7168
6803dnl You might wonder (I did) why epaths.h is generated by running make, 7169dnl The following commands are run on the host system when building
6804dnl rather than just letting configure generate it from epaths.in. 7170dnl Emacs.
6805dnl One reason is that the various paths are not fully expanded (see above); 7171
6806dnl e.g., gamedir='${localstatedir}/games/emacs'. 7172if test "$XCONFIGURE" != "android"; then
6807dnl Secondly, the GNU Coding standards require that one should be able 7173 dnl You might wonder (I did) why epaths.h is generated by running
6808dnl to run 'make prefix=/some/where/else' and override the values set 7174 dnl make, rather than just letting configure generate it from
6809dnl by configure. This also explains the 'move-if-change' test and 7175 dnl epaths.in. One reason is that the various paths are not fully
6810dnl the use of force in the 'epaths-force' rule in Makefile.in. 7176 dnl expanded (see above); e.g.,
6811AC_CONFIG_COMMANDS([src/epaths.h], [ 7177 dnl gamedir='${localstatedir}/games/emacs'. Secondly, the GNU
6812if test "${opsys}" = "mingw32"; then 7178 dnl Coding standards require that one should be able to run 'make
6813 ${MAKE-make} MAKEFILE_NAME=do-not-make-Makefile epaths-force-w32 7179 dnl prefix=/some/where/else' and override the values set by
6814elif test "$HAVE_NS" = "yes" && test "$EN_NS_SELF_CONTAINED" = "yes"; then 7180 dnl configure. This also explains the 'move-if-change' test and the
6815 ${MAKE-make} MAKEFILE_NAME=do-not-make-Makefile epaths-force-ns-self-contained 7181 dnl use of force in the 'epaths-force' rule in Makefile.in.
6816else 7182 AC_CONFIG_COMMANDS([src/epaths.h], [
6817 ${MAKE-make} MAKEFILE_NAME=do-not-make-Makefile epaths-force 7183 if test "${opsys}" = "mingw32"; then
6818fi || AC_MSG_ERROR(['src/epaths.h' could not be made.]) 7184 ${MAKE-make} MAKEFILE_NAME=do-not-make-Makefile epaths-force-w32
6819], [GCC="$GCC" CPPFLAGS="$CPPFLAGS" opsys="$opsys" HAVE_NS="$HAVE_NS" 7185 elif test "$HAVE_NS" = "yes" && test "$EN_NS_SELF_CONTAINED" = "yes"; then
6820 EN_NS_SELF_CONTAINED="$EN_NS_SELF_CONTAINED"]) 7186 ${MAKE-make} MAKEFILE_NAME=do-not-make-Makefile epaths-force-ns-self-contained
6821 7187 else
6822dnl NB we have to cheat and use the ac_... version because abs_top_srcdir 7188 ${MAKE-make} MAKEFILE_NAME=do-not-make-Makefile epaths-force
6823dnl is not yet set, sigh. Or we could use ../$srcdir/src/.gdbinit, 7189 fi || AC_MSG_ERROR(['src/epaths.h' could not be made.])
6824dnl or a symlink? 7190 ], [GCC="$GCC" CPPFLAGS="$CPPFLAGS" opsys="$opsys" HAVE_NS="$HAVE_NS"
6825AC_CONFIG_COMMANDS([src/.gdbinit], [ 7191 EN_NS_SELF_CONTAINED="$EN_NS_SELF_CONTAINED"])
6826if test ! -f src/.gdbinit && test -f "$srcdir/src/.gdbinit"; then 7192
6827 AS_ECHO(["source $ac_abs_top_srcdir/src/.gdbinit"]) > src/.gdbinit 7193 dnl NB we have to cheat and use the ac_... version because abs_top_srcdir
6828fi 7194 dnl is not yet set, sigh. Or we could use ../$srcdir/src/.gdbinit,
6829]) 7195 dnl or a symlink?
7196 AC_CONFIG_COMMANDS([src/.gdbinit], [
7197 if test ! -f src/.gdbinit && test -f "$srcdir/src/.gdbinit"; then
7198 AS_ECHO(["source $ac_abs_top_srcdir/src/.gdbinit"]) > src/.gdbinit
7199 fi
7200 ])
6830 7201
6831dnl Perhaps this would be better named doc-emacs-emacsver.texi? 7202 dnl Perhaps this would be better named doc-emacs-emacsver.texi?
6832dnl See comments for etc-refcards-emacsver.tex. 7203 dnl See comments for etc-refcards-emacsver.tex.
6833dnl Since we get a doc/emacs directory generated anyway, for the Makefile, 7204 dnl Since we get a doc/emacs directory generated anyway, for the Makefile,
6834dnl it is not quite the same. But we are generating in $srcdir. 7205 dnl it is not quite the same. But we are generating in $srcdir.
6835AC_CONFIG_COMMANDS([doc/emacs/emacsver.texi], [ 7206 AC_CONFIG_COMMANDS([doc/emacs/emacsver.texi], [
6836${MAKE-make} -s --no-print-directory -C doc/emacs doc-emacsver || \ 7207 ${MAKE-make} -s --no-print-directory -C doc/emacs doc-emacsver || \
6837AC_MSG_ERROR(['doc/emacs/emacsver.texi' could not be made.]) 7208 AC_MSG_ERROR(['doc/emacs/emacsver.texi' could not be made.])
6838]) 7209 ])
6839 7210
6840dnl If we give this the more natural name, etc/refcards/emacsver.texi, 7211 dnl If we give this the more natural name, etc/refcards/emacsver.texi,
6841dnl then a directory etc/refcards is created in the build directory, 7212 dnl then a directory etc/refcards is created in the build directory,
6842dnl which is probably harmless, but confusing (in out-of-tree builds). 7213 dnl which is probably harmless, but confusing (in out-of-tree builds).
6843dnl (If we were to generate etc/refcards/Makefile, this might change.) 7214 dnl (If we were to generate etc/refcards/Makefile, this might change.)
6844dnl It is really $srcdir/etc/refcards/emacsver.tex that we generate. 7215 dnl It is really $srcdir/etc/refcards/emacsver.tex that we generate.
6845AC_CONFIG_COMMANDS([etc-refcards-emacsver.tex], [ 7216 AC_CONFIG_COMMANDS([etc-refcards-emacsver.tex], [
6846${MAKE-make} -s MAKEFILE_NAME=do-not-make-Makefile etc-emacsver || \ 7217 ${MAKE-make} -s MAKEFILE_NAME=do-not-make-Makefile etc-emacsver || \
6847AC_MSG_ERROR(['etc/refcards/emacsver.tex' could not be made.]) 7218 AC_MSG_ERROR(['etc/refcards/emacsver.tex' could not be made.])
6848]) 7219 ])
6849 7220
6850if test $AUTO_DEPEND = yes; then
6851 for dir in $AUTODEPEND_PARENTS; do
6852 AS_MKDIR_P([$dir/deps])
6853 done
6854fi
6855if $gl_gnulib_enabled_dynarray || $gl_gnulib_enabled_scratch_buffer; then
6856 AS_MKDIR_P([lib/malloc])
6857 if test $AUTO_DEPEND = yes; then 7221 if test $AUTO_DEPEND = yes; then
6858 AS_MKDIR_P([lib/deps/malloc]) 7222 for dir in $AUTODEPEND_PARENTS; do
7223 AS_MKDIR_P([$dir/deps])
7224 done
7225 fi
7226 if $gl_gnulib_enabled_dynarray || $gl_gnulib_enabled_scratch_buffer; then
7227 AS_MKDIR_P([lib/malloc])
7228 if test $AUTO_DEPEND = yes; then
7229 AS_MKDIR_P([lib/deps/malloc])
7230 fi
6859 fi 7231 fi
6860fi 7232fi
6861 7233
7234# Make java/Makefile
7235ARCH_INDEPENDENT_CONFIG_FILES([java/Makefile])
7236ARCH_INDEPENDENT_CONFIG_FILES([xcompile/Makefile])
7237
6862AC_OUTPUT 7238AC_OUTPUT
6863 7239
6864if test ! "$with_mailutils"; then 7240if test ! "$with_mailutils"; then
diff --git a/etc/DEBUG b/etc/DEBUG
index 01c75f8da7a..2fe2fbc2ce3 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -1094,6 +1094,30 @@ Please refer to the LLDB reference on the web for more information
1094about LLDB. If you already know GDB, you will also find a mapping 1094about LLDB. If you already know GDB, you will also find a mapping
1095from GDB commands to corresponding LLDB commands there. 1095from GDB commands to corresponding LLDB commands there.
1096 1096
1097** Debugging Emacs on Android.
1098
1099Attaching GDB to Emacs running inside the Android application setup
1100requires a special script found in the java/ directory, and a suitable
1101GDB server binary to be present on the Android device, which is
1102present on the free versions of Android. Connecting to the device
1103also requires the `adb' (Android Debug Bridge) utility, and telling
1104the Android system to resume the Emacs process after startup requires
1105the Java debugger (jdb).
1106
1107If all three of those tools are present, simply run (from the Emacs
1108source directory):
1109
1110 ../java/debug.sh -- [any extra arguments you wish to pass to gdb]
1111
1112After which, upon waiting a while, the GDB prompt will show up.
1113
1114If Emacs crashes and "JNI ERROR" shows up in the Android system log,
1115then placing a breakpoint on:
1116
1117 break art::JavaVMExt::JniAbort
1118
1119will let you find the source of the crash.
1120
1097 1121
1098This file is part of GNU Emacs. 1122This file is part of GNU Emacs.
1099 1123
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
new file mode 100644
index 00000000000..75aa5bdf409
--- /dev/null
+++ b/java/AndroidManifest.xml
@@ -0,0 +1,54 @@
1<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2 package="org.gnu.emacs" android:installLocation="auto">
3
4 <!-- Paste in every permission in existence so Emacs can do
5 anything. -->
6
7 <uses-permission android:name="android.permission.READ_CONTACTS" />
8 <uses-permission android:name="android.permission.WRITE_CONTACTS" />
9 <uses-permission android:name="android.permission.VIBRATE" />
10 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
11 <uses-permission android:name="android.permission.INTERNET" />
12 <uses-permission android:name="android.permission.SET_WALLPAPER" />
13 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
14 <uses-permission android:name="android.permission.SEND_SMS" />
15 <uses-permission android:name="android.permission.RECEIVE_SMS" />
16 <uses-permission android:name="android.permission.RECEIVE_MMS"/>
17 <uses-permission android:name="android.permission.WRITE_SMS"/>
18 <uses-permission android:name="android.permission.READ_SMS"/>
19 <uses-permission android:name="android.permission.NFC" />
20 <uses-permission android:name="android.permission.TRANSMIT_IR" />
21 <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
22 <uses-permission android:name="android.permission.WAKE_LOCK"/>
23 <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
24 <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
25 <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>
26 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
27 <uses-permission android:name="android.permission.RECORD_AUDIO" />
28 <uses-permission android:name="android.permission.CAMERA" />
29
30 <uses-sdk android:minSdkVersion="7"
31 android:targetSdkVersion="28"/>
32
33 <application android:name="org.gnu.emacs.EmacsApplication"
34 android:label="GNU Emacs"
35 android:hardwareAccelerated="true"
36 android:supportsRtl="true"
37 android:theme="@android:style/Theme"
38 android:debuggable="true"
39 android:extractNativeLibs="true">
40 <activity android:name="org.gnu.emacs.EmacsActivity">
41 <intent-filter>
42 <action android:name="android.intent.action.MAIN" />
43 <category android:name="android.intent.category.DEFAULT" />
44 <category android:name="android.intent.category.LAUNCHER" />
45 </intent-filter>
46 </activity>
47
48 <service android:name="org.gnu.emacs.EmacsService"
49 android:directBootAware="false"
50 android:enabled="true"
51 android:exported="false"
52 android:label="GNU Emacs service"/>
53 </application>
54</manifest>
diff --git a/java/Makefile.in b/java/Makefile.in
new file mode 100644
index 00000000000..e9fcc625cb2
--- /dev/null
+++ b/java/Makefile.in
@@ -0,0 +1,150 @@
1### @configure_input@
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
10# (at 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
20top_builddir = @top_builddir@
21
22-include ${top_builddir}/src/verbose.mk
23
24SHELL = @SHELL@
25JAVAC = @JAVAC@
26AAPT = @AAPT@
27DX = @DX@
28ZIPALIGN = @ZIPALIGN@
29JARSIGNER = @JARSIGNER@
30ANDROID_JAR = @ANDROID_JAR@
31ANDROID_ABI = @ANDROID_ABI@
32
33WARN_JAVAFLAGS = -Xlint:deprecation
34JAVAFLAGS = -classpath "$(ANDROID_JAR):." -target 1.7 -source 1.7 \
35 $(WARN_JAVAFLAGS)
36
37SIGN_EMACS = -keystore emacs.keystore -storepass emacs1
38
39JAVA_FILES = $(shell find . -type f -name *.java)
40CLASS_FILES = $(foreach file,$(JAVA_FILES),$(basename $(file)).class)
41
42# How this stuff works.
43
44# emacs.apk depends on emacs.apk-in, which is simply a ZIP archive
45# containing the following files:
46# lib/$(ANDROID_ABI)/libemacs.so
47# lib/$(ANDROID_ABI)/libandroid-emacs.so
48# lib/$(ANDROID_ABI)/libctags.so
49# lib/$(ANDROID_ABI)/libhexl.so
50# lib/$(ANDROID_ABI)/libmovemail.so
51# lib/$(ANDROID_ABI)/librcs2log.so
52# lib/$(ANDROID_ABI)/libebrowse.so
53# assets/info/
54# assets/etc/
55# assets/lisp/
56
57.PHONY: emacs.apk-in all
58all: emacs.apk
59
60# Binaries to cross-compile.
61CROSS_BINS = ../xcompile/src/android-emacs ../xcompile/lib-src/ctags \
62 ../xcompile/lib-src/hexl ../xcompile/lib-src/movemail \
63 ../xcompile/lib-src/ebrowse
64
65# Libraries to cross-compile.
66CROSS_LIBS = ../xcompile/src/libemacs.so
67
68.PHONY: $(CROSS_BINS) $(CROSS_LIBS)
69
70../xcompile/src/android-emacs ../xcompile/src/libemacs.so:
71 make -C ../xcompile src/$(notdir $@)
72
73../xcompile/lib-src/hexl ../xcompile/lib-src/movemail \
74../xcompile/lib-src/ctags ../xcompile/lib-src/ebrowse &:
75 make -C ../xcompile lib-src/$(notdir $@)
76
77emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) AndroidManifest.xml
78# Make the working directory for this stuff
79 rm -rf install_temp
80 mkdir -p install_temp/lib/$(ANDROID_ABI)
81 mkdir -p install_temp/assets/etc
82 mkdir -p install_temp/assets/lisp
83 mkdir -p install_temp/assets/info
84# Install architecture independents to assets/etc and assets/lisp
85 cp -r $(top_builddir)/lisp install_temp/assets
86 cp -r $(top_builddir)/etc install_temp/assets
87# Remove undesirable files from those directories.
88 for subdir in `find install_temp -type d -print`; do \
89 chmod a+rx $${subdir} ; \
90 rm -rf $${subdir}/.gitignore ; \
91 rm -rf $${subdir}/.DS_Store ; \
92 rm -rf $${subdir}/#* ; \
93 rm -rf $${subdir}/.#* ; \
94 rm -rf $${subdir}/*~ ; \
95 rm -rf $${subdir}/*.orig ; \
96 rm -rf $${subdir}/ChangeLog* ; \
97 rm -rf $${subdir}/[mM]akefile*[.-]in ; \
98 rm -rf $${subdir}/Makefile; \
99 done
100# Install architecture dependents to lib/$(ANDROID_ABI). This
101# perculiar naming scheme is required to make Android preserve these
102# binaries upon installation.
103 for file in $(CROSS_BINS); do \
104 if [ -x $$file ]; then \
105 filename=`basename $$file`; \
106 cp -f $$file install_temp/lib/$(ANDROID_ABI)/lib$${filename}.so; \
107 fi \
108 done
109 for file in $(CROSS_LIBS); do \
110 if [ -x $$file ]; then \
111 cp -f $$file install_temp/lib/$(ANDROID_ABI); \
112 fi \
113 done
114# Package everything.
115 $(AAPT) package -I "$(ANDROID_JAR)" -F $@ -f -M AndroidManifest.xml
116 pushd install_temp; $(AAPT) add ../$@ `find lib -type f`; popd
117 pushd install_temp; $(AAPT) add ../$@ `find assets -type f`; popd
118 rm -rf install_temp
119
120.SUFFIXES: .java .class
121.java.class &:
122 $(AM_V_JAVAC) $(JAVAC) $(JAVAFLAGS) $<
123
124# N.B. that find must be called all over again in case javac generated
125# nested classes.
126
127classes.dex: $(CLASS_FILES)
128 $(AM_V_DX) $(DX) --classpath $(ANDROID_JAR) \
129 $(subst $$,\$$,$(shell find . -type f -name *.class))
130
131# When emacs.keystore expires, regenerate it with:
132#
133# keytool -genkey -v -keystore emacs.keystore -alias "Emacs keystore" \
134# -keyalg RSA -sigalg SHA1withRSA -keysize 2048 -validity 100000
135
136.PHONY: clean maintainer-clean
137
138emacs.apk: classes.dex emacs.apk-in emacs.keystore
139 cp -f emacs.apk-in $@.unaligned
140 $(AAPT) add $@.unaligned classes.dex
141 $(JARSIGNER) $(SIGN_EMACS) $@.unaligned "Emacs keystore"
142 $(ZIPALIGN) -f 4 $@.unaligned $@
143 rm -f $@.unaligned
144
145clean:
146 rm -f emacs.apk emacs.apk-in *.dex *.unaligned *.class
147 rm -rf install-temp
148 find . -name '*.class' -delete
149
150maintainer-clean: clean
diff --git a/java/README b/java/README
new file mode 100644
index 00000000000..50c2332ce95
--- /dev/null
+++ b/java/README
@@ -0,0 +1,6 @@
1This directory holds the Java sources of the port of GNU Emacs to
2Android-like systems.
3
4Please keep the Java code indented with tabs and formatted according
5to the rules for C code in the GNU coding standards. Always use
6C-style comments.
diff --git a/java/debug.sh b/java/debug.sh
new file mode 100755
index 00000000000..dd710dc31af
--- /dev/null
+++ b/java/debug.sh
@@ -0,0 +1,242 @@
1#!/bin/bash
2### Run Emacs under GDB or JDB on Android.
3
4## Copyright (C) 2023 Free Software Foundation, Inc.
5
6## This file is part of GNU Emacs.
7
8## GNU Emacs is free software: you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation, either version 3 of the License, or
11## (at your option) any later version.
12
13## GNU Emacs is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16## GNU General Public License for more details.
17
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/>.
20
21set -m
22oldpwd=`pwd`
23cd `dirname $0`
24
25devices=`adb devices | grep device | awk -- '/device\y/ { print $1 }' -`
26device=
27progname=$0
28package=org.gnu.emacs
29activity=org.gnu.emacs.EmacsActivity
30gdb_port=5039
31jdb_port=64013
32jdb=no
33
34while [ $# -gt 0 ]; do
35 case "$1" in
36 ## This option specifies the serial number of a device to use.
37 "--device" )
38 device="$2"
39 if [ -z device ]; then
40 echo "You must specify an argument to --device"
41 exit 1
42 fi
43 ;;
44 "--help" )
45 echo "Usage: $progname [options] -- [gdb options]"
46 echo ""
47 echo " --device DEVICE run Emacs on the specified device"
48 echo " --port PORT run the GDB server on a specific port"
49 echo " --jdb-port PORT run the JDB server on a specific port"
50 echo " --jdb run JDB instead of GDB"
51 echo " --help print this message"
52 echo ""
53 echo "Available devices:"
54 for device in $devices; do
55 echo " " $device
56 done
57 echo ""
58 exit 0
59 ;;
60 "--jdb" )
61 jdb=yes
62 ;;
63 "--port" )
64 gdb_port=$1
65 ;;
66 "--" )
67 shift
68 gdbargs=$@
69 break;
70 ;;
71 * )
72 echo "$progname: Unrecognized argument $1"
73 exit 1
74 ;;
75 esac
76 shift
77done
78
79if [ -z $devices ]; then
80 echo "No devices are available."
81 exit 1
82fi
83
84if [ -z $device ]; then
85 device=$devices
86fi
87
88if [ `wc -w <<< "$devices"` -gt 1 ] && [ -z device ]; then
89 echo "Multiple devices are available. Please pick one using"
90 echo "--device and try again."
91fi
92
93echo "Looking for $package on device $device"
94
95# Find the application data directory
96app_data_dir=`adb -s $device shell run-as $package sh -c 'pwd 2> /dev/null'`
97
98if [ -z $app_data_dir ]; then
99 echo "The data directory for the package $package was not found."
100 echo "Is it installed?"
101fi
102
103echo "Found application data directory at $app_data_dir..."
104
105# Find which PIDs are associated with org.gnu.emacs
106package_uid=`adb -s $device shell run-as $package id -u`
107
108if [ -z $package_uid ]; then
109 echo "Failed to obtain UID of packages named $package"
110 exit 1
111fi
112
113# First, run ps -u $package_uid -o PID,CMD to fetch the list of
114# process IDs.
115package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD`
116
117# Next, remove lines matching "ps" itself.
118package_pids=`awk -- '{
119 if (!match ($0, /(PID|ps)/))
120 print $1
121}' <<< $package_pids`
122
123# Finally, kill each existing process.
124for pid in $package_pids; do
125 echo "Killing existing process $pid..."
126 adb -s $device shell run-as $package kill -9 $pid &> /dev/null
127done
128
129# Now run the main activity. This must be done as the adb user and
130# not as the package user.
131echo "Starting activity $activity and attaching debugger"
132
133# Exit if the activity could not be started.
134adb -s $device shell am start -D "$package/$activity"
135if [ ! $? ]; then
136 exit 1;
137fi
138
139# Now look for processes matching the package again.
140package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD`
141
142# Next, remove lines matching "ps" itself.
143package_pids=`awk -- '{
144 if (!match ($0, /(PID|ps)/))
145 print $1
146}' <<< $package_pids`
147
148pid=$package_pids
149num_pids=`wc -w <<< "$package_pids"`
150
151if [ $num_pids -gt 1 ]; then
152 echo "More than one process was started:"
153 echo ""
154 adb -s $device shell run-as $package ps -u $package_uid | awk -- '{
155 if (!match ($0, /ps/))
156 print $0
157 }'
158 echo ""
159 printf "Which one do you want to attach to? "
160 read pid
161elif [ -z $package_pids ]; then
162 echo "No processes were found to attach to."
163 exit 1
164fi
165
166# Start JDB to make the wait dialog disappear.
167echo "Attaching JDB to unblock the application."
168adb -s $device forward --remove-all
169adb -s $device forward "tcp:$jdb_port" "jdwp:$pid"
170
171if [ ! $? ]; then
172 echo "Failed to forward jdwp:$pid to $jdb_port!"
173 echo "Perhaps you need to specify a different port with --port?"
174 exit 1;
175fi
176
177jdb_command="jdb -connect \
178 com.sun.jdi.SocketAttach:hostname=localhost,port=$jdb_port"
179
180if [ $jdb = "yes" ]; then
181 # Just start JDB and then exit
182 $jdb_command
183 exit 1
184fi
185
186exec 4<> /tmp/file-descriptor-stamp
187
188# Now run JDB with IO redirected to file descriptor 4 in a subprocess.
189$jdb_command <&4 >&4 &
190
191character=
192# Next, wait until the prompt is found.
193while read -n1 -u 4 character; do
194 if [ "$character" = ">" ]; then
195 echo "JDB attached successfully"
196 break;
197 fi
198done
199
200# Now start gdbserver on the device asynchronously.
201
202echo "Attaching gdbserver to $pid on $device..."
203exec 5<> /tmp/file-descriptor-stamp
204adb -s $device shell run-as $package /system/bin/gdbserver --once \
205 "+debug.$package_uid.socket" --attach $pid >&5 &
206
207# Wait until gdbserver successfully runs.
208line=
209while read -u 5 line; do
210 case "$line" in
211 *Attached* )
212 break;
213 ;;
214 *error* | *Error* | failed )
215 echo $line
216 exit 1
217 ;;
218 * )
219 ;;
220 esac
221done
222
223# Send EOF to JDB to make it go away. This will also cause Android to
224# allow Emacs to continue executing.
225echo "Making JDB go away..."
226echo "exit" >&4
227read -u 4 line
228echo "JDB has gone away with $line"
229
230# Forward the gdb server port here.
231adb -s $device forward "tcp:$gdb_port" \
232 "localfilesystem:$app_data_dir/debug.$package_uid.socket"
233if [ ! $? ]; then
234 echo "Failed to forward $app_data_dir/debug.$package_uid.socket"
235 echo "to $gdb_port! Perhaps you need to specify a different port"
236 echo "with --port?"
237 exit 1;
238fi
239
240# Finally, start gdb with any extra arguments needed.
241cd "$oldpwd"
242gdb --eval-command "" --eval-command "target remote localhost:$gdb_port" $gdbargs
diff --git a/java/emacs.keystore b/java/emacs.keystore
new file mode 100644
index 00000000000..76d80b6db65
--- /dev/null
+++ b/java/emacs.keystore
Binary files differ
diff --git a/java/org/gnu/emacs/EmacsActivity.java b/java/org/gnu/emacs/EmacsActivity.java
new file mode 100644
index 00000000000..cacd5f13e60
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsActivity.java
@@ -0,0 +1,146 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.IllegalStateException;
23import java.util.List;
24import java.util.ArrayList;
25
26import android.app.Activity;
27import android.content.Context;
28import android.content.Intent;
29import android.os.Bundle;
30import android.util.Log;
31import android.widget.FrameLayout;
32import android.widget.FrameLayout.LayoutParams;
33
34public class EmacsActivity extends Activity
35{
36 public static final String TAG = "EmacsActivity";
37
38 /* List of all activities that do not have an associated
39 EmacsWindow. */
40 public static List<EmacsActivity> availableActivities;
41
42 /* The currently attached EmacsWindow, or null if none. */
43 private EmacsWindow window;
44
45 /* The frame layout associated with the activity. */
46 private FrameLayout layout;
47
48 static
49 {
50 /* Set up the list of available activities. */
51 availableActivities = new ArrayList<EmacsActivity> ();
52 };
53
54 public void
55 attachChild (EmacsWindow child)
56 {
57 if (window != null)
58 throw new IllegalStateException ("trying to attach window when one"
59 + " already exists");
60
61 /* Record and attach the view. */
62 window = child;
63 layout.addView (window.view);
64
65 /* Remove the objects from the lists of what is available. */
66 EmacsService.availableChildren.remove (child);
67 availableActivities.remove (this);
68
69 /* Now set child->activity. */
70 child.setActivity (this);
71 }
72
73 /* Make this activity available for future windows to attach
74 again. */
75
76 public void
77 makeAvailable ()
78 {
79 window = null;
80
81 for (EmacsWindow iterWindow
82 : EmacsService.availableChildren)
83 {
84 synchronized (iterWindow)
85 {
86 if (!iterWindow.isDestroyed ())
87 attachChild (iterWindow);
88
89 return;
90 }
91 }
92
93 availableActivities.add (this);
94 }
95
96 @Override
97 public void
98 onCreate (Bundle savedInstanceState)
99 {
100 FrameLayout.LayoutParams params;
101
102 params = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT,
103 LayoutParams.MATCH_PARENT);
104
105 /* Make the frame layout. */
106 layout = new FrameLayout (this);
107 layout.setLayoutParams (params);
108
109 /* Set it as the content view. */
110 setContentView (layout);
111
112 /* Make the activity available before starting the
113 service. */
114 makeAvailable ();
115
116 if (EmacsService.SERVICE == null)
117 /* Start the Emacs service now. */
118 startService (new Intent (this, EmacsService.class));
119
120 super.onCreate (savedInstanceState);
121 }
122
123 @Override
124 public void
125 onStop ()
126 {
127 /* The activity is no longer visible. If there is a window
128 attached, detach it. */
129
130 if (window != null)
131 {
132 layout.removeView (window.view);
133
134 /* Notice that the window is already available too. But do
135 not call noticeAvailableChild; that might assign it to some
136 other activity, which behaves badly. */
137 EmacsService.availableChildren.add (window);
138 window = null;
139 }
140
141 /* Finally, remove this activity from the list of available
142 activities. */
143 availableActivities.remove (this);
144 super.onStop ();
145 }
146};
diff --git a/java/org/gnu/emacs/EmacsApplication.java b/java/org/gnu/emacs/EmacsApplication.java
new file mode 100644
index 00000000000..125da05cfd4
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsApplication.java
@@ -0,0 +1,27 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.app.Application;
23
24public class EmacsApplication extends Application
25{
26 /* This class currently does nothing. */
27};
diff --git a/java/org/gnu/emacs/EmacsCopyArea.java b/java/org/gnu/emacs/EmacsCopyArea.java
new file mode 100644
index 00000000000..f34d1ecde01
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsCopyArea.java
@@ -0,0 +1,131 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Bitmap;
23import android.graphics.Canvas;
24import android.graphics.Paint;
25import android.graphics.PorterDuff.Mode;
26import android.graphics.PorterDuffXfermode;
27import android.graphics.Rect;
28import android.graphics.Xfermode;
29
30public class EmacsCopyArea implements EmacsPaintReq
31{
32 private int src_x, src_y, dest_x, dest_y, width, height;
33 private EmacsDrawable destination, source;
34 private EmacsGC immutableGC;
35 private static Xfermode xorAlu, srcInAlu;
36
37 static
38 {
39 xorAlu = new PorterDuffXfermode (Mode.XOR);
40 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
41 };
42
43 public
44 EmacsCopyArea (EmacsDrawable destination, EmacsDrawable source,
45 int src_x, int src_y, int width, int height,
46 int dest_x, int dest_y, EmacsGC immutableGC)
47 {
48 this.destination = destination;
49 this.source = source;
50 this.src_x = src_x;
51 this.src_y = src_y;
52 this.width = width;
53 this.height = height;
54 this.dest_x = dest_x;
55 this.dest_y = dest_y;
56 this.immutableGC = immutableGC;
57 }
58
59 @Override
60 public Rect
61 getRect ()
62 {
63 return new Rect (dest_x, dest_y, dest_x + width,
64 dest_y + height);
65 }
66
67 @Override
68 public EmacsDrawable
69 getDrawable ()
70 {
71 return destination;
72 }
73
74 @Override
75 public EmacsGC
76 getGC ()
77 {
78 return immutableGC;
79 }
80
81 @Override
82 public void
83 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
84 {
85 int alu;
86 Bitmap bitmap;
87 Paint maskPaint;
88 Canvas maskCanvas;
89 Bitmap maskBitmap;
90 Rect rect, srcRect;
91
92 /* TODO implement stippling. */
93 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
94 return;
95
96 alu = immutableGC.function;
97 rect = getRect ();
98 bitmap = source.getBitmap ();
99
100 if (alu == EmacsGC.GC_COPY)
101 paint.setXfermode (null);
102 else
103 paint.setXfermode (xorAlu);
104
105 if (immutableGC.clip_mask == null)
106 canvas.drawBitmap (bitmap, new Rect (src_x, src_y,
107 src_x + width,
108 src_y + height),
109 rect, paint);
110 else
111 {
112 maskPaint = new Paint ();
113 srcRect = new Rect (0, 0, rect.width (),
114 rect.height ());
115 maskBitmap
116 = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
117 true);
118
119 if (maskBitmap == null)
120 return;
121
122 maskPaint.setXfermode (srcInAlu);
123 maskCanvas = new Canvas (maskBitmap);
124 maskCanvas.drawBitmap (bitmap, new Rect (src_x, src_y,
125 src_x + width,
126 src_y + height),
127 srcRect, maskPaint);
128 canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
129 }
130 }
131}
diff --git a/java/org/gnu/emacs/EmacsDrawLine.java b/java/org/gnu/emacs/EmacsDrawLine.java
new file mode 100644
index 00000000000..6389031bbfa
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsDrawLine.java
@@ -0,0 +1,137 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.Math;
23
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
26import android.graphics.Paint;
27import android.graphics.PorterDuff.Mode;
28import android.graphics.PorterDuffXfermode;
29import android.graphics.Rect;
30import android.graphics.Xfermode;
31
32public class EmacsDrawLine implements EmacsPaintReq
33{
34 private int x, y, x2, y2;
35 private EmacsDrawable drawable;
36 private EmacsGC immutableGC;
37 private static Xfermode xorAlu, srcInAlu;
38
39 static
40 {
41 xorAlu = new PorterDuffXfermode (Mode.XOR);
42 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
43 };
44
45 public
46 EmacsDrawLine (EmacsDrawable drawable, int x, int y,
47 int x2, int y2, EmacsGC immutableGC)
48 {
49 this.drawable = drawable;
50 this.x = x;
51 this.y = y;
52 this.x2 = x2;
53 this.y2 = y2;
54 this.immutableGC = immutableGC;
55 }
56
57 @Override
58 public Rect
59 getRect ()
60 {
61 return new Rect (Math.min (x, x2 + 1),
62 Math.min (y, y2 + 1),
63 Math.max (x2 + 1, x),
64 Math.max (y2 + 1, y));
65 }
66
67 @Override
68 public EmacsDrawable
69 getDrawable ()
70 {
71 return drawable;
72 }
73
74 @Override
75 public EmacsGC
76 getGC ()
77 {
78 return immutableGC;
79 }
80
81 @Override
82 public void
83 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
84 {
85 int alu;
86 Paint maskPaint;
87 Canvas maskCanvas;
88 Bitmap maskBitmap;
89 Rect rect, srcRect;
90 int width, height;
91
92 /* TODO implement stippling. */
93 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
94 return;
95
96 alu = immutableGC.function;
97 rect = getRect ();
98 width = rect.width ();
99 height = rect.height ();
100
101 paint.setStyle (Paint.Style.STROKE);
102
103 if (alu == EmacsGC.GC_COPY)
104 paint.setXfermode (null);
105 else
106 paint.setXfermode (xorAlu);
107
108 if (immutableGC.clip_mask == null)
109 {
110 paint.setColor (immutableGC.foreground | 0xff000000);
111 canvas.drawLine ((float) x, (float) y,
112 (float) x2, (float) y2,
113 paint);
114 }
115 else
116 {
117 maskPaint = new Paint ();
118 maskBitmap
119 = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
120 true);
121
122 if (maskBitmap == null)
123 return;
124
125 maskPaint.setXfermode (srcInAlu);
126 maskPaint.setColor (immutableGC.foreground | 0xff000000);
127 maskCanvas = new Canvas (maskBitmap);
128 srcRect = new Rect (0, 0, maskBitmap.getWidth (),
129 maskBitmap.getHeight ());
130 maskCanvas.drawLine (0.0f, 0.0f, (float) Math.abs (x - x2),
131 (float) Math.abs (y - y2), maskPaint);
132 canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
133 }
134
135 paint.setXfermode (null);
136 }
137}
diff --git a/java/org/gnu/emacs/EmacsDrawPoint.java b/java/org/gnu/emacs/EmacsDrawPoint.java
new file mode 100644
index 00000000000..772757ff424
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsDrawPoint.java
@@ -0,0 +1,30 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22public class EmacsDrawPoint extends EmacsDrawRectangle
23{
24 public
25 EmacsDrawPoint (EmacsDrawable drawable, int x, int y,
26 EmacsGC immutableGC)
27 {
28 super (drawable, x, y, 1, 1, immutableGC);
29 }
30}
diff --git a/java/org/gnu/emacs/EmacsDrawRectangle.java b/java/org/gnu/emacs/EmacsDrawRectangle.java
new file mode 100644
index 00000000000..462bf7c85b5
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsDrawRectangle.java
@@ -0,0 +1,127 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Bitmap;
23import android.graphics.Canvas;
24import android.graphics.Paint;
25import android.graphics.PorterDuff.Mode;
26import android.graphics.PorterDuffXfermode;
27import android.graphics.Rect;
28import android.graphics.Xfermode;
29
30public class EmacsDrawRectangle implements EmacsPaintReq
31{
32 private int x, y, width, height;
33 private EmacsDrawable drawable;
34 private EmacsGC immutableGC;
35 private static Xfermode xorAlu, srcInAlu;
36
37 static
38 {
39 xorAlu = new PorterDuffXfermode (Mode.XOR);
40 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
41 };
42
43 public
44 EmacsDrawRectangle (EmacsDrawable drawable, int x, int y,
45 int width, int height,
46 EmacsGC immutableGC)
47 {
48 this.drawable = drawable;
49 this.x = x;
50 this.y = y;
51 this.width = width;
52 this.height = height;
53 this.immutableGC = immutableGC;
54 }
55
56 @Override
57 public Rect
58 getRect ()
59 {
60 return new Rect (x, y, x + width, y + height);
61 }
62
63 @Override
64 public EmacsDrawable
65 getDrawable ()
66 {
67 return drawable;
68 }
69
70 @Override
71 public EmacsGC
72 getGC ()
73 {
74 return immutableGC;
75 }
76
77 @Override
78 public void
79 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
80 {
81 int alu;
82 Paint maskPaint;
83 Canvas maskCanvas;
84 Bitmap maskBitmap;
85 Rect rect, srcRect;
86
87 /* TODO implement stippling. */
88 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
89 return;
90
91 alu = immutableGC.function;
92 rect = getRect ();
93
94 paint.setStyle (Paint.Style.STROKE);
95
96 if (alu == EmacsGC.GC_COPY)
97 paint.setXfermode (null);
98 else
99 paint.setXfermode (xorAlu);
100
101 if (immutableGC.clip_mask == null)
102 {
103 paint.setColor (immutableGC.foreground | 0xff000000);
104 canvas.drawRect (rect, paint);
105 }
106 else
107 {
108 maskPaint = new Paint ();
109 maskBitmap
110 = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
111 true);
112
113 if (maskBitmap == null)
114 return;
115
116 maskPaint.setXfermode (srcInAlu);
117 maskPaint.setColor (immutableGC.foreground | 0xff000000);
118 maskCanvas = new Canvas (maskBitmap);
119 srcRect = new Rect (0, 0, maskBitmap.getWidth (),
120 maskBitmap.getHeight ());
121 maskCanvas.drawRect (srcRect, maskPaint);
122 canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
123 }
124
125 paint.setXfermode (null);
126 }
127}
diff --git a/java/org/gnu/emacs/EmacsDrawable.java b/java/org/gnu/emacs/EmacsDrawable.java
new file mode 100644
index 00000000000..19062137213
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsDrawable.java
@@ -0,0 +1,33 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Rect;
23import android.graphics.Bitmap;
24import android.graphics.Canvas;
25
26public interface EmacsDrawable
27{
28 public Canvas lockCanvas ();
29 public void unlockCanvas ();
30 public void damageRect (Rect damageRect);
31 public Bitmap getBitmap ();
32 public boolean isDestroyed ();
33};
diff --git a/java/org/gnu/emacs/EmacsFillPolygon.java b/java/org/gnu/emacs/EmacsFillPolygon.java
new file mode 100644
index 00000000000..3198c7f07c4
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsFillPolygon.java
@@ -0,0 +1,150 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.Math;
23
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
26import android.graphics.Paint;
27import android.graphics.Path;
28import android.graphics.Point;
29import android.graphics.PorterDuff.Mode;
30import android.graphics.PorterDuffXfermode;
31import android.graphics.Rect;
32import android.graphics.RectF;
33import android.graphics.Xfermode;
34
35public class EmacsFillPolygon implements EmacsPaintReq
36{
37 private EmacsDrawable drawable;
38 private EmacsGC immutableGC;
39 private Path path;
40
41 private static Xfermode xorAlu, srcInAlu;
42
43 static
44 {
45 xorAlu = new PorterDuffXfermode (Mode.XOR);
46 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
47 };
48
49 public
50 EmacsFillPolygon (EmacsDrawable drawable, Point points[],
51 EmacsGC immutableGC)
52 {
53 int i;
54
55 this.drawable = drawable;
56 this.immutableGC = immutableGC;
57
58 /* Build the path from the given array of points. */
59 path = new Path ();
60
61 if (points.length >= 1)
62 {
63 path.moveTo (points[0].x, points[0].y);
64
65 for (i = 1; i < points.length; ++i)
66 path.lineTo (points[i].x, points[i].y);
67
68 path.close ();
69 }
70 }
71
72 @Override
73 public Rect
74 getRect ()
75 {
76 RectF rect;
77
78 rect = new RectF (0, 0, 0, 0);
79 path.computeBounds (rect, true);
80
81 return new Rect ((int) Math.floor (rect.left),
82 (int) Math.floor (rect.top),
83 (int) Math.ceil (rect.right),
84 (int) Math.ceil (rect.bottom));
85 }
86
87 @Override
88 public EmacsDrawable
89 getDrawable ()
90 {
91 return drawable;
92 }
93
94 @Override
95 public EmacsGC
96 getGC ()
97 {
98 return immutableGC;
99 }
100
101 @Override
102 public void
103 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
104 {
105 int alu;
106 Paint maskPaint;
107 Canvas maskCanvas;
108 Bitmap maskBitmap;
109 Rect rect;
110
111 /* TODO implement stippling. */
112 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
113 return;
114
115 alu = immutableGC.function;
116 rect = getRect ();
117
118 if (alu == EmacsGC.GC_COPY)
119 paint.setXfermode (null);
120 else
121 paint.setXfermode (xorAlu);
122
123 paint.setStyle (Paint.Style.FILL);
124
125 if (immutableGC.clip_mask == null)
126 {
127 paint.setColor (immutableGC.foreground | 0xff000000);
128 canvas.drawPath (path, paint);
129 }
130 else
131 {
132 maskPaint = new Paint ();
133 maskBitmap = immutableGC.clip_mask.bitmap;
134 maskBitmap = maskBitmap.copy (Bitmap.Config.ARGB_8888,
135 true);
136
137 if (maskBitmap == null)
138 return;
139
140 maskPaint.setXfermode (srcInAlu);
141 maskPaint.setColor (immutableGC.foreground | 0xff000000);
142 maskCanvas = new Canvas (maskBitmap);
143 path.offset (-rect.left, -rect.top, null);
144 maskCanvas.drawPath (path, maskPaint);
145 canvas.drawBitmap (maskBitmap, new Rect (0, 0, rect.width (),
146 rect.height ()),
147 rect, paint);
148 }
149 }
150}
diff --git a/java/org/gnu/emacs/EmacsFillRectangle.java b/java/org/gnu/emacs/EmacsFillRectangle.java
new file mode 100644
index 00000000000..7246c13de7f
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsFillRectangle.java
@@ -0,0 +1,129 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Bitmap;
23import android.graphics.Canvas;
24import android.graphics.Paint;
25import android.graphics.PorterDuff.Mode;
26import android.graphics.PorterDuffXfermode;
27import android.graphics.Rect;
28import android.graphics.Xfermode;
29
30import android.util.Log;
31
32public class EmacsFillRectangle implements EmacsPaintReq
33{
34 private int x, y, width, height;
35 private EmacsDrawable drawable;
36 private EmacsGC immutableGC;
37 private static Xfermode xorAlu, srcInAlu;
38
39 static
40 {
41 xorAlu = new PorterDuffXfermode (Mode.XOR);
42 srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
43 };
44
45 public
46 EmacsFillRectangle (EmacsDrawable drawable, int x, int y,
47 int width, int height,
48 EmacsGC immutableGC)
49 {
50 this.drawable = drawable;
51 this.x = x;
52 this.y = y;
53 this.width = width;
54 this.height = height;
55 this.immutableGC = immutableGC;
56 }
57
58 @Override
59 public Rect
60 getRect ()
61 {
62 return new Rect (x, y, x + width, y + height);
63 }
64
65 @Override
66 public EmacsDrawable
67 getDrawable ()
68 {
69 return drawable;
70 }
71
72 @Override
73 public EmacsGC
74 getGC ()
75 {
76 return immutableGC;
77 }
78
79 @Override
80 public void
81 paintTo (Canvas canvas, Paint paint, EmacsGC immutableGC)
82 {
83 int alu;
84 Paint maskPaint;
85 Canvas maskCanvas;
86 Bitmap maskBitmap;
87 Rect rect, srcRect;
88
89 /* TODO implement stippling. */
90 if (immutableGC.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
91 return;
92
93 alu = immutableGC.function;
94 rect = getRect ();
95
96 paint.setStyle (Paint.Style.FILL);
97
98 if (alu == EmacsGC.GC_COPY)
99 paint.setXfermode (null);
100 else
101 paint.setXfermode (xorAlu);
102
103 if (immutableGC.clip_mask == null)
104 {
105 paint.setColor (immutableGC.foreground | 0xff000000);
106 canvas.drawRect (rect, paint);
107 }
108 else
109 {
110 maskPaint = new Paint ();
111 maskBitmap
112 = immutableGC.clip_mask.bitmap.copy (Bitmap.Config.ARGB_8888,
113 true);
114
115 if (maskBitmap == null)
116 return;
117
118 maskPaint.setXfermode (srcInAlu);
119 maskPaint.setColor (immutableGC.foreground | 0xff000000);
120 maskCanvas = new Canvas (maskBitmap);
121 srcRect = new Rect (0, 0, maskBitmap.getWidth (),
122 maskBitmap.getHeight ());
123 maskCanvas.drawRect (srcRect, maskPaint);
124 canvas.drawBitmap (maskBitmap, srcRect, rect, paint);
125 }
126
127 paint.setXfermode (null);
128 }
129}
diff --git a/java/org/gnu/emacs/EmacsFontDriver.java b/java/org/gnu/emacs/EmacsFontDriver.java
new file mode 100644
index 00000000000..f419e71059d
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsFontDriver.java
@@ -0,0 +1,150 @@
1/* Font backend for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.util.List;
23
24public abstract class EmacsFontDriver
25{
26 /* Font weights. */
27 public static final int THIN = 0;
28 public static final int ULTRA_LIGHT = 40;
29 public static final int LIGHT = 50;
30 public static final int SEMI_LIGHT = 55;
31 public static final int REGULAR = 80;
32 public static final int MEDIUM = 100;
33 public static final int SEMI_BOLD = 180;
34 public static final int BOLD = 200;
35 public static final int EXTRA_BOLD = 205;
36 public static final int BLACK = 210;
37 public static final int ULTRA_HEAVY = 250;
38
39 /* Font slants. */
40 public static final int REVERSE_OBLIQUE = 0;
41 public static final int REVERSE_ITALIC = 10;
42 public static final int NORMAL = 100;
43 public static final int ITALIC = 200;
44 public static final int OBLIQUE = 210;
45
46 /* Font widths. */
47 public static final int ULTRA_CONDENSED = 50;
48 public static final int EXTRA_CONDENSED = 63;
49 public static final int CONDENSED = 75;
50 public static final int SEMI_CONDENSED = 87;
51 public static final int UNSPECIFIED = 100;
52 public static final int SEMI_EXPANDED = 113;
53 public static final int EXPANDED = 125;
54 public static final int EXTRA_EXPANDED = 150;
55 public static final int ULTRA_EXPANDED = 200;
56
57 /* Font spacings. */
58 public static final int PROPORTIONAL = 0;
59 public static final int DUAL = 90;
60 public static final int MONO = 100;
61 public static final int CHARCELL = 110;
62
63 public class FontSpec
64 {
65 /* The fields below mean the same as they do in enum
66 font_property_index in font.h. */
67
68 public String foundry;
69 public String family;
70 public String adstyle;
71 public String registry;
72 public Integer width;
73 public Integer weight;
74 public Integer slant;
75 public Integer size;
76 public Integer spacing;
77 public Integer avgwidth;
78
79 @Override
80 public String
81 toString ()
82 {
83 return ("foundry: " + foundry
84 + " family: " + family
85 + " adstyle: " + adstyle
86 + " registry: " + registry
87 + " width: " + width
88 + " weight: " + weight
89 + " slant: " + slant
90 + " spacing: " + spacing
91 + " avgwidth: " + avgwidth);
92 }
93 };
94
95 public class FontMetrics
96 {
97 public short lbearing;
98 public short rbearing;
99 public short width;
100 public short ascent;
101 public short descent;
102 }
103
104 public class FontEntity extends FontSpec
105 {
106 /* No extra fields here. */
107 };
108
109 public abstract class FontObject extends FontSpec
110 {
111 public int minWidth;
112 public int maxWidth;
113 public int pixelSize;
114 public int height;
115 public int spaceWidth;
116 public int averageWidth;
117 public int ascent;
118 public int descent;
119 public int underlineThickness;
120 public int underlinePosition;
121 public int baselineOffset;
122 public int relativeCompose;
123 public int defaultAscent;
124 public int encodingCharset;
125 public int repertoryCharset;
126
127 public
128 FontObject ()
129 {
130 encodingCharset = -1;
131 repertoryCharset = -1;
132 }
133 };
134
135 /* These mean the same as they do in struct font_driver. */
136 public abstract FontEntity[] list (FontSpec fontSpec);
137 public abstract FontEntity match (FontSpec fontSpec);
138 public abstract String[] listFamilies ();
139 public abstract FontObject openFont (FontEntity fontEntity, int pixelSize);
140 public abstract int hasChar (FontSpec font, char charCode);
141 public abstract void textExtents (FontObject font, int code[],
142 FontMetrics fontMetrics[]);
143 public abstract int encodeChar (FontObject fontObject, char charCode);
144
145 public static EmacsFontDriver
146 createFontDriver ()
147 {
148 return new EmacsSdk7FontDriver ();
149 }
150};
diff --git a/java/org/gnu/emacs/EmacsGC.java b/java/org/gnu/emacs/EmacsGC.java
new file mode 100644
index 00000000000..0becb04519d
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsGC.java
@@ -0,0 +1,116 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Rect;
23
24/* X like graphics context structures. Keep the enums in synch with
25 androidgui.h! */
26
27public class EmacsGC extends EmacsHandleObject
28{
29 public static final int GC_COPY = 0;
30 public static final int GC_XOR = 1;
31
32 public static final int GC_FILL_SOLID = 0;
33 public static final int GC_FILL_OPAQUE_STIPPLED = 1;
34
35 public int function, fill_style;
36 public int foreground, background;
37 public int clip_x_origin, clip_y_origin;
38 public int ts_origin_x, ts_origin_y;
39 public Rect clip_rects[];
40 public EmacsPixmap clip_mask, stipple;
41 private boolean dirty;
42 private EmacsGC immutableGC;
43
44 /* The following fields are only set on immutable GCs. */
45
46 public
47 EmacsGC (short handle)
48 {
49 /* For historical reasons the C code has an extra layer of
50 indirection above this GC handle. struct android_gc is the GC
51 used by Emacs code, while android_gcontext is the type of the
52 handle. */
53 super (handle);
54
55 fill_style = GC_FILL_SOLID;
56 function = GC_COPY;
57 foreground = 0;
58 background = 0xffffffff;
59 }
60
61 public
62 EmacsGC (EmacsGC source)
63 {
64 super ((short) 0);
65
66 int i;
67
68 function = source.function;
69 fill_style = source.fill_style;
70 foreground = source.foreground;
71 background = source.background;
72 clip_x_origin = source.clip_x_origin;
73 clip_y_origin = source.clip_y_origin;
74 clip_rects = source.clip_rects;
75 clip_mask = source.clip_mask;
76 stipple = source.stipple;
77 ts_origin_x = source.ts_origin_x;
78 ts_origin_y = source.ts_origin_y;
79
80 /* Offset all the clip rects by ts_origin_x and ts_origin_y. */
81
82 if ((ts_origin_x != 0 || ts_origin_y != 0)
83 && clip_rects != null)
84 {
85 clip_rects = new Rect[clip_rects.length];
86
87 for (i = 0; i < clip_rects.length; ++i)
88 {
89 clip_rects[i] = new Rect (source.clip_rects[i]);
90 clip_rects[i].offset (ts_origin_x,
91 ts_origin_y);
92 }
93 }
94 }
95
96 /* Mark this GC as dirty. This means immutableGC will return a new
97 copy of this GC the next time it is called. */
98
99 public void
100 markDirty ()
101 {
102 dirty = true;
103 }
104
105 public EmacsGC
106 immutableGC ()
107 {
108 if (immutableGC == null || dirty)
109 {
110 immutableGC = new EmacsGC (this);
111 dirty = false;
112 }
113
114 return immutableGC;
115 };
116};
diff --git a/java/org/gnu/emacs/EmacsHandleObject.java b/java/org/gnu/emacs/EmacsHandleObject.java
new file mode 100644
index 00000000000..a57a3bbdfa9
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsHandleObject.java
@@ -0,0 +1,62 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.util.List;
23import java.util.ArrayList;
24import java.lang.Object;
25import java.lang.IllegalStateException;
26
27/* This defines something that is a so-called ``handle''. Handles
28 must be created by C code, and will remain existing until
29 destroyHandle is called. C code then refers to the handle by a
30 number which maps into the Java object representing the handle.
31
32 All handle operations must be done from the Emacs thread. */
33
34public abstract class EmacsHandleObject
35{
36 /* Whether or not this handle has been destroyed. */
37 volatile boolean destroyed;
38
39 /* The handle associated with this object. */
40 public short handle;
41
42 public
43 EmacsHandleObject (short handle)
44 {
45 this.handle = handle;
46 }
47
48 public void
49 destroyHandle () throws IllegalStateException
50 {
51 synchronized (this)
52 {
53 destroyed = true;
54 }
55 }
56
57 public boolean
58 isDestroyed ()
59 {
60 return destroyed;
61 }
62};
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java
new file mode 100644
index 00000000000..6550e6fa2a1
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -0,0 +1,72 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.System;
23
24import android.content.res.AssetManager;
25
26public class EmacsNative
27{
28 /* Set certain parameters before initializing Emacs. This proves
29 that libemacs.so is being loaded from Java code.
30
31 assetManager must be the asset manager associated with the
32 context that is loading Emacs. It is saved and remains for the
33 remainder the lifetime of the Emacs process.
34
35 filesDir must be the package's data storage location for the
36 current Android user.
37
38 libDir must be the package's data storage location for native
39 libraries. It is used as PATH.
40
41 emacsService must be the emacsService singleton. */
42 public static native void setEmacsParams (AssetManager assetManager,
43 String filesDir,
44 String libDir,
45 EmacsService emacsService);
46
47 /* Initialize Emacs with the argument array ARGV. Each argument
48 must contain a NULL terminated string, or else the behavior is
49 undefined. */
50 public static native void initEmacs (String argv[]);
51
52 /* Abort and generate a native core dump. */
53 public static native void emacsAbort ();
54
55 /* Send an ANDROID_CONFIGURE_NOTIFY event. */
56 public static native void sendConfigureNotify (short window, long time,
57 int x, int y, int width,
58 int height);
59
60 /* Send an ANDROID_KEY_PRESS event. */
61 public static native void sendKeyPress (short window, long time, int state,
62 int keyCode);
63
64 /* Send an ANDROID_KEY_RELEASE event. */
65 public static native void sendKeyRelease (short window, long time, int state,
66 int keyRelease);
67
68 static
69 {
70 System.loadLibrary ("emacs");
71 };
72};
diff --git a/java/org/gnu/emacs/EmacsPaintQueue.java b/java/org/gnu/emacs/EmacsPaintQueue.java
new file mode 100644
index 00000000000..5af5868d3b9
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsPaintQueue.java
@@ -0,0 +1,138 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.util.LinkedList;
23import java.util.List;
24
25import android.graphics.Canvas;
26import android.graphics.Paint;
27import android.graphics.Rect;
28
29public class EmacsPaintQueue
30{
31 /* Queue of paint operations. This is modified from the Emacs
32 thread, and entire paint queues are periodically flushed to the
33 application thread where it is executed. */
34 private List<EmacsPaintReq> paintOperations;
35
36 /* Number of operations in this queue. */
37 public int numRequests;
38
39 public
40 EmacsPaintQueue ()
41 {
42 paintOperations = new LinkedList<EmacsPaintReq> ();
43 }
44
45 public void
46 run ()
47 {
48 EmacsDrawable drawable, last;
49 Canvas canvas;
50 EmacsGC gc, lastGC;
51 int i;
52 Paint paint;
53 Rect rect, offsetRect, copyRect;
54
55 canvas = null;
56 last = null;
57 gc = null;
58 paint = new Paint ();
59
60 for (EmacsPaintReq req : paintOperations)
61 {
62 drawable = req.getDrawable ();
63
64 synchronized (req)
65 {
66 /* Ignore graphics requests for drawables that have been
67 destroyed. */
68 if (drawable.isDestroyed ())
69 continue;
70 }
71
72 canvas = drawable.lockCanvas ();
73
74 if (canvas == null)
75 /* No canvas is currently available. */
76 continue;
77
78 lastGC = gc;
79 gc = req.getGC ();
80 rect = req.getRect ();
81
82 if (gc.clip_rects == null)
83 {
84 /* No clipping is applied. Just draw and continue. */
85 canvas.save ();
86 req.paintTo (canvas, paint, gc);
87 canvas.restore ();
88 drawable.damageRect (rect);
89 continue;
90 }
91
92 if (gc.clip_rects != null && gc.clip_rects.length > 0)
93 {
94 canvas.save ();
95
96 if (gc.clip_rects.length == 1)
97 {
98 /* There is only a single clip rect, which is simple
99 enough. */
100 canvas.clipRect (gc.clip_rects[0]);
101 req.paintTo (canvas, paint, gc);
102 }
103 else
104 {
105 /* There are multiple clip rects. Android doesn't let
106 programs use RegionOp.UNION on the clip rectangle,
107 so Emacs must iterate over each intersection and
108 paint it manually. This seems inefficient but
109 thankfully Emacs never seems to use more than one
110 clip rect. */
111
112 for (i = 0; i < gc.clip_rects.length; ++i)
113 {
114 copyRect = new Rect (gc.clip_rects[i]);
115
116 if (copyRect.intersect (rect))
117 {
118 canvas.save ();
119 canvas.clipRect (copyRect);
120 req.paintTo (canvas, paint, gc);
121 canvas.restore ();
122 }
123 }
124 }
125
126 drawable.damageRect (rect);
127 canvas.restore ();
128 }
129 }
130 }
131
132 public void
133 appendPaintOperation (EmacsPaintReq req)
134 {
135 paintOperations.add (req);
136 numRequests++;
137 }
138};
diff --git a/java/org/gnu/emacs/EmacsPaintReq.java b/java/org/gnu/emacs/EmacsPaintReq.java
new file mode 100644
index 00000000000..5b14b005093
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsPaintReq.java
@@ -0,0 +1,33 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.graphics.Canvas;
23import android.graphics.Paint;
24import android.graphics.Rect;
25
26public interface EmacsPaintReq
27{
28 public EmacsDrawable getDrawable ();
29 public EmacsGC getGC ();
30 public void paintTo (Canvas canvas, Paint paint,
31 EmacsGC immutableGC);
32 public Rect getRect ();
33};
diff --git a/java/org/gnu/emacs/EmacsPixmap.java b/java/org/gnu/emacs/EmacsPixmap.java
new file mode 100644
index 00000000000..ccd5f1e0043
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsPixmap.java
@@ -0,0 +1,102 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.IllegalArgumentException;
23
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
26import android.graphics.Rect;
27
28/* Drawable backed by bitmap. */
29
30public class EmacsPixmap extends EmacsHandleObject
31 implements EmacsDrawable
32{
33 /* The depth of the bitmap. This is not actually used, just defined
34 in order to be consistent with X. */
35 public int depth, width, height;
36
37 /* The bitmap itself. */
38 public Bitmap bitmap;
39
40 /* The canvas used to draw to BITMAP. */
41 public Canvas canvas;
42
43 public
44 EmacsPixmap (short handle, int colors[], int width,
45 int height, int depth)
46 {
47 super (handle);
48
49 if (depth != 1 && depth != 24)
50 throw new IllegalArgumentException ("Invalid depth specified"
51 + " for pixmap: " + depth);
52
53 switch (depth)
54 {
55 case 1:
56 bitmap = Bitmap.createBitmap (colors, width, height,
57 Bitmap.Config.ALPHA_8);
58 break;
59
60 case 24:
61 bitmap = Bitmap.createBitmap (colors, width, height,
62 Bitmap.Config.ARGB_8888);
63 bitmap.setHasAlpha (false);
64 break;
65 }
66
67 this.width = width;
68 this.height = height;
69 this.depth = depth;
70 }
71
72 @Override
73 public Canvas
74 lockCanvas ()
75 {
76 if (canvas == null)
77 canvas = new Canvas (bitmap);
78
79 return canvas;
80 }
81
82 @Override
83 public void
84 unlockCanvas ()
85 {
86
87 }
88
89 @Override
90 public void
91 damageRect (Rect damageRect)
92 {
93
94 }
95
96 @Override
97 public Bitmap
98 getBitmap ()
99 {
100 return bitmap;
101 }
102};
diff --git a/java/org/gnu/emacs/EmacsSdk7FontDriver.java b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
new file mode 100644
index 00000000000..5a8cdbfc75b
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
@@ -0,0 +1,460 @@
1/* Font backend for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.io.File;
23import java.io.IOException;
24
25import java.util.LinkedList;
26import java.util.List;
27
28import android.graphics.Paint;
29import android.graphics.Rect;
30import android.graphics.Typeface;
31
32import android.util.Log;
33
34public class EmacsSdk7FontDriver extends EmacsFontDriver
35{
36 private static final String TOFU_STRING = "\uDB3F\uDFFD";
37 private static final String EM_STRING = "m";
38 private static final String TAG = "EmacsSdk7FontDriver";
39
40 private class Sdk7Typeface
41 {
42 /* The typeface and paint. */
43 public Typeface typeface;
44 public Paint typefacePaint;
45 public String familyName;
46 public int slant, width, weight, spacing;
47
48 public
49 Sdk7Typeface (String fileName, Typeface typeface)
50 {
51 String style, testString;
52 int index, measured, i;
53 float[] widths;
54
55 slant = NORMAL;
56 weight = REGULAR;
57 width = UNSPECIFIED;
58 spacing = PROPORTIONAL;
59
60 typefacePaint = new Paint ();
61 typefacePaint.setTypeface (typeface);
62
63 /* For the calls to measureText below. */
64 typefacePaint.setTextSize (10.0f);
65
66 /* Parse the file name into some useful data. First, strip off
67 the extension. */
68 fileName = fileName.split ("\\.", 2)[0];
69
70 /* Next, split the file name by dashes. Everything before the
71 last dash is part of the family name. */
72 index = fileName.lastIndexOf ("-");
73
74 if (index > 0)
75 {
76 style = fileName.substring (index + 1, fileName.length ());
77 familyName = fileName.substring (0, index);
78
79 /* Look for something describing the weight. */
80 if (style.contains ("Thin"))
81 weight = THIN;
82 else if (style.contains ("UltraLight"))
83 weight = ULTRA_LIGHT;
84 else if (style.contains ("SemiLight"))
85 weight = SEMI_LIGHT;
86 else if (style.contains ("Light"))
87 weight = LIGHT;
88 else if (style.contains ("Medium"))
89 weight = MEDIUM;
90 else if (style.contains ("SemiBold"))
91 weight = SEMI_BOLD;
92 else if (style.contains ("ExtraBold"))
93 weight = EXTRA_BOLD;
94 else if (style.contains ("Bold"))
95 weight = BOLD;
96 else if (style.contains ("Black"))
97 weight = BLACK;
98 else if (style.contains ("UltraHeavy"))
99 weight = ULTRA_HEAVY;
100
101 /* And the slant. */
102 if (style.contains ("ReverseOblique"))
103 slant = OBLIQUE;
104 else if (style.contains ("ReverseItalic"))
105 slant = REVERSE_ITALIC;
106 else if (style.contains ("Italic"))
107 slant = ITALIC;
108 else if (style.contains ("Oblique"))
109 slant = OBLIQUE;
110
111 /* Finally, the width. */
112 if (style.contains ("UltraCondensed"))
113 width = ULTRA_CONDENSED;
114 else if (style.contains ("ExtraCondensed"))
115 width = EXTRA_CONDENSED;
116 else if (style.contains ("SemiCondensed"))
117 width = SEMI_CONDENSED;
118 else if (style.contains ("Condensed"))
119 width = CONDENSED;
120 else if (style.contains ("SemiExpanded"))
121 width = SEMI_EXPANDED;
122 else if (style.contains ("ExtraExpanded"))
123 width = EXTRA_EXPANDED;
124 else if (style.contains ("UltraExpanded"))
125 width = ULTRA_EXPANDED;
126 else if (style.contains ("Expanded"))
127 width = EXPANDED;
128
129 /* Guess the spacing information. */
130 testString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
131 widths = new float[testString.length ()];
132
133 measured = typefacePaint.getTextWidths (testString,
134 0, testString.length (),
135 widths);
136 spacing = MONO;
137 for (i = 0; i < measured; ++i)
138 {
139 if (i != 0 && widths[i - 1] != widths[i])
140 /* This isn't a monospace font. */
141 spacing = PROPORTIONAL;
142 }
143 }
144 else
145 familyName = fileName;
146
147 Log.d (TAG, "Initialized new typeface " + familyName);
148 }
149
150 @Override
151 public String
152 toString ()
153 {
154 return ("Sdk7Typeface ("
155 + String.valueOf (familyName) + ", "
156 + String.valueOf (slant) + ", "
157 + String.valueOf (width) + ", "
158 + String.valueOf (weight) + ", "
159 + String.valueOf (spacing) + ")");
160 }
161 };
162
163 private class Sdk7FontEntity extends FontEntity
164 {
165 /* The typeface. */
166 public Sdk7Typeface typeface;
167
168 public
169 Sdk7FontEntity (Sdk7Typeface typeface)
170 {
171 float width;
172
173 foundry = "Google";
174 family = typeface.familyName;
175 adstyle = null;
176 weight = typeface.weight;
177 slant = typeface.slant;
178 spacing = typeface.spacing;
179 width = typeface.width;
180
181 this.typeface = typeface;
182 }
183 };
184
185 private class Sdk7FontObject extends FontObject
186 {
187 /* The typeface. */
188 public Sdk7Typeface typeface;
189
190 /* The text size. */
191 public int pixelSize;
192
193 public
194 Sdk7FontObject (Sdk7Typeface typeface, int pixelSize)
195 {
196 float totalWidth;
197 String testWidth, testString;
198
199 this.typeface = typeface;
200 this.pixelSize = pixelSize;
201
202 family = typeface.familyName;
203 adstyle = null;
204 weight = typeface.weight;
205 slant = typeface.slant;
206 spacing = typeface.spacing;
207 width = typeface.width;
208
209 /* Compute the ascent and descent. */
210 typeface.typefacePaint.setTextSize (pixelSize);
211 ascent
212 = Math.round (-typeface.typefacePaint.ascent ());
213 descent
214 = Math.round (typeface.typefacePaint.descent ());
215
216 /* Compute the average width. */
217 testString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
218 totalWidth = typeface.typefacePaint.measureText (testString);
219
220 if (totalWidth > 0)
221 avgwidth = Math.round (totalWidth
222 / testString.length ());
223
224 /* Android doesn't expose the font average width and height
225 information, so this will have to do. */
226 minWidth = maxWidth = avgwidth;
227
228 /* This is different from avgwidth in the font spec! */
229 averageWidth = avgwidth;
230
231 /* Set the space width. */
232 totalWidth = typeface.typefacePaint.measureText (" ");
233 spaceWidth = Math.round (totalWidth);
234
235 /* Set the height and default ascent. */
236 height = ascent + descent;
237 defaultAscent = ascent;
238 }
239 };
240
241 private String[] fontFamilyList;
242 private Sdk7Typeface[] typefaceList;
243 private Sdk7Typeface fallbackTypeface;
244
245 public
246 EmacsSdk7FontDriver ()
247 {
248 int i;
249 File systemFontsDirectory, fontFile;
250 Typeface typeface;
251
252 systemFontsDirectory = new File ("/system/fonts");
253
254 fontFamilyList = systemFontsDirectory.list ();
255 typefaceList = new Sdk7Typeface[fontFamilyList.length];
256
257 /* It would be nice to avoid opening each and every font upon
258 startup. But that doesn't seem to be possible on
259 Android. */
260
261 for (i = 0; i < fontFamilyList.length; ++i)
262 {
263 fontFile = new File (systemFontsDirectory,
264 fontFamilyList[i]);
265 typeface = Typeface.createFromFile (fontFile);
266 typefaceList[i] = new Sdk7Typeface (fontFile.getName (),
267 typeface);
268 }
269
270 fallbackTypeface = new Sdk7Typeface ("monospace",
271 Typeface.MONOSPACE);
272 }
273
274 private boolean
275 checkMatch (Sdk7Typeface typeface, FontSpec fontSpec)
276 {
277 if (fontSpec.family != null
278 && !fontSpec.family.equals (typeface.familyName))
279 return false;
280
281
282 if (fontSpec.adstyle != null
283 && !fontSpec.adstyle.isEmpty ())
284 /* return false; */;
285
286 if (fontSpec.slant != null
287 && !fontSpec.weight.equals (typeface.weight))
288 return false;
289
290 if (fontSpec.spacing != null
291 && !fontSpec.spacing.equals (typeface.spacing))
292 return false;
293
294 if (fontSpec.weight != null
295 && !fontSpec.weight.equals (typeface.weight))
296 return false;
297
298 if (fontSpec.width != null
299 && !fontSpec.width.equals (typeface.width))
300 return false;
301
302 return true;
303 }
304
305 @Override
306 public FontEntity[]
307 list (FontSpec fontSpec)
308 {
309 LinkedList<FontEntity> list;
310 int i;
311
312 list = new LinkedList<FontEntity> ();
313
314 Log.d (TAG, ("Looking for fonts matching font spec: "
315 + fontSpec.toString ()));
316
317 for (i = 0; i < typefaceList.length; ++i)
318 {
319 if (checkMatch (typefaceList[i], fontSpec))
320 list.add (new Sdk7FontEntity (typefaceList[i]));
321 }
322
323 Log.d (TAG, "Found font entities: " + list.toString ());
324
325 return (FontEntity[]) list.toArray (new FontEntity[0]);
326 }
327
328 @Override
329 public FontEntity
330 match (FontSpec fontSpec)
331 {
332 FontEntity[] entities;
333 int i;
334
335 entities = this.list (fontSpec);
336
337 if (entities.length == 0)
338 return new Sdk7FontEntity (fallbackTypeface);
339
340 return entities[0];
341 }
342
343 @Override
344 public String[]
345 listFamilies ()
346 {
347 return fontFamilyList;
348 }
349
350 @Override
351 public FontObject
352 openFont (FontEntity fontEntity, int pixelSize)
353 {
354 return new Sdk7FontObject (((Sdk7FontEntity) fontEntity).typeface,
355 pixelSize);
356 }
357
358 @Override
359 public int
360 hasChar (FontSpec font, char charCode)
361 {
362 float missingGlyphWidth, emGlyphWidth, width;
363 Rect rect1, rect2;
364 Paint paint;
365 Sdk7FontObject fontObject;
366
367 if (font instanceof Sdk7FontObject)
368 {
369 fontObject = (Sdk7FontObject) font;
370 paint = fontObject.typeface.typefacePaint;
371 }
372 else
373 paint = ((Sdk7FontEntity) font).typeface.typefacePaint;
374
375 paint.setTextSize (10);
376
377 if (Character.isWhitespace (charCode))
378 return 1;
379
380 missingGlyphWidth = paint.measureText (TOFU_STRING);
381 emGlyphWidth = paint.measureText (EM_STRING);
382 width = paint.measureText ("" + charCode);
383
384 if (width == 0f)
385 return 0;
386
387 if (width != missingGlyphWidth)
388 return 1;
389
390 rect1 = new Rect ();
391 rect2 = new Rect ();
392
393 paint.getTextBounds (TOFU_STRING, 0, TOFU_STRING.length (),
394 rect1);
395 paint.getTextBounds ("" + charCode, 0, 1, rect2);
396 return rect1.equals (rect2) ? 1 : 0;
397 }
398
399 private void
400 textExtents1 (Sdk7FontObject font, int code, FontMetrics metrics,
401 Paint paint, Rect bounds)
402 {
403 char[] text;
404 float[] width;
405
406 text = new char[1];
407 text[0] = (char) code;
408
409 paint.getTextBounds (text, 0, 1, bounds);
410 width = new float[1];
411 paint.getTextWidths (text, 0, 1, width);
412
413 /* bounds is the bounding box of the glyph corresponding to CODE.
414 Translate these into XCharStruct values.
415
416 The origin is at 0, 0, and lbearing is the distance counting
417 rightwards from the origin to the left most pixel in the glyph
418 raster. rbearing is the distance between the origin and the
419 rightmost pixel in the glyph raster. ascent is the distance
420 counting upwards between the the topmost pixel in the glyph
421 raster. descent is the distance (once again counting
422 downwards) between the origin and the bottommost pixel in the
423 glyph raster.
424
425 width is the distance between the origin and the origin of any
426 character to the right. */
427
428 metrics.lbearing = (short) bounds.left;
429 metrics.rbearing = (short) bounds.right;
430 metrics.ascent = (short) -bounds.top;
431 metrics.descent = (short) bounds.bottom;
432 metrics.width = (short) Math.round (width[0]);
433 }
434
435 @Override
436 public void
437 textExtents (FontObject font, int code[], FontMetrics fontMetrics[])
438 {
439 int i;
440 Paint paintCache;
441 Rect boundsCache;
442 Sdk7FontObject fontObject;
443
444 fontObject = (Sdk7FontObject) font;
445 paintCache = fontObject.typeface.typefacePaint;
446 paintCache.setTextSize (fontObject.pixelSize);
447 boundsCache = new Rect ();
448
449 for (i = 0; i < code.length; ++i)
450 textExtents1 ((Sdk7FontObject) font, code[i], fontMetrics[i],
451 paintCache, boundsCache);
452 }
453
454 @Override
455 public int
456 encodeChar (FontObject fontObject, char charCode)
457 {
458 return charCode;
459 }
460};
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
new file mode 100644
index 00000000000..311226e6f7e
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -0,0 +1,384 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.Runnable;
23import java.io.IOException;
24import java.util.List;
25import java.util.ArrayList;
26
27import android.graphics.Canvas;
28import android.graphics.Bitmap;
29import android.graphics.Point;
30
31import android.annotation.TargetApi;
32import android.app.Service;
33import android.content.Context;
34import android.content.Intent;
35import android.content.res.AssetManager;
36import android.os.Build;
37import android.os.Looper;
38import android.os.IBinder;
39import android.os.Handler;
40import android.util.Log;
41
42class Holder<T>
43{
44 T thing;
45};
46
47/* EmacsService is the service that starts the thread running Emacs
48 and handles requests by that Emacs instance. */
49
50public class EmacsService extends Service
51{
52 public static final String TAG = "EmacsService";
53 public static final int MAX_PENDING_REQUESTS = 256;
54 public static volatile EmacsService SERVICE;
55
56 private EmacsThread thread;
57 private Handler handler;
58 private EmacsPaintQueue paintQueue;
59
60 /* List of all EmacsWindows that are available to attach to an
61 activity. */
62 public static List<EmacsWindow> availableChildren;
63
64 static
65 {
66 availableChildren = new ArrayList<EmacsWindow> ();
67 };
68
69 @Override
70 public int
71 onStartCommand (Intent intent, int flags, int startId)
72 {
73 return START_NOT_STICKY;
74 }
75
76 @Override
77 public IBinder
78 onBind (Intent intent)
79 {
80 return null;
81 }
82
83 @TargetApi (Build.VERSION_CODES.GINGERBREAD)
84 String
85 getLibraryDirectory ()
86 {
87 int apiLevel;
88 Context context;
89
90 context = getApplicationContext ();
91 apiLevel = android.os.Build.VERSION.SDK_INT;
92
93 if (apiLevel >= Build.VERSION_CODES.GINGERBREAD)
94 return context.getApplicationInfo().nativeLibraryDir;
95 else if (apiLevel >= Build.VERSION_CODES.DONUT)
96 return context.getApplicationInfo().dataDir + "/lib";
97
98 return "/data/data/" + context.getPackageName() + "/lib";
99 }
100
101 @Override
102 public void
103 onCreate ()
104 {
105 AssetManager manager;
106 Context app_context;
107 String filesDir, libDir;
108
109 SERVICE = this;
110 handler = new Handler (Looper.getMainLooper ());
111 manager = getAssets ();
112 app_context = getApplicationContext ();
113
114 try
115 {
116 /* Configure Emacs with the asset manager and other necessary
117 parameters. */
118 filesDir = app_context.getFilesDir ().getCanonicalPath ();
119 libDir = getLibraryDirectory ();
120
121 Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir
122 + " and libDir = " + libDir);
123
124 EmacsNative.setEmacsParams (manager, filesDir, libDir,
125 this);
126
127 /* Start the thread that runs Emacs. */
128 thread = new EmacsThread (this);
129 thread.start ();
130 }
131 catch (IOException exception)
132 {
133 EmacsNative.emacsAbort ();
134 return;
135 }
136 }
137
138
139
140 /* Functions from here on must only be called from the Emacs
141 thread. */
142
143 void
144 runOnUiThread (Runnable runnable)
145 {
146 handler.post (runnable);
147 }
148
149 EmacsView
150 getEmacsView (final EmacsWindow window)
151 {
152 Runnable runnable;
153 final Holder<EmacsView> view;
154
155 view = new Holder<EmacsView> ();
156
157 runnable = new Runnable () {
158 public void
159 run ()
160 {
161 synchronized (this)
162 {
163 view.thing = new EmacsView (window);
164 notify ();
165 }
166 }
167 };
168
169 synchronized (runnable)
170 {
171 runOnUiThread (runnable);
172
173 try
174 {
175 runnable.wait ();
176 }
177 catch (InterruptedException e)
178 {
179 EmacsNative.emacsAbort ();
180 }
181 }
182
183 return view.thing;
184 }
185
186 /* Notice that a child of the root window named WINDOW is now
187 available for attachment to a specific activity. */
188
189 public void
190 noticeAvailableChild (final EmacsWindow window)
191 {
192 Log.d (TAG, "A new child is available: " + window);
193
194 handler.post (new Runnable () {
195 public void
196 run ()
197 {
198 for (EmacsActivity activity
199 : EmacsActivity.availableActivities)
200 {
201 /* TODO: check if the activity matches. */
202 activity.attachChild (window);
203 break;
204 }
205
206 /* Nope, wait for an activity to become available. */
207 availableChildren.add (window);
208 }
209 });
210 }
211
212 /* Notice that a child of the root window named WINDOW has been
213 destroyed. */
214
215 public void
216 noticeChildDestroyed (final EmacsWindow child)
217 {
218 handler.post (new Runnable () {
219 @Override
220 public void
221 run ()
222 {
223 availableChildren.remove (child);
224 }
225 });
226 }
227
228 /* X drawing operations. These are quite primitive operations. The
229 drawing queue is kept on the Emacs thread, but is periodically
230 flushed to the application thread, upon buffers swaps and once it
231 gets too big. */
232
233
234
235 private void
236 ensurePaintQueue ()
237 {
238 if (paintQueue == null)
239 paintQueue = new EmacsPaintQueue ();
240 }
241
242 public void
243 flushPaintQueue ()
244 {
245 final EmacsPaintQueue queue;
246
247 if (paintQueue == null)
248 return;
249
250 if (paintQueue.numRequests < 1)
251 /* No requests to flush. */
252 return;
253
254 queue = paintQueue;
255
256 handler.post (new Runnable () {
257 @Override
258 public void
259 run ()
260 {
261 queue.run ();
262 }
263 });
264
265 /* Clear the paint queue. */
266 paintQueue = null;
267 }
268
269 private void
270 checkFlush ()
271 {
272 if (paintQueue != null
273 && paintQueue.numRequests > MAX_PENDING_REQUESTS)
274 flushPaintQueue ();
275 }
276
277 public void
278 fillRectangle (EmacsDrawable drawable, EmacsGC gc,
279 int x, int y, int width, int height)
280 {
281 EmacsPaintReq req;
282
283 ensurePaintQueue ();
284
285 req = new EmacsFillRectangle (drawable, x, y,
286 width, height,
287 gc.immutableGC ());
288 paintQueue.appendPaintOperation (req);
289 checkFlush ();
290 }
291
292 public void
293 fillPolygon (EmacsDrawable drawable, EmacsGC gc,
294 Point points[])
295 {
296 EmacsPaintReq req;
297
298 ensurePaintQueue ();
299
300 req = new EmacsFillPolygon (drawable, points,
301 gc.immutableGC ());
302 paintQueue.appendPaintOperation (req);
303 checkFlush ();
304 }
305
306 public void
307 drawRectangle (EmacsDrawable drawable, EmacsGC gc,
308 int x, int y, int width, int height)
309 {
310 EmacsPaintReq req;
311
312 ensurePaintQueue ();
313
314 if (gc.clip_rects != null && gc.clip_rects.length >= 1)
315 android.util.Log.d ("drawRectangle",
316 gc.clip_rects[0].toString ()
317 + " " + gc.toString ());
318
319 req = new EmacsDrawRectangle (drawable, x, y,
320 width, height,
321 gc.immutableGC ());
322 paintQueue.appendPaintOperation (req);
323 checkFlush ();
324 }
325
326 public void
327 drawLine (EmacsDrawable drawable, EmacsGC gc,
328 int x, int y, int x2, int y2)
329 {
330 EmacsPaintReq req;
331
332 ensurePaintQueue ();
333
334 req = new EmacsDrawLine (drawable, x, y,
335 x2, y2,
336 gc.immutableGC ());
337 paintQueue.appendPaintOperation (req);
338 checkFlush ();
339 }
340
341 public void
342 drawPoint (EmacsDrawable drawable, EmacsGC gc,
343 int x, int y)
344 {
345 EmacsPaintReq req;
346
347 ensurePaintQueue ();
348
349 req = new EmacsDrawPoint (drawable, x, y,
350 gc.immutableGC ());
351 paintQueue.appendPaintOperation (req);
352 checkFlush ();
353 }
354
355 public void
356 copyArea (EmacsDrawable srcDrawable, EmacsDrawable dstDrawable,
357 EmacsGC gc,
358 int srcX, int srcY, int width, int height, int destX,
359 int destY)
360 {
361 EmacsPaintReq req;
362
363 ensurePaintQueue ();
364
365 req = new EmacsCopyArea (srcDrawable, dstDrawable,
366 srcX, srcY, width, height, destX,
367 destY, gc.immutableGC ());
368 paintQueue.appendPaintOperation (req);
369 checkFlush ();
370 }
371
372 public void
373 clearWindow (EmacsWindow window)
374 {
375 window.clearWindow ();
376 }
377
378 public void
379 clearArea (EmacsWindow window, int x, int y, int width,
380 int height)
381 {
382 window.clearArea (x, y, width, height);
383 }
384};
diff --git a/java/org/gnu/emacs/EmacsSurfaceView.java b/java/org/gnu/emacs/EmacsSurfaceView.java
new file mode 100644
index 00000000000..194f6ad37a3
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsSurfaceView.java
@@ -0,0 +1,83 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.view.SurfaceView;
23import android.view.SurfaceHolder;
24
25import android.graphics.Canvas;
26import android.graphics.Rect;
27
28public class EmacsSurfaceView extends SurfaceView
29{
30 private boolean created;
31
32 public
33 EmacsSurfaceView (final EmacsView view)
34 {
35 super (view.getContext ());
36
37 getHolder ().addCallback (new SurfaceHolder.Callback () {
38 @Override
39 public void
40 surfaceChanged (SurfaceHolder holder, int format,
41 int width, int height)
42 {
43
44 }
45
46 @Override
47 public void
48 surfaceCreated (SurfaceHolder holder)
49 {
50 created = true;
51
52 /* Force a buffer swap now to get the contents of the Emacs
53 view on screen. */
54 view.swapBuffers ();
55 }
56
57 @Override
58 public void
59 surfaceDestroyed (SurfaceHolder holder)
60 {
61 created = false;
62 }
63 });
64 }
65
66 public boolean
67 isCreated ()
68 {
69 return created;
70 }
71
72 public Canvas
73 lockCanvas (Rect damage)
74 {
75 return getHolder ().lockCanvas (damage);
76 }
77
78 public void
79 unlockCanvasAndPost (Canvas canvas)
80 {
81 getHolder ().unlockCanvasAndPost (canvas);
82 }
83};
diff --git a/java/org/gnu/emacs/EmacsThread.java b/java/org/gnu/emacs/EmacsThread.java
new file mode 100644
index 00000000000..e9281a13391
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsThread.java
@@ -0,0 +1,44 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.Thread;
23
24public class EmacsThread extends Thread
25{
26 EmacsService context;
27
28 public
29 EmacsThread (EmacsService service)
30 {
31 context = service;
32 }
33
34 public void
35 run ()
36 {
37 String args[];
38
39 args = new String[] { "android-emacs", };
40
41 /* Run the native code now. */
42 EmacsNative.initEmacs (args);
43 }
44};
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java
new file mode 100644
index 00000000000..237946d6366
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -0,0 +1,211 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import android.view.View;
23import android.view.KeyEvent;
24import android.view.ViewGroup;
25import android.graphics.Bitmap;
26import android.graphics.Canvas;
27import android.graphics.Rect;
28import android.graphics.Region;
29import android.graphics.Paint;
30import android.util.Log;
31
32import android.os.Build;
33
34/* This is an Android view which has a back and front buffer. When
35 swapBuffers is called, the back buffer is swapped to the front
36 buffer, and any damage is invalidated. frontBitmap and backBitmap
37 are modified and used both from the UI and the Emacs thread. As a
38 result, there is a lock held during all drawing operations.
39
40 It is also a ViewGroup, as it also lays out children. */
41
42public class EmacsView extends ViewGroup
43{
44 public static final String TAG = "EmacsView";
45
46 /* The associated EmacsWindow. */
47 public EmacsWindow window;
48
49 /* The buffer bitmap. */
50 public Bitmap bitmap;
51
52 /* The associated canvases. */
53 public Canvas canvas;
54
55 /* The damage region. */
56 public Region damageRegion;
57
58 /* The paint. */
59 public Paint paint;
60
61 /* The associated surface view. */
62 private EmacsSurfaceView surfaceView;
63
64 public
65 EmacsView (EmacsWindow window)
66 {
67 super (EmacsService.SERVICE);
68
69 this.window = window;
70 this.damageRegion = new Region ();
71 this.paint = new Paint ();
72
73 /* Create the surface view. */
74 this.surfaceView = new EmacsSurfaceView (this);
75
76 setFocusable (FOCUSABLE);
77 addView (this.surfaceView);
78 }
79
80 @Override
81 protected void
82 onMeasure (int widthMeasureSpec, int heightMeasureSpec)
83 {
84 Rect measurements;
85 int width, height;
86
87 /* Return the width and height of the window regardless of what
88 the parent says. */
89 measurements = window.getGeometry ();
90
91 width = measurements.width ();
92 height = measurements.height ();
93
94 /* Now apply any extra requirements in widthMeasureSpec and
95 heightMeasureSpec. */
96
97 if (MeasureSpec.getMode (widthMeasureSpec) == MeasureSpec.EXACTLY)
98 width = MeasureSpec.getSize (widthMeasureSpec);
99 else if (MeasureSpec.getMode (widthMeasureSpec) == MeasureSpec.AT_MOST
100 && width > MeasureSpec.getSize (widthMeasureSpec))
101 width = MeasureSpec.getSize (widthMeasureSpec);
102
103 if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.EXACTLY)
104 height = MeasureSpec.getSize (heightMeasureSpec);
105 else if (MeasureSpec.getMode (heightMeasureSpec) == MeasureSpec.AT_MOST
106 && height > MeasureSpec.getSize (heightMeasureSpec))
107 height = MeasureSpec.getSize (heightMeasureSpec);
108
109 super.setMeasuredDimension (width, height);
110 }
111
112 @Override
113 protected void
114 onLayout (boolean changed, int left, int top, int right,
115 int bottom)
116 {
117 int count, i;
118 View child;
119 Rect windowRect;
120
121 if (changed)
122 {
123 window.viewLayout (left, top, right, bottom);
124
125 /* Recreate the front and back buffer bitmaps. */
126 bitmap
127 = Bitmap.createBitmap (right - left, bottom - top,
128 Bitmap.Config.ARGB_8888);
129
130 /* And canvases. */
131 canvas = new Canvas (bitmap);
132 }
133
134 count = getChildCount ();
135
136 for (i = 0; i < count; ++i)
137 {
138 child = getChildAt (i);
139
140 if (child == surfaceView)
141 /* The child is the surface view, so give it the entire
142 view. */
143 child.layout (left, top, right, bottom);
144 else if (child.getVisibility () != GONE)
145 {
146 if (!(child instanceof EmacsView))
147 continue;
148
149 /* What to do: lay out the view precisely according to its
150 window rect. */
151 windowRect = ((EmacsView) child).window.getGeometry ();
152 child.layout (windowRect.left, windowRect.top,
153 windowRect.right, windowRect.bottom);
154 }
155 }
156 }
157
158 public void
159 damageRect (Rect damageRect)
160 {
161 damageRegion.union (damageRect);
162 }
163
164 public void
165 swapBuffers ()
166 {
167 Bitmap back;
168 Canvas canvas;
169 Rect damageRect;
170
171 if (damageRegion.isEmpty ())
172 return;
173
174 if (!surfaceView.isCreated ())
175 return;
176
177 if (bitmap == null)
178 return;
179
180 /* Lock the canvas with the specified damage. */
181 damageRect = damageRegion.getBounds ();
182 canvas = surfaceView.lockCanvas (damageRect);
183
184 /* Return if locking the canvas failed. */
185 if (canvas == null)
186 return;
187
188 /* Copy from the back buffer to the canvas. */
189 canvas.drawBitmap (bitmap, damageRect, damageRect, paint);
190
191 /* Unlock the canvas and clear the damage. */
192 surfaceView.unlockCanvasAndPost (canvas);
193 damageRegion.setEmpty ();
194 }
195
196 @Override
197 public boolean
198 onKeyDown (int keyCode, KeyEvent event)
199 {
200 window.onKeyDown (keyCode, event);
201 return true;
202 }
203
204 @Override
205 public boolean
206 onKeyUp (int keyCode, KeyEvent event)
207 {
208 window.onKeyUp (keyCode, event);
209 return true;
210 }
211};
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java
new file mode 100644
index 00000000000..28db04a261d
--- /dev/null
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -0,0 +1,336 @@
1/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20package org.gnu.emacs;
21
22import java.lang.IllegalStateException;
23import java.util.ArrayList;
24import java.util.List;
25
26import android.graphics.Rect;
27import android.graphics.Canvas;
28import android.graphics.Bitmap;
29import android.graphics.Point;
30
31import android.view.View;
32import android.view.ViewGroup;
33import android.view.KeyEvent;
34
35/* This defines a window, which is a handle. Windows represent a
36 rectangular subset of the screen with their own contents.
37
38 Windows either have a parent window, in which case their views are
39 attached to the parent's view, or are "floating", in which case
40 their views are attached to the parent activity (if any), else
41 nothing.
42
43 Views are also drawables, meaning they can accept drawing
44 requests. */
45
46public class EmacsWindow extends EmacsHandleObject
47 implements EmacsDrawable
48{
49 /* The view associated with the window. */
50 public EmacsView view;
51
52 /* The geometry of the window. */
53 private Rect rect;
54
55 /* The parent window, or null if it is the root window. */
56 private EmacsWindow parent;
57
58 /* List of all children in stacking order. This must be kept
59 consistent! */
60 private ArrayList<EmacsWindow> children;
61
62 /* The EmacsActivity currently attached, if it exists. */
63 private EmacsActivity attached;
64
65 /* The window background scratch GC. foreground is always the
66 window background. */
67 private EmacsGC scratchGC;
68
69 public
70 EmacsWindow (short handle, final EmacsWindow parent, int x, int y,
71 int width, int height)
72 {
73 super (handle);
74
75 rect = new Rect (x, y, x + width, y + height);
76
77 /* Create the view from the context's UI thread. */
78 view = EmacsService.SERVICE.getEmacsView (this);
79 this.parent = parent;
80 children = new ArrayList<EmacsWindow> ();
81
82 /* The window is unmapped by default. */
83 view.setVisibility (View.GONE);
84
85 /* If parent is the root window, notice that there are new
86 children available for interested activites to pick up. */
87 if (parent == null)
88 EmacsService.SERVICE.noticeAvailableChild (this);
89 else
90 {
91 /* Otherwise, directly add this window as a child of that
92 window's view. */
93 synchronized (parent)
94 {
95 parent.children.add (this);
96 parent.view.post (new Runnable () {
97 @Override
98 public void
99 run ()
100 {
101 parent.view.addView (view);
102 }
103 });
104 }
105 }
106
107 scratchGC = new EmacsGC ((short) 0);
108 }
109
110 public void
111 changeWindowBackground (int pixel)
112 {
113 /* scratchGC is used as the argument to a FillRectangles req. */
114 scratchGC.foreground = pixel;
115 scratchGC.markDirty ();
116 }
117
118 public Rect
119 getGeometry ()
120 {
121 synchronized (this)
122 {
123 /* Huh, this is it. */
124 return rect;
125 }
126 }
127
128 @Override
129 public void
130 destroyHandle () throws IllegalStateException
131 {
132 synchronized (this)
133 {
134 if (!children.isEmpty ())
135 throw new IllegalStateException ("Trying to destroy window with "
136 + "children!");
137 }
138
139 /* Notice that the child has been destroyed. */
140 EmacsService.SERVICE.noticeChildDestroyed (this);
141
142 /* Remove the view from its parent and make it invisible. */
143 view.post (new Runnable () {
144 public void
145 run ()
146 {
147 view.setVisibility (View.GONE);
148
149 if (view.getParent () != null)
150 ((ViewGroup) view.getParent ()).removeView (view);
151
152 if (attached != null)
153 attached.makeAvailable ();
154 }
155 });
156
157 super.destroyHandle ();
158 }
159
160 public void
161 setActivity (EmacsActivity activity)
162 {
163 synchronized (this)
164 {
165 activity = activity;
166 }
167 }
168
169 public void
170 viewLayout (int left, int top, int right, int bottom)
171 {
172 synchronized (this)
173 {
174 rect.left = left;
175 rect.top = top;
176 rect.right = right;
177 rect.bottom = bottom;
178
179 EmacsNative.sendConfigureNotify (this.handle,
180 System.currentTimeMillis (),
181 left, top, rect.width (),
182 rect.height ());
183 }
184 }
185
186 public void
187 requestViewLayout ()
188 {
189 view.post (new Runnable () {
190 @Override
191 public void
192 run ()
193 {
194 view.requestLayout ();
195 }
196 });
197 }
198
199 public void
200 resizeWindow (int width, int height)
201 {
202 synchronized (this)
203 {
204 rect.right = rect.left + width;
205 rect.bottom = rect.top + height;
206 }
207 }
208
209 public void
210 moveWindow (int x, int y)
211 {
212 int width, height;
213
214 synchronized (this)
215 {
216 width = rect.width ();
217 height = rect.height ();
218
219 rect.left = x;
220 rect.top = y;
221 rect.right = x + width;
222 rect.bottom = y + height;
223
224 requestViewLayout ();
225 }
226 }
227
228 public void
229 mapWindow ()
230 {
231 view.post (new Runnable () {
232 @Override
233 public void
234 run ()
235 {
236 view.setVisibility (View.VISIBLE);
237 }
238 });
239 }
240
241 public void
242 unmapWindow ()
243 {
244 view.post (new Runnable () {
245 @Override
246 public void
247 run ()
248 {
249 view.setVisibility (View.GONE);
250 }
251 });
252 }
253
254 @Override
255 public Canvas
256 lockCanvas ()
257 {
258 if (view.canvas != null)
259 return view.canvas;
260
261 return null;
262 }
263
264 @Override
265 public void
266 unlockCanvas ()
267 {
268
269 }
270
271 @Override
272 public void
273 damageRect (Rect damageRect)
274 {
275 view.damageRect (damageRect);
276 }
277
278 public void
279 swapBuffers ()
280 {
281 /* Before calling swapBuffers, make sure to flush the paint
282 queue. */
283 EmacsService.SERVICE.flushPaintQueue ();
284 view.post (new Runnable () {
285 @Override
286 public void
287 run ()
288 {
289 view.swapBuffers ();
290 }
291 });
292 }
293
294 public void
295 clearWindow ()
296 {
297 synchronized (this)
298 {
299 EmacsService.SERVICE.fillRectangle (this, scratchGC,
300 0, 0, rect.width (),
301 rect.height ());
302 }
303 }
304
305 public void
306 clearArea (int x, int y, int width, int height)
307 {
308 EmacsService.SERVICE.fillRectangle (this, scratchGC,
309 x, y, width, height);
310 }
311
312 @Override
313 public Bitmap
314 getBitmap ()
315 {
316 return view.bitmap;
317 }
318
319 public void
320 onKeyDown (int keyCode, KeyEvent event)
321 {
322 EmacsNative.sendKeyPress (this.handle,
323 event.getEventTime (),
324 event.getModifiers (),
325 keyCode);
326 }
327
328 public void
329 onKeyUp (int keyCode, KeyEvent event)
330 {
331 EmacsNative.sendKeyRelease (this.handle,
332 event.getEventTime (),
333 event.getModifiers (),
334 keyCode);
335 }
336};
diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in
index cfad3fc3941..e3e4fefe651 100644
--- a/lib-src/Makefile.in
+++ b/lib-src/Makefile.in
@@ -96,6 +96,14 @@ localstatedir=@localstatedir@
96srcdir=@srcdir@ 96srcdir=@srcdir@
97VPATH=@srcdir@ 97VPATH=@srcdir@
98 98
99# Cross-compilation setup
100
101XCONFIGURE=@XCONFIGURE@
102
103ifneq ($(XCONFIGURE),)
104vpath $(srcdir)
105endif
106
99# The top-level source directory, also set by configure. 107# The top-level source directory, also set by configure.
100top_srcdir=@top_srcdir@ 108top_srcdir=@top_srcdir@
101# MinGW CPPFLAGS may use this. 109# MinGW CPPFLAGS may use this.
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 8b950136241..caf8e0fbec3 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -20,6 +20,130 @@
20srcdir = @srcdir@ 20srcdir = @srcdir@
21VPATH = @srcdir@ 21VPATH = @srcdir@
22 22
23# This is not empty if this is a Makefile that will be copied to
24# xcompile/lib.
25XCONFIGURE = @XCONFIGURE@
26
27# This is required to make sure symbol visibility is correct and
28# functions like readlinkat do not end up replacing their OS
29# counterparts.
30ANDROID_CFLAGS = @ANDROID_CFLAGS@
31
32ifneq ($(XCONFIGURE),)
33
34# Set vpath. Only look for C files and some headers in srcdir:
35# Headers that are generated by gnulib must be spared, or otherwise
36# the versions previously built on the host will be used, if builddir
37# is the same as srcdir. Following this is a list of files in lib/
38# that are not generated during the gnulib build process. Please keep
39# it up to date!
40
41vpath _Noreturn.h $(srcdir)
42vpath acl-internal.h $(srcdir)
43vpath acl.h $(srcdir)
44vpath af_alg.h $(srcdir)
45vpath alloca.in.h $(srcdir)
46vpath allocator.h $(srcdir)
47vpath arg-nonnull.h $(srcdir)
48vpath assert.in.h $(srcdir)
49vpath attribute.h $(srcdir)
50vpath binary-io.h $(srcdir)
51vpath byteswap.in.h $(srcdir)
52vpath c++defs.h $(srcdir)
53vpath c-ctype.h $(srcdir)
54vpath c-strcase.h $(srcdir)
55vpath careadlinkat.h $(srcdir)
56vpath cdefs.h $(srcdir)
57vpath cloexec.h $(srcdir)
58vpath close-stream.h $(srcdir)
59vpath count-leading-zeros.h $(srcdir)
60vpath count-one-bits.h $(srcdir)
61vpath count-trailing-zeros.h $(srcdir)
62vpath diffseq.h $(srcdir)
63vpath dirent.h $(srcdir)
64vpath dirent.in.h $(srcdir)
65vpath dynarray.h $(srcdir)
66vpath eloop-threshold.h $(srcdir)
67vpath errno.in.h $(srcdir)
68vpath execinfo.in.h $(srcdir)
69vpath fcntl.in.h $(srcdir)
70vpath filemode.h $(srcdir)
71vpath filename.h $(srcdir)
72vpath filevercmp.h $(srcdir)
73vpath fingerprint.h $(srcdir)
74vpath flexmember.h $(srcdir)
75vpath fpending.h $(srcdir)
76vpath fsusage.h $(srcdir)
77vpath ftoastr.h $(srcdir)
78vpath getopt-cdefs.in.h $(srcdir)
79vpath getopt-core.h $(srcdir)
80vpath getopt-ext.h $(srcdir)
81vpath getopt-pfx-core.h $(srcdir)
82vpath getopt-pfx-ext.h $(srcdir)
83vpath getopt.in.h $(srcdir)
84vpath getopt_int.h $(srcdir)
85vpath gettext.h $(srcdir)
86vpath idx.h $(srcdir)
87vpath ieee754.in.h $(srcdir)
88vpath ignore-value.h $(srcdir)
89vpath intprops-internal.h $(srcdir)
90vpath intprops.h $(srcdir)
91vpath inttypes.in.h $(srcdir)
92vpath libc-config.h $(srcdir)
93vpath limits.in.h $(srcdir)
94vpath malloc/dynarray.h $(srcdir)
95vpath malloc/scratch_buffer.h $(srcdir)
96vpath md5.h $(srcdir)
97vpath min-max.h $(srcdir)
98vpath mini-gmp.h $(srcdir)
99vpath minmax.h $(srcdir)
100vpath mktime-internal.h $(srcdir)
101vpath nproc.h $(srcdir)
102vpath openat-priv.h $(srcdir)
103vpath openat.h $(srcdir)
104vpath pathmax.h $(srcdir)
105vpath regex.h $(srcdir)
106vpath regex_internal.h $(srcdir)
107vpath root-uid.h $(srcdir)
108vpath save-cwd.h $(srcdir)
109vpath scratch_buffer.h $(srcdir)
110vpath sha1.h $(srcdir)
111vpath sha256.h $(srcdir)
112vpath sha512.h $(srcdir)
113vpath sig2str.h $(srcdir)
114vpath signal.in.h $(srcdir)
115vpath stat-time.h $(srcdir)
116vpath stdalign.in.h $(srcdir)
117vpath stdckdint.in.h $(srcdir)
118vpath stddef.in.h $(srcdir)
119vpath stdint.in.h $(srcdir)
120vpath stdio-impl.h $(srcdir)
121vpath stdio.h $(srcdir)
122vpath stdio.in.h $(srcdir)
123vpath stdlib.in.h $(srcdir)
124vpath str-two-way.h $(srcdir)
125vpath strftime.h $(srcdir)
126vpath string.in.h $(srcdir)
127vpath sys_random.in.h $(srcdir)
128vpath sys_select.in.h $(srcdir)
129vpath sys_stat.in.h $(srcdir)
130vpath sys_time.in.h $(srcdir)
131vpath sys_types.in.h $(srcdir)
132vpath tempname.h $(srcdir)
133vpath time-internal.h $(srcdir)
134vpath time.in.h $(srcdir)
135vpath timespec.h $(srcdir)
136vpath u64.h $(srcdir)
137vpath unistd.in.h $(srcdir)
138vpath unlocked-io.h $(srcdir)
139vpath utimens.h $(srcdir)
140vpath verify.h $(srcdir)
141vpath vla.h $(srcdir)
142vpath warn-on-use.h $(srcdir)
143vpath xalloc-oversized.h $(srcdir)
144vpath %.c $(srcdir)
145endif
146
23# Variables substituted by 'configure', and not autogenerated in gnulib.mk, 147# Variables substituted by 'configure', and not autogenerated in gnulib.mk,
24# or needed before gnulib.mk is included. 148# or needed before gnulib.mk is included.
25abs_top_srcdir = @abs_top_srcdir@ 149abs_top_srcdir = @abs_top_srcdir@
@@ -33,11 +157,11 @@ all:
33 157
34HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@ 158HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@
35 159
36ALL_CFLAGS= \ 160ALL_CFLAGS = \
37 $(C_SWITCH_SYSTEM) $(C_SWITCH_MACHINE) $(DEPFLAGS) \ 161 $(C_SWITCH_SYSTEM) $(C_SWITCH_MACHINE) $(DEPFLAGS) \
38 $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS) $(PROFILING_CFLAGS) $(CFLAGS) \ 162 $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS) $(PROFILING_CFLAGS) $(CFLAGS) \
39 -I. -I../src -I$(srcdir) -I$(srcdir)/../src \ 163 -I. -I../src -I$(srcdir) -I$(srcdir)/../src \
40 $(if $(patsubst e-%,,$(notdir $<)),,-Demacs) 164 $(if $(patsubst e-%,,$(notdir $<)),,-Demacs) $(ANDROID_CFLAGS)
41 165
42ifeq ($(HAVE_NATIVE_COMP),yes) 166ifeq ($(HAVE_NATIVE_COMP),yes)
43ALL_CFLAGS += -DGL_COMPILE_CRYPTO_STREAM 167ALL_CFLAGS += -DGL_COMPILE_CRYPTO_STREAM
@@ -52,6 +176,12 @@ ifneq ($(SYSTEM_TYPE),windows-nt)
52 libgnu_a_SOURCES += openat-die.c save-cwd.c 176 libgnu_a_SOURCES += openat-die.c save-cwd.c
53endif 177endif
54 178
179ifeq ($(XCONFIGURE),android)
180# The next line is necessary to override -I$(srcdir), which will end
181# up pulling in lots of headers from the host.
182ALL_CFLAGS += -I$(top_srcdir)/xcompile -I.
183endif
184
55DEPDIR = deps 185DEPDIR = deps
56ifeq ($(AUTO_DEPEND),yes) 186ifeq ($(AUTO_DEPEND),yes)
57 DEPFLAGS = -MMD -MF $(DEPDIR)/$*.d -MP 187 DEPFLAGS = -MMD -MF $(DEPDIR)/$*.d -MP
@@ -60,11 +190,14 @@ else
60 DEPFLAGS = 190 DEPFLAGS =
61endif 191endif
62 192
193# This piece of code interferes with cross compilation
194ifeq ($(XCONFIGURE),)
63.PRECIOUS: ../config.status Makefile 195.PRECIOUS: ../config.status Makefile
64../config.status: $(top_srcdir)/configure.ac $(top_srcdir)/m4/*.m4 196../config.status: $(top_srcdir)/configure.ac $(top_srcdir)/m4/*.m4
65 $(MAKE) -C .. $(notdir $@) 197 $(MAKE) -C .. $(notdir $@)
66Makefile: ../config.status $(srcdir)/Makefile.in 198Makefile: ../config.status $(srcdir)/Makefile.in
67 $(MAKE) -C .. lib/$@ 199 $(MAKE) -C .. lib/$@
200endif
68 201
69# Object modules that need not be built for Emacs. 202# Object modules that need not be built for Emacs.
70# Emacs does not need e-regex.o (it has its own regex-emacs.c), 203# Emacs does not need e-regex.o (it has its own regex-emacs.c),
diff --git a/lib/faccessat.c b/lib/faccessat.c
index c1737d03a10..30a22da7eb1 100644
--- a/lib/faccessat.c
+++ b/lib/faccessat.c
@@ -43,7 +43,11 @@ orig_faccessat (int fd, char const *name, int mode, int flag)
43/* Write "unistd.h" here, not <unistd.h>, otherwise OSF/1 5.1 DTK cc 43/* Write "unistd.h" here, not <unistd.h>, otherwise OSF/1 5.1 DTK cc
44 eliminates this include because of the preliminary #include <unistd.h> 44 eliminates this include because of the preliminary #include <unistd.h>
45 above. */ 45 above. */
46#ifdef __ANROID__
47#include <unistd.h>
48#else
46#include "unistd.h" 49#include "unistd.h"
50#endif
47 51
48#ifndef HAVE_ACCESS 52#ifndef HAVE_ACCESS
49/* Mingw lacks access, but it also lacks real vs. effective ids, so 53/* Mingw lacks access, but it also lacks real vs. effective ids, so
diff --git a/lib/fpending.c b/lib/fpending.c
index 6408cff4647..45daa2586a0 100644
--- a/lib/fpending.c
+++ b/lib/fpending.c
@@ -33,13 +33,15 @@
33size_t 33size_t
34__fpending (FILE *fp) 34__fpending (FILE *fp)
35{ 35{
36#if defined __ANDROID__
37 return 0;
36 /* Most systems provide FILE as a struct and the necessary bitmask in 38 /* Most systems provide FILE as a struct and the necessary bitmask in
37 <stdio.h>, because they need it for implementing getc() and putc() as 39 <stdio.h>, because they need it for implementing getc() and putc() as
38 fast macros. */ 40 fast macros. */
39#if defined _IO_EOF_SEEN || defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 41#elif defined _IO_EOF_SEEN || defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1
40 /* GNU libc, BeOS, Haiku, Linux libc5 */ 42 /* GNU libc, BeOS, Haiku, Linux libc5 */
41 return fp->_IO_write_ptr - fp->_IO_write_base; 43 return fp->_IO_write_ptr - fp->_IO_write_base;
42#elif defined __sferror || defined __DragonFly__ || defined __ANDROID__ 44#elif defined __sferror || defined __DragonFly__
43 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin < 1.7.34, Minix 3, Android */ 45 /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin < 1.7.34, Minix 3, Android */
44 return fp->_p - fp->_bf._base; 46 return fp->_p - fp->_bf._base;
45#elif defined __EMX__ /* emx+gcc */ 47#elif defined __EMX__ /* emx+gcc */
diff --git a/lib/open.c b/lib/open.c
index 170bff108e3..dd7c90b3bd6 100644
--- a/lib/open.c
+++ b/lib/open.c
@@ -40,7 +40,11 @@ orig_open (const char *filename, int flags, mode_t mode)
40/* Specification. */ 40/* Specification. */
41/* Write "fcntl.h" here, not <fcntl.h>, otherwise OSF/1 5.1 DTK cc eliminates 41/* Write "fcntl.h" here, not <fcntl.h>, otherwise OSF/1 5.1 DTK cc eliminates
42 this include because of the preliminary #include <fcntl.h> above. */ 42 this include because of the preliminary #include <fcntl.h> above. */
43#ifdef __ANDROID__
44#include <fnctl.h>
45#else
43#include "fcntl.h" 46#include "fcntl.h"
47#endif
44 48
45#include "cloexec.h" 49#include "cloexec.h"
46 50
diff --git a/lib/unistd.c b/lib/unistd.c
index 95978e6ad0a..dcc70091155 100644
--- a/lib/unistd.c
+++ b/lib/unistd.c
@@ -18,5 +18,5 @@
18#include <config.h> 18#include <config.h>
19 19
20#define _GL_UNISTD_INLINE _GL_EXTERN_INLINE 20#define _GL_UNISTD_INLINE _GL_EXTERN_INLINE
21#include "unistd.h" 21#include <unistd.h>
22typedef int dummy; 22typedef int dummy;
diff --git a/lisp/frame.el b/lisp/frame.el
index e4cd2cd8ae2..62cc4d7a38d 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -2137,7 +2137,8 @@ frames and several different fonts at once. This is true for displays
2137that use a window system such as X, and false for text-only terminals. 2137that use a window system such as X, and false for text-only terminals.
2138DISPLAY can be a display name, a frame, or nil (meaning the selected 2138DISPLAY can be a display name, a frame, or nil (meaning the selected
2139frame's display)." 2139frame's display)."
2140 (not (null (memq (framep-on-display display) '(x w32 ns pgtk haiku))))) 2140 (not (null (memq (framep-on-display display) '(x w32 ns pgtk haiku
2141 android)))))
2141 2142
2142(defun display-images-p (&optional display) 2143(defun display-images-p (&optional display)
2143 "Return non-nil if DISPLAY can display images. 2144 "Return non-nil if DISPLAY can display images.
@@ -2202,7 +2203,7 @@ DISPLAY should be either a frame or a display name (a string).
2202If DISPLAY is omitted or nil, it defaults to the selected frame's display." 2203If DISPLAY is omitted or nil, it defaults to the selected frame's display."
2203 (let ((frame-type (framep-on-display display))) 2204 (let ((frame-type (framep-on-display display)))
2204 (cond 2205 (cond
2205 ((memq frame-type '(x w32 ns haiku pgtk)) 2206 ((memq frame-type '(x w32 ns haiku pgtk android))
2206 (x-display-screens display)) 2207 (x-display-screens display))
2207 (t 2208 (t
2208 1)))) 2209 1))))
@@ -2222,7 +2223,7 @@ with DISPLAY. To get information for each physical monitor, use
2222`display-monitor-attributes-list'." 2223`display-monitor-attributes-list'."
2223 (let ((frame-type (framep-on-display display))) 2224 (let ((frame-type (framep-on-display display)))
2224 (cond 2225 (cond
2225 ((memq frame-type '(x w32 ns haiku pgtk)) 2226 ((memq frame-type '(x w32 ns haiku pgtk android))
2226 (x-display-pixel-height display)) 2227 (x-display-pixel-height display))
2227 (t 2228 (t
2228 (frame-height (if (framep display) display (selected-frame))))))) 2229 (frame-height (if (framep display) display (selected-frame)))))))
@@ -2242,7 +2243,7 @@ with DISPLAY. To get information for each physical monitor, use
2242`display-monitor-attributes-list'." 2243`display-monitor-attributes-list'."
2243 (let ((frame-type (framep-on-display display))) 2244 (let ((frame-type (framep-on-display display)))
2244 (cond 2245 (cond
2245 ((memq frame-type '(x w32 ns haiku pgtk)) 2246 ((memq frame-type '(x w32 ns haiku pgtk android))
2246 (x-display-pixel-width display)) 2247 (x-display-pixel-width display))
2247 (t 2248 (t
2248 (frame-width (if (framep display) display (selected-frame))))))) 2249 (frame-width (if (framep display) display (selected-frame)))))))
@@ -2280,7 +2281,7 @@ For graphical terminals, note that on \"multi-monitor\" setups this
2280refers to the height in millimeters for all physical monitors 2281refers to the height in millimeters for all physical monitors
2281associated with DISPLAY. To get information for each physical 2282associated with DISPLAY. To get information for each physical
2282monitor, use `display-monitor-attributes-list'." 2283monitor, use `display-monitor-attributes-list'."
2283 (and (memq (framep-on-display display) '(x w32 ns haiku pgtk)) 2284 (and (memq (framep-on-display display) '(x w32 ns haiku pgtk android))
2284 (or (cddr (assoc (or display (frame-parameter nil 'display)) 2285 (or (cddr (assoc (or display (frame-parameter nil 'display))
2285 display-mm-dimensions-alist)) 2286 display-mm-dimensions-alist))
2286 (cddr (assoc t display-mm-dimensions-alist)) 2287 (cddr (assoc t display-mm-dimensions-alist))
@@ -2301,7 +2302,7 @@ For graphical terminals, note that on \"multi-monitor\" setups this
2301refers to the width in millimeters for all physical monitors 2302refers to the width in millimeters for all physical monitors
2302associated with DISPLAY. To get information for each physical 2303associated with DISPLAY. To get information for each physical
2303monitor, use `display-monitor-attributes-list'." 2304monitor, use `display-monitor-attributes-list'."
2304 (and (memq (framep-on-display display) '(x w32 ns haiku pgtk)) 2305 (and (memq (framep-on-display display) '(x w32 ns haiku pgtk android))
2305 (or (cadr (assoc (or display (frame-parameter nil 'display)) 2306 (or (cadr (assoc (or display (frame-parameter nil 'display))
2306 display-mm-dimensions-alist)) 2307 display-mm-dimensions-alist))
2307 (cadr (assoc t display-mm-dimensions-alist)) 2308 (cadr (assoc t display-mm-dimensions-alist))
@@ -2319,7 +2320,7 @@ DISPLAY can be a display name or a frame.
2319If DISPLAY is omitted or nil, it defaults to the selected frame's display." 2320If DISPLAY is omitted or nil, it defaults to the selected frame's display."
2320 (let ((frame-type (framep-on-display display))) 2321 (let ((frame-type (framep-on-display display)))
2321 (cond 2322 (cond
2322 ((memq frame-type '(x w32 ns haiku pgtk)) 2323 ((memq frame-type '(x w32 ns haiku pgtk android))
2323 (x-display-backing-store display)) 2324 (x-display-backing-store display))
2324 (t 2325 (t
2325 'not-useful)))) 2326 'not-useful))))
@@ -2332,7 +2333,7 @@ DISPLAY can be a display name or a frame.
2332If DISPLAY is omitted or nil, it defaults to the selected frame's display." 2333If DISPLAY is omitted or nil, it defaults to the selected frame's display."
2333 (let ((frame-type (framep-on-display display))) 2334 (let ((frame-type (framep-on-display display)))
2334 (cond 2335 (cond
2335 ((memq frame-type '(x w32 ns haiku pgtk)) 2336 ((memq frame-type '(x w32 ns haiku pgtk android))
2336 (x-display-save-under display)) 2337 (x-display-save-under display))
2337 (t 2338 (t
2338 'not-useful)))) 2339 'not-useful))))
@@ -2345,7 +2346,7 @@ DISPLAY can be a display name or a frame.
2345If DISPLAY is omitted or nil, it defaults to the selected frame's display." 2346If DISPLAY is omitted or nil, it defaults to the selected frame's display."
2346 (let ((frame-type (framep-on-display display))) 2347 (let ((frame-type (framep-on-display display)))
2347 (cond 2348 (cond
2348 ((memq frame-type '(x w32 ns haiku pgtk)) 2349 ((memq frame-type '(x w32 ns haiku pgtk android))
2349 (x-display-planes display)) 2350 (x-display-planes display))
2350 ((eq frame-type 'pc) 2351 ((eq frame-type 'pc)
2351 4) 2352 4)
@@ -2360,7 +2361,7 @@ DISPLAY can be a display name or a frame.
2360If DISPLAY is omitted or nil, it defaults to the selected frame's display." 2361If DISPLAY is omitted or nil, it defaults to the selected frame's display."
2361 (let ((frame-type (framep-on-display display))) 2362 (let ((frame-type (framep-on-display display)))
2362 (cond 2363 (cond
2363 ((memq frame-type '(x w32 ns haiku pgtk)) 2364 ((memq frame-type '(x w32 ns haiku pgtk android))
2364 (x-display-color-cells display)) 2365 (x-display-color-cells display))
2365 ((eq frame-type 'pc) 2366 ((eq frame-type 'pc)
2366 16) 2367 16)
@@ -2377,7 +2378,7 @@ DISPLAY can be a display name or a frame.
2377If DISPLAY is omitted or nil, it defaults to the selected frame's display." 2378If DISPLAY is omitted or nil, it defaults to the selected frame's display."
2378 (let ((frame-type (framep-on-display display))) 2379 (let ((frame-type (framep-on-display display)))
2379 (cond 2380 (cond
2380 ((memq frame-type '(x w32 ns haiku pgtk)) 2381 ((memq frame-type '(x w32 ns haiku pgtk android))
2381 (x-display-visual-class display)) 2382 (x-display-visual-class display))
2382 ((and (memq frame-type '(pc t)) 2383 ((and (memq frame-type '(pc t))
2383 (tty-display-color-p display)) 2384 (tty-display-color-p display))
diff --git a/lisp/image/wallpaper.el b/lisp/image/wallpaper.el
index f083477ddf4..bc76f1a1087 100644
--- a/lisp/image/wallpaper.el
+++ b/lisp/image/wallpaper.el
@@ -432,6 +432,8 @@ See also `wallpaper-default-width'.")
432 432
433;;; wallpaper-set 433;;; wallpaper-set
434 434
435(declare-function x-open-connection "xfns.c")
436
435(defun wallpaper--x-monitor-name () 437(defun wallpaper--x-monitor-name ()
436 "Get the monitor name for `wallpaper-set'. 438 "Get the monitor name for `wallpaper-set'.
437On a graphical display, try using the same monitor as the current 439On a graphical display, try using the same monitor as the current
diff --git a/lisp/loadup.el b/lisp/loadup.el
index 2a9aff4c1fe..16ad531cb68 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -306,6 +306,11 @@
306 (load "term/common-win") 306 (load "term/common-win")
307 (load "term/haiku-win"))) 307 (load "term/haiku-win")))
308 308
309(if (featurep 'android)
310 (progn
311 (load "term/common-win")
312 (load "term/android-win")))
313
309(if (or (eq system-type 'windows-nt) 314(if (or (eq system-type 'windows-nt)
310 (featurep 'w32)) 315 (featurep 'w32))
311 (progn 316 (progn
diff --git a/lisp/net/eww.el b/lisp/net/eww.el
index a8a985b8dea..9ffaa5cd369 100644
--- a/lisp/net/eww.el
+++ b/lisp/net/eww.el
@@ -240,7 +240,7 @@ parameter, and should return the (possibly) transformed URL."
240 :version "29.1") 240 :version "29.1")
241 241
242(defface eww-form-submit 242(defface eww-form-submit
243 '((((type x w32 ns haiku pgtk) (class color)) ; Like default mode line 243 '((((type x w32 ns haiku pgtk android) (class color)) ; Like default mode line
244 :box (:line-width 2 :style released-button) 244 :box (:line-width 2 :style released-button)
245 :background "#808080" :foreground "black")) 245 :background "#808080" :foreground "black"))
246 "Face for eww buffer buttons." 246 "Face for eww buffer buttons."
@@ -248,7 +248,7 @@ parameter, and should return the (possibly) transformed URL."
248 :group 'eww) 248 :group 'eww)
249 249
250(defface eww-form-file 250(defface eww-form-file
251 '((((type x w32 ns haiku pgtk) (class color)) ; Like default mode line 251 '((((type x w32 ns haiku pgtk android) (class color)) ; Like default mode line
252 :box (:line-width 2 :style released-button) 252 :box (:line-width 2 :style released-button)
253 :background "#808080" :foreground "black")) 253 :background "#808080" :foreground "black"))
254 "Face for eww buffer buttons." 254 "Face for eww buffer buttons."
@@ -256,7 +256,7 @@ parameter, and should return the (possibly) transformed URL."
256 :group 'eww) 256 :group 'eww)
257 257
258(defface eww-form-checkbox 258(defface eww-form-checkbox
259 '((((type x w32 ns haiku pgtk) (class color)) ; Like default mode line 259 '((((type x w32 ns haiku pgtk android) (class color)) ; Like default mode line
260 :box (:line-width 2 :style released-button) 260 :box (:line-width 2 :style released-button)
261 :background "lightgrey" :foreground "black")) 261 :background "lightgrey" :foreground "black"))
262 "Face for eww buffer buttons." 262 "Face for eww buffer buttons."
@@ -264,7 +264,7 @@ parameter, and should return the (possibly) transformed URL."
264 :group 'eww) 264 :group 'eww)
265 265
266(defface eww-form-select 266(defface eww-form-select
267 '((((type x w32 ns haiku pgtk) (class color)) ; Like default mode line 267 '((((type x w32 ns haiku pgtk android) (class color)) ; Like default mode line
268 :box (:line-width 2 :style released-button) 268 :box (:line-width 2 :style released-button)
269 :background "lightgrey" :foreground "black")) 269 :background "lightgrey" :foreground "black"))
270 "Face for eww buffer buttons." 270 "Face for eww buffer buttons."
diff --git a/lisp/term/android-win.el b/lisp/term/android-win.el
new file mode 100644
index 00000000000..8aeabee567d
--- /dev/null
+++ b/lisp/term/android-win.el
@@ -0,0 +1,62 @@
1;;; x-win.el --- parse relevant switches and set up for Android -*- lexical-binding:t -*-
2
3;; Copyright (C) 2023 Free Software Foundation, Inc.
4
5;; Author: FSF
6;; Keywords: terminals, i18n, android
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software: you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
22
23;;; Commentary:
24
25;; This file contains the support for initializing the Lisp side of
26;; Android windowing.
27
28;;; Code:
29
30
31(unless (featurep 'android)
32 (error "%s: Loading android-win without having Android"
33 invocation-name))
34
35;; Documentation-purposes only: actually loaded in loadup.el.
36(require 'frame)
37(require 'mouse)
38(require 'fontset)
39(require 'dnd)
40
41(add-to-list 'display-format-alist '(".*" . android))
42
43;; Window system initialization. This is extremely simple because all
44;; initialization is done in android_term_init.
45
46(cl-defmethod window-system-initialization (&context (window-system android)
47 &optional _ignored)
48 "Set up the window system. WINDOW-SYSTEM must be ANDROID.
49DISPLAY is ignored on Android."
50 ;; Just make sure the window system was initialized at startup.
51 (android-get-connection))
52
53(cl-defmethod frame-creation-function (params &context (window-system android))
54 (x-create-frame-with-faces params))
55
56(cl-defmethod handle-args-function (_ignored &context (window-system android))
57 ;; Nothing to do here: Android has no command line to provide
58 ;; arguments on.
59 (ignore))
60
61(provide 'android-win)
62;; android-win.el ends here.
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.
34abs_top_srcdir=@abs_top_srcdir@ 34abs_top_srcdir=@abs_top_srcdir@
35VPATH = $(srcdir) 35VPATH = $(srcdir)
36
37# This is not empty if this is a Makefile that will be copied to
38# xcompile/src.
39XCONFIGURE = @XCONFIGURE@
40
41ifneq ($(XCONFIGURE),)
42vpath %.c := $(srcdir)
43vpath %.h := $(srcdir)
44endif
45
36CC = @CC@ 46CC = @CC@
37CXX = @CXX@ 47CXX = @CXX@
38CFLAGS = @CFLAGS@ 48CFLAGS = @CFLAGS@
@@ -48,6 +58,7 @@ LIBOBJS = @LIBOBJS@
48 58
49lispsource = $(top_srcdir)/lisp 59lispsource = $(top_srcdir)/lisp
50lib = ../lib 60lib = ../lib
61hostlib = $(top_builddir)/lib
51libsrc = ../lib-src 62libsrc = ../lib-src
52etc = ../etc 63etc = ../etc
53oldXMenudir = ../oldXMenu 64oldXMenudir = ../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
327FONT_OBJ=@FONT_OBJ@ 338FONT_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.
330CM_OBJ=@CM_OBJ@ 341CM_OBJ=@CM_OBJ@
331 342
332LIBGPM = @LIBGPM@ 343LIBGPM = @LIBGPM@
@@ -370,6 +381,10 @@ HAIKU_CXX_OBJ = @HAIKU_CXX_OBJ@
370HAIKU_LIBS = @HAIKU_LIBS@ 381HAIKU_LIBS = @HAIKU_LIBS@
371HAIKU_CFLAGS = @HAIKU_CFLAGS@ 382HAIKU_CFLAGS = @HAIKU_CFLAGS@
372 383
384ANDROID_OBJ = @ANDROID_OBJ@
385ANDROID_LIBS = @ANDROID_LIBS@
386ANDROID_CFLAGS = @ANDROID_CFLAGS@
387
373DUMPING=@DUMPING@ 388DUMPING=@DUMPING@
374CHECK_STRUCTS = @CHECK_STRUCTS@ 389CHECK_STRUCTS = @CHECK_STRUCTS@
375HAVE_PDUMPER = @HAVE_PDUMPER@ 390HAVE_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)
415ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) 431ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS)
416ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \ 432ALL_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)
453doc_obj = $(base_obj) $(NS_OBJC_OBJ) 469doc_obj = $(base_obj) $(NS_OBJC_OBJ)
454obj = $(doc_obj) $(HAIKU_CXX_OBJ) 470obj = $(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.
472GMALLOC_OBJ=@GMALLOC_OBJ@ 489GMALLOC_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
664buildobj.h: Makefile 682buildobj.h: Makefile
@@ -719,6 +737,27 @@ ifeq ($(DUMPING),unexec)
719 endif 737 endif
720endif 738endif
721 739
740ifeq ($(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
747libemacs.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
756android-emacs: libemacs.so android-emacs.o
757 $(AM_V_CCLD)$(CC) -o $@ $(ALL_CFLAGS) $(LDFLAGS) \
758 -L. "-l:libemacs.so" android-emacs.o
759endif
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
749mostlyclean: 788mostlyclean:
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
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
26int
27main (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
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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. */
43bool 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
58struct 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
67enum android_fd_table_entry_flags
68 {
69 ANDROID_FD_TABLE_ENTRY_IS_VALID = 1,
70 };
71
72struct 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
85struct android_emacs_pixmap
86{
87 jclass class;
88 jmethodID constructor;
89};
90
91struct android_graphics_point
92{
93 jclass class;
94 jmethodID constructor;
95};
96
97/* The asset manager being used. */
98static AAssetManager *asset_manager;
99
100/* Whether or not Emacs has been initialized. */
101static int emacs_initialized;
102
103/* The path used to store site-lisp. */
104char *android_site_load_path;
105
106/* The path used to store native libraries. */
107char *android_lib_dir;
108
109/* The Android application data directory. */
110static 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. */
115static struct android_fd_table_entry android_table[ANDROID_MAX_ASSET_FD];
116
117/* The Java environment being used for the main thread. */
118JNIEnv *android_java_env;
119
120/* The EmacsGC class. */
121static jclass emacs_gc_class;
122
123/* Various fields. */
124static jfieldID emacs_gc_foreground, emacs_gc_background;
125static jfieldID emacs_gc_function, emacs_gc_clip_rects;
126static jfieldID emacs_gc_clip_x_origin, emacs_gc_clip_y_origin;
127static jfieldID emacs_gc_stipple, emacs_gc_clip_mask;
128static jfieldID emacs_gc_fill_style, emacs_gc_ts_origin_x;
129static jfieldID emacs_gc_ts_origin_y;
130
131/* The constructor and one function. */
132static jmethodID emacs_gc_constructor, emacs_gc_mark_dirty;
133
134/* The Rect class. */
135static jclass android_rect_class;
136
137/* Its constructor. */
138static jmethodID android_rect_constructor;
139
140/* The EmacsService object. */
141static jobject emacs_service;
142
143/* Various methods associated with the EmacsService. */
144static struct android_emacs_service service_class;
145
146/* Various methods associated with the EmacsPixmap class. */
147static struct android_emacs_pixmap pixmap_class;
148
149/* Various methods associated with the Point class. */
150static 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
160struct 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
169struct 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. */
195static volatile int android_pselect_nfds;
196static fd_set *volatile android_pselect_readfds;
197static fd_set *volatile android_pselect_writefds;
198static fd_set *volatile android_pselect_exceptfds;
199static struct timespec *volatile android_pselect_timeout;
200static const sigset_t *volatile android_pselect_sigset;
201
202/* Value of pselect. */
203static int android_pselect_rc;
204
205/* Whether or not pselect finished. */
206static volatile bool android_pselect_completed;
207
208/* The global event queue. */
209static struct android_event_queue event_queue;
210
211/* Semaphore used to signal select completion. */
212static sem_t android_pselect_sem;
213
214static void *
215android_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
268static void
269android_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
283static void
284android_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
332int
333android_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
344void
345android_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
376static void
377android_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
403int
404android_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
459static void *
460android_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
495char *
496android_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
507static const char *
508android_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
522int
523android_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
540int
541android_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
575bool
576android_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
614static int
615android_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
686int
687android_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
791int
792android_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
813JNIEXPORT void JNICALL
814NATIVE_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
919static void
920android_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
973static void
974android_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
1004static void
1005android_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
1034extern JNIEXPORT void JNICALL
1035NATIVE_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
1074extern JNIEXPORT void JNICALL
1075NATIVE_NAME (emacsAbort) (JNIEnv *env, jobject object)
1076{
1077 emacs_abort ();
1078}
1079
1080extern JNIEXPORT void JNICALL
1081NATIVE_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
1099extern JNIEXPORT void JNICALL
1100NATIVE_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
1115extern JNIEXPORT void JNICALL
1116NATIVE_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
1145enum android_handle_type
1146 {
1147 ANDROID_HANDLE_WINDOW,
1148 ANDROID_HANDLE_GCONTEXT,
1149 ANDROID_HANDLE_PIXMAP,
1150 };
1151
1152struct 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. */
1162struct android_handle_entry android_handles[USHRT_MAX];
1163
1164/* The largest handle ID currently known, but subject to
1165 wraparound. */
1166static android_handle max_handle;
1167
1168/* Allocate a new, unused, handle identifier. If Emacs is out of
1169 identifiers, return 0. */
1170
1171static android_handle
1172android_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
1204static void
1205android_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
1248static jobject
1249android_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
1273static jobject
1274android_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
1299static jmethodID android_lookup_method (const char *, const char *,
1300 const char *);
1301
1302void
1303android_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
1325android_window
1326android_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
1391void
1392android_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
1401void
1402android_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
1414static void
1415android_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
1444static void
1445android_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
1528struct android_gc *
1529android_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
1574void
1575android_free_gc (struct android_gc *gc)
1576{
1577 android_destroy_handle (gc->gcontext);
1578 xfree (gc);
1579}
1580
1581void
1582android_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
1672void
1673android_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
1743void
1744android_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
1756static jmethodID
1757android_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
1791void
1792android_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
1804void
1805android_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
1818void
1819android_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
1832void
1833android_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
1848void
1849android_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
1863void
1864android_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
1883void
1884android_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
1947void
1948android_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
1956void
1957android_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
1979android_pixmap
1980android_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
2060void
2061android_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
2069void
2070android_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
2079void
2080android_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
2105void
2106android_free_pixmap (android_pixmap pixmap)
2107{
2108 android_destroy_handle (pixmap);
2109}
2110
2111void
2112android_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
2120void
2121android_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
2174void
2175android_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
2194void
2195android_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
2213void
2214android_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
2233android_pixmap
2234android_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
2289void
2290android_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
2301void
2302android_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
2320struct android_gc *
2321android_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
2328void
2329android_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
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
37extern bool ANDROID_EXPORT android_init_gui;
38extern int ANDROID_EXPORT android_emacs_init (int, char **);
39
40#ifndef ANDROID_STUBIFY
41
42extern int android_select (int, fd_set *, fd_set *, fd_set *,
43 struct timespec *, const sigset_t *);
44
45extern bool android_file_access_p (const char *, int);
46extern int android_open (const char *, int, int);
47extern char *android_user_full_name (struct passwd *);
48extern int android_fstat (int, struct stat *);
49extern int android_fstatat (int, const char *restrict,
50 struct stat *restrict, int);
51extern 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
61extern 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
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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. */
31static ptrdiff_t image_cache_refcount;
32
33#endif
34
35static struct android_display_info *
36android_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
53static struct android_display_info *
54check_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
91Display_Info *
92check_x_display_info (Lisp_Object object)
93{
94 return check_android_display_info (object);
95}
96
97
98
99#ifndef ANDROID_STUBIFY
100
101void
102gamma_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
118bool
119android_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
140static unsigned long
141android_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
154void
155android_implicitly_set_name (struct frame *f, Lisp_Object arg,
156 Lisp_Object oldval)
157{
158
159}
160
161void
162android_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
174static void
175android_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
193void
194android_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
246static void
247android_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
269void
270android_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
325void
326android_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
340void
341android_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
355static void
356android_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
380static void
381android_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
410static void
411android_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
445void
446android_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
475static Lisp_Object
476unwind_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
508static void
509do_unwind_create_frame (Lisp_Object frame)
510{
511 unwind_create_frame (frame);
512}
513
514void
515android_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
555static void
556android_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
579DEFUN ("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
1052DEFUN ("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
1074DEFUN ("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
1096DEFUN ("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
1104DEFUN ("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
1112DEFUN ("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
1126DEFUN ("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
1140DEFUN ("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
1152DEFUN ("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
1171DEFUN ("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
1179DEFUN ("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
1192DEFUN ("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
1205DEFUN ("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
1217DEFUN ("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
1227DEFUN ("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
1242DEFUN ("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
1255DEFUN ("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
1269DEFUN ("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
1282DEFUN ("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
1291DEFUN ("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
1301DEFUN ("android-get-connection", Fandroid_get_connection,
1302 Sandroid_get_connection, 0, 0, 0,
1303 doc: /* Get the connection to the display server.
1304Return the terminal if it exists, else nil.
1305
1306Emacs cannot open a connection to the display server itself under
1307Android, 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
1325DEFUN ("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
1340DEFUN ("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
1354DEFUN ("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
1371static void
1372android_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
1398static void
1399android_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
1408static void
1409android_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
1453static void
1454android_set_cursor_type (struct frame *f, Lisp_Object arg,
1455 Lisp_Object oldval)
1456{
1457 set_frame_cursor_types (f, arg);
1458}
1459
1460static void
1461android_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
1494static void
1495android_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
1519static void
1520android_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
1537static void
1538android_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
1605static void
1606android_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
1614static void
1615android_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
1632static void
1633android_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
1685frame_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
1743void
1744syms_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
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
42struct 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
57struct 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
72struct 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
82struct 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
102struct android_integer
103{
104 jclass class;
105 jmethodID constructor;
106 jmethodID int_value;
107};
108
109struct androidfont_info
110{
111 /* The font pseudo-vector object. */
112 struct font font;
113
114 /* The Java-side font. */
115 jobject object;
116};
117
118struct 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
130struct android_emacs_font_driver font_driver_class;
131
132/* Field and class identifiers associated with the
133 EmacsFontDriver$FontSpec class. */
134
135struct android_emacs_font_spec font_spec_class;
136
137/* Method and class identifiers associated with the Integer class. */
138
139struct android_integer integer_class;
140
141/* Field and class identifiers associated with the
142 EmacsFontDriver$FontMetrics class. */
143
144struct android_emacs_font_metrics font_metrics_class;
145
146/* Field and class identifiers associated with the
147 EmacsFontDriver$FontObject class. */
148
149struct android_emacs_font_object font_object_class;
150
151/* The font cache. */
152
153static Lisp_Object font_cache;
154
155/* The Java-side font driver. */
156
157static 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
164static void
165android_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
218static void
219android_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
258static void
259android_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
293static void
294android_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
324static void
325android_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
369static Lisp_Object
370androidfont_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
378static jobject
379androidfont_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
458static void
459androidfont_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
516static Lisp_Object
517androidfont_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
574static Lisp_Object
575androidfont_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
612static int
613androidfont_draw (struct glyph_string *s, int from, int to,
614 int x, int y, bool with_background)
615{
616 return 0;
617}
618
619static Lisp_Object
620androidfont_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
709static void
710androidfont_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
726static int
727androidfont_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
752static unsigned
753androidfont_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
765static void
766androidfont_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
869static Lisp_Object
870androidfont_list_family (struct frame *f)
871{
872 return Qnil;
873}
874
875struct 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
891static void
892syms_of_androidfont_for_pdumper (void)
893{
894 register_font_driver (&androidfont_driver, NULL);
895}
896
897void
898syms_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
908void
909init_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
940void
941android_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
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or (at
9your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
18
19#ifndef _ANDROID_GUI_H_
20#define _ANDROID_GUI_H_
21
22struct android_char_struct
23{
24 int rbearing;
25 int lbearing;
26 int width;
27 int ascent;
28 int descent;
29};
30
31typedef struct android_char_struct XCharStruct;
32
33typedef unsigned short android_handle;
34
35typedef android_handle android_pixmap, Emacs_Pixmap;
36typedef android_handle android_window, Emacs_Window;
37typedef android_handle android_gcontext, GContext;
38typedef android_handle android_drawable, Drawable;
39
40typedef unsigned int android_time;
41
42struct android_rectangle
43{
44 int x, y;
45 unsigned width, height;
46};
47
48struct android_point
49{
50 int x, y;
51};
52
53/* Keep this in sync with EmacsGC.java! */
54
55enum android_gc_function
56 {
57 ANDROID_GC_COPY = 0,
58 ANDROID_GC_XOR = 1,
59 };
60
61enum 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
75enum android_fill_style
76 {
77 ANDROID_FILL_SOLID = 0,
78 ANDROID_FILL_OPAQUE_STIPPLED = 1,
79 };
80
81enum android_window_value_mask
82 {
83 ANDROID_CW_BACK_PIXEL = (1 << 1),
84 };
85
86struct android_set_window_attributes
87{
88 /* The background pixel. */
89 unsigned long background_pixel;
90};
91
92struct 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
117struct android_gc
118{
119 /* The Java-side handle. */
120 android_gcontext gcontext;
121};
122
123enum android_swap_action
124 {
125 ANDROID_COPIED,
126 };
127
128enum android_shape
129 {
130 ANDROID_CONVEX,
131 };
132
133enum android_coord_mode
134 {
135 ANDROID_COORD_MODE_ORIGIN,
136 };
137
138struct 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. */
149typedef 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. */
194static 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
199enum android_event_type
200 {
201 ANDROID_KEY_PRESS,
202 ANDROID_KEY_RELEASE,
203 ANDROID_CONFIGURE_NOTIFY,
204 };
205
206struct android_any_event
207{
208 enum android_event_type type;
209 android_window window;
210};
211
212struct 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
221struct 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
230union 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
238extern int android_pending (void);
239extern void android_next_event (union android_event *);
240
241extern 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 *);
246extern void android_change_window_attributes (android_window,
247 enum android_window_value_mask,
248 struct
249 android_set_window_attributes *);
250extern void android_set_window_background (android_window, unsigned long);
251extern void android_destroy_window (android_window);
252extern void android_reparent_window (android_window, android_window,
253 int, int);
254extern void android_set_clip_rectangles (struct android_gc *,
255 int, int,
256 struct android_rectangle *,
257 int);
258extern void android_change_gc (struct android_gc *,
259 enum android_gc_value_mask,
260 struct android_gc_values *);
261
262extern void android_clear_window (android_window);
263extern void android_map_window (android_window);
264extern void android_unmap_window (android_window);
265extern void android_resize_window (android_window, unsigned int,
266 unsigned int);
267extern void android_move_window (android_window, int, int);
268extern void android_swap_buffers (struct android_swap_info *, int);
269extern void android_get_gc_values (struct android_gc *,
270 enum android_gc_value_mask,
271 struct android_gc_values *);
272extern void android_set_foreground (struct android_gc *,
273 unsigned long);
274extern void android_fill_rectangle (android_drawable, struct android_gc *,
275 int, int, unsigned int, unsigned int);
276extern android_pixmap android_create_pixmap_from_bitmap_data (char *,
277 unsigned int,
278 unsigned int,
279 unsigned long,
280 unsigned long,
281 unsigned int);
282extern void android_set_clip_mask (struct android_gc *, android_pixmap);
283extern void android_set_fill_style (struct android_gc *,
284 enum android_fill_style);
285extern void android_copy_area (android_drawable, android_drawable,
286 struct android_gc *, int, int,
287 unsigned int, unsigned int, int, int);
288extern void android_free_pixmap (android_drawable);
289
290extern void android_set_background (struct android_gc *, unsigned long);
291extern void android_fill_polygon (android_drawable, struct android_gc *,
292 struct android_point *, int,
293 enum android_shape,
294 enum android_coord_mode);
295extern void android_draw_rectangle (android_drawable, struct android_gc *,
296 int, int, unsigned int, unsigned int);
297extern void android_draw_point (android_window, struct android_gc *,
298 int, int);
299extern void android_draw_line (android_window, struct android_gc *,
300 int, int, int, int);
301extern android_pixmap android_create_pixmap (unsigned int, unsigned int,
302 int);
303extern void android_set_ts_origin (struct android_gc *, int, int);
304extern 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
311extern struct android_gc *android_create_gc (enum android_gc_value_mask,
312 struct android_gc_values *);
313extern 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
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
34struct android_display_info *x_display_list;
35
36
37
38/* Android terminal interface functions. */
39
40#ifndef ANDROID_STUBIFY
41
42enum
43 {
44 ANDROID_EVENT_NORMAL,
45 ANDROID_EVENT_GOTO_OUT,
46 ANDROID_EVENT_DROP,
47 };
48
49static struct frame *
50android_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
73static void
74android_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
82static void
83android_ring_bell (struct frame *f)
84{
85 /* TODO */
86}
87
88static void
89android_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
100static void
101android_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
111static void
112android_update_end (struct frame *f)
113{
114 /* Mouse highlight may be displayed again. */
115 MOUSE_HL_INFO (f)->mouse_face_defer = false;
116}
117
118static void
119show_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
131static void
132android_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
144static int
145handle_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
220static int
221android_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
256static void
257android_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
271static void
272android_buffer_flipping_unblocked_hook (struct frame *f)
273{
274 block_input ();
275 show_back_buffer (f);
276 unblock_input ();
277}
278
279static void
280android_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
290int
291android_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
326bool
327android_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
337void
338android_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
350static void
351android_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
359static Lisp_Object
360android_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
374static void
375android_focus_frame (struct frame *f, bool noactivate)
376{
377 /* TODO */
378}
379
380static void
381android_frame_rehighlight (struct frame *f)
382{
383 /* TODO */
384}
385
386static void
387android_frame_raise_lower (struct frame *f, bool raise_flag)
388{
389 /* TODO */
390}
391
392void
393android_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
401void
402android_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
410static void
411android_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
419static void
420android_fullscreen_hook (struct frame *f)
421{
422 /* TODO */
423}
424
425void
426android_iconify_frame (struct frame *f)
427{
428 /* TODO */
429}
430
431static void
432android_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
448void
449android_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
471static void
472android_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
490static void
491android_set_alpha (struct frame *f)
492{
493 /* TODO */
494}
495
496static Lisp_Object
497android_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
542static bool
543android_bitmap_icon (struct frame *f, Lisp_Object file)
544{
545 /* TODO */
546 return false;
547}
548
549static void
550android_free_pixmap_hook (struct frame *f, Emacs_Pixmap pixmap)
551{
552 android_free_pixmap (pixmap);
553}
554
555void
556android_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
595static void
596android_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
603static void
604android_delete_terminal (struct terminal *terminal)
605{
606 error ("Cannot terminate connection to Android display server");
607}
608
609
610
611/* RIF functions. */
612
613static void
614android_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
660static void
661android_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
669static void
670android_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
681static void
682android_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
696static void
697android_reset_clip_rectangles (struct frame *f, struct android_gc *gc)
698{
699 android_set_clip_mask (gc, ANDROID_NONE);
700}
701
702static void
703android_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
720static void
721android_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
815static void
816android_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
864static void
865android_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
899static void
900android_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
909static void
910android_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
951static void
952android_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
967static void
968android_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
982static void
983android_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
1013static void
1014android_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
1020static void
1021android_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
1058static void
1059android_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
1075static struct android_point
1076android_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
1086static bool
1087android_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
1103static void
1104android_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
1116static void
1117android_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
1236static void
1237android_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
1274static bool
1275android_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
1350static void
1351android_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
1381static void
1382android_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
1415static void
1416android_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
1481static void
1482android_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
1497static void
1498android_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
1587static void
1588android_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
1688static void
1689android_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
1768static void
1769android_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
1877static void
1878android_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
1991static void
1992android_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
2047static void
2048android_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
2094static void
2095android_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
2183static void
2184android_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
2266static void
2267android_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
2615static void
2616android_define_frame_cursor (struct frame *f, Emacs_Cursor cursor)
2617{
2618 /* Not supported, because cursors are not supported on Android. */
2619}
2620
2621static void
2622android_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
2629void
2630android_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
2678static void
2679android_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
2725static void
2726android_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
2827static void
2828android_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
2876static void
2877android_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
2892static void
2893android_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
2961extern frame_parm_handler android_frame_parm_handlers[];
2962
2963#endif /* !ANDROID_STUBIFY */
2964
2965static 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
3001void
3002frame_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
3008char *
3009get_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
3019static struct terminal *
3020android_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
3090void
3091android_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
3137void
3138syms_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
3156void
3157mark_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
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
29struct 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
44struct 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
128struct 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
252struct 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. */
303extern 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
312extern void android_free_gcs (struct frame *);
313extern void android_default_font_parameter (struct frame *, Lisp_Object);
314
315/* Defined in androidterm.c. */
316
317extern void android_term_init (void);
318extern void android_set_window_size (struct frame *, bool, int, int);
319extern void android_iconify_frame (struct frame *);
320extern void android_make_frame_visible (struct frame *);
321extern void android_make_frame_invisible (struct frame *);
322extern void android_free_frame_resources (struct frame *);
323
324extern int android_parse_color (struct frame *, const char *,
325 Emacs_Color *);
326extern bool android_alloc_nearest_color (struct frame *, Emacs_Color *);
327extern void android_query_colors (struct frame *, Emacs_Color *, int);
328extern void android_clear_under_internal_border (struct frame *);
329
330extern void syms_of_androidterm (void);
331extern void mark_androidterm (void);
332
333/* Defined in androidfns.c. */
334
335extern void android_change_tab_bar_height (struct frame *, int);
336extern void android_change_tool_bar_height (struct frame *, int);
337extern void android_set_scroll_bar_default_width (struct frame *);
338extern void android_set_scroll_bar_default_height (struct frame *);
339extern bool android_defined_color (struct frame *, const char *,
340 Emacs_Color *, bool, bool);
341extern void android_implicitly_set_name (struct frame *, Lisp_Object,
342 Lisp_Object);
343extern void android_explicitly_set_name (struct frame *, Lisp_Object,
344 Lisp_Object);
345
346extern void syms_of_androidfns (void);
347
348/* Defined in androidfont.c. */
349
350extern struct font_driver androidfont_driver;
351
352extern void init_androidfont (void);
353extern void syms_of_androidfont (void);
354
355extern 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. */
60typedef struct 67typedef 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
75typedef 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. */
67typedef struct 80typedef struct
68{ 81{
@@ -144,6 +157,13 @@ typedef Emacs_Pixmap Emacs_Pix_Container;
144typedef Emacs_Pixmap Emacs_Pix_Context; 157typedef Emacs_Pixmap Emacs_Pix_Context;
145#endif 158#endif
146 159
160#ifdef HAVE_ANDROID
161#include "androidgui.h"
162typedef struct android_display_info Display_Info;
163typedef Emacs_Pixmap Emacs_Pix_Container;
164typedef 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 *);
3502extern void cancel_mouse_face (struct frame *); 3526extern void cancel_mouse_face (struct frame *);
3503extern bool clear_mouse_face (Mouse_HLInfo *); 3527extern bool clear_mouse_face (Mouse_HLInfo *);
3504extern bool cursor_in_mouse_face_p (struct window *w); 3528extern bool cursor_in_mouse_face_p (struct window *w);
3529#ifndef HAVE_ANDROID
3505extern void tty_draw_row_with_mouse_face (struct window *, struct glyph_row *, 3530extern 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);
3507extern void display_tty_menu_item (const char *, int, int, int, int, bool); 3532extern void display_tty_menu_item (const char *, int, int, int, int, bool);
3533#endif
3508extern struct glyph *x_y_to_hpos_vpos (struct window *, int, int, int *, int *, 3534extern 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 *);
3566ptrdiff_t lookup_image (struct frame *, Lisp_Object, int); 3592ptrdiff_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
3648void gamma_correct (struct frame *, Emacs_Color *); 3674void gamma_correct (struct frame *, Emacs_Color *);
3649#endif 3675#endif
3676#ifdef HAVE_ANDROID
3677extern 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,
5059static bool 5065static bool
5060scrolling (struct frame *frame) 5066scrolling (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
1237int
1238android_emacs_init (int argc, char **argv)
1239#else
1228int 1240int
1229main (int argc, char **argv) 1241main (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.
3472Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix, 3501Anything else (in Emacs 26, the possibilities are: aix, berkeley-unix,
3473hpux, usg-unix-v) indicates some sort of Unix system. */); 3502hpux, 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.
18You should have received a copy of the GNU General Public License 18You should have received a copy of the GNU General Public License
19along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ 19along 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
100extern char *android_site_load_path;
101extern 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;
135static Lisp_Object Vwrite_region_annotation_buffers; 139static Lisp_Object Vwrite_region_annotation_buffers;
136 140
137static Lisp_Object emacs_readlinkat (int, char const *); 141static Lisp_Object emacs_readlinkat (int, char const *);
138static Lisp_Object file_name_directory (Lisp_Object);
139static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, 142static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t,
140 Lisp_Object *, struct coding_system *); 143 Lisp_Object *, struct coding_system *);
141static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, 144static 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
373static Lisp_Object 382Lisp_Object
374file_name_directory (Lisp_Object filename) 383file_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
diff --git a/src/fns.c b/src/fns.c
index eeb65cadf3f..b63f5c49660 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -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
185Lisp_Object
186font_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);
823extern Lisp_Object merge_font_spec (Lisp_Object, Lisp_Object); 823extern Lisp_Object merge_font_spec (Lisp_Object, Lisp_Object);
824 824
825extern Lisp_Object font_make_entity (void); 825extern Lisp_Object font_make_entity (void);
826#ifdef HAVE_ANDROID
827extern Lisp_Object font_make_entity_android (int);
828#endif
826extern Lisp_Object font_make_object (int, Lisp_Object, int); 829extern 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)
828extern Lisp_Object font_build_object (int, Lisp_Object, Lisp_Object, double); 831extern 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.
231See also `frame-live-p'. */) 232See 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
283FRAME defaults to the currently selected frame. 287FRAME 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
1232static struct frame * 1237static struct frame *
1233make_terminal_frame (struct terminal *terminal) 1238make_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
1320DEFUN ("make-terminal-frame", Fmake_terminal_frame, Smake_terminal_frame, 1327DEFUN ("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
1336affects all frames on the same terminal device. */) 1343affects 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
717INLINE void 718INLINE void
718fset_menu_bar_window (struct frame *f, Lisp_Object val) 719fset_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"
180typedef 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
178static void image_disable_image (struct frame *, struct image *); 200static void image_disable_image (struct frame *, struct image *);
179static void image_edge_detection (struct frame *, struct image *, Lisp_Object, 201static 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,
3646static Emacs_Pix_Container 3690static Emacs_Pix_Container
3647image_get_x_image (struct frame *f, struct image *img, bool mask_p) 3691image_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
6397static void 6459static void
6398image_pixmap_draw_cross (struct frame *f, Emacs_Pixmap pixmap, 6460image_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
4733extern Lisp_Object file_name_directory (Lisp_Object);
4729extern char *splice_dir_file (char *, char const *, char const *) 4734extern char *splice_dir_file (char *, char const *, char const *)
4730 ATTRIBUTE_RETURNS_NONNULL; 4735 ATTRIBUTE_RETURNS_NONNULL;
4731extern bool file_name_absolute_p (const char *); 4736extern bool file_name_absolute_p (const char *);
@@ -5063,7 +5068,12 @@ extern void init_random (void);
5063extern void emacs_backtrace (int); 5068extern void emacs_backtrace (int);
5064extern AVOID emacs_abort (void) NO_INLINE; 5069extern AVOID emacs_abort (void) NO_INLINE;
5065extern int emacs_fstatat (int, char const *, void *, int); 5070extern int emacs_fstatat (int, char const *, void *, int);
5071#ifdef HAVE_SYS_STAT_H
5072extern int sys_fstat (int, struct stat *);
5073#endif
5074#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
5066extern int emacs_openat (int, char const *, int, int); 5075extern int emacs_openat (int, char const *, int, int);
5076#endif
5067extern int emacs_open (const char *, int, int); 5077extern int emacs_open (const char *, int, int);
5068extern int emacs_open_noquit (const char *, int, int); 5078extern int emacs_open_noquit (const char *, int, int);
5069extern int emacs_pipe (int[2]); 5079extern 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
5104extern int *char_ins_del_vector; 5115extern int *char_ins_del_vector;
5116#endif
5105extern void syms_of_term (void); 5117extern void syms_of_term (void);
5106extern AVOID fatal (const char *msgid, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); 5118extern 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. */
138extern void tputs (const char *, int, int (*)(int)); 142extern 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
795static void 800static 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
805void 811void
806request_sigio (void) 812request_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. */
976static void 984static void
977widen_foreground_group (int fd) 985widen_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
1917static bool 1937static bool
1918init_sigsegv (void) 1938init_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
1925static void 1947static 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
2328emacs_fstatat (int dirfd, char const *filename, void *st, int flags) 2357emacs_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
2336static int 2374static int
2337sys_openat (int dirfd, char const *file, int oflags, int mode) 2375sys_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
2390int
2391sys_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
2358int 2410int
2359emacs_openat (int dirfd, char const *file, int oflags, int mode) 2411emacs_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
2370int 2424int
2371emacs_open (char const *file, int oflags, int mode) 2425emacs_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
2439static int 2512static 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)
2472int 2547int
2473emacs_close (int fd) 2548emacs_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)
2729void 2812void
2730close_output_streams (void) 2813close_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
65static void tty_set_scroll_region (struct frame *f, int start, int stop); 67static void tty_set_scroll_region (struct frame *f, int start, int stop);
66static void turn_on_face (struct frame *, int face_id); 68static void turn_on_face (struct frame *, int face_id);
67static void turn_off_face (struct frame *, int face_id); 69static void turn_off_face (struct frame *, int face_id);
@@ -73,11 +75,15 @@ static void clear_tty_hooks (struct terminal *terminal);
73static void set_tty_hooks (struct terminal *terminal); 75static void set_tty_hooks (struct terminal *terminal);
74static void dissociate_if_controlling_tty (int fd); 76static void dissociate_if_controlling_tty (int fd);
75static void delete_tty (struct terminal *); 77static void delete_tty (struct terminal *);
78
79#endif
80
76static AVOID maybe_fatal (bool, struct terminal *, const char *, const char *, 81static 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);
79static AVOID vfatal (const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0); 84static 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
122static int max_frame_cols; 132static 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;
133static int last_mouse_x, last_mouse_y; 145static 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
138static void 152static 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
737unsigned char *
738encode_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
1046string_cost (const char *str) 1073string_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
1058string_cost_one_line (const char *str) 1087string_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
1070per_line_cost (const char *str) 1101per_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
1150void 1185void
1151calculate_costs (struct frame *frame) 1186calculate_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
1211struct fkey_table { 1248struct 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. */
1523void 1566void
1524tty_append_glyph (struct it *it) 1567tty_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)
1549void 1593void
1550produce_glyphs (struct it *it) 1594produce_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)
2027bool 2076bool
2028tty_capable_p (struct tty_display_info *tty, unsigned int caps) 2077tty_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
2191char * 2244char *
2192tty_type_name (Lisp_Object terminal) 2245tty_type_name (Lisp_Object terminal)
@@ -2278,6 +2331,7 @@ suspended.
2278A suspended tty may be resumed by calling `resume-tty' on it. */) 2331A 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
2337frame's terminal). */) 2395frame'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
2403DEFUN ("tty--set-output-buffer-size", Ftty__set_output_buffer_size, 2469DEFUN ("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. */
2449void 2517void
@@ -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
3863static void 3938static 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
3966struct terminal * 4050struct terminal *
3967init_tty (const char *name, const char *terminal_type, bool must_succeed) 4051init_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
4495static void 4592static void
@@ -4547,6 +4644,8 @@ delete_tty (struct terminal *terminal)
4547 xfree (tty); 4644 xfree (tty);
4548} 4645}
4549 4646
4647#endif
4648
4550void 4649void
4551syms_of_term (void) 4650syms_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
935extern struct terminal *decode_live_terminal (Lisp_Object); 941extern 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 =
32AM_V_GLOBALS = 32AM_V_GLOBALS =
33AM_V_NO_PD = 33AM_V_NO_PD =
34AM_V_RC = 34AM_V_RC =
35AM_V_JAVAC =
36AM_V_DX =
37AM_V_AAPT =
38AM_V_ZIPALIGN =
35else 39else
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 $@)
76AM_V_GLOBALS = @$(info $ GEN globals.h) 80AM_V_GLOBALS = @$(info $ GEN globals.h)
77AM_V_NO_PD = --no-print-directory 81AM_V_NO_PD = --no-print-directory
78AM_V_RC = @$(info $ RC $@) 82AM_V_RC = @$(info $ RC $@)
83
84# These are used for the Android port.
85AM_V_JAVAC = @$(info $ JAVAC $@)
86AM_V_DX = @$(info $ DX $@)
79endif 87endif
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. */
26435static void 26444static void
26436deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from) 26445deep_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
618static struct android_gc *
619x_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
639static void
640x_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 ();
diff --git a/xcompile/Makefile.in b/xcompile/Makefile.in
new file mode 100644
index 00000000000..a63dbc2bb8b
--- /dev/null
+++ b/xcompile/Makefile.in
@@ -0,0 +1,209 @@
1### @configure_input@
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
10# (at 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
20top_srcdir = @top_srcdir@
21top_builddir = @top_builddir@
22
23# Cross-compiling Emacs for Android.
24
25# The cross compiled binaries are built by having ``variant''
26# Makefiles generated at configure-time. First,
27# $(top_builddir)/src/Makefile.android,
28# $(top_builddir)/lib/Makefile.android,
29# $(top_builddir)/lib/gnulib.mk.android and
30# $(top_builddir)/lib-src/Makefile.android are copied to their usual
31# locations in this directory.
32
33# Finally, the following commands are executed in order, to produce
34# libgnu.a, various binaries in lib-src, and src/aemacs:
35# make -C lib libgnu.a
36# make -C lib-src src/aemacs
37# make -C src aemacs
38
39# This is possibly the ugliest Makefile ever written!
40
41LIB_SRCDIR = $(realpath $(top_srcdir)/lib)
42LIB_TOP_SRCDIR = $(realpath $(top_srcdir))
43
44SRC_SRCDIR = $(realpath $(top_srcdir)/src)
45SRC_TOP_SRCDIR = $(realpath $(top_srcdir))
46
47LIB_SRC_SRCDIR = $(realpath $(top_srcdir)/lib-src)
48LIB_SRC_TOP_SRCDIR = $(realpath $(top_src))
49
50# This is a list of binaries to build and install in lib-src.
51
52LIBSRC_BINARIES = lib-src/etags lib-src/ctags lib-src/emacsclient \
53 lib-src/ebrowse lib-src/hexl lib-src/movemail
54
55CLEAN_SUBDIRS=lib src lib-src
56
57.PHONY: all
58all: lib/libgnu.a src/libemacs.so src/android-emacs $(LIBSRC_BINARIES)
59
60# This Makefile relies on builddir and top_builddir being relative
61# paths in *.android.
62
63# This file is used to trick lib/gnulib.mk, it is not actually useful.
64config.status:
65 touch config.status
66
67src/verbose.mk: verbose.mk.android
68 mkdir -p src
69 cp -f verbose.mk.android src/verbose.mk
70
71UGLY_HOST_HEADERS = dirent.h stdlib.h sys/random.h limits.h \
72 string.h signal.h time.h inttypes.h assert.h \
73 stdint.h unistd.h stdlib.h sys/types.h sys/time.h \
74 sys/stat.h getopt.h fcntl.h sys/select.h alloca.h \
75 stdio.h sys/random.h
76
77# Gnulib, make-fingerprint and make-docfile must be built before
78# entering any of the rules below, or they will get the Android
79# versions of many headers.
80
81.PHONY: $(top_builddir)/lib/libgnu.a
82$(top_builddir)/lib/libgnu.a:
83 + make -C $(top_builddir)/lib libgnu.a
84
85.PHONY: $(top_builddir)/lib-src/make-fingerprint
86$(top_builddir)/lib-src/make-fingerprint:
87 make -C $(top_builddir)/lib-src make-fingerprint
88
89.PHONY: $(top_builddir)/lib-src/make-docfile
90$(top_builddir)/lib-src/make-docfile:
91 make -C $(top_builddir)/lib-src make-docfile
92
93PRE_BUILD_DEPS=$(top_builddir)/lib/libgnu.a \
94 $(top_builddir)/lib-src/make-fingerprint \
95 $(top_builddir)/lib-src/make-docfile
96
97.PHONY: lib/libgnu.a
98lib/libgnu.a: src/verbose.mk config.status $(PRE_BUILD_DEPS)
99 mkdir -p lib/deps lib/deps/malloc
100# Temporarily move config.h to config.h.bak and config.h.android to
101# config.h
102 cp -f -p $(top_builddir)/src/config.h.android lib/config.h
103# And the Makefiles.
104 cp -f -p $(top_builddir)/lib/gnulib.mk.android lib/gnulib.mk
105 cp -f -p $(top_builddir)/lib/Makefile.android lib/Makefile
106# Next, move srcdir and top_srcdir in the Makefiles copied.
107 sed -i 's/srcdir =.*$$/srcdir = $(subst /,\/,$(LIB_SRCDIR))/g' lib/Makefile
108 sed -i 's/top_srcdir =.*$$/top_srcdir = $(subst /,\/,$(LIB_TOP_SRCDIR))/g' \
109 lib/Makefile
110 sed -i 's/srcdir =.*$$/srcdir = $(subst /,\/,$(LIB_SRCDIR))/g' lib/gnulib.mk
111# Ugly hack: hide some troublesome headers in $(top_builddir)/lib
112# while building lib. Otherwise, they will end up overriding the
113# system headers used on Android through #include_next and cause
114# trouble.
115 mkdir -p sys
116 for ugly_header in $(UGLY_HOST_HEADERS); do \
117 if [ -e "$(top_builddir)/lib/$$ugly_header" ]; then \
118 mv -f $(top_builddir)/lib/$$ugly_header $$ugly_header.bak; \
119 fi \
120 done
121# And make libgnu.a. Restore config.h if it fails.
122 -make -C lib libgnu.a
123# Move the hiden headers back
124 for ugly_header in $(UGLY_HOST_HEADERS); do \
125 if [ -e "$$ugly_header.bak" ]; then \
126 mv -f $$ugly_header.bak $(top_builddir)/lib/$$ugly_header; \
127 fi \
128 done
129
130src/Makefile src/config.h &: $(top_builddir)/src/config.h.android \
131 $(top_builddir)/src/Makefile.android $(PRE_BUILD_DEPS)
132 mkdir -p src src/deps
133# Copy config.h to src/
134 cp -f -p $(top_builddir)/src/config.h.android src/config.h
135# And the Makefile.
136 cp -f -p $(top_builddir)/src/Makefile.android src/Makefile
137# Next, edit srcdir and top_srcdir to the right location.
138 sed -i 's/srcdir =.*$$/srcdir = $(subst /,\/,$(SRC_SRCDIR))/g' src/Makefile
139 sed -i 's/top_srcdir =.*$$/top_srcdir = $(subst /,\/,$(LIB_TOP_SRCDIR))/g' \
140 src/Makefile
141# Edit references to ../admin/unidata to read ../../admin/unidata.
142 sed -i 's/\.\.\/admin\/unidata/..\/..\/admin\/unidata/g' src/Makefile
143 sed -i 's/\.\.\/admin\/charsets/..\/..\/admin\/charsets/g' src/Makefile
144# Next, edit libsrc to the location at top_srcdir! It is important
145# that src/Makefile uses the binaries there, instead of any
146# cross-compiled binaries at ./lib-src.
147 sed -i 's/libsrc =.*$$/libsrc = \.\.\/\.\.\/lib-src/g' src/Makefile
148
149.PHONY: src/android-emacs src/libemacs.so
150src/android-emacs src/libemacs.so &: src/Makefile src/config.h \
151 src/verbose.mk lib/libgnu.a $(PRE_BUILD_DEPS)
152# Ugly hack: hide some troublesome headers in $(top_builddir)/lib
153# while building lib. Otherwise, they will end up overriding the
154# system headers used on Android through #include_next and cause
155# trouble.
156 mkdir -p sys
157 for ugly_header in $(UGLY_HOST_HEADERS); do \
158 if [ -e "$(top_builddir)/lib/$$ugly_header" ]; then \
159 mv -f $(top_builddir)/lib/$$ugly_header $$ugly_header.bak; \
160 fi \
161 done
162# Finally, go into src and make
163 +make -C src android-emacs libemacs.so
164# Move the hidden headers back
165 for ugly_header in $(UGLY_HOST_HEADERS); do \
166 if [ -e "$$ugly_header.bak" ]; then \
167 mv -f $$ugly_header.bak $(top_builddir)/lib/$$ugly_header; \
168 fi \
169 done
170
171lib-src/Makefile: $(top_builddir)/lib-src/Makefile.android
172 mkdir -p lib-src
173 cp -f -p $< $@
174
175.PHONY: $(LIBSRC_BINARIES)
176$(LIBSRC_BINARIES) &: src/verbose.mk $(top_builddir)/$@ lib/libgnu.a \
177 src/config.h lib-src/Makefile $(PRE_BUILD_DEPS)
178 mkdir -p src lib-src
179# Next, edit srcdir and top_srcdir to the right location.
180 sed -i 's/srcdir=.*$$/srcdir = $(subst /,\/,$(LIB_SRC_SRCDIR))/g' \
181 lib-src/Makefile
182 sed -i 's/top_srcdir=.*$$/top_srcdir = $(subst /,\/,$(LIB_SRC_TOP_SRCDIR))/g' \
183 lib-src/Makefile
184# Edit out SCRIPTS, it interferes with the build.
185 sed -i 's/^SCRIPTS=.*$$/SCRIPTS=/g' lib-src/Makefile
186# Ugly hack: hide some troublesome headers in $(top_builddir)/lib
187# while building lib. Otherwise, they will end up overriding the
188# system headers used on Android through #include_next and cause
189# trouble.
190 mkdir -p sys
191 for ugly_header in $(UGLY_HOST_HEADERS); do \
192 if [ -e "$(top_builddir)/lib/$$ugly_header" ]; then \
193 mv -f $(top_builddir)/lib/$$ugly_header $$ugly_header.bak; \
194 fi \
195 done
196# Finally, go into lib-src and make everything being built
197 +make -C lib-src $(foreach bin,$(LIBSRC_BINARIES),$(notdir $(bin)))
198# Move the hidden headers back
199 for ugly_header in $(UGLY_HOST_HEADERS); do \
200 if [ -e "$$ugly_header.bak" ]; then \
201 mv -f $$ugly_header.bak $(top_builddir)/lib/$$ugly_header; \
202 fi \
203 done
204
205.PHONY: clean maintainer-clean
206clean:
207 rm -rf $(CLEAN_SUBDIRS) *.bak sys
208
209maintainer-clean: clean
diff --git a/xcompile/README b/xcompile/README
new file mode 100644
index 00000000000..a631b978dae
--- /dev/null
+++ b/xcompile/README
@@ -0,0 +1,7 @@
1This directory holds Makefiles and other required assets to build an
2Emacs binary independently for another toolchain, which is currently
3required when building for Android.
4
5The files here are extremely ugly, and contain rules that cannot be
6interrupted without leaving the build tree in an unsafe state. At
7some point that should be fixed!
diff --git a/xcompile/langinfo.h b/xcompile/langinfo.h
new file mode 100644
index 00000000000..b296ba8db80
--- /dev/null
+++ b/xcompile/langinfo.h
@@ -0,0 +1,20 @@
1/* Replacement langinfo.h file for building GNU Emacs on Android.
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20#define nl_langinfo(ignore) "ASCII"